mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20200914-1' into staging
* hw/misc/a9scu: Do not allow invalid CPU count * hw/misc/a9scu: Minor cleanups * hw/timer/armv7m_systick: assert that board code set system_clock_scale * decodetree: Improve identifier matching * target/arm: Clean up neon fp insn size field decode * target/arm: Remove KVM support for 32-bit Arm hosts * hw/arm/mps2: New board models mps2-an386, mps2-an500 * Deprecate Unicore32 port * Deprecate lm32 port * target/arm: Count PMU events when MDCR.SPME is set * hw/arm: versal-virt: Correct the tx/rx GEM clocks * New Nuvoton iBMC board models npcm750-evb, quanta-gsj # gpg: Signature made Mon 14 Sep 2020 16:02:06 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20200914-1: (32 commits) tests/acceptance: console boot tests for quanta-gsj docs/system: Add Nuvoton machine documentation hw/arm/npcm7xx: add board setup stub for CPU and UART clocks hw/arm: Wire up BMC boot flash for npcm750-evb and quanta-gsj hw/ssi: NPCM7xx Flash Interface Unit device model hw/mem: Stubbed out NPCM7xx Memory Controller model hw/nvram: NPCM7xx OTP device model hw/arm: Load -bios image as a boot ROM for npcm7xx roms: Add virtual Boot ROM for NPCM7xx SoCs hw/arm: Add two NPCM7xx-based machines hw/arm: Add NPCM730 and NPCM750 SoC models hw/timer: Add NPCM7xx Timer device model hw/misc: Add NPCM7xx Clock Controller device model hw/misc: Add NPCM7xx System Global Control Registers device model hw/arm: versal-virt: Correct the tx/rx GEM clocks target/arm: Count PMU events when MDCR.SPME is set Deprecate lm32 port Deprecate Unicore32 port docs/system/arm/mps2.rst: Make board list consistent hw/arm/mps2: New board model mps2-an500 ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -61,3 +61,6 @@
|
||||
[submodule "meson"]
|
||||
path = meson
|
||||
url = https://github.com/mesonbuild/meson/
|
||||
[submodule "roms/vbootrom"]
|
||||
path = roms/vbootrom
|
||||
url = https://github.com/google/vbootrom.git
|
||||
|
||||
+10
@@ -750,6 +750,16 @@ S: Odd Fixes
|
||||
F: hw/arm/musicpal.c
|
||||
F: docs/system/arm/musicpal.rst
|
||||
|
||||
Nuvoton NPCM7xx
|
||||
M: Havard Skinnemoen <hskinnemoen@google.com>
|
||||
M: Tyrone Ting <kfting@nuvoton.com>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Supported
|
||||
F: hw/*/npcm7xx*
|
||||
F: include/hw/*/npcm7xx*
|
||||
F: pc-bios/npcm7xx_bootrom.bin
|
||||
F: roms/vbootrom
|
||||
|
||||
nSeries
|
||||
M: Andrzej Zaborowski <balrogg@gmail.com>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
|
||||
@@ -234,7 +234,7 @@ supported_kvm_target() {
|
||||
test "$kvm" = "yes" || return 1
|
||||
glob "$1" "*-softmmu" || return 1
|
||||
case "${1%-softmmu}:$cpu" in
|
||||
arm:arm | aarch64:aarch64 | \
|
||||
aarch64:aarch64 | \
|
||||
i386:i386 | i386:x86_64 | i386:x32 | \
|
||||
x86_64:i386 | x86_64:x86_64 | x86_64:x32 | \
|
||||
mips:mips | mipsel:mips | mips64:mips | mips64el:mips | \
|
||||
|
||||
@@ -27,6 +27,7 @@ CONFIG_GUMSTIX=y
|
||||
CONFIG_SPITZ=y
|
||||
CONFIG_TOSA=y
|
||||
CONFIG_Z2=y
|
||||
CONFIG_NPCM7XX=y
|
||||
CONFIG_COLLIE=y
|
||||
CONFIG_ASPEED_SOC=y
|
||||
CONFIG_NETDUINO2=y
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Arm MPS2 boards (``mps2-an385``, ``mps2-an505``, ``mps2-an511``, ``mps2-an521``)
|
||||
================================================================================
|
||||
Arm MPS2 boards (``mps2-an385``, ``mps2-an386``, ``mps2-an500``, ``mps2-an505``, ``mps2-an511``, ``mps2-an521``)
|
||||
================================================================================================================
|
||||
|
||||
These board models all use Arm M-profile CPUs.
|
||||
|
||||
@@ -11,17 +11,21 @@ as seen by the guest depend significantly on the FPGA image.
|
||||
QEMU models the following FPGA images:
|
||||
|
||||
``mps2-an385``
|
||||
Cortex-M3 as documented in ARM Application Note AN385
|
||||
``mps2-an511``
|
||||
Cortex-M3 'DesignStart' as documented in AN511
|
||||
Cortex-M3 as documented in Arm Application Note AN385
|
||||
``mps2-an386``
|
||||
Cortex-M4 as documented in Arm Application Note AN386
|
||||
``mps2-an500``
|
||||
Cortex-M7 as documented in Arm Application Note AN500
|
||||
``mps2-an505``
|
||||
Cortex-M33 as documented in ARM Application Note AN505
|
||||
Cortex-M33 as documented in Arm Application Note AN505
|
||||
``mps2-an511``
|
||||
Cortex-M3 'DesignStart' as documented in Arm Application Note AN511
|
||||
``mps2-an521``
|
||||
Dual Cortex-M33 as documented in Application Note AN521
|
||||
Dual Cortex-M33 as documented in Arm Application Note AN521
|
||||
|
||||
Differences between QEMU and real hardware:
|
||||
|
||||
- AN385 remapping of low 16K of memory to either ZBT SSRAM1 or to
|
||||
- AN385/AN386 remapping of low 16K of memory to either ZBT SSRAM1 or to
|
||||
block RAM is unimplemented (QEMU always maps this to ZBT SSRAM1, as
|
||||
if zbt_boot_ctrl is always zero)
|
||||
- QEMU provides a LAN9118 ethernet rather than LAN9220; the only guest
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
Nuvoton iBMC boards (``npcm750-evb``, ``quanta-gsj``)
|
||||
=====================================================
|
||||
|
||||
The `Nuvoton iBMC`_ chips (NPCM7xx) are a family of ARM-based SoCs that are
|
||||
designed to be used as Baseboard Management Controllers (BMCs) in various
|
||||
servers. They all feature one or two ARM Cortex A9 CPU cores, as well as an
|
||||
assortment of peripherals targeted for either Enterprise or Data Center /
|
||||
Hyperscale applications. The former is a superset of the latter, so NPCM750 has
|
||||
all the peripherals of NPCM730 and more.
|
||||
|
||||
.. _Nuvoton iBMC: https://www.nuvoton.com/products/cloud-computing/ibmc/
|
||||
|
||||
The NPCM750 SoC has two Cortex A9 cores and is targeted for the Enterprise
|
||||
segment. The following machines are based on this chip :
|
||||
|
||||
- ``npcm750-evb`` Nuvoton NPCM750 Evaluation board
|
||||
|
||||
The NPCM730 SoC has two Cortex A9 cores and is targeted for Data Center and
|
||||
Hyperscale applications. The following machines are based on this chip :
|
||||
|
||||
- ``quanta-gsj`` Quanta GSJ server BMC
|
||||
|
||||
There are also two more SoCs, NPCM710 and NPCM705, which are single-core
|
||||
variants of NPCM750 and NPCM730, respectively. These are currently not
|
||||
supported by QEMU.
|
||||
|
||||
Supported devices
|
||||
-----------------
|
||||
|
||||
* SMP (Dual Core Cortex-A9)
|
||||
* Cortex-A9MPCore built-in peripherals: SCU, GIC, Global Timer, Private Timer
|
||||
and Watchdog.
|
||||
* SRAM, ROM and DRAM mappings
|
||||
* System Global Control Registers (GCR)
|
||||
* Clock and reset controller (CLK)
|
||||
* Timer controller (TIM)
|
||||
* Serial ports (16550-based)
|
||||
* DDR4 memory controller (dummy interface indicating memory training is done)
|
||||
* OTP controllers (no protection features)
|
||||
* Flash Interface Unit (FIU; no protection features)
|
||||
|
||||
Missing devices
|
||||
---------------
|
||||
|
||||
* GPIO controller
|
||||
* LPC/eSPI host-to-BMC interface, including
|
||||
|
||||
* Keyboard and mouse controller interface (KBCI)
|
||||
* Keyboard Controller Style (KCS) channels
|
||||
* BIOS POST code FIFO
|
||||
* System Wake-up Control (SWC)
|
||||
* Shared memory (SHM)
|
||||
* eSPI slave interface
|
||||
|
||||
* Ethernet controllers (GMAC and EMC)
|
||||
* USB host (USBH)
|
||||
* USB device (USBD)
|
||||
* SMBus controller (SMBF)
|
||||
* Peripheral SPI controller (PSPI)
|
||||
* Analog to Digital Converter (ADC)
|
||||
* SD/MMC host
|
||||
* Random Number Generator (RNG)
|
||||
* PECI interface
|
||||
* Pulse Width Modulation (PWM)
|
||||
* Tachometer
|
||||
* PCI and PCIe root complex and bridges
|
||||
* VDM and MCTP support
|
||||
* Serial I/O expansion
|
||||
* LPC/eSPI host
|
||||
* Coprocessor
|
||||
* Graphics
|
||||
* Video capture
|
||||
* Encoding compression engine
|
||||
* Security features
|
||||
|
||||
Boot options
|
||||
------------
|
||||
|
||||
The Nuvoton machines can boot from an OpenBMC firmware image, or directly into
|
||||
a kernel using the ``-kernel`` option. OpenBMC images for `quanta-gsj` and
|
||||
possibly others can be downloaded from the OpenPOWER jenkins :
|
||||
|
||||
https://openpower.xyz/
|
||||
|
||||
The firmware image should be attached as an MTD drive. Example :
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-arm -machine quanta-gsj -nographic \
|
||||
-drive file=image-bmc,if=mtd,bus=0,unit=0,format=raw
|
||||
|
||||
The default root password for test images is usually ``0penBmc``.
|
||||
@@ -329,14 +329,6 @@ The ``compat`` property used to set backwards compatibility modes for
|
||||
the processor has been deprecated. The ``max-cpu-compat`` property of
|
||||
the ``pseries`` machine type should be used instead.
|
||||
|
||||
KVM guest support on 32-bit Arm hosts (since 5.0)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The Linux kernel has dropped support for allowing 32-bit Arm systems
|
||||
to host KVM guests as of the 5.7 kernel. Accordingly, QEMU is deprecating
|
||||
its support for this configuration and will remove it in a future version.
|
||||
Running 32-bit guests on a 64-bit Arm host remains supported.
|
||||
|
||||
System emulator devices
|
||||
-----------------------
|
||||
|
||||
@@ -416,6 +408,22 @@ The above, converted to the current supported format::
|
||||
linux-user mode CPUs
|
||||
--------------------
|
||||
|
||||
``lm32`` CPUs (since 5.2.0)
|
||||
'''''''''''''''''''''''''''
|
||||
|
||||
The ``lm32`` guest CPU support is deprecated and will be removed in
|
||||
a future version of QEMU. The only public user of this architecture
|
||||
was the milkymist project, which has been dead for years; there was
|
||||
never an upstream Linux port.
|
||||
|
||||
``unicore32`` CPUs (since 5.2.0)
|
||||
''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``unicore32`` guest CPU support is deprecated and will be removed in
|
||||
a future version of QEMU. Support for this CPU was removed from the
|
||||
upstream Linux kernel, and there is no available upstream toolchain
|
||||
to build binaries for it.
|
||||
|
||||
``tilegx`` CPUs (since 5.1.0)
|
||||
'''''''''''''''''''''''''''''
|
||||
|
||||
@@ -543,6 +551,14 @@ should be used instead of the 1.09.1 version.
|
||||
System emulator CPUS
|
||||
--------------------
|
||||
|
||||
KVM guest support on 32-bit Arm hosts (removed in 5.2)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The Linux kernel has dropped support for allowing 32-bit Arm systems
|
||||
to host KVM guests as of the 5.7 kernel. Accordingly, QEMU is deprecating
|
||||
its support for this configuration and will remove it in a future version.
|
||||
Running 32-bit guests on a 64-bit Arm host remains supported.
|
||||
|
||||
RISC-V ISA Specific CPUs (removed in 5.1)
|
||||
'''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ undocumented; you can get a complete list by running
|
||||
arm/musicpal
|
||||
arm/gumstix
|
||||
arm/nseries
|
||||
arm/nuvoton
|
||||
arm/orangepi
|
||||
arm/palm
|
||||
arm/xscale
|
||||
|
||||
@@ -355,6 +355,15 @@ config XLNX_VERSAL
|
||||
select VIRTIO_MMIO
|
||||
select UNIMP
|
||||
|
||||
config NPCM7XX
|
||||
bool
|
||||
select A9MPCORE
|
||||
select ARM_GIC
|
||||
select PL310 # cache controller
|
||||
select SERIAL
|
||||
select SSI
|
||||
select UNIMP
|
||||
|
||||
config FSL_IMX25
|
||||
bool
|
||||
select IMX
|
||||
|
||||
@@ -13,6 +13,7 @@ arm_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c'))
|
||||
arm_ss.add(when: 'CONFIG_MUSICPAL', if_true: files('musicpal.c'))
|
||||
arm_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c'))
|
||||
arm_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c'))
|
||||
arm_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c'))
|
||||
arm_ss.add(when: 'CONFIG_NSERIES', if_true: files('nseries.c'))
|
||||
arm_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c'))
|
||||
arm_ss.add(when: 'CONFIG_CHEETAH', if_true: files('palm.c'))
|
||||
|
||||
+83
-14
@@ -15,6 +15,8 @@
|
||||
* as seen by the guest depend significantly on the FPGA image.
|
||||
* We model the following FPGA images:
|
||||
* "mps2-an385" -- Cortex-M3 as documented in ARM Application Note AN385
|
||||
* "mps2-an386" -- Cortex-M4 as documented in ARM Application Note AN386
|
||||
* "mps2-an500" -- Cortex-M7 as documented in ARM Application Note AN500
|
||||
* "mps2-an511" -- Cortex-M3 'DesignStart' as documented in AN511
|
||||
*
|
||||
* Links to the TRM for the board itself and to the various Application
|
||||
@@ -48,6 +50,8 @@
|
||||
|
||||
typedef enum MPS2FPGAType {
|
||||
FPGA_AN385,
|
||||
FPGA_AN386,
|
||||
FPGA_AN500,
|
||||
FPGA_AN511,
|
||||
} MPS2FPGAType;
|
||||
|
||||
@@ -55,6 +59,9 @@ struct MPS2MachineClass {
|
||||
MachineClass parent;
|
||||
MPS2FPGAType fpga_type;
|
||||
uint32_t scc_id;
|
||||
bool has_block_ram;
|
||||
hwaddr ethernet_base;
|
||||
hwaddr psram_base;
|
||||
};
|
||||
typedef struct MPS2MachineClass MPS2MachineClass;
|
||||
|
||||
@@ -82,6 +89,8 @@ typedef struct MPS2MachineState MPS2MachineState;
|
||||
|
||||
#define TYPE_MPS2_MACHINE "mps2"
|
||||
#define TYPE_MPS2_AN385_MACHINE MACHINE_TYPE_NAME("mps2-an385")
|
||||
#define TYPE_MPS2_AN386_MACHINE MACHINE_TYPE_NAME("mps2-an386")
|
||||
#define TYPE_MPS2_AN500_MACHINE MACHINE_TYPE_NAME("mps2-an500")
|
||||
#define TYPE_MPS2_AN511_MACHINE MACHINE_TYPE_NAME("mps2-an511")
|
||||
|
||||
DECLARE_OBJ_CHECKERS(MPS2MachineState, MPS2MachineClass,
|
||||
@@ -139,13 +148,14 @@ static void mps2_common_init(MachineState *machine)
|
||||
* tradeoffs. For QEMU they're all just RAM, though. We arbitrarily
|
||||
* call the 16MB our "system memory", as it's the largest lump.
|
||||
*
|
||||
* Common to both boards:
|
||||
* 0x21000000..0x21ffffff : PSRAM (16MB)
|
||||
* AN385 only:
|
||||
* AN385/AN386/AN511:
|
||||
* 0x21000000 .. 0x21ffffff : PSRAM (16MB)
|
||||
* AN385/AN386/AN500:
|
||||
* 0x00000000 .. 0x003fffff : ZBT SSRAM1
|
||||
* 0x00400000 .. 0x007fffff : mirror of ZBT SSRAM1
|
||||
* 0x20000000 .. 0x203fffff : ZBT SSRAM 2&3
|
||||
* 0x20400000 .. 0x207fffff : mirror of ZBT SSRAM 2&3
|
||||
* AN385/AN386 only:
|
||||
* 0x01000000 .. 0x01003fff : block RAM (16K)
|
||||
* 0x01004000 .. 0x01007fff : mirror of above
|
||||
* 0x01008000 .. 0x0100bfff : mirror of above
|
||||
@@ -155,21 +165,17 @@ static void mps2_common_init(MachineState *machine)
|
||||
* 0x00400000 .. 0x007fffff : ZBT SSRAM1
|
||||
* 0x20000000 .. 0x2001ffff : SRAM
|
||||
* 0x20400000 .. 0x207fffff : ZBT SSRAM 2&3
|
||||
* AN500 only:
|
||||
* 0x60000000 .. 0x60ffffff : PSRAM (16MB)
|
||||
*
|
||||
* The AN385 has a feature where the lowest 16K can be mapped
|
||||
* The AN385/AN386 has a feature where the lowest 16K can be mapped
|
||||
* either to the bottom of the ZBT SSRAM1 or to the block RAM.
|
||||
* This is of no use for QEMU so we don't implement it (as if
|
||||
* zbt_boot_ctrl is always zero).
|
||||
*/
|
||||
memory_region_add_subregion(system_memory, 0x21000000, machine->ram);
|
||||
memory_region_add_subregion(system_memory, mmc->psram_base, machine->ram);
|
||||
|
||||
switch (mmc->fpga_type) {
|
||||
case FPGA_AN385:
|
||||
make_ram(&mms->ssram1, "mps.ssram1", 0x0, 0x400000);
|
||||
make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x400000);
|
||||
make_ram(&mms->ssram23, "mps.ssram23", 0x20000000, 0x400000);
|
||||
make_ram_alias(&mms->ssram23_m, "mps.ssram23_m",
|
||||
&mms->ssram23, 0x20400000);
|
||||
if (mmc->has_block_ram) {
|
||||
make_ram(&mms->blockram, "mps.blockram", 0x01000000, 0x4000);
|
||||
make_ram_alias(&mms->blockram_m1, "mps.blockram_m1",
|
||||
&mms->blockram, 0x01004000);
|
||||
@@ -177,6 +183,17 @@ static void mps2_common_init(MachineState *machine)
|
||||
&mms->blockram, 0x01008000);
|
||||
make_ram_alias(&mms->blockram_m3, "mps.blockram_m3",
|
||||
&mms->blockram, 0x0100c000);
|
||||
}
|
||||
|
||||
switch (mmc->fpga_type) {
|
||||
case FPGA_AN385:
|
||||
case FPGA_AN386:
|
||||
case FPGA_AN500:
|
||||
make_ram(&mms->ssram1, "mps.ssram1", 0x0, 0x400000);
|
||||
make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x400000);
|
||||
make_ram(&mms->ssram23, "mps.ssram23", 0x20000000, 0x400000);
|
||||
make_ram_alias(&mms->ssram23_m, "mps.ssram23_m",
|
||||
&mms->ssram23, 0x20400000);
|
||||
break;
|
||||
case FPGA_AN511:
|
||||
make_ram(&mms->blockram, "mps.blockram", 0x0, 0x40000);
|
||||
@@ -192,6 +209,8 @@ static void mps2_common_init(MachineState *machine)
|
||||
armv7m = DEVICE(&mms->armv7m);
|
||||
switch (mmc->fpga_type) {
|
||||
case FPGA_AN385:
|
||||
case FPGA_AN386:
|
||||
case FPGA_AN500:
|
||||
qdev_prop_set_uint32(armv7m, "num-irq", 32);
|
||||
break;
|
||||
case FPGA_AN511:
|
||||
@@ -228,6 +247,8 @@ static void mps2_common_init(MachineState *machine)
|
||||
|
||||
switch (mmc->fpga_type) {
|
||||
case FPGA_AN385:
|
||||
case FPGA_AN386:
|
||||
case FPGA_AN500:
|
||||
{
|
||||
/* The overflow IRQs for UARTs 0, 1 and 2 are ORed together.
|
||||
* Overflow for UARTs 4 and 5 doesn't trigger any interrupt.
|
||||
@@ -377,9 +398,9 @@ static void mps2_common_init(MachineState *machine)
|
||||
/* In hardware this is a LAN9220; the LAN9118 is software compatible
|
||||
* except that it doesn't support the checksum-offload feature.
|
||||
*/
|
||||
lan9118_init(&nd_table[0], 0x40200000,
|
||||
lan9118_init(&nd_table[0], mmc->ethernet_base,
|
||||
qdev_get_gpio_in(armv7m,
|
||||
mmc->fpga_type == FPGA_AN385 ? 13 : 47));
|
||||
mmc->fpga_type == FPGA_AN511 ? 47 : 13));
|
||||
|
||||
system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
|
||||
|
||||
@@ -406,6 +427,37 @@ static void mps2_an385_class_init(ObjectClass *oc, void *data)
|
||||
mmc->fpga_type = FPGA_AN385;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
|
||||
mmc->scc_id = 0x41043850;
|
||||
mmc->psram_base = 0x21000000;
|
||||
mmc->ethernet_base = 0x40200000;
|
||||
mmc->has_block_ram = true;
|
||||
}
|
||||
|
||||
static void mps2_an386_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "ARM MPS2 with AN386 FPGA image for Cortex-M4";
|
||||
mmc->fpga_type = FPGA_AN386;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m4");
|
||||
mmc->scc_id = 0x41043860;
|
||||
mmc->psram_base = 0x21000000;
|
||||
mmc->ethernet_base = 0x40200000;
|
||||
mmc->has_block_ram = true;
|
||||
}
|
||||
|
||||
static void mps2_an500_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "ARM MPS2 with AN500 FPGA image for Cortex-M7";
|
||||
mmc->fpga_type = FPGA_AN500;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m7");
|
||||
mmc->scc_id = 0x41045000;
|
||||
mmc->psram_base = 0x60000000;
|
||||
mmc->ethernet_base = 0xa0000000;
|
||||
mmc->has_block_ram = false;
|
||||
}
|
||||
|
||||
static void mps2_an511_class_init(ObjectClass *oc, void *data)
|
||||
@@ -417,6 +469,9 @@ static void mps2_an511_class_init(ObjectClass *oc, void *data)
|
||||
mmc->fpga_type = FPGA_AN511;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
|
||||
mmc->scc_id = 0x41045110;
|
||||
mmc->psram_base = 0x21000000;
|
||||
mmc->ethernet_base = 0x40200000;
|
||||
mmc->has_block_ram = false;
|
||||
}
|
||||
|
||||
static const TypeInfo mps2_info = {
|
||||
@@ -434,6 +489,18 @@ static const TypeInfo mps2_an385_info = {
|
||||
.class_init = mps2_an385_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo mps2_an386_info = {
|
||||
.name = TYPE_MPS2_AN386_MACHINE,
|
||||
.parent = TYPE_MPS2_MACHINE,
|
||||
.class_init = mps2_an386_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo mps2_an500_info = {
|
||||
.name = TYPE_MPS2_AN500_MACHINE,
|
||||
.parent = TYPE_MPS2_MACHINE,
|
||||
.class_init = mps2_an500_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo mps2_an511_info = {
|
||||
.name = TYPE_MPS2_AN511_MACHINE,
|
||||
.parent = TYPE_MPS2_MACHINE,
|
||||
@@ -444,6 +511,8 @@ static void mps2_machine_init(void)
|
||||
{
|
||||
type_register_static(&mps2_info);
|
||||
type_register_static(&mps2_an385_info);
|
||||
type_register_static(&mps2_an386_info);
|
||||
type_register_static(&mps2_an500_info);
|
||||
type_register_static(&mps2_an511_info);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Machine definitions for boards featuring an NPCM7xx SoC.
|
||||
*
|
||||
* 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 "exec/address-spaces.h"
|
||||
#include "hw/arm/npcm7xx.h"
|
||||
#include "hw/core/cpu.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/units.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7
|
||||
#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff
|
||||
|
||||
static const char npcm7xx_default_bootrom[] = "npcm7xx_bootrom.bin";
|
||||
|
||||
static void npcm7xx_load_bootrom(MachineState *machine, NPCM7xxState *soc)
|
||||
{
|
||||
g_autofree char *filename = NULL;
|
||||
int ret;
|
||||
|
||||
if (!bios_name) {
|
||||
bios_name = npcm7xx_default_bootrom;
|
||||
}
|
||||
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
if (!filename) {
|
||||
error_report("Could not find ROM image '%s'", bios_name);
|
||||
if (!machine->kernel_filename) {
|
||||
/* We can't boot without a bootrom or a kernel image. */
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ret = load_image_mr(filename, &soc->irom);
|
||||
if (ret < 0) {
|
||||
error_report("Failed to load ROM image '%s'", filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void npcm7xx_connect_flash(NPCM7xxFIUState *fiu, int cs_no,
|
||||
const char *flash_type, DriveInfo *dinfo)
|
||||
{
|
||||
DeviceState *flash;
|
||||
qemu_irq flash_cs;
|
||||
|
||||
flash = qdev_new(flash_type);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive(flash, "drive", blk_by_legacy_dinfo(dinfo));
|
||||
}
|
||||
qdev_realize_and_unref(flash, BUS(fiu->spi), &error_fatal);
|
||||
|
||||
flash_cs = qdev_get_gpio_in_named(flash, SSI_GPIO_CS, 0);
|
||||
qdev_connect_gpio_out_named(DEVICE(fiu), "cs", cs_no, flash_cs);
|
||||
}
|
||||
|
||||
static void npcm7xx_connect_dram(NPCM7xxState *soc, MemoryRegion *dram)
|
||||
{
|
||||
memory_region_add_subregion(get_system_memory(), NPCM7XX_DRAM_BA, dram);
|
||||
|
||||
object_property_set_link(OBJECT(soc), "dram-mr", OBJECT(dram),
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
|
||||
uint32_t hw_straps)
|
||||
{
|
||||
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
|
||||
MachineClass *mc = &nmc->parent;
|
||||
Object *obj;
|
||||
|
||||
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
|
||||
error_report("This board can only be used with %s",
|
||||
mc->default_cpu_type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
obj = object_new_with_props(nmc->soc_type, OBJECT(machine), "soc",
|
||||
&error_abort, NULL);
|
||||
object_property_set_uint(obj, "power-on-straps", hw_straps, &error_abort);
|
||||
|
||||
return NPCM7XX(obj);
|
||||
}
|
||||
|
||||
static void npcm750_evb_init(MachineState *machine)
|
||||
{
|
||||
NPCM7xxState *soc;
|
||||
|
||||
soc = npcm7xx_create_soc(machine, NPCM750_EVB_POWER_ON_STRAPS);
|
||||
npcm7xx_connect_dram(soc, machine->ram);
|
||||
qdev_realize(DEVICE(soc), NULL, &error_fatal);
|
||||
|
||||
npcm7xx_load_bootrom(machine, soc);
|
||||
npcm7xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0));
|
||||
npcm7xx_load_kernel(machine, soc);
|
||||
}
|
||||
|
||||
static void quanta_gsj_init(MachineState *machine)
|
||||
{
|
||||
NPCM7xxState *soc;
|
||||
|
||||
soc = npcm7xx_create_soc(machine, QUANTA_GSJ_POWER_ON_STRAPS);
|
||||
npcm7xx_connect_dram(soc, machine->ram);
|
||||
qdev_realize(DEVICE(soc), NULL, &error_fatal);
|
||||
|
||||
npcm7xx_load_bootrom(machine, soc);
|
||||
npcm7xx_connect_flash(&soc->fiu[0], 0, "mx25l25635e",
|
||||
drive_get(IF_MTD, 0, 0));
|
||||
npcm7xx_load_kernel(machine, soc);
|
||||
}
|
||||
|
||||
static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type)
|
||||
{
|
||||
NPCM7xxClass *sc = NPCM7XX_CLASS(object_class_by_name(type));
|
||||
MachineClass *mc = MACHINE_CLASS(nmc);
|
||||
|
||||
nmc->soc_type = type;
|
||||
mc->default_cpus = mc->min_cpus = mc->max_cpus = sc->num_cpus;
|
||||
}
|
||||
|
||||
static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
mc->default_ram_id = "ram";
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
|
||||
}
|
||||
|
||||
/*
|
||||
* Schematics:
|
||||
* https://github.com/Nuvoton-Israel/nuvoton-info/blob/master/npcm7xx-poleg/evaluation-board/board_deliverables/NPCM750x_EB_ver.A1.1_COMPLETE.pdf
|
||||
*/
|
||||
static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
npcm7xx_set_soc_type(nmc, TYPE_NPCM750);
|
||||
|
||||
mc->desc = "Nuvoton NPCM750 Evaluation Board (Cortex A9)";
|
||||
mc->init = npcm750_evb_init;
|
||||
mc->default_ram_size = 512 * MiB;
|
||||
};
|
||||
|
||||
static void gsj_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
npcm7xx_set_soc_type(nmc, TYPE_NPCM730);
|
||||
|
||||
mc->desc = "Quanta GSJ (Cortex A9)";
|
||||
mc->init = quanta_gsj_init;
|
||||
mc->default_ram_size = 512 * MiB;
|
||||
};
|
||||
|
||||
static const TypeInfo npcm7xx_machine_types[] = {
|
||||
{
|
||||
.name = TYPE_NPCM7XX_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(NPCM7xxMachine),
|
||||
.class_size = sizeof(NPCM7xxMachineClass),
|
||||
.class_init = npcm7xx_machine_class_init,
|
||||
.abstract = true,
|
||||
}, {
|
||||
.name = MACHINE_TYPE_NAME("npcm750-evb"),
|
||||
.parent = TYPE_NPCM7XX_MACHINE,
|
||||
.class_init = npcm750_evb_machine_class_init,
|
||||
}, {
|
||||
.name = MACHINE_TYPE_NAME("quanta-gsj"),
|
||||
.parent = TYPE_NPCM7XX_MACHINE,
|
||||
.class_init = gsj_machine_class_init,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_TYPES(npcm7xx_machine_types)
|
||||
@@ -214,7 +214,7 @@ static void fdt_add_gem_nodes(VersalVirt *s)
|
||||
s->phandle.ethernet_phy[i]);
|
||||
qemu_fdt_setprop_cells(s->fdt, name, "clocks",
|
||||
s->phandle.clk_25Mhz, s->phandle.clk_25Mhz,
|
||||
s->phandle.clk_25Mhz, s->phandle.clk_25Mhz);
|
||||
s->phandle.clk_125Mhz, s->phandle.clk_125Mhz);
|
||||
qemu_fdt_setprop(s->fdt, name, "clock-names",
|
||||
clocknames, sizeof(clocknames));
|
||||
qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mem_ss = ss.source_set()
|
||||
mem_ss.add(files('memory-device.c'))
|
||||
mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c'))
|
||||
mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c'))
|
||||
mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c'))
|
||||
|
||||
softmmu_ss.add_all(when: 'CONFIG_MEM_DEVICE', if_true: mem_ss)
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Nuvoton NPCM7xx Memory Controller stub
|
||||
*
|
||||
* 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/mem/npcm7xx_mc.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/units.h"
|
||||
|
||||
#define NPCM7XX_MC_REGS_SIZE (4 * KiB)
|
||||
|
||||
static uint64_t npcm7xx_mc_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
/*
|
||||
* If bits 8..11 @ offset 0 are not zero, the boot block thinks the memory
|
||||
* controller has already been initialized and will skip DDR training.
|
||||
*/
|
||||
if (addr == 0) {
|
||||
return 0x100;
|
||||
}
|
||||
|
||||
qemu_log_mask(LOG_UNIMP, "%s: mostly unimplemented\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void npcm7xx_mc_write(void *opaque, hwaddr addr, uint64_t v,
|
||||
unsigned int size)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "%s: mostly unimplemented\n", __func__);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps npcm7xx_mc_ops = {
|
||||
.read = npcm7xx_mc_read,
|
||||
.write = npcm7xx_mc_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
NPCM7xxMCState *s = NPCM7XX_MC(dev);
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs",
|
||||
NPCM7XX_MC_REGS_SIZE);
|
||||
sysbus_init_mmio(&s->parent, &s->mmio);
|
||||
}
|
||||
|
||||
static void npcm7xx_mc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "NPCM7xx Memory Controller stub";
|
||||
dc->realize = npcm7xx_mc_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo npcm7xx_mc_types[] = {
|
||||
{
|
||||
.name = TYPE_NPCM7XX_MC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(NPCM7xxMCState),
|
||||
.class_init = npcm7xx_mc_class_init,
|
||||
},
|
||||
};
|
||||
DEFINE_TYPES(npcm7xx_mc_types);
|
||||
+28
-31
@@ -12,8 +12,12 @@
|
||||
#include "hw/misc/a9scu.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
|
||||
#define A9_SCU_CPU_MAX 4
|
||||
|
||||
static uint64_t a9_scu_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
@@ -25,12 +29,6 @@ static uint64_t a9_scu_read(void *opaque, hwaddr offset,
|
||||
return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
|
||||
case 0x08: /* CPU Power Status */
|
||||
return s->status;
|
||||
case 0x09: /* CPU status. */
|
||||
return s->status >> 8;
|
||||
case 0x0a: /* CPU status. */
|
||||
return s->status >> 16;
|
||||
case 0x0b: /* CPU status. */
|
||||
return s->status >> 24;
|
||||
case 0x0c: /* Invalidate All Registers In Secure State */
|
||||
return 0;
|
||||
case 0x40: /* Filtering Start Address Register */
|
||||
@@ -41,6 +39,8 @@ static uint64_t a9_scu_read(void *opaque, hwaddr offset,
|
||||
case 0x54: /* SCU Non-secure Access Control Register */
|
||||
/* unimplemented, fall through */
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx"\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -49,23 +49,6 @@ static void a9_scu_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
A9SCUState *s = (A9SCUState *)opaque;
|
||||
uint32_t mask;
|
||||
uint32_t shift;
|
||||
switch (size) {
|
||||
case 1:
|
||||
mask = 0xff;
|
||||
break;
|
||||
case 2:
|
||||
mask = 0xffff;
|
||||
break;
|
||||
case 4:
|
||||
mask = 0xffffffff;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
|
||||
size, (unsigned)offset);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case 0x00: /* Control */
|
||||
@@ -74,9 +57,7 @@ static void a9_scu_write(void *opaque, hwaddr offset,
|
||||
case 0x4: /* Configuration: RO */
|
||||
break;
|
||||
case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
|
||||
shift = (offset - 0x8) * 8;
|
||||
s->status &= ~(mask << shift);
|
||||
s->status |= ((value & mask) << shift);
|
||||
s->status = value;
|
||||
break;
|
||||
case 0x0c: /* Invalidate All Registers In Secure State */
|
||||
/* no-op as we do not implement caches */
|
||||
@@ -89,6 +70,9 @@ static void a9_scu_write(void *opaque, hwaddr offset,
|
||||
case 0x54: /* SCU Non-secure Access Control Register */
|
||||
/* unimplemented, fall through */
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx
|
||||
" value 0x%"PRIx64"\n",
|
||||
__func__, offset, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -96,6 +80,14 @@ static void a9_scu_write(void *opaque, hwaddr offset,
|
||||
static const MemoryRegionOps a9_scu_ops = {
|
||||
.read = a9_scu_read,
|
||||
.write = a9_scu_write,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
@@ -105,12 +97,17 @@ static void a9_scu_reset(DeviceState *dev)
|
||||
s->control = 0;
|
||||
}
|
||||
|
||||
static void a9_scu_init(Object *obj)
|
||||
static void a9_scu_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
A9SCUState *s = A9_SCU(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
A9SCUState *s = A9_SCU(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &a9_scu_ops, s,
|
||||
if (!s->num_cpu || s->num_cpu > A9_SCU_CPU_MAX) {
|
||||
error_setg(errp, "Illegal CPU count: %u", s->num_cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &a9_scu_ops, s,
|
||||
"a9-scu", 0x100);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
@@ -138,13 +135,13 @@ static void a9_scu_class_init(ObjectClass *klass, void *data)
|
||||
device_class_set_props(dc, a9_scu_properties);
|
||||
dc->vmsd = &vmstate_a9_scu;
|
||||
dc->reset = a9_scu_reset;
|
||||
dc->realize = a9_scu_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo a9_scu_info = {
|
||||
.name = TYPE_A9_SCU,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(A9SCUState),
|
||||
.instance_init = a9_scu_init,
|
||||
.class_init = a9_scu_class_init,
|
||||
};
|
||||
|
||||
|
||||
@@ -56,6 +56,10 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files(
|
||||
))
|
||||
softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-hpdmc.c', 'milkymist-pfpu.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
|
||||
'npcm7xx_clk.c',
|
||||
'npcm7xx_gcr.c',
|
||||
))
|
||||
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
|
||||
'omap_clk.c',
|
||||
'omap_gpmc.c',
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Nuvoton NPCM7xx Clock 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_clk.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/units.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define PLLCON_LOKI BIT(31)
|
||||
#define PLLCON_LOKS BIT(30)
|
||||
#define PLLCON_PWDEN BIT(12)
|
||||
|
||||
enum NPCM7xxCLKRegisters {
|
||||
NPCM7XX_CLK_CLKEN1,
|
||||
NPCM7XX_CLK_CLKSEL,
|
||||
NPCM7XX_CLK_CLKDIV1,
|
||||
NPCM7XX_CLK_PLLCON0,
|
||||
NPCM7XX_CLK_PLLCON1,
|
||||
NPCM7XX_CLK_SWRSTR,
|
||||
NPCM7XX_CLK_IPSRST1 = 0x20 / sizeof(uint32_t),
|
||||
NPCM7XX_CLK_IPSRST2,
|
||||
NPCM7XX_CLK_CLKEN2,
|
||||
NPCM7XX_CLK_CLKDIV2,
|
||||
NPCM7XX_CLK_CLKEN3,
|
||||
NPCM7XX_CLK_IPSRST3,
|
||||
NPCM7XX_CLK_WD0RCR,
|
||||
NPCM7XX_CLK_WD1RCR,
|
||||
NPCM7XX_CLK_WD2RCR,
|
||||
NPCM7XX_CLK_SWRSTC1,
|
||||
NPCM7XX_CLK_SWRSTC2,
|
||||
NPCM7XX_CLK_SWRSTC3,
|
||||
NPCM7XX_CLK_SWRSTC4,
|
||||
NPCM7XX_CLK_PLLCON2,
|
||||
NPCM7XX_CLK_CLKDIV3,
|
||||
NPCM7XX_CLK_CORSTC,
|
||||
NPCM7XX_CLK_PLLCONG,
|
||||
NPCM7XX_CLK_AHBCKFI,
|
||||
NPCM7XX_CLK_SECCNT,
|
||||
NPCM7XX_CLK_CNTR25M,
|
||||
NPCM7XX_CLK_REGS_END,
|
||||
};
|
||||
|
||||
/*
|
||||
* These reset values were taken from version 0.91 of the NPCM750R data sheet.
|
||||
*
|
||||
* 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] = {
|
||||
[NPCM7XX_CLK_CLKEN1] = 0xffffffff,
|
||||
[NPCM7XX_CLK_CLKSEL] = 0x004aaaaa,
|
||||
[NPCM7XX_CLK_CLKDIV1] = 0x5413f855,
|
||||
[NPCM7XX_CLK_PLLCON0] = 0x00222101 | PLLCON_LOKI,
|
||||
[NPCM7XX_CLK_PLLCON1] = 0x00202101 | PLLCON_LOKI,
|
||||
[NPCM7XX_CLK_IPSRST1] = 0x00001000,
|
||||
[NPCM7XX_CLK_IPSRST2] = 0x80000000,
|
||||
[NPCM7XX_CLK_CLKEN2] = 0xffffffff,
|
||||
[NPCM7XX_CLK_CLKDIV2] = 0xaa4f8f9f,
|
||||
[NPCM7XX_CLK_CLKEN3] = 0xffffffff,
|
||||
[NPCM7XX_CLK_IPSRST3] = 0x03000000,
|
||||
[NPCM7XX_CLK_WD0RCR] = 0xffffffff,
|
||||
[NPCM7XX_CLK_WD1RCR] = 0xffffffff,
|
||||
[NPCM7XX_CLK_WD2RCR] = 0xffffffff,
|
||||
[NPCM7XX_CLK_SWRSTC1] = 0x00000003,
|
||||
[NPCM7XX_CLK_PLLCON2] = 0x00c02105 | PLLCON_LOKI,
|
||||
[NPCM7XX_CLK_CORSTC] = 0x04000003,
|
||||
[NPCM7XX_CLK_PLLCONG] = 0x01228606 | PLLCON_LOKI,
|
||||
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
|
||||
};
|
||||
|
||||
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
uint32_t reg = offset / sizeof(uint32_t);
|
||||
NPCM7xxCLKState *s = opaque;
|
||||
int64_t now_ns;
|
||||
uint32_t value = 0;
|
||||
|
||||
if (reg >= NPCM7XX_CLK_NR_REGS) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: offset 0x%04" HWADDR_PRIx " out of range\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case NPCM7XX_CLK_SWRSTR:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: register @ 0x%04" HWADDR_PRIx " is write-only\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
|
||||
case NPCM7XX_CLK_SECCNT:
|
||||
now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
value = (now_ns - s->ref_ns) / NANOSECONDS_PER_SECOND;
|
||||
break;
|
||||
|
||||
case NPCM7XX_CLK_CNTR25M:
|
||||
now_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
/*
|
||||
* This register counts 25 MHz cycles, updating every 640 ns. It rolls
|
||||
* over to zero every second.
|
||||
*
|
||||
* The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
|
||||
*/
|
||||
value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_TIMER_REF_HZ;
|
||||
break;
|
||||
|
||||
default:
|
||||
value = s->regs[reg];
|
||||
break;
|
||||
};
|
||||
|
||||
trace_npcm7xx_clk_read(offset, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void npcm7xx_clk_write(void *opaque, hwaddr offset,
|
||||
uint64_t v, unsigned size)
|
||||
{
|
||||
uint32_t reg = offset / sizeof(uint32_t);
|
||||
NPCM7xxCLKState *s = opaque;
|
||||
uint32_t value = v;
|
||||
|
||||
trace_npcm7xx_clk_write(offset, value);
|
||||
|
||||
if (reg >= NPCM7XX_CLK_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_CLK_SWRSTR:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: SW reset not implemented: 0x%02x\n",
|
||||
__func__, value);
|
||||
value = 0;
|
||||
break;
|
||||
|
||||
case NPCM7XX_CLK_PLLCON0:
|
||||
case NPCM7XX_CLK_PLLCON1:
|
||||
case NPCM7XX_CLK_PLLCON2:
|
||||
case NPCM7XX_CLK_PLLCONG:
|
||||
if (value & PLLCON_PWDEN) {
|
||||
/* Power down -- clear lock and indicate loss of lock */
|
||||
value &= ~PLLCON_LOKI;
|
||||
value |= PLLCON_LOKS;
|
||||
} else {
|
||||
/* Normal mode -- assume always locked */
|
||||
value |= PLLCON_LOKI;
|
||||
/* Keep LOKS unchanged unless cleared by writing 1 */
|
||||
if (value & PLLCON_LOKS) {
|
||||
value &= ~PLLCON_LOKS;
|
||||
} else {
|
||||
value |= (value & PLLCON_LOKS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NPCM7XX_CLK_CNTR25M:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
|
||||
__func__, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
s->regs[reg] = value;
|
||||
}
|
||||
|
||||
static const struct MemoryRegionOps npcm7xx_clk_ops = {
|
||||
.read = npcm7xx_clk_read,
|
||||
.write = npcm7xx_clk_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values));
|
||||
|
||||
switch (type) {
|
||||
case RESET_TYPE_COLD:
|
||||
memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
|
||||
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* A small number of registers need to be reset on a core domain reset,
|
||||
* but no such reset type exists yet.
|
||||
*/
|
||||
qemu_log_mask(LOG_UNIMP, "%s: reset type %d not implemented.",
|
||||
__func__, type);
|
||||
}
|
||||
|
||||
static void npcm7xx_clk_init(Object *obj)
|
||||
{
|
||||
NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
|
||||
TYPE_NPCM7XX_CLK, 4 * KiB);
|
||||
sysbus_init_mmio(&s->parent, &s->iomem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_npcm7xx_clk = {
|
||||
.name = "npcm7xx-clk",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
|
||||
VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static void npcm7xx_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->desc = "NPCM7xx Clock Control Registers";
|
||||
dc->vmsd = &vmstate_npcm7xx_clk;
|
||||
rc->phases.enter = npcm7xx_clk_enter_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo npcm7xx_clk_info = {
|
||||
.name = TYPE_NPCM7XX_CLK,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(NPCM7xxCLKState),
|
||||
.instance_init = npcm7xx_clk_init,
|
||||
.class_init = npcm7xx_clk_class_init,
|
||||
};
|
||||
|
||||
static void npcm7xx_clk_register_type(void)
|
||||
{
|
||||
type_register_static(&npcm7xx_clk_info);
|
||||
}
|
||||
type_init(npcm7xx_clk_register_type);
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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));
|
||||
|
||||
switch (type) {
|
||||
case RESET_TYPE_COLD:
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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(&s->parent, &s->iomem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_npcm7xx_gcr = {
|
||||
.name = "npcm7xx-gcr",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, NPCM7xxGCRState, NPCM7XX_GCR_NR_REGS),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static Property npcm7xx_gcr_properties[] = {
|
||||
DEFINE_PROP_UINT32("disabled-modules", NPCM7xxGCRState, reset_mdlr, 0),
|
||||
DEFINE_PROP_UINT32("power-on-straps", NPCM7xxGCRState, reset_pwron, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
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);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user