aboutsummaryrefslogtreecommitdiff
path: root/hw/misc
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2025-02-21 07:14:03 +0800
committerStefan Hajnoczi <stefanha@redhat.com>2025-02-21 07:14:03 +0800
commitf41af4c5857b6983766aaffc041580ff170d0679 (patch)
tree9d79ee877ba0cf60f69ea761278ec925d6986d81 /hw/misc
parent40efe733e10cc00e4fb4f9f5790a28e744e63c62 (diff)
parent1c3169179b8242866316108386800379c4e22974 (diff)
downloadqemu-f41af4c5857b6983766aaffc041580ff170d0679.zip
qemu-f41af4c5857b6983766aaffc041580ff170d0679.tar.gz
qemu-f41af4c5857b6983766aaffc041580ff170d0679.tar.bz2
Merge tag 'pull-target-arm-20250220' of https://git.linaro.org/people/pmaydell/qemu-arm into staging
target-arm queue: * Fix some incorrect syndrome values in various sysreg traps * Clean up sysreg trap code to avoid similar future bugs * Make boards/SoCs using a9mpcore and a15mpcore objects specify number of GIC interrupts explicitly * Kconfig: Extract CONFIG_USB_CHIPIDEA from CONFIG_IMX * target/arm: Use uint32_t in t32_expandimm_imm() * New board model: NPCM845 Evaluation board "npcm845-evb" # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAme3Vk8ZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3t8QD/48yOUtFwUMFrwbbszK5rss # Ghhtk0ylKIxPQirgzjLUNq4hV2MZEtdmyiqaEllvA0aS839oWhFW0hbsGmoL/TVF # tqXVP3Y1dMubmNHCGcgiFqaxaInnNSC9S1ALiEm5a37g519706WLXPVLqJJ9t31b # uWHKT1hqxstzWSExhGrEkSEghcgN3u1KyCz0zyq9bk/F3OFWZfHNH6JqutQX18Ua # 5HtcD1Pum6WjayBc3y4AYVYH4xyQclY7LPR+zKNf2d5GuZ+J6MlXMyfCuE2/J//m # wHAtAoeuFhi/HFHR4vQP4L7HrhFrECbjfWha85F/rmiOAo6LnbICyPt4tAPe5So3 # FCtSHfht9ToulBqULE+F/AWVCdt8UeDRgOANSHFsMkxYiUK8QpMv8A2AtwJUqiMp # WbAzw31f6SgANgFQObhoRNE3QyX8V53ZJAsPhDooTxwMiglqVTM3Xux8W2zz9FdU # BTwCy23efBqKf4RWfeHjAXctGshePI1mTBJmvEKG5G5ligMNeg7ZiQqqfRVBagc/ # gpsQKNjpN9MVVds3thUvMCYO/9NOeeAtcVA2vW7qf7HrYaM72UngCPWjhNfAj/9I # 9hxgqEnKC6qoD/zMyFv+XwqNlL1PuD79rbvN8TWFd/f8iBIYOY6WVEYmsi7WGugI # WzYI93RqFaQhrpyHDcRVGw== # =djUd # -----END PGP SIGNATURE----- # gpg: Signature made Fri 21 Feb 2025 00:20:31 HKT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [full] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [unknown] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20250220' of https://git.linaro.org/people/pmaydell/qemu-arm: (41 commits) docs/system/arm: Add Description for NPCM8XX SoC hw/arm: Add NPCM845 Evaluation board hw/arm: Add NPCM8XX SoC hw/net: Add NPCM8XX PCS Module hw/misc: Support NPCM8XX CLK Module Registers hw/misc: Add nr_regs and cold_reset_values to NPCM CLK hw/misc: Move NPCM7XX CLK to NPCM CLK hw/misc: Rename npcm7xx_clk to npcm_clk hw/misc: Support 8-bytes memop in NPCM GCR module hw/misc: Store DRAM size in NPCM8XX GCR Module hw/misc: Add support for NPCM8XX GCR hw/misc: Add nr_regs and cold_reset_values to NPCM GCR hw/misc: Move NPCM7XX GCR to NPCM GCR hw/misc: Rename npcm7xx_gcr to npcm_gcr hw/ssi: Make flash size a property in NPCM7XX FIU pc-bios: Add NPCM8XX vBootrom roms: Update vbootrom to 1287b6e target/arm: Use uint32_t in t32_expandimm_imm() Kconfig: Extract CONFIG_USB_CHIPIDEA from CONFIG_IMX hw/cpu/arm_mpcore: Remove default values for GIC external IRQs ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'hw/misc')
-rw-r--r--hw/misc/meson.build4
-rw-r--r--hw/misc/npcm7xx_gcr.c264
-rw-r--r--hw/misc/npcm_clk.c (renamed from hw/misc/npcm7xx_clk.c)235
-rw-r--r--hw/misc/npcm_gcr.c482
-rw-r--r--hw/misc/trace-events12
5 files changed, 670 insertions, 327 deletions
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 55f4935..edd36a3 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -69,8 +69,8 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx_rngc.c',
))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
- 'npcm7xx_clk.c',
- 'npcm7xx_gcr.c',
+ 'npcm_clk.c',
+ 'npcm_gcr.c',
'npcm7xx_mft.c',
'npcm7xx_pwm.c',
'npcm7xx_rng.c',
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
deleted file mode 100644
index 07464a4..0000000
--- a/hw/misc/npcm7xx_gcr.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Nuvoton NPCM7xx System Global Control Registers.
- *
- * Copyright 2020 Google LLC
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include "qemu/osdep.h"
-
-#include "hw/misc/npcm7xx_gcr.h"
-#include "hw/qdev-properties.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-#include "qemu/cutils.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qemu/units.h"
-
-#include "trace.h"
-
-#define NPCM7XX_GCR_MIN_DRAM_SIZE (128 * MiB)
-#define NPCM7XX_GCR_MAX_DRAM_SIZE (2 * GiB)
-
-enum NPCM7xxGCRRegisters {
- NPCM7XX_GCR_PDID,
- NPCM7XX_GCR_PWRON,
- NPCM7XX_GCR_MFSEL1 = 0x0c / sizeof(uint32_t),
- NPCM7XX_GCR_MFSEL2,
- NPCM7XX_GCR_MISCPE,
- NPCM7XX_GCR_SPSWC = 0x038 / sizeof(uint32_t),
- NPCM7XX_GCR_INTCR,
- NPCM7XX_GCR_INTSR,
- NPCM7XX_GCR_HIFCR = 0x050 / sizeof(uint32_t),
- NPCM7XX_GCR_INTCR2 = 0x060 / sizeof(uint32_t),
- NPCM7XX_GCR_MFSEL3,
- NPCM7XX_GCR_SRCNT,
- NPCM7XX_GCR_RESSR,
- NPCM7XX_GCR_RLOCKR1,
- NPCM7XX_GCR_FLOCKR1,
- NPCM7XX_GCR_DSCNT,
- NPCM7XX_GCR_MDLR,
- NPCM7XX_GCR_SCRPAD3,
- NPCM7XX_GCR_SCRPAD2,
- NPCM7XX_GCR_DAVCLVLR = 0x098 / sizeof(uint32_t),
- NPCM7XX_GCR_INTCR3,
- NPCM7XX_GCR_VSINTR = 0x0ac / sizeof(uint32_t),
- NPCM7XX_GCR_MFSEL4,
- NPCM7XX_GCR_CPBPNTR = 0x0c4 / sizeof(uint32_t),
- NPCM7XX_GCR_CPCTL = 0x0d0 / sizeof(uint32_t),
- NPCM7XX_GCR_CP2BST,
- NPCM7XX_GCR_B2CPNT,
- NPCM7XX_GCR_CPPCTL,
- NPCM7XX_GCR_I2CSEGSEL,
- NPCM7XX_GCR_I2CSEGCTL,
- NPCM7XX_GCR_VSRCR,
- NPCM7XX_GCR_MLOCKR,
- NPCM7XX_GCR_SCRPAD = 0x013c / sizeof(uint32_t),
- NPCM7XX_GCR_USB1PHYCTL,
- NPCM7XX_GCR_USB2PHYCTL,
- NPCM7XX_GCR_REGS_END,
-};
-
-static const uint32_t cold_reset_values[NPCM7XX_GCR_NR_REGS] = {
- [NPCM7XX_GCR_PDID] = 0x04a92750, /* Poleg A1 */
- [NPCM7XX_GCR_MISCPE] = 0x0000ffff,
- [NPCM7XX_GCR_SPSWC] = 0x00000003,
- [NPCM7XX_GCR_INTCR] = 0x0000035e,
- [NPCM7XX_GCR_HIFCR] = 0x0000004e,
- [NPCM7XX_GCR_INTCR2] = (1U << 19), /* DDR initialized */
- [NPCM7XX_GCR_RESSR] = 0x80000000,
- [NPCM7XX_GCR_DSCNT] = 0x000000c0,
- [NPCM7XX_GCR_DAVCLVLR] = 0x5a00f3cf,
- [NPCM7XX_GCR_SCRPAD] = 0x00000008,
- [NPCM7XX_GCR_USB1PHYCTL] = 0x034730e4,
- [NPCM7XX_GCR_USB2PHYCTL] = 0x034730e4,
-};
-
-static uint64_t npcm7xx_gcr_read(void *opaque, hwaddr offset, unsigned size)
-{
- uint32_t reg = offset / sizeof(uint32_t);
- NPCM7xxGCRState *s = opaque;
-
- if (reg >= NPCM7XX_GCR_NR_REGS) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
- __func__, offset);
- return 0;
- }
-
- trace_npcm7xx_gcr_read(offset, s->regs[reg]);
-
- return s->regs[reg];
-}
-
-static void npcm7xx_gcr_write(void *opaque, hwaddr offset,
- uint64_t v, unsigned size)
-{
- uint32_t reg = offset / sizeof(uint32_t);
- NPCM7xxGCRState *s = opaque;
- uint32_t value = v;
-
- trace_npcm7xx_gcr_write(offset, value);
-
- if (reg >= NPCM7XX_GCR_NR_REGS) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
- __func__, offset);
- return;
- }
-
- switch (reg) {
- case NPCM7XX_GCR_PDID:
- case NPCM7XX_GCR_PWRON:
- case NPCM7XX_GCR_INTSR:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
- __func__, offset);
- return;
-
- case NPCM7XX_GCR_RESSR:
- case NPCM7XX_GCR_CP2BST:
- /* Write 1 to clear */
- value = s->regs[reg] & ~value;
- break;
-
- case NPCM7XX_GCR_RLOCKR1:
- case NPCM7XX_GCR_MDLR:
- /* Write 1 to set */
- value |= s->regs[reg];
- break;
- };
-
- s->regs[reg] = value;
-}
-
-static const struct MemoryRegionOps npcm7xx_gcr_ops = {
- .read = npcm7xx_gcr_read,
- .write = npcm7xx_gcr_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- },
-};
-
-static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type)
-{
- NPCM7xxGCRState *s = NPCM7XX_GCR(obj);
-
- QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
-
- memcpy(s->regs, cold_reset_values, sizeof(s->regs));
- s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
- s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
- s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3;
-}
-
-static void npcm7xx_gcr_realize(DeviceState *dev, Error **errp)
-{
- ERRP_GUARD();
- NPCM7xxGCRState *s = NPCM7XX_GCR(dev);
- uint64_t dram_size;
- Object *obj;
-
- obj = object_property_get_link(OBJECT(dev), "dram-mr", errp);
- if (!obj) {
- error_prepend(errp, "%s: required dram-mr link not found: ", __func__);
- return;
- }
- dram_size = memory_region_size(MEMORY_REGION(obj));
- if (!is_power_of_2(dram_size) ||
- dram_size < NPCM7XX_GCR_MIN_DRAM_SIZE ||
- dram_size > NPCM7XX_GCR_MAX_DRAM_SIZE) {
- g_autofree char *sz = size_to_str(dram_size);
- g_autofree char *min_sz = size_to_str(NPCM7XX_GCR_MIN_DRAM_SIZE);
- g_autofree char *max_sz = size_to_str(NPCM7XX_GCR_MAX_DRAM_SIZE);
- error_setg(errp, "%s: unsupported DRAM size %s", __func__, sz);
- error_append_hint(errp,
- "DRAM size must be a power of two between %s and %s,"
- " inclusive.\n", min_sz, max_sz);
- return;
- }
-
- /* Power-on reset value */
- s->reset_intcr3 = 0x00001002;
-
- /*
- * The GMMAP (Graphics Memory Map) field is used by u-boot to detect the
- * DRAM size, and is normally initialized by the boot block as part of DRAM
- * training. However, since we don't have a complete emulation of the
- * memory controller and try to make it look like it has already been
- * initialized, the boot block will skip this initialization, and we need
- * to make sure this field is set correctly up front.
- *
- * WARNING: some versions of u-boot only looks at bits 8 and 9, so 2 GiB of
- * DRAM will be interpreted as 128 MiB.
- *
- * https://github.com/Nuvoton-Israel/u-boot/blob/2aef993bd2aafeb5408dbaad0f3ce099ee40c4aa/board/nuvoton/poleg/poleg.c#L244
- */
- s->reset_intcr3 |= ctz64(dram_size / NPCM7XX_GCR_MIN_DRAM_SIZE) << 8;
-}
-
-static void npcm7xx_gcr_init(Object *obj)
-{
- NPCM7xxGCRState *s = NPCM7XX_GCR(obj);
-
- memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
- TYPE_NPCM7XX_GCR, 4 * KiB);
- sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
-}
-
-static const VMStateDescription vmstate_npcm7xx_gcr = {
- .name = "npcm7xx-gcr",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, NPCM7xxGCRState, NPCM7XX_GCR_NR_REGS),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static const Property npcm7xx_gcr_properties[] = {
- DEFINE_PROP_UINT32("disabled-modules", NPCM7xxGCRState, reset_mdlr, 0),
- DEFINE_PROP_UINT32("power-on-straps", NPCM7xxGCRState, reset_pwron, 0),
-};
-
-static void npcm7xx_gcr_class_init(ObjectClass *klass, void *data)
-{
- ResettableClass *rc = RESETTABLE_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- QEMU_BUILD_BUG_ON(NPCM7XX_GCR_REGS_END > NPCM7XX_GCR_NR_REGS);
-
- dc->desc = "NPCM7xx System Global Control Registers";
- dc->realize = npcm7xx_gcr_realize;
- dc->vmsd = &vmstate_npcm7xx_gcr;
- rc->phases.enter = npcm7xx_gcr_enter_reset;
-
- device_class_set_props(dc, npcm7xx_gcr_properties);
-}
-
-static const TypeInfo npcm7xx_gcr_info = {
- .name = TYPE_NPCM7XX_GCR,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(NPCM7xxGCRState),
- .instance_init = npcm7xx_gcr_init,
- .class_init = npcm7xx_gcr_class_init,
-};
-
-static void npcm7xx_gcr_register_type(void)
-{
- type_register_static(&npcm7xx_gcr_info);
-}
-type_init(npcm7xx_gcr_register_type);
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm_clk.c
index 46f907b..d1f2975 100644
--- a/hw/misc/npcm7xx_clk.c
+++ b/hw/misc/npcm_clk.c
@@ -1,5 +1,5 @@
/*
- * Nuvoton NPCM7xx Clock Control Registers.
+ * Nuvoton NPCM7xx/8xx Clock Control Registers.
*
* Copyright 2020 Google LLC
*
@@ -16,7 +16,7 @@
#include "qemu/osdep.h"
-#include "hw/misc/npcm7xx_clk.h"
+#include "hw/misc/npcm_clk.h"
#include "hw/timer/npcm7xx_timer.h"
#include "hw/qdev-clock.h"
#include "migration/vmstate.h"
@@ -72,7 +72,57 @@ enum NPCM7xxCLKRegisters {
NPCM7XX_CLK_AHBCKFI,
NPCM7XX_CLK_SECCNT,
NPCM7XX_CLK_CNTR25M,
- NPCM7XX_CLK_REGS_END,
+};
+
+enum NPCM8xxCLKRegisters {
+ NPCM8XX_CLK_CLKEN1,
+ NPCM8XX_CLK_CLKSEL,
+ NPCM8XX_CLK_CLKDIV1,
+ NPCM8XX_CLK_PLLCON0,
+ NPCM8XX_CLK_PLLCON1,
+ NPCM8XX_CLK_SWRSTR,
+ NPCM8XX_CLK_IPSRST1 = 0x20 / sizeof(uint32_t),
+ NPCM8XX_CLK_IPSRST2,
+ NPCM8XX_CLK_CLKEN2,
+ NPCM8XX_CLK_CLKDIV2,
+ NPCM8XX_CLK_CLKEN3,
+ NPCM8XX_CLK_IPSRST3,
+ NPCM8XX_CLK_WD0RCR,
+ NPCM8XX_CLK_WD1RCR,
+ NPCM8XX_CLK_WD2RCR,
+ NPCM8XX_CLK_SWRSTC1,
+ NPCM8XX_CLK_SWRSTC2,
+ NPCM8XX_CLK_SWRSTC3,
+ NPCM8XX_CLK_TIPRSTC,
+ NPCM8XX_CLK_PLLCON2,
+ NPCM8XX_CLK_CLKDIV3,
+ NPCM8XX_CLK_CORSTC,
+ NPCM8XX_CLK_PLLCONG,
+ NPCM8XX_CLK_AHBCKFI,
+ NPCM8XX_CLK_SECCNT,
+ NPCM8XX_CLK_CNTR25M,
+ /* Registers unique to NPCM8XX SoC */
+ NPCM8XX_CLK_CLKEN4,
+ NPCM8XX_CLK_IPSRST4,
+ NPCM8XX_CLK_BUSTO,
+ NPCM8XX_CLK_CLKDIV4,
+ NPCM8XX_CLK_WD0RCRB,
+ NPCM8XX_CLK_WD1RCRB,
+ NPCM8XX_CLK_WD2RCRB,
+ NPCM8XX_CLK_SWRSTC1B,
+ NPCM8XX_CLK_SWRSTC2B,
+ NPCM8XX_CLK_SWRSTC3B,
+ NPCM8XX_CLK_TIPRSTCB,
+ NPCM8XX_CLK_CORSTCB,
+ NPCM8XX_CLK_IPSRSTDIS1,
+ NPCM8XX_CLK_IPSRSTDIS2,
+ NPCM8XX_CLK_IPSRSTDIS3,
+ NPCM8XX_CLK_IPSRSTDIS4,
+ NPCM8XX_CLK_CLKENDIS1,
+ NPCM8XX_CLK_CLKENDIS2,
+ NPCM8XX_CLK_CLKENDIS3,
+ NPCM8XX_CLK_CLKENDIS4,
+ NPCM8XX_CLK_THRTL_CNT,
};
/*
@@ -81,7 +131,7 @@ enum NPCM7xxCLKRegisters {
* All are loaded on power-up reset. CLKENx and SWRSTR should also be loaded on
* core domain reset, but this reset type is not yet supported by QEMU.
*/
-static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
+static const uint32_t npcm7xx_cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
[NPCM7XX_CLK_CLKEN1] = 0xffffffff,
[NPCM7XX_CLK_CLKSEL] = 0x004aaaaa,
[NPCM7XX_CLK_CLKDIV1] = 0x5413f855,
@@ -103,6 +153,46 @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
};
+/*
+ * These reset values were taken from version 0.92 of the NPCM8xx data sheet.
+ */
+static const uint32_t npcm8xx_cold_reset_values[NPCM8XX_CLK_NR_REGS] = {
+ [NPCM8XX_CLK_CLKEN1] = 0xffffffff,
+ [NPCM8XX_CLK_CLKSEL] = 0x154aaaaa,
+ [NPCM8XX_CLK_CLKDIV1] = 0x5413f855,
+ [NPCM8XX_CLK_PLLCON0] = 0x00222101 | PLLCON_LOKI,
+ [NPCM8XX_CLK_PLLCON1] = 0x00202101 | PLLCON_LOKI,
+ [NPCM8XX_CLK_IPSRST1] = 0x00001000,
+ [NPCM8XX_CLK_IPSRST2] = 0x80000000,
+ [NPCM8XX_CLK_CLKEN2] = 0xffffffff,
+ [NPCM8XX_CLK_CLKDIV2] = 0xaa4f8f9f,
+ [NPCM8XX_CLK_CLKEN3] = 0xffffffff,
+ [NPCM8XX_CLK_IPSRST3] = 0x03000000,
+ [NPCM8XX_CLK_WD0RCR] = 0xffffffff,
+ [NPCM8XX_CLK_WD1RCR] = 0xffffffff,
+ [NPCM8XX_CLK_WD2RCR] = 0xffffffff,
+ [NPCM8XX_CLK_SWRSTC1] = 0x00000003,
+ [NPCM8XX_CLK_SWRSTC2] = 0x00000001,
+ [NPCM8XX_CLK_SWRSTC3] = 0x00000001,
+ [NPCM8XX_CLK_TIPRSTC] = 0x00000001,
+ [NPCM8XX_CLK_PLLCON2] = 0x00c02105 | PLLCON_LOKI,
+ [NPCM8XX_CLK_CLKDIV3] = 0x00009100,
+ [NPCM8XX_CLK_CORSTC] = 0x04000003,
+ [NPCM8XX_CLK_PLLCONG] = 0x01228606 | PLLCON_LOKI,
+ [NPCM8XX_CLK_AHBCKFI] = 0x000000c8,
+ [NPCM8XX_CLK_CLKEN4] = 0xffffffff,
+ [NPCM8XX_CLK_CLKDIV4] = 0x70009000,
+ [NPCM8XX_CLK_IPSRST4] = 0x02000000,
+ [NPCM8XX_CLK_WD0RCRB] = 0xfffffe71,
+ [NPCM8XX_CLK_WD1RCRB] = 0xfffffe71,
+ [NPCM8XX_CLK_WD2RCRB] = 0xfffffe71,
+ [NPCM8XX_CLK_SWRSTC1B] = 0xfffffe71,
+ [NPCM8XX_CLK_SWRSTC2B] = 0xfffffe71,
+ [NPCM8XX_CLK_SWRSTC3B] = 0xfffffe71,
+ [NPCM8XX_CLK_TIPRSTCB] = 0xfffffe71,
+ [NPCM8XX_CLK_CORSTCB] = 0xfffffe71,
+};
+
/* The number of watchdogs that can trigger a reset. */
#define NPCM7XX_NR_WATCHDOGS (3)
@@ -198,7 +288,7 @@ static NPCM7xxClockPLL find_pll_by_reg(enum NPCM7xxCLKRegisters reg)
}
}
-static void npcm7xx_clk_update_all_plls(NPCM7xxCLKState *clk)
+static void npcm7xx_clk_update_all_plls(NPCMCLKState *clk)
{
int i;
@@ -207,7 +297,7 @@ static void npcm7xx_clk_update_all_plls(NPCM7xxCLKState *clk)
}
}
-static void npcm7xx_clk_update_all_sels(NPCM7xxCLKState *clk)
+static void npcm7xx_clk_update_all_sels(NPCMCLKState *clk)
{
int i;
@@ -216,7 +306,7 @@ static void npcm7xx_clk_update_all_sels(NPCM7xxCLKState *clk)
}
}
-static void npcm7xx_clk_update_all_dividers(NPCM7xxCLKState *clk)
+static void npcm7xx_clk_update_all_dividers(NPCMCLKState *clk)
{
int i;
@@ -225,7 +315,7 @@ static void npcm7xx_clk_update_all_dividers(NPCM7xxCLKState *clk)
}
}
-static void npcm7xx_clk_update_all_clocks(NPCM7xxCLKState *clk)
+static void npcm7xx_clk_update_all_clocks(NPCMCLKState *clk)
{
clock_update_hz(clk->clkref, NPCM7XX_CLOCK_REF_HZ);
npcm7xx_clk_update_all_plls(clk);
@@ -635,7 +725,7 @@ static void npcm7xx_clk_divider_init(Object *obj)
}
static void npcm7xx_init_clock_pll(NPCM7xxClockPLLState *pll,
- NPCM7xxCLKState *clk, const PLLInitInfo *init_info)
+ NPCMCLKState *clk, const PLLInitInfo *init_info)
{
pll->name = init_info->name;
pll->clk = clk;
@@ -647,7 +737,7 @@ static void npcm7xx_init_clock_pll(NPCM7xxClockPLLState *pll,
}
static void npcm7xx_init_clock_sel(NPCM7xxClockSELState *sel,
- NPCM7xxCLKState *clk, const SELInitInfo *init_info)
+ NPCMCLKState *clk, const SELInitInfo *init_info)
{
int input_size = init_info->input_size;
@@ -664,7 +754,7 @@ static void npcm7xx_init_clock_sel(NPCM7xxClockSELState *sel,
}
static void npcm7xx_init_clock_divider(NPCM7xxClockDividerState *div,
- NPCM7xxCLKState *clk, const DividerInitInfo *init_info)
+ NPCMCLKState *clk, const DividerInitInfo *init_info)
{
div->name = init_info->name;
div->clk = clk;
@@ -683,7 +773,7 @@ static void npcm7xx_init_clock_divider(NPCM7xxClockDividerState *div,
}
}
-static Clock *npcm7xx_get_clock(NPCM7xxCLKState *clk, ClockSrcType type,
+static Clock *npcm7xx_get_clock(NPCMCLKState *clk, ClockSrcType type,
int index)
{
switch (type) {
@@ -700,7 +790,7 @@ static Clock *npcm7xx_get_clock(NPCM7xxCLKState *clk, ClockSrcType type,
}
}
-static void npcm7xx_connect_clocks(NPCM7xxCLKState *clk)
+static void npcm7xx_connect_clocks(NPCMCLKState *clk)
{
int i, j;
Clock *src;
@@ -724,14 +814,15 @@ static void npcm7xx_connect_clocks(NPCM7xxCLKState *clk)
}
}
-static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
+static uint64_t npcm_clk_read(void *opaque, hwaddr offset, unsigned size)
{
uint32_t reg = offset / sizeof(uint32_t);
- NPCM7xxCLKState *s = opaque;
+ NPCMCLKState *s = opaque;
+ NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
int64_t now_ns;
uint32_t value = 0;
- if (reg >= NPCM7XX_CLK_NR_REGS) {
+ if (reg >= c->nr_regs) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: offset 0x%04" HWADDR_PRIx " out of range\n",
__func__, offset);
@@ -766,21 +857,22 @@ static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
break;
};
- trace_npcm7xx_clk_read(offset, value);
+ trace_npcm_clk_read(offset, value);
return value;
}
-static void npcm7xx_clk_write(void *opaque, hwaddr offset,
+static void npcm_clk_write(void *opaque, hwaddr offset,
uint64_t v, unsigned size)
{
uint32_t reg = offset / sizeof(uint32_t);
- NPCM7xxCLKState *s = opaque;
+ NPCMCLKState *s = opaque;
+ NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
uint32_t value = v;
- trace_npcm7xx_clk_write(offset, value);
+ trace_npcm_clk_write(offset, value);
- if (reg >= NPCM7XX_CLK_NR_REGS) {
+ if (reg >= c->nr_regs) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: offset 0x%04" HWADDR_PRIx " out of range\n",
__func__, offset);
@@ -842,7 +934,7 @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
static void npcm7xx_clk_perform_watchdog_reset(void *opaque, int n,
int level)
{
- NPCM7xxCLKState *clk = NPCM7XX_CLK(opaque);
+ NPCMCLKState *clk = NPCM_CLK(opaque);
uint32_t rcr;
g_assert(n >= 0 && n <= NPCM7XX_NR_WATCHDOGS);
@@ -856,9 +948,9 @@ static void npcm7xx_clk_perform_watchdog_reset(void *opaque, int n,
}
}
-static const struct MemoryRegionOps npcm7xx_clk_ops = {
- .read = npcm7xx_clk_read,
- .write = npcm7xx_clk_write,
+static const struct MemoryRegionOps npcm_clk_ops = {
+ .read = npcm_clk_read,
+ .write = npcm_clk_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
@@ -867,13 +959,13 @@ static const struct MemoryRegionOps npcm7xx_clk_ops = {
},
};
-static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
+static void npcm_clk_enter_reset(Object *obj, ResetType type)
{
- NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
+ NPCMCLKState *s = NPCM_CLK(obj);
+ NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
- QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
-
- memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
+ g_assert(sizeof(s->regs) >= c->nr_regs * sizeof(uint32_t));
+ memcpy(s->regs, c->cold_reset_values, sizeof(s->regs));
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
npcm7xx_clk_update_all_clocks(s);
/*
@@ -882,7 +974,7 @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
*/
}
-static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
+static void npcm7xx_clk_init_clock_hierarchy(NPCMCLKState *s)
{
int i;
@@ -918,19 +1010,19 @@ static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
clock_update_hz(s->clkref, NPCM7XX_CLOCK_REF_HZ);
}
-static void npcm7xx_clk_init(Object *obj)
+static void npcm_clk_init(Object *obj)
{
- NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
+ NPCMCLKState *s = NPCM_CLK(obj);
- memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
- TYPE_NPCM7XX_CLK, 4 * KiB);
+ memory_region_init_io(&s->iomem, obj, &npcm_clk_ops, s,
+ TYPE_NPCM_CLK, 4 * KiB);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
}
-static int npcm7xx_clk_post_load(void *opaque, int version_id)
+static int npcm_clk_post_load(void *opaque, int version_id)
{
if (version_id >= 1) {
- NPCM7xxCLKState *clk = opaque;
+ NPCMCLKState *clk = opaque;
npcm7xx_clk_update_all_clocks(clk);
}
@@ -938,10 +1030,10 @@ static int npcm7xx_clk_post_load(void *opaque, int version_id)
return 0;
}
-static void npcm7xx_clk_realize(DeviceState *dev, Error **errp)
+static void npcm_clk_realize(DeviceState *dev, Error **errp)
{
int i;
- NPCM7xxCLKState *s = NPCM7XX_CLK(dev);
+ NPCMCLKState *s = NPCM_CLK(dev);
qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
@@ -996,15 +1088,15 @@ static const VMStateDescription vmstate_npcm7xx_clk_divider = {
},
};
-static const VMStateDescription vmstate_npcm7xx_clk = {
- .name = "npcm7xx-clk",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = npcm7xx_clk_post_load,
+static const VMStateDescription vmstate_npcm_clk = {
+ .name = "npcm-clk",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .post_load = npcm_clk_post_load,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
- VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
- VMSTATE_CLOCK(clkref, NPCM7xxCLKState),
+ VMSTATE_UINT32_ARRAY(regs, NPCMCLKState, NPCM_CLK_MAX_NR_REGS),
+ VMSTATE_INT64(ref_ns, NPCMCLKState),
+ VMSTATE_CLOCK(clkref, NPCMCLKState),
VMSTATE_END_OF_LIST(),
},
};
@@ -1033,17 +1125,34 @@ static void npcm7xx_clk_divider_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_npcm7xx_clk_divider;
}
-static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
+static void npcm_clk_class_init(ObjectClass *klass, void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- QEMU_BUILD_BUG_ON(NPCM7XX_CLK_REGS_END > NPCM7XX_CLK_NR_REGS);
+ dc->vmsd = &vmstate_npcm_clk;
+ dc->realize = npcm_clk_realize;
+ rc->phases.enter = npcm_clk_enter_reset;
+}
+
+static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
+{
+ NPCMCLKClass *c = NPCM_CLK_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "NPCM7xx Clock Control Registers";
- dc->vmsd = &vmstate_npcm7xx_clk;
- dc->realize = npcm7xx_clk_realize;
- rc->phases.enter = npcm7xx_clk_enter_reset;
+ c->nr_regs = NPCM7XX_CLK_NR_REGS;
+ c->cold_reset_values = npcm7xx_cold_reset_values;
+}
+
+static void npcm8xx_clk_class_init(ObjectClass *klass, void *data)
+{
+ NPCMCLKClass *c = NPCM_CLK_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "NPCM8xx Clock Control Registers";
+ c->nr_regs = NPCM8XX_CLK_NR_REGS;
+ c->cold_reset_values = npcm8xx_cold_reset_values;
}
static const TypeInfo npcm7xx_clk_pll_info = {
@@ -1070,19 +1179,35 @@ static const TypeInfo npcm7xx_clk_divider_info = {
.class_init = npcm7xx_clk_divider_class_init,
};
+static const TypeInfo npcm_clk_info = {
+ .name = TYPE_NPCM_CLK,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCMCLKState),
+ .instance_init = npcm_clk_init,
+ .class_size = sizeof(NPCMCLKClass),
+ .class_init = npcm_clk_class_init,
+ .abstract = true,
+};
+
static const TypeInfo npcm7xx_clk_info = {
.name = TYPE_NPCM7XX_CLK,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(NPCM7xxCLKState),
- .instance_init = npcm7xx_clk_init,
+ .parent = TYPE_NPCM_CLK,
.class_init = npcm7xx_clk_class_init,
};
+static const TypeInfo npcm8xx_clk_info = {
+ .name = TYPE_NPCM8XX_CLK,
+ .parent = TYPE_NPCM_CLK,
+ .class_init = npcm8xx_clk_class_init,
+};
+
static void npcm7xx_clk_register_type(void)
{
type_register_static(&npcm7xx_clk_pll_info);
type_register_static(&npcm7xx_clk_sel_info);
type_register_static(&npcm7xx_clk_divider_info);
+ type_register_static(&npcm_clk_info);
type_register_static(&npcm7xx_clk_info);
+ type_register_static(&npcm8xx_clk_info);
}
type_init(npcm7xx_clk_register_type);
diff --git a/hw/misc/npcm_gcr.c b/hw/misc/npcm_gcr.c
new file mode 100644
index 0000000..4e8ce2c
--- /dev/null
+++ b/hw/misc/npcm_gcr.c
@@ -0,0 +1,482 @@
+/*
+ * Nuvoton NPCM7xx/8xx System Global Control Registers.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/misc/npcm_gcr.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+
+#include "trace.h"
+
+#define NPCM7XX_GCR_MIN_DRAM_SIZE (128 * MiB)
+#define NPCM7XX_GCR_MAX_DRAM_SIZE (2 * GiB)
+
+enum NPCM7xxGCRRegisters {
+ NPCM7XX_GCR_PDID,
+ NPCM7XX_GCR_PWRON,
+ NPCM7XX_GCR_MFSEL1 = 0x0c / sizeof(uint32_t),
+ NPCM7XX_GCR_MFSEL2,
+ NPCM7XX_GCR_MISCPE,
+ NPCM7XX_GCR_SPSWC = 0x038 / sizeof(uint32_t),
+ NPCM7XX_GCR_INTCR,
+ NPCM7XX_GCR_INTSR,
+ NPCM7XX_GCR_HIFCR = 0x050 / sizeof(uint32_t),
+ NPCM7XX_GCR_INTCR2 = 0x060 / sizeof(uint32_t),
+ NPCM7XX_GCR_MFSEL3,
+ NPCM7XX_GCR_SRCNT,
+ NPCM7XX_GCR_RESSR,
+ NPCM7XX_GCR_RLOCKR1,
+ NPCM7XX_GCR_FLOCKR1,
+ NPCM7XX_GCR_DSCNT,
+ NPCM7XX_GCR_MDLR,
+ NPCM7XX_GCR_SCRPAD3,
+ NPCM7XX_GCR_SCRPAD2,
+ NPCM7XX_GCR_DAVCLVLR = 0x098 / sizeof(uint32_t),
+ NPCM7XX_GCR_INTCR3,
+ NPCM7XX_GCR_VSINTR = 0x0ac / sizeof(uint32_t),
+ NPCM7XX_GCR_MFSEL4,
+ NPCM7XX_GCR_CPBPNTR = 0x0c4 / sizeof(uint32_t),
+ NPCM7XX_GCR_CPCTL = 0x0d0 / sizeof(uint32_t),
+ NPCM7XX_GCR_CP2BST,
+ NPCM7XX_GCR_B2CPNT,
+ NPCM7XX_GCR_CPPCTL,
+ NPCM7XX_GCR_I2CSEGSEL,
+ NPCM7XX_GCR_I2CSEGCTL,
+ NPCM7XX_GCR_VSRCR,
+ NPCM7XX_GCR_MLOCKR,
+ NPCM7XX_GCR_SCRPAD = 0x013c / sizeof(uint32_t),
+ NPCM7XX_GCR_USB1PHYCTL,
+ NPCM7XX_GCR_USB2PHYCTL,
+};
+
+static const uint32_t npcm7xx_cold_reset_values[NPCM7XX_GCR_NR_REGS] = {
+ [NPCM7XX_GCR_PDID] = 0x04a92750, /* Poleg A1 */
+ [NPCM7XX_GCR_MISCPE] = 0x0000ffff,
+ [NPCM7XX_GCR_SPSWC] = 0x00000003,
+ [NPCM7XX_GCR_INTCR] = 0x0000035e,
+ [NPCM7XX_GCR_HIFCR] = 0x0000004e,
+ [NPCM7XX_GCR_INTCR2] = (1U << 19), /* DDR initialized */
+ [NPCM7XX_GCR_RESSR] = 0x80000000,
+ [NPCM7XX_GCR_DSCNT] = 0x000000c0,
+ [NPCM7XX_GCR_DAVCLVLR] = 0x5a00f3cf,
+ [NPCM7XX_GCR_SCRPAD] = 0x00000008,
+ [NPCM7XX_GCR_USB1PHYCTL] = 0x034730e4,
+ [NPCM7XX_GCR_USB2PHYCTL] = 0x034730e4,
+};
+
+enum NPCM8xxGCRRegisters {
+ NPCM8XX_GCR_PDID,
+ NPCM8XX_GCR_PWRON,
+ NPCM8XX_GCR_MISCPE = 0x014 / sizeof(uint32_t),
+ NPCM8XX_GCR_FLOCKR2 = 0x020 / sizeof(uint32_t),
+ NPCM8XX_GCR_FLOCKR3,
+ NPCM8XX_GCR_A35_MODE = 0x034 / sizeof(uint32_t),
+ NPCM8XX_GCR_SPSWC,
+ NPCM8XX_GCR_INTCR,
+ NPCM8XX_GCR_INTSR,
+ NPCM8XX_GCR_HIFCR = 0x050 / sizeof(uint32_t),
+ NPCM8XX_GCR_INTCR2 = 0x060 / sizeof(uint32_t),
+ NPCM8XX_GCR_SRCNT = 0x068 / sizeof(uint32_t),
+ NPCM8XX_GCR_RESSR,
+ NPCM8XX_GCR_RLOCKR1,
+ NPCM8XX_GCR_FLOCKR1,
+ NPCM8XX_GCR_DSCNT,
+ NPCM8XX_GCR_MDLR,
+ NPCM8XX_GCR_SCRPAD_C = 0x080 / sizeof(uint32_t),
+ NPCM8XX_GCR_SCRPAD_B,
+ NPCM8XX_GCR_DAVCLVLR = 0x098 / sizeof(uint32_t),
+ NPCM8XX_GCR_INTCR3,
+ NPCM8XX_GCR_PCIRCTL = 0x0a0 / sizeof(uint32_t),
+ NPCM8XX_GCR_VSINTR,
+ NPCM8XX_GCR_SD2SUR1 = 0x0b4 / sizeof(uint32_t),
+ NPCM8XX_GCR_SD2SUR2,
+ NPCM8XX_GCR_INTCR4 = 0x0c0 / sizeof(uint32_t),
+ NPCM8XX_GCR_CPCTL = 0x0d0 / sizeof(uint32_t),
+ NPCM8XX_GCR_CP2BST,
+ NPCM8XX_GCR_B2CPNT,
+ NPCM8XX_GCR_CPPCTL,
+ NPCM8XX_GCR_I2CSEGSEL = 0x0e0 / sizeof(uint32_t),
+ NPCM8XX_GCR_I2CSEGCTL,
+ NPCM8XX_GCR_VSRCR,
+ NPCM8XX_GCR_MLOCKR,
+ NPCM8XX_GCR_SCRPAD = 0x13c / sizeof(uint32_t),
+ NPCM8XX_GCR_USB1PHYCTL,
+ NPCM8XX_GCR_USB2PHYCTL,
+ NPCM8XX_GCR_USB3PHYCTL,
+ NPCM8XX_GCR_MFSEL1 = 0x260 / sizeof(uint32_t),
+ NPCM8XX_GCR_MFSEL2,
+ NPCM8XX_GCR_MFSEL3,
+ NPCM8XX_GCR_MFSEL4,
+ NPCM8XX_GCR_MFSEL5,
+ NPCM8XX_GCR_MFSEL6,
+ NPCM8XX_GCR_MFSEL7,
+ NPCM8XX_GCR_MFSEL_LK1 = 0x280 / sizeof(uint32_t),
+ NPCM8XX_GCR_MFSEL_LK2,
+ NPCM8XX_GCR_MFSEL_LK3,
+ NPCM8XX_GCR_MFSEL_LK4,
+ NPCM8XX_GCR_MFSEL_LK5,
+ NPCM8XX_GCR_MFSEL_LK6,
+ NPCM8XX_GCR_MFSEL_LK7,
+ NPCM8XX_GCR_MFSEL_SET1 = 0x2a0 / sizeof(uint32_t),
+ NPCM8XX_GCR_MFSEL_SET2,
+ NPCM8XX_GCR_MFSEL_SET3,
+ NPCM8XX_GCR_MFSEL_SET4,
+ NPCM8XX_GCR_MFSEL_SET5,
+ NPCM8XX_GCR_MFSEL_SET6,
+ NPCM8XX_GCR_MFSEL_SET7,
+ NPCM8XX_GCR_MFSEL_CLR1 = 0x2c0 / sizeof(uint32_t),
+ NPCM8XX_GCR_MFSEL_CLR2,
+ NPCM8XX_GCR_MFSEL_CLR3,
+ NPCM8XX_GCR_MFSEL_CLR4,
+ NPCM8XX_GCR_MFSEL_CLR5,
+ NPCM8XX_GCR_MFSEL_CLR6,
+ NPCM8XX_GCR_MFSEL_CLR7,
+ NPCM8XX_GCR_WD0RCRLK = 0x400 / sizeof(uint32_t),
+ NPCM8XX_GCR_WD1RCRLK,
+ NPCM8XX_GCR_WD2RCRLK,
+ NPCM8XX_GCR_SWRSTC1LK,
+ NPCM8XX_GCR_SWRSTC2LK,
+ NPCM8XX_GCR_SWRSTC3LK,
+ NPCM8XX_GCR_TIPRSTCLK,
+ NPCM8XX_GCR_CORSTCLK,
+ NPCM8XX_GCR_WD0RCRBLK,
+ NPCM8XX_GCR_WD1RCRBLK,
+ NPCM8XX_GCR_WD2RCRBLK,
+ NPCM8XX_GCR_SWRSTC1BLK,
+ NPCM8XX_GCR_SWRSTC2BLK,
+ NPCM8XX_GCR_SWRSTC3BLK,
+ NPCM8XX_GCR_TIPRSTCBLK,
+ NPCM8XX_GCR_CORSTCBLK,
+ /* 64 scratch pad registers start here. 0xe00 ~ 0xefc */
+ NPCM8XX_GCR_SCRPAD_00 = 0xe00 / sizeof(uint32_t),
+ /* 32 semaphore registers start here. 0xf00 ~ 0xf7c */
+ NPCM8XX_GCR_GP_SEMFR_00 = 0xf00 / sizeof(uint32_t),
+ NPCM8XX_GCR_GP_SEMFR_31 = 0xf7c / sizeof(uint32_t),
+};
+
+static const uint32_t npcm8xx_cold_reset_values[NPCM8XX_GCR_NR_REGS] = {
+ [NPCM8XX_GCR_PDID] = 0x04a35850, /* Arbel A1 */
+ [NPCM8XX_GCR_MISCPE] = 0x0000ffff,
+ [NPCM8XX_GCR_A35_MODE] = 0xfff4ff30,
+ [NPCM8XX_GCR_SPSWC] = 0x00000003,
+ [NPCM8XX_GCR_INTCR] = 0x0010035e,
+ [NPCM8XX_GCR_HIFCR] = 0x0000004e,
+ [NPCM8XX_GCR_SD2SUR1] = 0xfdc80000,
+ [NPCM8XX_GCR_SD2SUR2] = 0x5200b130,
+ [NPCM8XX_GCR_INTCR2] = (1U << 19), /* DDR initialized */
+ [NPCM8XX_GCR_RESSR] = 0x80000000,
+ [NPCM8XX_GCR_DAVCLVLR] = 0x5a00f3cf,
+ [NPCM8XX_GCR_INTCR3] = 0x5e001002,
+ [NPCM8XX_GCR_VSRCR] = 0x00004800,
+ [NPCM8XX_GCR_SCRPAD] = 0x00000008,
+ [NPCM8XX_GCR_USB1PHYCTL] = 0x034730e4,
+ [NPCM8XX_GCR_USB2PHYCTL] = 0x034730e4,
+ [NPCM8XX_GCR_USB3PHYCTL] = 0x034730e4,
+ /* All 32 semaphores should be initialized to 1. */
+ [NPCM8XX_GCR_GP_SEMFR_00...NPCM8XX_GCR_GP_SEMFR_31] = 0x00000001,
+};
+
+static uint64_t npcm_gcr_read(void *opaque, hwaddr offset, unsigned size)
+{
+ uint32_t reg = offset / sizeof(uint32_t);
+ NPCMGCRState *s = opaque;
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(s);
+ uint64_t value;
+
+ if (reg >= c->nr_regs) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (size) {
+ case 4:
+ value = s->regs[reg];
+ break;
+
+ case 8:
+ g_assert(!(reg & 1));
+ value = deposit64(s->regs[reg], 32, 32, s->regs[reg + 1]);
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ trace_npcm_gcr_read(offset, value);
+ return value;
+}
+
+static void npcm_gcr_write(void *opaque, hwaddr offset,
+ uint64_t v, unsigned size)
+{
+ uint32_t reg = offset / sizeof(uint32_t);
+ NPCMGCRState *s = opaque;
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(s);
+ uint32_t value = v;
+
+ trace_npcm_gcr_write(offset, v);
+
+ if (reg >= c->nr_regs) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
+ __func__, offset);
+ return;
+ }
+
+ switch (size) {
+ case 4:
+ switch (reg) {
+ case NPCM7XX_GCR_PDID:
+ case NPCM7XX_GCR_PWRON:
+ case NPCM7XX_GCR_INTSR:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
+ __func__, offset);
+ return;
+
+ case NPCM7XX_GCR_RESSR:
+ case NPCM7XX_GCR_CP2BST:
+ /* Write 1 to clear */
+ value = s->regs[reg] & ~value;
+ break;
+
+ case NPCM7XX_GCR_RLOCKR1:
+ case NPCM7XX_GCR_MDLR:
+ /* Write 1 to set */
+ value |= s->regs[reg];
+ break;
+ };
+ s->regs[reg] = value;
+ break;
+
+ case 8:
+ g_assert(!(reg & 1));
+ s->regs[reg] = value;
+ s->regs[reg + 1] = extract64(v, 32, 32);
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static bool npcm_gcr_check_mem_op(void *opaque, hwaddr offset,
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
+{
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(opaque);
+
+ if (offset >= c->nr_regs * sizeof(uint32_t)) {
+ return false;
+ }
+
+ switch (size) {
+ case 4:
+ return true;
+ case 8:
+ if (offset >= NPCM8XX_GCR_SCRPAD_00 * sizeof(uint32_t) &&
+ offset < (NPCM8XX_GCR_NR_REGS - 1) * sizeof(uint32_t)) {
+ return true;
+ } else {
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
+static const struct MemoryRegionOps npcm_gcr_ops = {
+ .read = npcm_gcr_read,
+ .write = npcm_gcr_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ .accepts = npcm_gcr_check_mem_op,
+ .unaligned = false,
+ },
+};
+
+static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type)
+{
+ NPCMGCRState *s = NPCM_GCR(obj);
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(obj);
+
+ g_assert(sizeof(s->regs) >= sizeof(c->cold_reset_values));
+ g_assert(sizeof(s->regs) >= c->nr_regs * sizeof(uint32_t));
+ memcpy(s->regs, c->cold_reset_values, c->nr_regs * sizeof(uint32_t));
+ /* These 3 registers are at the same location in both 7xx and 8xx. */
+ s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
+ s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
+ s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3;
+}
+
+static void npcm8xx_gcr_enter_reset(Object *obj, ResetType type)
+{
+ NPCMGCRState *s = NPCM_GCR(obj);
+ NPCMGCRClass *c = NPCM_GCR_GET_CLASS(obj);
+
+ memcpy(s->regs, c->cold_reset_values, c->nr_regs * sizeof(uint32_t));
+ /* These 3 registers are at the same location in both 7xx and 8xx. */
+ s->regs[NPCM8XX_GCR_PWRON] = s->reset_pwron;
+ s->regs[NPCM8XX_GCR_MDLR] = s->reset_mdlr;
+ s->regs[NPCM8XX_GCR_INTCR3] = s->reset_intcr3;
+ s->regs[NPCM8XX_GCR_SCRPAD_B] = s->reset_scrpad_b;
+}
+
+static void npcm_gcr_realize(DeviceState *dev, Error **errp)
+{
+ ERRP_GUARD();
+ NPCMGCRState *s = NPCM_GCR(dev);
+ uint64_t dram_size;
+ Object *obj;
+
+ obj = object_property_get_link(OBJECT(dev), "dram-mr", errp);
+ if (!obj) {
+ error_prepend(errp, "%s: required dram-mr link not found: ", __func__);
+ return;
+ }
+ dram_size = memory_region_size(MEMORY_REGION(obj));
+ if (!is_power_of_2(dram_size) ||
+ dram_size < NPCM7XX_GCR_MIN_DRAM_SIZE ||
+ dram_size > NPCM7XX_GCR_MAX_DRAM_SIZE) {
+ g_autofree char *sz = size_to_str(dram_size);
+ g_autofree char *min_sz = size_to_str(NPCM7XX_GCR_MIN_DRAM_SIZE);
+ g_autofree char *max_sz = size_to_str(NPCM7XX_GCR_MAX_DRAM_SIZE);
+ error_setg(errp, "%s: unsupported DRAM size %s", __func__, sz);
+ error_append_hint(errp,
+ "DRAM size must be a power of two between %s and %s,"
+ " inclusive.\n", min_sz, max_sz);
+ return;
+ }
+
+ /* Power-on reset value */
+ s->reset_intcr3 = 0x00001002;
+
+ /*
+ * The GMMAP (Graphics Memory Map) field is used by u-boot to detect the
+ * DRAM size, and is normally initialized by the boot block as part of DRAM
+ * training. However, since we don't have a complete emulation of the
+ * memory controller and try to make it look like it has already been
+ * initialized, the boot block will skip this initialization, and we need
+ * to make sure this field is set correctly up front.
+ *
+ * WARNING: some versions of u-boot only looks at bits 8 and 9, so 2 GiB of
+ * DRAM will be interpreted as 128 MiB.
+ *
+ * https://github.com/Nuvoton-Israel/u-boot/blob/2aef993bd2aafeb5408dbaad0f3ce099ee40c4aa/board/nuvoton/poleg/poleg.c#L244
+ */
+ s->reset_intcr3 |= ctz64(dram_size / NPCM7XX_GCR_MIN_DRAM_SIZE) << 8;
+
+ /*
+ * The boot block starting from 0.0.6 for NPCM8xx SoCs stores the DRAM size
+ * in the SCRPAD2 registers. We need to set this field correctly since
+ * the initialization is skipped as we mentioned above.
+ * https://github.com/Nuvoton-Israel/u-boot/blob/npcm8mnx-v2019.01_tmp/board/nuvoton/arbel/arbel.c#L737
+ */
+ s->reset_scrpad_b = dram_size;
+}
+
+static void npcm_gcr_init(Object *obj)
+{
+ NPCMGCRState *s = NPCM_GCR(obj);
+
+ memory_region_init_io(&s->iomem, obj, &npcm_gcr_ops, s,
+ TYPE_NPCM_GCR, 4 * KiB);
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+}
+
+static const VMStateDescription vmstate_npcm_gcr = {
+ .name = "npcm-gcr",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, NPCMGCRState, NPCM_GCR_MAX_NR_REGS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static const Property npcm_gcr_properties[] = {
+ DEFINE_PROP_UINT32("disabled-modules", NPCMGCRState, reset_mdlr, 0),
+ DEFINE_PROP_UINT32("power-on-straps", NPCMGCRState, reset_pwron, 0),
+};
+
+static void npcm_gcr_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = npcm_gcr_realize;
+ dc->vmsd = &vmstate_npcm_gcr;
+
+ device_class_set_props(dc, npcm_gcr_properties);
+}
+
+static void npcm7xx_gcr_class_init(ObjectClass *klass, void *data)
+{
+ NPCMGCRClass *c = NPCM_GCR_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->desc = "NPCM7xx System Global Control Registers";
+ rc->phases.enter = npcm7xx_gcr_enter_reset;
+
+ c->nr_regs = NPCM7XX_GCR_NR_REGS;
+ c->cold_reset_values = npcm7xx_cold_reset_values;
+ rc->phases.enter = npcm7xx_gcr_enter_reset;
+}
+
+static void npcm8xx_gcr_class_init(ObjectClass *klass, void *data)
+{
+ NPCMGCRClass *c = NPCM_GCR_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->desc = "NPCM8xx System Global Control Registers";
+ c->nr_regs = NPCM8XX_GCR_NR_REGS;
+ c->cold_reset_values = npcm8xx_cold_reset_values;
+ rc->phases.enter = npcm8xx_gcr_enter_reset;
+}
+
+static const TypeInfo npcm_gcr_info[] = {
+ {
+ .name = TYPE_NPCM_GCR,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCMGCRState),
+ .instance_init = npcm_gcr_init,
+ .class_size = sizeof(NPCMGCRClass),
+ .class_init = npcm_gcr_class_init,
+ .abstract = true,
+ },
+ {
+ .name = TYPE_NPCM7XX_GCR,
+ .parent = TYPE_NPCM_GCR,
+ .class_init = npcm7xx_gcr_class_init,
+ },
+ {
+ .name = TYPE_NPCM8XX_GCR,
+ .parent = TYPE_NPCM_GCR,
+ .class_init = npcm8xx_gcr_class_init,
+ },
+};
+DEFINE_TYPES(npcm_gcr_info)
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index b35b0e7..4383808 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -130,13 +130,13 @@ mos6522_set_sr_int(void) "set sr_int"
mos6522_write(uint64_t addr, const char *name, uint64_t val) "reg=0x%"PRIx64 " [%s] val=0x%"PRIx64
mos6522_read(uint64_t addr, const char *name, unsigned val) "reg=0x%"PRIx64 " [%s] val=0x%x"
-# npcm7xx_clk.c
-npcm7xx_clk_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
-npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+# npcm_clk.c
+npcm_clk_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+npcm_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
-# npcm7xx_gcr.c
-npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
-npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
+# npcm_gcr.c
+npcm_gcr_read(uint64_t offset, uint64_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx64
+npcm_gcr_write(uint64_t offset, uint64_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx64
# npcm7xx_mft.c
npcm7xx_mft_read(const char *name, uint64_t offset, uint16_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx16