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>
This commit is contained in:
Stefan Hajnoczi
2025-02-21 07:14:03 +08:00
45 changed files with 2626 additions and 497 deletions
+1
View File
@@ -878,6 +878,7 @@ F: include/hw/*/npcm*
F: tests/qtest/npcm*
F: tests/qtest/adm1266-test.c
F: pc-bios/npcm7xx_bootrom.bin
F: pc-bios/npcm8xx_bootrom.bin
F: roms/vbootrom
F: docs/system/arm/nuvoton.rst
F: tests/functional/test_arm_quanta_gsj.py
@@ -8,3 +8,4 @@ include ../arm-softmmu/default.mak
# CONFIG_XLNX_ZYNQMP_ARM=n
# CONFIG_XLNX_VERSAL=n
# CONFIG_SBSA_REF=n
# CONFIG_NPCM8XX=n
+20 -7
View File
@@ -1,12 +1,13 @@
Nuvoton iBMC boards (``kudo-bmc``, ``mori-bmc``, ``npcm750-evb``, ``quanta-gbs-bmc``, ``quanta-gsj``)
=====================================================================================================
Nuvoton iBMC boards (``kudo-bmc``, ``mori-bmc``, ``npcm750-evb``, ``quanta-gbs-bmc``, ``quanta-gsj``, ``npcm845-evb``)
======================================================================================================================
The `Nuvoton iBMC`_ chips (NPCM7xx) are a family of ARM-based SoCs that are
The `Nuvoton iBMC`_ chips 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.
servers. Currently there are two families: NPCM7XX series and
NPCM8XX series. NPCM7XX series feature one or two Arm Cortex-A9 CPU cores,
while NPCM8XX feature 4 Arm Cortex-A35 CPU cores. Both series contain a
different assortment of peripherals targeted for either Enterprise or Data
Center / Hyperscale applications.
.. _Nuvoton iBMC: https://www.nuvoton.com/products/cloud-computing/ibmc/
@@ -27,6 +28,11 @@ 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.
The NPCM8xx SoC is the successor of the NPCM7xx SoC. It has 4 Cortex-A35 cores.
The following machines are based on this chip :
- ``npcm845-evb`` Nuvoton NPCM845 Evaluation board
Supported devices
-----------------
@@ -62,6 +68,8 @@ Missing devices
* System Wake-up Control (SWC)
* Shared memory (SHM)
* eSPI slave interface
* Block-transfer interface (8XX only)
* Virtual UART (8XX only)
* Ethernet controller (GMAC)
* USB device (USBD)
@@ -76,6 +84,11 @@ Missing devices
* Video capture
* Encoding compression engine
* Security features
* I3C buses (8XX only)
* Temperature sensor interface (8XX only)
* Virtual UART (8XX only)
* Flash monitor (8XX only)
* JTAG master (8XX only)
Boot options
------------
+18 -1
View File
@@ -303,7 +303,7 @@ config ZYNQ
select PL330
select SDHCI
select SSI_M25P80
select USB_EHCI_SYSBUS
select USB_CHIPIDEA
select XILINX # UART
select XILINX_AXI
select XILINX_SPI
@@ -481,6 +481,19 @@ config NPCM7XX
select PCA954X
select USB_OHCI_SYSBUS
config NPCM8XX
bool
default y
depends on TCG && AARCH64
select ARM_GIC
select SMBUS
select PL310 # cache controller
select NPCM7XX
select SERIAL
select SSI
select UNIMP
config FSL_IMX25
bool
default y
@@ -489,6 +502,7 @@ config FSL_IMX25
select IMX
select IMX_FEC
select IMX_I2C
select USB_CHIPIDEA
select WDT_IMX2
select SDHCI
@@ -516,6 +530,7 @@ config FSL_IMX6
select PL310 # cache controller
select PCI_EXPRESS_DESIGNWARE
select SDHCI
select USB_CHIPIDEA
select OR_IRQ
config ASPEED_SOC
@@ -576,6 +591,7 @@ config FSL_IMX7
select SDHCI
select OR_IRQ
select UNIMP
select USB_CHIPIDEA
config ARM_SMMUV3
bool
@@ -591,6 +607,7 @@ config FSL_IMX6UL
select IMX_I2C
select WDT_IMX2
select SDHCI
select USB_CHIPIDEA
select UNIMP
config MICROBIT
+8 -2
View File
@@ -103,6 +103,8 @@
#define EXYNOS4210_PL330_BASE1_ADDR 0x12690000
#define EXYNOS4210_PL330_BASE2_ADDR 0x12850000
#define GIC_EXT_IRQS 64 /* FIXME: verify for this SoC */
enum ExtGicId {
EXT_GIC_ID_MDMA_LCD0 = 66,
EXT_GIC_ID_PDMA0,
@@ -394,7 +396,8 @@ static void exynos4210_init_board_irqs(Exynos4210State *s)
}
if (irq_id) {
qdev_connect_gpio_out(splitter, splitin,
qdev_get_gpio_in(extgicdev, irq_id - 32));
qdev_get_gpio_in(extgicdev,
irq_id - GIC_INTERNAL));
}
}
for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
@@ -421,7 +424,8 @@ static void exynos4210_init_board_irqs(Exynos4210State *s)
s->irq_table[n] = qdev_get_gpio_in(splitter, 0);
qdev_connect_gpio_out(splitter, 0, qdev_get_gpio_in(intcdev, n));
qdev_connect_gpio_out(splitter, 1,
qdev_get_gpio_in(extgicdev, irq_id - 32));
qdev_get_gpio_in(extgicdev,
irq_id - GIC_INTERNAL));
} else {
s->irq_table[n] = qdev_get_gpio_in(intcdev, n);
}
@@ -586,6 +590,8 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
/* Private memory region and Internal GIC */
qdev_prop_set_uint32(DEVICE(&s->a9mpcore), "num-cpu", EXYNOS4210_NCPUS);
qdev_prop_set_uint32(DEVICE(&s->a9mpcore), "num-irq",
GIC_EXT_IRQS + GIC_INTERNAL);
busdev = SYS_BUS_DEVICE(&s->a9mpcore);
sysbus_realize(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
+4 -4
View File
@@ -45,7 +45,7 @@
#define MVBAR_ADDR 0x200
#define BOARD_SETUP_ADDR (MVBAR_ADDR + 8 * sizeof(uint32_t))
#define NIRQ_GIC 160
#define GIC_EXT_IRQS 128 /* EnergyCore ECX-1000 & ECX-2000 */
/* Board init. */
@@ -180,7 +180,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
{
DeviceState *dev = NULL;
SysBusDevice *busdev;
qemu_irq pic[128];
qemu_irq pic[GIC_EXT_IRQS];
int n;
unsigned int smp_cpus = machine->smp.cpus;
qemu_irq cpu_irq[4];
@@ -260,7 +260,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
break;
}
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
qdev_prop_set_uint32(dev, "num-irq", GIC_EXT_IRQS + GIC_INTERNAL);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
@@ -271,7 +271,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
sysbus_connect_irq(busdev, n + 3 * smp_cpus, cpu_vfiq[n]);
}
for (n = 0; n < 128; n++) {
for (n = 0; n < GIC_EXT_IRQS; n++) {
pic[n] = qdev_get_gpio_in(dev, n);
}
+1
View File
@@ -12,6 +12,7 @@ arm_ss.add(when: 'CONFIG_MUSICPAL', if_true: files('musicpal.c'))
arm_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c'))
arm_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c'))
arm_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c'))
arm_ss.add(when: 'CONFIG_NPCM8XX', if_true: files('npcm8xx.c', 'npcm8xx_boards.c'))
arm_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c'))
arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c'))
arm_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c'))
+6
View File
@@ -292,17 +292,21 @@ static const struct {
hwaddr regs_addr;
int cs_count;
const hwaddr *flash_addr;
size_t flash_size;
} npcm7xx_fiu[] = {
{
.name = "fiu0",
.regs_addr = 0xfb000000,
.cs_count = ARRAY_SIZE(npcm7xx_fiu0_flash_addr),
.flash_addr = npcm7xx_fiu0_flash_addr,
.flash_size = 128 * MiB,
}, {
.name = "fiu3",
.regs_addr = 0xc0000000,
.cs_count = ARRAY_SIZE(npcm7xx_fiu3_flash_addr),
.flash_addr = npcm7xx_fiu3_flash_addr,
.flash_size = 128 * MiB,
},
};
@@ -735,6 +739,8 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
object_property_set_int(OBJECT(sbd), "cs-count",
npcm7xx_fiu[i].cs_count, &error_abort);
object_property_set_int(OBJECT(sbd), "flash-size",
npcm7xx_fiu[i].flash_size, &error_abort);
sysbus_realize(sbd, &error_abort);
sysbus_mmio_map(sbd, 0, npcm7xx_fiu[i].regs_addr);
+805
View File
File diff suppressed because it is too large Load Diff
+254
View File
@@ -0,0 +1,254 @@
/*
* Machine definitions for boards featuring an NPCM8xx SoC.
*
* Copyright 2021 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 "chardev/char.h"
#include "hw/boards.h"
#include "hw/arm/npcm8xx.h"
#include "hw/core/cpu.h"
#include "hw/loader.h"
#include "hw/qdev-core.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/datadir.h"
#include "qemu/units.h"
#define NPCM845_EVB_POWER_ON_STRAPS 0x000017ff
static const char npcm8xx_default_bootrom[] = "npcm8xx_bootrom.bin";
static void npcm8xx_load_bootrom(MachineState *machine, NPCM8xxState *soc)
{
const char *bios_name = machine->firmware ?: npcm8xx_default_bootrom;
g_autofree char *filename = NULL;
int ret;
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, machine->ram);
if (ret < 0) {
error_report("Failed to load ROM image '%s'", filename);
exit(1);
}
}
static void npcm8xx_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 npcm8xx_connect_dram(NPCM8xxState *soc, MemoryRegion *dram)
{
memory_region_add_subregion(get_system_memory(), NPCM8XX_DRAM_BA, dram);
object_property_set_link(OBJECT(soc), "dram-mr", OBJECT(dram),
&error_abort);
}
static NPCM8xxState *npcm8xx_create_soc(MachineState *machine,
uint32_t hw_straps)
{
NPCM8xxMachineClass *nmc = NPCM8XX_MACHINE_GET_CLASS(machine);
Object *obj;
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 NPCM8XX(obj);
}
static I2CBus *npcm8xx_i2c_get_bus(NPCM8xxState *soc, uint32_t num)
{
g_assert(num < ARRAY_SIZE(soc->smbus));
return I2C_BUS(qdev_get_child_bus(DEVICE(&soc->smbus[num]), "i2c-bus"));
}
static void npcm8xx_init_pwm_splitter(NPCM8xxMachine *machine,
NPCM8xxState *soc, const int *fan_counts)
{
SplitIRQ *splitters = machine->fan_splitter;
/*
* PWM 0~3 belong to module 0 output 0~3.
* PWM 4~7 belong to module 1 output 0~3.
*/
for (int i = 0; i < NPCM8XX_NR_PWM_MODULES; ++i) {
for (int j = 0; j < NPCM7XX_PWM_PER_MODULE; ++j) {
int splitter_no = i * NPCM7XX_PWM_PER_MODULE + j;
DeviceState *splitter;
if (fan_counts[splitter_no] < 1) {
continue;
}
object_initialize_child(OBJECT(machine), "fan-splitter[*]",
&splitters[splitter_no], TYPE_SPLIT_IRQ);
splitter = DEVICE(&splitters[splitter_no]);
qdev_prop_set_uint16(splitter, "num-lines",
fan_counts[splitter_no]);
qdev_realize(splitter, NULL, &error_abort);
qdev_connect_gpio_out_named(DEVICE(&soc->pwm[i]), "duty-gpio-out",
j, qdev_get_gpio_in(splitter, 0));
}
}
}
static void npcm8xx_connect_pwm_fan(NPCM8xxState *soc, SplitIRQ *splitter,
int fan_no, int output_no)
{
DeviceState *fan;
int fan_input;
qemu_irq fan_duty_gpio;
g_assert(fan_no >= 0 && fan_no <= NPCM7XX_MFT_MAX_FAN_INPUT);
/*
* Fan 0~1 belong to module 0 input 0~1.
* Fan 2~3 belong to module 1 input 0~1.
* ...
* Fan 14~15 belong to module 7 input 0~1.
* Fan 16~17 belong to module 0 input 2~3.
* Fan 18~19 belong to module 1 input 2~3.
*/
if (fan_no < 16) {
fan = DEVICE(&soc->mft[fan_no / 2]);
fan_input = fan_no % 2;
} else {
fan = DEVICE(&soc->mft[(fan_no - 16) / 2]);
fan_input = fan_no % 2 + 2;
}
/* Connect the Fan to PWM module */
fan_duty_gpio = qdev_get_gpio_in_named(fan, "duty", fan_input);
qdev_connect_gpio_out(DEVICE(splitter), output_no, fan_duty_gpio);
}
static void npcm845_evb_i2c_init(NPCM8xxState *soc)
{
/* tmp100 temperature sensor on SVB, tmp105 is compatible */
i2c_slave_create_simple(npcm8xx_i2c_get_bus(soc, 6), "tmp105", 0x48);
}
static void npcm845_evb_fan_init(NPCM8xxMachine *machine, NPCM8xxState *soc)
{
SplitIRQ *splitter = machine->fan_splitter;
static const int fan_counts[] = {2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0};
npcm8xx_init_pwm_splitter(machine, soc, fan_counts);
npcm8xx_connect_pwm_fan(soc, &splitter[0], 0x00, 0);
npcm8xx_connect_pwm_fan(soc, &splitter[0], 0x01, 1);
npcm8xx_connect_pwm_fan(soc, &splitter[1], 0x02, 0);
npcm8xx_connect_pwm_fan(soc, &splitter[1], 0x03, 1);
npcm8xx_connect_pwm_fan(soc, &splitter[2], 0x04, 0);
npcm8xx_connect_pwm_fan(soc, &splitter[2], 0x05, 1);
npcm8xx_connect_pwm_fan(soc, &splitter[3], 0x06, 0);
npcm8xx_connect_pwm_fan(soc, &splitter[3], 0x07, 1);
npcm8xx_connect_pwm_fan(soc, &splitter[4], 0x08, 0);
npcm8xx_connect_pwm_fan(soc, &splitter[4], 0x09, 1);
npcm8xx_connect_pwm_fan(soc, &splitter[5], 0x0a, 0);
npcm8xx_connect_pwm_fan(soc, &splitter[5], 0x0b, 1);
npcm8xx_connect_pwm_fan(soc, &splitter[6], 0x0c, 0);
npcm8xx_connect_pwm_fan(soc, &splitter[6], 0x0d, 1);
npcm8xx_connect_pwm_fan(soc, &splitter[7], 0x0e, 0);
npcm8xx_connect_pwm_fan(soc, &splitter[7], 0x0f, 1);
}
static void npcm845_evb_init(MachineState *machine)
{
NPCM8xxState *soc;
soc = npcm8xx_create_soc(machine, NPCM845_EVB_POWER_ON_STRAPS);
npcm8xx_connect_dram(soc, machine->ram);
qdev_realize(DEVICE(soc), NULL, &error_fatal);
npcm8xx_load_bootrom(machine, soc);
npcm8xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0));
npcm845_evb_i2c_init(soc);
npcm845_evb_fan_init(NPCM8XX_MACHINE(machine), soc);
npcm8xx_load_kernel(machine, soc);
}
static void npcm8xx_set_soc_type(NPCM8xxMachineClass *nmc, const char *type)
{
NPCM8xxClass *sc = NPCM8XX_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 npcm8xx_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a9"),
NULL
};
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
mc->default_ram_id = "ram";
mc->valid_cpu_types = valid_cpu_types;
}
static void npcm845_evb_machine_class_init(ObjectClass *oc, void *data)
{
NPCM8xxMachineClass *nmc = NPCM8XX_MACHINE_CLASS(oc);
MachineClass *mc = MACHINE_CLASS(oc);
npcm8xx_set_soc_type(nmc, TYPE_NPCM8XX);
mc->desc = "Nuvoton NPCM845 Evaluation Board (Cortex-A35)";
mc->init = npcm845_evb_init;
mc->default_ram_size = 1 * GiB;
};
static const TypeInfo npcm8xx_machine_types[] = {
{
.name = TYPE_NPCM8XX_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(NPCM8xxMachine),
.class_size = sizeof(NPCM8xxMachineClass),
.class_init = npcm8xx_machine_class_init,
.abstract = true,
}, {
.name = MACHINE_TYPE_NAME("npcm845-evb"),
.parent = TYPE_NPCM8XX_MACHINE,
.class_init = npcm845_evb_machine_class_init,
},
};
DEFINE_TYPES(npcm8xx_machine_types)
+9 -2
View File
@@ -35,6 +35,8 @@
#define SMP_BOOT_ADDR 0xe0000000
#define SMP_BOOTREG_ADDR 0x10000030
#define GIC_EXT_IRQS 64 /* Realview PBX-A9 development board */
/* Board init. */
static struct arm_boot_info realview_binfo = {
@@ -185,7 +187,12 @@ static void realview_init(MachineState *machine,
sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
if (is_mpcore) {
dev = qdev_new(is_pb ? TYPE_A9MPCORE_PRIV : "realview_mpcore");
if (is_pb) {
dev = qdev_new(TYPE_A9MPCORE_PRIV);
qdev_prop_set_uint32(dev, "num-irq", GIC_EXT_IRQS + GIC_INTERNAL);
} else {
dev = qdev_new("realview_mpcore");
}
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
@@ -201,7 +208,7 @@ static void realview_init(MachineState *machine,
/* For now just create the nIRQ GIC, and ignore the others. */
dev = sysbus_create_simple(TYPE_REALVIEW_GIC, gic_addr, cpu_irq[0]);
}
for (n = 0; n < 64; n++) {
for (n = 0; n < GIC_EXT_IRQS; n++) {
pic[n] = qdev_get_gpio_in(dev, n);
}
+5 -2
View File
@@ -51,6 +51,8 @@
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024)
#define GIC_EXT_IRQS 64 /* Versatile Express A9 development board */
/* Number of virtio transports to create (0..8; limited by
* number of available IRQ lines).
*/
@@ -241,6 +243,7 @@ static void init_cpus(MachineState *ms, const char *cpu_type,
*/
dev = qdev_new(privdev);
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
qdev_prop_set_uint32(dev, "num-irq", GIC_EXT_IRQS + GIC_INTERNAL);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, periphbase);
@@ -251,7 +254,7 @@ static void init_cpus(MachineState *ms, const char *cpu_type,
* external interrupts starting from 32 (because there
* are internal interrupts 0..31).
*/
for (n = 0; n < 64; n++) {
for (n = 0; n < GIC_EXT_IRQS; n++) {
pic[n] = qdev_get_gpio_in(dev, n);
}
@@ -543,7 +546,7 @@ static void vexpress_common_init(MachineState *machine)
VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine);
VEDBoardInfo *daughterboard = vmc->daughterboard;
DeviceState *dev, *sysctl, *pl041;
qemu_irq pic[64];
qemu_irq pic[GIC_EXT_IRQS];
uint32_t sys_id;
DriveInfo *dinfo;
PFlashCFI01 *pflash0;
+22 -21
View File
@@ -54,11 +54,11 @@ OBJECT_DECLARE_SIMPLE_TYPE(ZynqMachineState, ZYNQ_MACHINE)
#define FLASH_SIZE (64 * 1024 * 1024)
#define FLASH_SECTOR_SIZE (128 * 1024)
#define IRQ_OFFSET 32 /* pic interrupts start from index 32 */
#define MPCORE_PERIPHBASE 0xF8F00000
#define ZYNQ_BOARD_MIDR 0x413FC090
#define GIC_EXT_IRQS 64 /* Zynq 7000 SoC */
static const int dma_irqs[8] = {
46, 47, 48, 49, 72, 73, 74, 75
};
@@ -207,7 +207,7 @@ static void zynq_init(MachineState *machine)
MemoryRegion *ocm_ram = g_new(MemoryRegion, 1);
DeviceState *dev, *slcr;
SysBusDevice *busdev;
qemu_irq pic[64];
qemu_irq pic[GIC_EXT_IRQS];
int n;
unsigned int smp_cpus = machine->smp.cpus;
@@ -263,6 +263,7 @@ static void zynq_init(MachineState *machine)
dev = qdev_new(TYPE_A9MPCORE_PRIV);
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
qdev_prop_set_uint32(dev, "num-irq", GIC_EXT_IRQS + GIC_INTERNAL);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, MPCORE_PERIPHBASE);
@@ -277,16 +278,16 @@ static void zynq_init(MachineState *machine)
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
}
for (n = 0; n < 64; n++) {
for (n = 0; n < GIC_EXT_IRQS; n++) {
pic[n] = qdev_get_gpio_in(dev, n);
}
n = zynq_init_spi_flashes(0xE0006000, pic[58 - IRQ_OFFSET], false, 0);
n = zynq_init_spi_flashes(0xE0007000, pic[81 - IRQ_OFFSET], false, n);
n = zynq_init_spi_flashes(0xE000D000, pic[51 - IRQ_OFFSET], true, n);
n = zynq_init_spi_flashes(0xE0006000, pic[58 - GIC_INTERNAL], false, 0);
n = zynq_init_spi_flashes(0xE0007000, pic[81 - GIC_INTERNAL], false, n);
n = zynq_init_spi_flashes(0xE000D000, pic[51 - GIC_INTERNAL], true, n);
sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - IRQ_OFFSET]);
sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - IRQ_OFFSET]);
sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - GIC_INTERNAL]);
sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - GIC_INTERNAL]);
dev = qdev_new(TYPE_CADENCE_UART);
busdev = SYS_BUS_DEVICE(dev);
@@ -295,7 +296,7 @@ static void zynq_init(MachineState *machine)
qdev_get_clock_out(slcr, "uart0_ref_clk"));
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, 0xE0000000);
sysbus_connect_irq(busdev, 0, pic[59 - IRQ_OFFSET]);
sysbus_connect_irq(busdev, 0, pic[59 - GIC_INTERNAL]);
dev = qdev_new(TYPE_CADENCE_UART);
busdev = SYS_BUS_DEVICE(dev);
qdev_prop_set_chr(dev, "chardev", serial_hd(1));
@@ -303,15 +304,15 @@ static void zynq_init(MachineState *machine)
qdev_get_clock_out(slcr, "uart1_ref_clk"));
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, 0xE0001000);
sysbus_connect_irq(busdev, 0, pic[82 - IRQ_OFFSET]);
sysbus_connect_irq(busdev, 0, pic[82 - GIC_INTERNAL]);
sysbus_create_varargs("cadence_ttc", 0xF8001000,
pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL);
pic[42-GIC_INTERNAL], pic[43-GIC_INTERNAL], pic[44-GIC_INTERNAL], NULL);
sysbus_create_varargs("cadence_ttc", 0xF8002000,
pic[69-IRQ_OFFSET], pic[70-IRQ_OFFSET], pic[71-IRQ_OFFSET], NULL);
pic[69-GIC_INTERNAL], pic[70-GIC_INTERNAL], pic[71-GIC_INTERNAL], NULL);
gem_init(0xE000B000, pic[54 - IRQ_OFFSET]);
gem_init(0xE000C000, pic[77 - IRQ_OFFSET]);
gem_init(0xE000B000, pic[54 - GIC_INTERNAL]);
gem_init(0xE000C000, pic[77 - GIC_INTERNAL]);
for (n = 0; n < 2; n++) {
int hci_irq = n ? 79 : 56;
@@ -330,7 +331,7 @@ static void zynq_init(MachineState *machine)
qdev_prop_set_uint64(dev, "capareg", ZYNQ_SDHCI_CAPABILITIES);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, hci_addr);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - IRQ_OFFSET]);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - GIC_INTERNAL]);
di = drive_get(IF_SD, 0, n);
blk = di ? blk_by_legacy_dinfo(di) : NULL;
@@ -343,7 +344,7 @@ static void zynq_init(MachineState *machine)
dev = qdev_new(TYPE_ZYNQ_XADC);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8007100);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-IRQ_OFFSET]);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[39-GIC_INTERNAL]);
dev = qdev_new("pl330");
object_property_set_link(OBJECT(dev), "memory",
@@ -363,15 +364,15 @@ static void zynq_init(MachineState *machine)
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, 0xF8003000);
sysbus_connect_irq(busdev, 0, pic[45-IRQ_OFFSET]); /* abort irq line */
sysbus_connect_irq(busdev, 0, pic[45-GIC_INTERNAL]); /* abort irq line */
for (n = 0; n < ARRAY_SIZE(dma_irqs); ++n) { /* event irqs */
sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]);
sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - GIC_INTERNAL]);
}
dev = qdev_new("xlnx.ps7-dev-cfg");
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]);
sysbus_connect_irq(busdev, 0, pic[40 - GIC_INTERNAL]);
sysbus_mmio_map(busdev, 0, 0xF8007000);
/*
@@ -460,7 +461,7 @@ static void zynq_machine_class_init(ObjectClass *oc, void *data)
};
MachineClass *mc = MACHINE_CLASS(oc);
ObjectProperty *prop;
mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9";
mc->desc = "Xilinx Zynq 7000 Platform Baseboard for Cortex-A9";
mc->init = zynq_init;
mc->max_cpus = ZYNQ_MAX_CPUS;
mc->ignore_memory_transaction_failures = true;
+12 -6
View File
@@ -58,6 +58,11 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
bool has_el2 = false;
Object *cpuobj;
if (s->num_irq < 32 || s->num_irq > 256) {
error_setg(errp, "Property 'num-irq' must be between 32 and 256");
return;
}
gicdev = DEVICE(&s->gic);
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
@@ -146,13 +151,14 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
static const Property a15mp_priv_properties[] = {
DEFINE_PROP_UINT32("num-cpu", A15MPPrivState, num_cpu, 1),
/* The Cortex-A15MP may have anything from 0 to 224 external interrupt
* IRQ lines (with another 32 internal). We default to 128+32, which
* is the number provided by the Cortex-A15MP test chip in the
* Versatile Express A15 development board.
* Other boards may differ and should set this property appropriately.
/*
* The Cortex-A15MP may have anything from 0 to 224 external interrupt
* lines, plus always 32 internal IRQs. This property sets the total
* of internal + external, so the valid range is from 32 to 256.
* The board model must set this to whatever the configuration
* used for the CPU on that board or SoC is.
*/
DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 160),
DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 0),
};
static void a15mp_priv_class_init(ObjectClass *klass, void *data)
+12 -6
View File
@@ -56,6 +56,11 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
CPUState *cpu0;
Object *cpuobj;
if (s->num_irq < 32 || s->num_irq > 256) {
error_setg(errp, "Property 'num-irq' must be between 32 and 256");
return;
}
cpu0 = qemu_get_cpu(0);
cpuobj = OBJECT(cpu0);
if (strcmp(object_get_typename(cpuobj), ARM_CPU_TYPE_NAME("cortex-a9"))) {
@@ -160,13 +165,14 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
static const Property a9mp_priv_properties[] = {
DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, num_cpu, 1),
/* The Cortex-A9MP may have anything from 0 to 224 external interrupt
* IRQ lines (with another 32 internal). We default to 64+32, which
* is the number provided by the Cortex-A9MP test chip in the
* Realview PBX-A9 and Versatile Express A9 development boards.
* Other boards may differ and should set this property appropriately.
/*
* The Cortex-A9MP may have anything from 0 to 224 external interrupt
* lines, plus always 32 internal IRQs. This property sets the total
* of internal + external, so the valid range is from 32 to 256.
* The board model must set this to whatever the configuration
* used for the CPU on that board or SoC is.
*/
DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 96),
DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 0),
};
static void a9mp_priv_class_init(ObjectClass *klass, void *data)
+3 -12
View File
@@ -2291,7 +2291,7 @@ static CPAccessResult gicv3_irqfiq_access(CPUARMState *env,
r = CP_ACCESS_TRAP_EL3;
break;
case 3:
if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
if (!arm_is_el3_or_mon(env)) {
r = CP_ACCESS_TRAP_EL3;
}
break;
@@ -2300,9 +2300,6 @@ static CPAccessResult gicv3_irqfiq_access(CPUARMState *env,
}
}
if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
r = CP_ACCESS_TRAP;
}
return r;
}
@@ -2356,7 +2353,7 @@ static CPAccessResult gicv3_fiq_access(CPUARMState *env,
r = CP_ACCESS_TRAP_EL3;
break;
case 3:
if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
if (!arm_is_el3_or_mon(env)) {
r = CP_ACCESS_TRAP_EL3;
}
break;
@@ -2365,9 +2362,6 @@ static CPAccessResult gicv3_fiq_access(CPUARMState *env,
}
}
if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
r = CP_ACCESS_TRAP;
}
return r;
}
@@ -2395,7 +2389,7 @@ static CPAccessResult gicv3_irq_access(CPUARMState *env,
r = CP_ACCESS_TRAP_EL3;
break;
case 3:
if (!is_a64(env) && !arm_is_el3_or_mon(env)) {
if (!arm_is_el3_or_mon(env)) {
r = CP_ACCESS_TRAP_EL3;
}
break;
@@ -2404,9 +2398,6 @@ static CPAccessResult gicv3_irq_access(CPUARMState *env,
}
}
if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
r = CP_ACCESS_TRAP;
}
return r;
}
+2 -2
View File
@@ -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',
-264
View File
@@ -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);
+180 -55
View File
@@ -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);
+482
View File
@@ -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)

Some files were not shown because too many files have changed in this diff Show More