target/arm: fix exception syndrome for AArch32 bkpt insn

pci, vmbus, adb, s390x/css-bridge: Switch buses to 3-phase reset
 system/vl.c: Fix handling of '-serial none -serial something'
 target/arm: Add ID_AA64ZFR0_EL1.B16B16 to the exposed-to-userspace set
 tests/qtest/xlnx-versal-trng-test.c: Drop use of variable length array
 target/arm: Reinstate "vfp" property on AArch32 CPUs
 doc/sphinx/hxtool.py: add optional label argument to SRST directive
 hw/arm: Check for CPU types in machine_run_board_init() for various boards
 pci-host: designware: Limit value range of iATU viewport register
 hw/arm: Convert some DPRINTF macros to trace events and guest errors
 hw/arm: NPCM7XX SoC: Add GMAC ethernet controller devices
 hw/arm: Implement BCM2835 SPI Controller
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmW9C84ZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3qS6D/wM0/JGEYfaadpuMEOAx4PG
 AnfScbPqVhx9J31P2Ks3VrB5F108aq/SaL2BmCb3BLF/ECChlhBXIjd7ukdHstts
 F1TvqtvLGDZQz6wSVUeB0YOvAjGa3vIskn+Xvk9e6Ne6PcXgVnxAof/cPsXUiYNy
 6DJjNiLJ/a9Xgq9rjFO6vzW3AL95U6/FmD2F0pOotWXERhNhoyYVV6RtyeqKlDQP
 yFVk5h601YURk9PeNZn9zpOpZqjAM7PxyF3X50N3Sv+G0uoKSr6b+c3/fDJbJo3+
 0LXomEa8hdheQxm1dLY5OD0JX3bvYxwH41bDg9B0iEdjxUdXt6LfXI9Nvw9BAwix
 8AcGJJUaL4XU4uPfHBpRJApM15+MRb0hqfv4ZcGk8e67IIqVeDbKL2clTQGoHSg1
 KaB0POhtFx//M/uBOyk/FR2gb2eBNU8GuoCgxdDwh0K5ylcaK1YPiX4Tcglu4iS0
 Frvazphb2pO1BK6JiJwN2/9ezzDkDJqTKoSqdc4g3ETVOGnxr+tXwcds3t2iK3g2
 y+pgijDOAT3bJO5kYeGvhoEJPKqXwJ3UQ8zTJsU2XSYwBjIyv5V3oOn6elwYJaWq
 yUDTC3QEK61KfnQnfTyLfdGWX1aVzHnYLWmQdO+3cczuQU0s0MP246Z1GAgDtgvD
 jGjDBz6mryWvP2H0xSmERQ==
 =azdP
 -----END PGP SIGNATURE-----

Merge tag 'pull-target-arm-20240202' of https://git.linaro.org/people/pmaydell/qemu-arm into staging

target/arm: fix exception syndrome for AArch32 bkpt insn
pci, vmbus, adb, s390x/css-bridge: Switch buses to 3-phase reset
system/vl.c: Fix handling of '-serial none -serial something'
target/arm: Add ID_AA64ZFR0_EL1.B16B16 to the exposed-to-userspace set
tests/qtest/xlnx-versal-trng-test.c: Drop use of variable length array
target/arm: Reinstate "vfp" property on AArch32 CPUs
doc/sphinx/hxtool.py: add optional label argument to SRST directive
hw/arm: Check for CPU types in machine_run_board_init() for various boards
pci-host: designware: Limit value range of iATU viewport register
hw/arm: Convert some DPRINTF macros to trace events and guest errors
hw/arm: NPCM7XX SoC: Add GMAC ethernet controller devices
hw/arm: Implement BCM2835 SPI Controller

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmW9C84ZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3qS6D/wM0/JGEYfaadpuMEOAx4PG
# AnfScbPqVhx9J31P2Ks3VrB5F108aq/SaL2BmCb3BLF/ECChlhBXIjd7ukdHstts
# F1TvqtvLGDZQz6wSVUeB0YOvAjGa3vIskn+Xvk9e6Ne6PcXgVnxAof/cPsXUiYNy
# 6DJjNiLJ/a9Xgq9rjFO6vzW3AL95U6/FmD2F0pOotWXERhNhoyYVV6RtyeqKlDQP
# yFVk5h601YURk9PeNZn9zpOpZqjAM7PxyF3X50N3Sv+G0uoKSr6b+c3/fDJbJo3+
# 0LXomEa8hdheQxm1dLY5OD0JX3bvYxwH41bDg9B0iEdjxUdXt6LfXI9Nvw9BAwix
# 8AcGJJUaL4XU4uPfHBpRJApM15+MRb0hqfv4ZcGk8e67IIqVeDbKL2clTQGoHSg1
# KaB0POhtFx//M/uBOyk/FR2gb2eBNU8GuoCgxdDwh0K5ylcaK1YPiX4Tcglu4iS0
# Frvazphb2pO1BK6JiJwN2/9ezzDkDJqTKoSqdc4g3ETVOGnxr+tXwcds3t2iK3g2
# y+pgijDOAT3bJO5kYeGvhoEJPKqXwJ3UQ8zTJsU2XSYwBjIyv5V3oOn6elwYJaWq
# yUDTC3QEK61KfnQnfTyLfdGWX1aVzHnYLWmQdO+3cczuQU0s0MP246Z1GAgDtgvD
# jGjDBz6mryWvP2H0xSmERQ==
# =azdP
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 02 Feb 2024 15:35:42 GMT
# 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]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20240202' of https://git.linaro.org/people/pmaydell/qemu-arm: (36 commits)
  hw/arm: Connect SPI Controller to BCM2835
  hw/ssi: Implement BCM2835 SPI Controller
  tests/qtest: Adding PCS Module test to GMAC Qtest
  hw/net: GMAC Tx Implementation
  hw/net: GMAC Rx Implementation
  tests/qtest: Creating qtest for GMAC Module
  hw/arm: Add GMAC devices to NPCM7XX SoC
  hw/net: Add NPCMXXX GMAC device
  hw/xen: convert stderr prints to error/warn reports
  hw/xen/xen-hvm-common.c: convert DPRINTF to tracepoints
  hw/xen/xen-mapcache.c: convert DPRINTF to tracepoints
  hw/arm/xen_arm.c: convert DPRINTF to trace events and error/warn reports
  hw/arm/z2: convert DPRINTF to trace events and guest errors
  hw/arm/strongarm.c: convert DPRINTF to trace events and guest errors
  pci-host: designware: Limit value range of iATU viewport register
  hw/arm/zynq: Check for CPU types in machine_run_board_init()
  hw/arm/vexpress: Check for CPU types in machine_run_board_init()
  hw/arm/npcm7xx_boards: Simplify setting MachineClass::valid_cpu_types[]
  hw/arm/musca: Simplify setting MachineClass::valid_cpu_types[]
  hw/arm/msf2: Simplify setting MachineClass::valid_cpu_types[]
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-02-02 18:56:32 +00:00
commit 4f2fdb10b5
50 changed files with 2388 additions and 244 deletions

View File

@ -30,6 +30,13 @@ nor the documentation output.
``SRST`` starts a reStructuredText section. Following lines ``SRST`` starts a reStructuredText section. Following lines
are put into the documentation verbatim, and discarded from the C output. are put into the documentation verbatim, and discarded from the C output.
The alternative form ``SRST()`` is used to define a label which can be
referenced from elsewhere in the rST documentation. The label will take
the form ``<DOCNAME-HXFILE-LABEL>``, where ``DOCNAME`` is the name of the
top level rST file, ``HXFILE`` is the filename of the .hx file without
the ``.hx`` extension, and ``LABEL`` is the text provided within the
``SRST()`` directive. For example,
``<system/invocation-qemu-options-initrd>``.
``ERST`` ends the documentation section started with ``SRST``, ``ERST`` ends the documentation section started with ``SRST``,
and switches back to a C code section. and switches back to a C code section.
@ -53,8 +60,9 @@ text, but in ``hmp-commands.hx`` the C code sections are elements
of an array of structs of type ``HMPCommand`` which define the of an array of structs of type ``HMPCommand`` which define the
name, behaviour and help text for each monitor command. name, behaviour and help text for each monitor command.
In the file ``qemu-options.hx``, do not try to define a In the file ``qemu-options.hx``, do not try to explicitly define a
reStructuredText label within a documentation section. This file reStructuredText label within a documentation section. This file
is included into two separate Sphinx documents, and some is included into two separate Sphinx documents, and some
versions of Sphinx will complain about the duplicate label versions of Sphinx will complain about the duplicate label
that results. that results. Use the ``SRST()`` directive documented above, to
emit an unambiguous label.

View File

@ -78,6 +78,14 @@ def parse_archheading(file, lnum, line):
serror(file, lnum, "Invalid ARCHHEADING line") serror(file, lnum, "Invalid ARCHHEADING line")
return match.group(1) return match.group(1)
def parse_srst(file, lnum, line):
"""Handle an SRST directive"""
# The input should be either "SRST", or "SRST(label)".
match = re.match(r'SRST(\((.*?)\))?', line)
if match is None:
serror(file, lnum, "Invalid SRST line")
return match.group(2)
class HxtoolDocDirective(Directive): class HxtoolDocDirective(Directive):
"""Extract rST fragments from the specified .hx file""" """Extract rST fragments from the specified .hx file"""
required_argument = 1 required_argument = 1
@ -113,6 +121,14 @@ class HxtoolDocDirective(Directive):
serror(hxfile, lnum, 'expected ERST, found SRST') serror(hxfile, lnum, 'expected ERST, found SRST')
else: else:
state = HxState.RST state = HxState.RST
label = parse_srst(hxfile, lnum, line)
if label:
rstlist.append("", hxfile, lnum - 1)
# Build label as _DOCNAME-HXNAME-LABEL
hx = os.path.splitext(os.path.basename(hxfile))[0]
refline = ".. _" + env.docname + "-" + hx + \
"-" + label + ":"
rstlist.append(refline, hxfile, lnum - 1)
elif directive == 'ERST': elif directive == 'ERST':
if state == HxState.CTEXT: if state == HxState.CTEXT:
serror(hxfile, lnum, 'expected SRST, found ERST') serror(hxfile, lnum, 'expected SRST, found ERST')

View File

@ -33,11 +33,11 @@ Implemented devices
* USB2 host controller (DWC2 and MPHI) * USB2 host controller (DWC2 and MPHI)
* MailBox controller (MBOX) * MailBox controller (MBOX)
* VideoCore firmware (property) * VideoCore firmware (property)
* Peripheral SPI controller (SPI)
Missing devices Missing devices
--------------- ---------------
* Peripheral SPI controller (SPI)
* Analog to Digital Converter (ADC) * Analog to Digital Converter (ADC)
* Pulse Width Modulation (PWM) * Pulse Width Modulation (PWM)

View File

@ -132,7 +132,8 @@ The example above provides the guest kernel command line after a separator
(" ``--`` ") on the Xen command line, and does not provide the guest kernel (" ``--`` ") on the Xen command line, and does not provide the guest kernel
with an actual initramfs, which would need to listed as a second multiboot with an actual initramfs, which would need to listed as a second multiboot
module. For more complicated alternatives, see the command line module. For more complicated alternatives, see the command line
documentation for the ``-initrd`` option. :ref:`documentation <system/invocation-qemu-options-initrd>` for the
``-initrd`` option.
Host OS requirements Host OS requirements
-------------------- --------------------

View File

@ -429,6 +429,7 @@ config RASPI
select PL011 # UART select PL011 # UART
select SDHCI select SDHCI
select USB_DWC2 select USB_DWC2
select BCM2835_SPI
config STM32F100_SOC config STM32F100_SOC
bool bool

View File

@ -144,6 +144,10 @@ static void bcm2835_peripherals_init(Object *obj)
/* Power Management */ /* Power Management */
object_initialize_child(obj, "powermgt", &s->powermgt, object_initialize_child(obj, "powermgt", &s->powermgt,
TYPE_BCM2835_POWERMGT); TYPE_BCM2835_POWERMGT);
/* SPI */
object_initialize_child(obj, "bcm2835-spi0", &s->spi[0],
TYPE_BCM2835_SPI);
} }
static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
@ -402,11 +406,22 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->peri_mr, PM_OFFSET, memory_region_add_subregion(&s->peri_mr, PM_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->powermgt), 0)); sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->powermgt), 0));
/* SPI */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[0]), errp)) {
return;
}
memory_region_add_subregion(&s->peri_mr, SPI0_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->spi[0]), 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[0]), 0,
qdev_get_gpio_in_named(DEVICE(&s->ic),
BCM2835_IC_GPU_IRQ,
INTERRUPT_SPI));
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000); create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40); create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100); create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100); create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
create_unimp(s, &s->bscsl, "bcm2835-spis", BSC_SL_OFFSET, 0x100); create_unimp(s, &s->bscsl, "bcm2835-spis", BSC_SL_OFFSET, 0x100);
create_unimp(s, &s->i2c[0], "bcm2835-i2c0", BSC0_OFFSET, 0x20); create_unimp(s, &s->i2c[0], "bcm2835-i2c0", BSC0_OFFSET, 0x20);
create_unimp(s, &s->i2c[1], "bcm2835-i2c1", BSC1_OFFSET, 0x20); create_unimp(s, &s->i2c[1], "bcm2835-i2c1", BSC1_OFFSET, 0x20);

View File

@ -556,6 +556,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
for (n = 0; n < EXYNOS4210_NCPUS; n++) { for (n = 0; n < EXYNOS4210_NCPUS; n++) {
Object *cpuobj = object_new(ARM_CPU_TYPE_NAME("cortex-a9")); Object *cpuobj = object_new(ARM_CPU_TYPE_NAME("cortex-a9"));
object_property_add_child(OBJECT(s), "cpu[*]", cpuobj);
/* By default A9 CPUs have EL3 enabled. This board does not currently /* By default A9 CPUs have EL3 enabled. This board does not currently
* support EL3 so the CPU EL3 property is disabled before realization. * support EL3 so the CPU EL3 property is disabled before realization.
*/ */

View File

@ -34,6 +34,7 @@
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/irq.h" #include "hw/irq.h"
#include "target/arm/cpu-qom.h"
#define SMDK_LAN9118_BASE_ADDR 0x05000000 #define SMDK_LAN9118_BASE_ADDR 0x05000000
@ -148,12 +149,18 @@ static void smdkc210_init(MachineState *machine)
arm_load_kernel(s->soc.cpu[0], machine, &exynos4_board_binfo); arm_load_kernel(s->soc.cpu[0], machine, &exynos4_board_binfo);
} }
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a9"),
NULL
};
static void nuri_class_init(ObjectClass *oc, void *data) static void nuri_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Samsung NURI board (Exynos4210)"; mc->desc = "Samsung NURI board (Exynos4210)";
mc->init = nuri_init; mc->init = nuri_init;
mc->valid_cpu_types = valid_cpu_types;
mc->max_cpus = EXYNOS4210_NCPUS; mc->max_cpus = EXYNOS4210_NCPUS;
mc->min_cpus = EXYNOS4210_NCPUS; mc->min_cpus = EXYNOS4210_NCPUS;
mc->default_cpus = EXYNOS4210_NCPUS; mc->default_cpus = EXYNOS4210_NCPUS;
@ -172,6 +179,7 @@ static void smdkc210_class_init(ObjectClass *oc, void *data)
mc->desc = "Samsung SMDKC210 board (Exynos4210)"; mc->desc = "Samsung SMDKC210 board (Exynos4210)";
mc->init = smdkc210_init; mc->init = smdkc210_init;
mc->valid_cpu_types = valid_cpu_types;
mc->max_cpus = EXYNOS4210_NCPUS; mc->max_cpus = EXYNOS4210_NCPUS;
mc->min_cpus = EXYNOS4210_NCPUS; mc->min_cpus = EXYNOS4210_NCPUS;
mc->default_cpus = EXYNOS4210_NCPUS; mc->default_cpus = EXYNOS4210_NCPUS;

View File

@ -209,6 +209,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
cpuobj = object_new(machine->cpu_type); cpuobj = object_new(machine->cpu_type);
cpu = ARM_CPU(cpuobj); cpu = ARM_CPU(cpuobj);
object_property_add_child(OBJECT(machine), "cpu[*]", cpuobj);
object_property_set_int(cpuobj, "psci-conduit", QEMU_PSCI_CONDUIT_SMC, object_property_set_int(cpuobj, "psci-conduit", QEMU_PSCI_CONDUIT_SMC,
&error_abort); &error_abort);
@ -342,10 +343,15 @@ static void midway_init(MachineState *machine)
static void highbank_class_init(ObjectClass *oc, void *data) static void highbank_class_init(ObjectClass *oc, void *data)
{ {
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a9"),
NULL
};
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Calxeda Highbank (ECX-1000)"; mc->desc = "Calxeda Highbank (ECX-1000)";
mc->init = highbank_init; mc->init = highbank_init;
mc->valid_cpu_types = valid_cpu_types;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1; mc->units_per_default_bus = 1;
mc->max_cpus = 4; mc->max_cpus = 4;
@ -361,10 +367,15 @@ static const TypeInfo highbank_type = {
static void midway_class_init(ObjectClass *oc, void *data) static void midway_class_init(ObjectClass *oc, void *data)
{ {
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a15"),
NULL
};
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Calxeda Midway (ECX-2000)"; mc->desc = "Calxeda Midway (ECX-2000)";
mc->init = midway_init; mc->init = midway_init;
mc->valid_cpu_types = valid_cpu_types;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
mc->units_per_default_bus = 1; mc->units_per_default_bus = 1;
mc->max_cpus = 4; mc->max_cpus = 4;

View File

@ -134,7 +134,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
armv7m = DEVICE(&s->armv7m); armv7m = DEVICE(&s->armv7m);
qdev_prop_set_uint32(armv7m, "num-irq", 81); qdev_prop_set_uint32(armv7m, "num-irq", 81);
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type); qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
qdev_prop_set_bit(armv7m, "enable-bitband", true); qdev_prop_set_bit(armv7m, "enable-bitband", true);
qdev_connect_clock_in(armv7m, "cpuclk", s->m3clk); qdev_connect_clock_in(armv7m, "cpuclk", s->m3clk);
qdev_connect_clock_in(armv7m, "refclk", s->refclk); qdev_connect_clock_in(armv7m, "refclk", s->refclk);
@ -227,7 +227,6 @@ static Property m2sxxx_soc_properties[] = {
* part name specifies the type of SmartFusion2 device variant(this * part name specifies the type of SmartFusion2 device variant(this
* property is for information purpose only. * property is for information purpose only.
*/ */
DEFINE_PROP_STRING("cpu-type", MSF2State, cpu_type),
DEFINE_PROP_STRING("part-name", MSF2State, part_name), DEFINE_PROP_STRING("part-name", MSF2State, part_name),
DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE), DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE),
DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size, DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size,

View File

@ -47,7 +47,6 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
DeviceState *dev; DeviceState *dev;
DeviceState *spi_flash; DeviceState *spi_flash;
MSF2State *soc; MSF2State *soc;
MachineClass *mc = MACHINE_GET_CLASS(machine);
DriveInfo *dinfo = drive_get(IF_MTD, 0, 0); DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
qemu_irq cs_line; qemu_irq cs_line;
BusState *spi_bus; BusState *spi_bus;
@ -62,8 +61,6 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
dev = qdev_new(TYPE_MSF2_SOC); dev = qdev_new(TYPE_MSF2_SOC);
object_property_add_child(OBJECT(machine), "soc", OBJECT(dev)); object_property_add_child(OBJECT(machine), "soc", OBJECT(dev));
qdev_prop_set_string(dev, "part-name", "M2S010"); qdev_prop_set_string(dev, "part-name", "M2S010");
qdev_prop_set_string(dev, "cpu-type", mc->default_cpu_type);
qdev_prop_set_uint64(dev, "eNVM-size", M2S010_ENVM_SIZE); qdev_prop_set_uint64(dev, "eNVM-size", M2S010_ENVM_SIZE);
qdev_prop_set_uint64(dev, "eSRAM-size", M2S010_ESRAM_SIZE); qdev_prop_set_uint64(dev, "eSRAM-size", M2S010_ESRAM_SIZE);
@ -108,7 +105,6 @@ static void emcraft_sf2_machine_init(MachineClass *mc)
mc->desc = "SmartFusion2 SOM kit from Emcraft (M2S010)"; mc->desc = "SmartFusion2 SOM kit from Emcraft (M2S010)";
mc->init = emcraft_sf2_s2s010_init; mc->init = emcraft_sf2_s2s010_init;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
mc->valid_cpu_types = valid_cpu_types; mc->valid_cpu_types = valid_cpu_types;
} }

View File

@ -605,7 +605,6 @@ static void musca_class_init(ObjectClass *oc, void *data)
mc->default_cpus = 2; mc->default_cpus = 2;
mc->min_cpus = mc->default_cpus; mc->min_cpus = mc->default_cpus;
mc->max_cpus = mc->default_cpus; mc->max_cpus = mc->default_cpus;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
mc->valid_cpu_types = valid_cpu_types; mc->valid_cpu_types = valid_cpu_types;
mc->init = musca_init; mc->init = musca_init;
} }

View File

@ -84,8 +84,10 @@ enum NPCM7xxInterrupt {
NPCM7XX_UART1_IRQ, NPCM7XX_UART1_IRQ,
NPCM7XX_UART2_IRQ, NPCM7XX_UART2_IRQ,
NPCM7XX_UART3_IRQ, NPCM7XX_UART3_IRQ,
NPCM7XX_GMAC1_IRQ = 14,
NPCM7XX_EMC1RX_IRQ = 15, NPCM7XX_EMC1RX_IRQ = 15,
NPCM7XX_EMC1TX_IRQ, NPCM7XX_EMC1TX_IRQ,
NPCM7XX_GMAC2_IRQ,
NPCM7XX_MMC_IRQ = 26, NPCM7XX_MMC_IRQ = 26,
NPCM7XX_PSPI2_IRQ = 28, NPCM7XX_PSPI2_IRQ = 28,
NPCM7XX_PSPI1_IRQ = 31, NPCM7XX_PSPI1_IRQ = 31,
@ -229,6 +231,12 @@ static const hwaddr npcm7xx_pspi_addr[] = {
0xf0201000, 0xf0201000,
}; };
/* Register base address for each GMAC Module */
static const hwaddr npcm7xx_gmac_addr[] = {
0xf0802000,
0xf0804000,
};
static const struct { static const struct {
hwaddr regs_addr; hwaddr regs_addr;
uint32_t unconnected_pins; uint32_t unconnected_pins;
@ -457,6 +465,10 @@ static void npcm7xx_init(Object *obj)
object_initialize_child(obj, "pspi[*]", &s->pspi[i], TYPE_NPCM_PSPI); object_initialize_child(obj, "pspi[*]", &s->pspi[i], TYPE_NPCM_PSPI);
} }
for (i = 0; i < ARRAY_SIZE(s->gmac); i++) {
object_initialize_child(obj, "gmac[*]", &s->gmac[i], TYPE_NPCM_GMAC);
}
object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI); object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
} }
@ -690,6 +702,29 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(sbd, 1, npcm7xx_irq(s, rx_irq)); sysbus_connect_irq(sbd, 1, npcm7xx_irq(s, rx_irq));
} }
/*
* GMAC Modules. Cannot fail.
*/
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gmac_addr) != ARRAY_SIZE(s->gmac));
QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->gmac) != 2);
for (i = 0; i < ARRAY_SIZE(s->gmac); i++) {
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->gmac[i]);
/*
* The device exists regardless of whether it's connected to a QEMU
* netdev backend. So always instantiate it even if there is no
* backend.
*/
sysbus_realize(sbd, &error_abort);
sysbus_mmio_map(sbd, 0, npcm7xx_gmac_addr[i]);
int irq = i == 0 ? NPCM7XX_GMAC1_IRQ : NPCM7XX_GMAC2_IRQ;
/*
* N.B. The values for the second argument sysbus_connect_irq are
* chosen to match the registration order in npcm7xx_emc_realize.
*/
sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, irq));
}
/* /*
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
* specified, but this is a programming error. * specified, but this is a programming error.
@ -752,8 +787,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB); create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB); create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB);
create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB); create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB);
create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB);
create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB);
create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB); create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB);
create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB); create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB);
create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB); create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB);

View File

@ -465,7 +465,6 @@ static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
mc->no_cdrom = 1; mc->no_cdrom = 1;
mc->no_parallel = 1; mc->no_parallel = 1;
mc->default_ram_id = "ram"; mc->default_ram_id = "ram";
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
mc->valid_cpu_types = valid_cpu_types; mc->valid_cpu_types = valid_cpu_types;
} }

View File

@ -46,8 +46,7 @@
#include "qemu/log.h" #include "qemu/log.h"
#include "qom/object.h" #include "qom/object.h"
#include "target/arm/cpu-qom.h" #include "target/arm/cpu-qom.h"
#include "trace.h"
//#define DEBUG
/* /*
TODO TODO
@ -66,12 +65,6 @@
- Enhance UART with modem signals - Enhance UART with modem signals
*/ */
#ifdef DEBUG
# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__)
#else
# define DPRINTF(format, ...) do { } while (0)
#endif
static struct { static struct {
hwaddr io_base; hwaddr io_base;
int irq; int irq;
@ -151,8 +144,9 @@ static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset,
case ICPR: case ICPR:
return s->pending; return s->pending;
default: default:
printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n", qemu_log_mask(LOG_GUEST_ERROR,
__func__, offset); "%s: Bad register offset 0x"HWADDR_FMT_plx"\n",
__func__, offset);
return 0; return 0;
} }
} }
@ -173,8 +167,9 @@ static void strongarm_pic_mem_write(void *opaque, hwaddr offset,
s->int_idle = (value & 1) ? 0 : ~0; s->int_idle = (value & 1) ? 0 : ~0;
break; break;
default: default:
printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n", qemu_log_mask(LOG_GUEST_ERROR,
__func__, offset); "%s: Bad register offset 0x"HWADDR_FMT_plx"\n",
__func__, offset);
break; break;
} }
strongarm_pic_update(s); strongarm_pic_update(s);
@ -333,7 +328,9 @@ static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr,
((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) / ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
(1000 * ((s->rttr & 0xffff) + 1)); (1000 * ((s->rttr & 0xffff) + 1));
default: default:
printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad rtc register read 0x"HWADDR_FMT_plx"\n",
__func__, addr);
return 0; return 0;
} }
} }
@ -375,7 +372,9 @@ static void strongarm_rtc_write(void *opaque, hwaddr addr,
break; break;
default: default:
printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad rtc register write 0x"HWADDR_FMT_plx"\n",
__func__, addr);
} }
} }
@ -556,12 +555,12 @@ static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset,
case GPSR: /* GPIO Pin-Output Set registers */ case GPSR: /* GPIO Pin-Output Set registers */
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
"strongarm GPIO: read from write only register GPSR\n"); "%s: read from write only register GPSR\n", __func__);
return 0; return 0;
case GPCR: /* GPIO Pin-Output Clear registers */ case GPCR: /* GPIO Pin-Output Clear registers */
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
"strongarm GPIO: read from write only register GPCR\n"); "%s: read from write only register GPCR\n", __func__);
return 0; return 0;
case GRER: /* GPIO Rising-Edge Detect Enable registers */ case GRER: /* GPIO Rising-Edge Detect Enable registers */
@ -581,7 +580,9 @@ static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset,
return s->status; return s->status;
default: default:
printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad gpio read offset 0x"HWADDR_FMT_plx"\n",
__func__, offset);
} }
return 0; return 0;
@ -626,7 +627,9 @@ static void strongarm_gpio_write(void *opaque, hwaddr offset,
break; break;
default: default:
printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad write offset 0x"HWADDR_FMT_plx"\n",
__func__, offset);
} }
} }
@ -782,7 +785,9 @@ static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset,
return s->ppfr | ~0x7f001; return s->ppfr | ~0x7f001;
default: default:
printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad ppc read offset 0x"HWADDR_FMT_plx "\n",
__func__, offset);
} }
return 0; return 0;
@ -817,7 +822,9 @@ static void strongarm_ppc_write(void *opaque, hwaddr offset,
break; break;
default: default:
printf("%s: Bad offset 0x" HWADDR_FMT_plx "\n", __func__, offset); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad ppc write offset 0x"HWADDR_FMT_plx"\n",
__func__, offset);
} }
} }
@ -1029,8 +1036,13 @@ static void strongarm_uart_update_parameters(StrongARMUARTState *s)
s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size; s->char_transmit_time = (NANOSECONDS_PER_SECOND / speed) * frame_size;
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label, trace_strongarm_uart_update_parameters((s->chr.chr ?
speed, parity, data_bits, stop_bits); s->chr.chr->label : "NULL") ?:
"NULL",
speed,
parity,
data_bits,
stop_bits);
} }
static void strongarm_uart_rx_to(void *opaque) static void strongarm_uart_rx_to(void *opaque)
@ -1164,7 +1176,9 @@ static uint64_t strongarm_uart_read(void *opaque, hwaddr addr,
return s->utsr1; return s->utsr1;
default: default:
printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad uart register read 0x"HWADDR_FMT_plx"\n",
__func__, addr);
return 0; return 0;
} }
} }
@ -1221,7 +1235,9 @@ static void strongarm_uart_write(void *opaque, hwaddr addr,
break; break;
default: default:
printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad uart register write 0x"HWADDR_FMT_plx"\n",
__func__, addr);
} }
} }
@ -1434,7 +1450,7 @@ static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr,
return 0xffffffff; return 0xffffffff;
} }
if (s->rx_level < 1) { if (s->rx_level < 1) {
printf("%s: SSP Rx Underrun\n", __func__); trace_strongarm_ssp_read_underrun();
return 0xffffffff; return 0xffffffff;
} }
s->rx_level--; s->rx_level--;
@ -1443,7 +1459,9 @@ static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr,
strongarm_ssp_fifo_update(s); strongarm_ssp_fifo_update(s);
return retval; return retval;
default: default:
printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad ssp register read 0x"HWADDR_FMT_plx"\n",
__func__, addr);
break; break;
} }
return 0; return 0;
@ -1458,8 +1476,8 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr,
case SSCR0: case SSCR0:
s->sscr[0] = value & 0xffbf; s->sscr[0] = value & 0xffbf;
if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) { if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
printf("%s: Wrong data size: %i bits\n", __func__, qemu_log_mask(LOG_GUEST_ERROR, "%s: Wrong data size: %i bits\n",
(int)SSCR0_DSS(value)); __func__, (int)SSCR0_DSS(value));
} }
if (!(value & SSCR0_SSE)) { if (!(value & SSCR0_SSE)) {
s->sssr = 0; s->sssr = 0;
@ -1471,7 +1489,9 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr,
case SSCR1: case SSCR1:
s->sscr[1] = value & 0x2f; s->sscr[1] = value & 0x2f;
if (value & SSCR1_LBM) { if (value & SSCR1_LBM) {
printf("%s: Attempt to use SSP LBM mode\n", __func__); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Attempt to use SSP LBM mode\n",
__func__);
} }
strongarm_ssp_fifo_update(s); strongarm_ssp_fifo_update(s);
break; break;
@ -1509,7 +1529,9 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr,
break; break;
default: default:
printf("%s: Bad register 0x" HWADDR_FMT_plx "\n", __func__, addr); qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad ssp register write 0x"HWADDR_FMT_plx"\n",
__func__, addr);
break; break;
} }
} }

View File

@ -55,3 +55,18 @@ smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s
smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s" smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint16_t vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64 smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint16_t vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
# strongarm.c
strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
strongarm_ssp_read_underrun(void) "SSP rx underrun"
# z2.c
z2_lcd_reg_update(uint8_t cur, uint8_t i_0, uint8_t i_1, uint8_t i_2, uint32_t value) "cur_reg = 0x%x, buf = [0x%x, 0x%x, 0x%x], value = 0x%x"
z2_lcd_enable_disable_result(const char *result) "LCD %s"
z2_aer915_send_too_long(int8_t msg) "message too long (%i bytes)"
z2_aer915_send(uint8_t reg, uint8_t value) "reg %d value 0x%02x"
z2_aer915_event(int8_t event, int8_t len) "i2c event =0x%x len=%d bytes"
# xen_arm.c
xen_create_virtio_mmio_devices(int i, int irq, uint64_t base) "Created virtio-mmio device %d: irq %d base 0x%"PRIx64
xen_init_ram(uint64_t machine_ram_size) "Initialized xen ram with size 0x%"PRIx64
xen_enable_tpm(uint64_t addr) "Connected tpmdev at address 0x%"PRIx64

View File

@ -783,22 +783,30 @@ static void vexpress_class_init(ObjectClass *oc, void *data)
static void vexpress_a9_class_init(ObjectClass *oc, void *data) static void vexpress_a9_class_init(ObjectClass *oc, void *data)
{ {
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a9"),
NULL
};
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
mc->desc = "ARM Versatile Express for Cortex-A9"; mc->desc = "ARM Versatile Express for Cortex-A9";
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); mc->valid_cpu_types = valid_cpu_types;
vmc->daughterboard = &a9_daughterboard; vmc->daughterboard = &a9_daughterboard;
} }
static void vexpress_a15_class_init(ObjectClass *oc, void *data) static void vexpress_a15_class_init(ObjectClass *oc, void *data)
{ {
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a15"),
NULL
};
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
mc->desc = "ARM Versatile Express for Cortex-A15"; mc->desc = "ARM Versatile Express for Cortex-A15";
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15"); mc->valid_cpu_types = valid_cpu_types;
vmc->daughterboard = &a15_daughterboard; vmc->daughterboard = &a15_daughterboard;

View File

@ -34,6 +34,7 @@
#include "hw/xen/xen-hvm-common.h" #include "hw/xen/xen-hvm-common.h"
#include "sysemu/tpm.h" #include "sysemu/tpm.h"
#include "hw/xen/arch_hvm.h" #include "hw/xen/arch_hvm.h"
#include "trace.h"
#define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh") #define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh")
OBJECT_DECLARE_SIMPLE_TYPE(XenArmState, XEN_ARM) OBJECT_DECLARE_SIMPLE_TYPE(XenArmState, XEN_ARM)
@ -91,8 +92,9 @@ static void xen_create_virtio_mmio_devices(XenArmState *xam)
sysbus_create_simple("virtio-mmio", base, irq); sysbus_create_simple("virtio-mmio", base, irq);
DPRINTF("Created virtio-mmio device %d: irq %d base 0x%lx\n", trace_xen_create_virtio_mmio_devices(i,
i, GUEST_VIRTIO_MMIO_SPI_FIRST + i, base); GUEST_VIRTIO_MMIO_SPI_FIRST + i,
base);
} }
} }
@ -101,6 +103,7 @@ static void xen_init_ram(MachineState *machine)
MemoryRegion *sysmem = get_system_memory(); MemoryRegion *sysmem = get_system_memory();
ram_addr_t block_len, ram_size[GUEST_RAM_BANKS]; ram_addr_t block_len, ram_size[GUEST_RAM_BANKS];
trace_xen_init_ram(machine->ram_size);
if (machine->ram_size <= GUEST_RAM0_SIZE) { if (machine->ram_size <= GUEST_RAM0_SIZE) {
ram_size[0] = machine->ram_size; ram_size[0] = machine->ram_size;
ram_size[1] = 0; ram_size[1] = 0;
@ -117,15 +120,10 @@ static void xen_init_ram(MachineState *machine)
memory_region_init_alias(&ram_lo, NULL, "xen.ram.lo", &ram_memory, memory_region_init_alias(&ram_lo, NULL, "xen.ram.lo", &ram_memory,
GUEST_RAM0_BASE, ram_size[0]); GUEST_RAM0_BASE, ram_size[0]);
memory_region_add_subregion(sysmem, GUEST_RAM0_BASE, &ram_lo); memory_region_add_subregion(sysmem, GUEST_RAM0_BASE, &ram_lo);
DPRINTF("Initialized region xen.ram.lo: base 0x%llx size 0x%lx\n",
GUEST_RAM0_BASE, ram_size[0]);
if (ram_size[1] > 0) { if (ram_size[1] > 0) {
memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &ram_memory, memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &ram_memory,
GUEST_RAM1_BASE, ram_size[1]); GUEST_RAM1_BASE, ram_size[1]);
memory_region_add_subregion(sysmem, GUEST_RAM1_BASE, &ram_hi); memory_region_add_subregion(sysmem, GUEST_RAM1_BASE, &ram_hi);
DPRINTF("Initialized region xen.ram.hi: base 0x%llx size 0x%lx\n",
GUEST_RAM1_BASE, ram_size[1]);
} }
} }
@ -158,7 +156,7 @@ static void xen_enable_tpm(XenArmState *xam)
TPMBackend *be = qemu_find_tpm_be("tpm0"); TPMBackend *be = qemu_find_tpm_be("tpm0");
if (be == NULL) { if (be == NULL) {
DPRINTF("Couldn't fine the backend for tpm0\n"); error_report("Couldn't find tmp0 backend");
return; return;
} }
dev = qdev_new(TYPE_TPM_TIS_SYSBUS); dev = qdev_new(TYPE_TPM_TIS_SYSBUS);
@ -168,7 +166,7 @@ static void xen_enable_tpm(XenArmState *xam)
sysbus_realize_and_unref(busdev, &error_fatal); sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, xam->cfg.tpm_base_addr); sysbus_mmio_map(busdev, 0, xam->cfg.tpm_base_addr);
DPRINTF("Connected tpmdev at address 0x%lx\n", xam->cfg.tpm_base_addr); trace_xen_enable_tpm(xam->cfg.tpm_base_addr);
} }
#endif #endif
@ -179,8 +177,9 @@ static void xen_arm_init(MachineState *machine)
xam->state = g_new0(XenIOState, 1); xam->state = g_new0(XenIOState, 1);
if (machine->ram_size == 0) { if (machine->ram_size == 0) {
DPRINTF("ram_size not specified. QEMU machine started without IOREQ" warn_report("%s non-zero ram size not specified. QEMU machine started"
"(no emulated devices including Virtio)\n"); " without IOREQ (no emulated devices including virtio)",
MACHINE_CLASS(object_get_class(OBJECT(machine)))->desc);
return; return;
} }
@ -194,7 +193,7 @@ static void xen_arm_init(MachineState *machine)
if (xam->cfg.tpm_base_addr) { if (xam->cfg.tpm_base_addr) {
xen_enable_tpm(xam); xen_enable_tpm(xam);
} else { } else {
DPRINTF("tpm-base-addr is not provided. TPM will not be enabled\n"); warn_report("tpm-base-addr is not provided. TPM will not be enabled");
} }
#endif #endif
} }

View File

@ -352,13 +352,17 @@ static void zynq_init(MachineState *machine)
static void zynq_machine_class_init(ObjectClass *oc, void *data) static void zynq_machine_class_init(ObjectClass *oc, void *data)
{ {
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a9"),
NULL
};
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9"; mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9";
mc->init = zynq_init; mc->init = zynq_init;
mc->max_cpus = 1; mc->max_cpus = 1;
mc->no_sdcard = 1; mc->no_sdcard = 1;
mc->ignore_memory_transaction_failures = true; mc->ignore_memory_transaction_failures = true;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); mc->valid_cpu_types = valid_cpu_types;
mc->default_ram_id = "zynq.ext_ram"; mc->default_ram_id = "zynq.ext_ram";
} }

View File

@ -27,13 +27,7 @@
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "qom/object.h" #include "qom/object.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "trace.h"
#ifdef DEBUG_Z2
#define DPRINTF(fmt, ...) \
printf(fmt, ## __VA_ARGS__)
#else
#define DPRINTF(fmt, ...)
#endif
static const struct keymap map[0x100] = { static const struct keymap map[0x100] = {
[0 ... 0xff] = { -1, -1 }, [0 ... 0xff] = { -1, -1 },
@ -119,6 +113,8 @@ static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value)
{ {
ZipitLCD *z = ZIPIT_LCD(dev); ZipitLCD *z = ZIPIT_LCD(dev);
uint16_t val; uint16_t val;
trace_z2_lcd_reg_update(z->cur_reg, z->buf[0], z->buf[1], z->buf[2], value);
if (z->selected) { if (z->selected) {
z->buf[z->pos] = value & 0xff; z->buf[z->pos] = value & 0xff;
z->pos++; z->pos++;
@ -126,22 +122,19 @@ static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value)
if (z->pos == 3) { if (z->pos == 3) {
switch (z->buf[0]) { switch (z->buf[0]) {
case 0x74: case 0x74:
DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]);
z->cur_reg = z->buf[2]; z->cur_reg = z->buf[2];
break; break;
case 0x76: case 0x76:
val = z->buf[1] << 8 | z->buf[2]; val = z->buf[1] << 8 | z->buf[2];
DPRINTF("%s: value: 0x%.4x\n", __func__, val);
if (z->cur_reg == 0x22 && val == 0x0000) { if (z->cur_reg == 0x22 && val == 0x0000) {
z->enabled = 1; z->enabled = 1;
printf("%s: LCD enabled\n", __func__); trace_z2_lcd_enable_disable_result("enabled");
} else if (z->cur_reg == 0x10 && val == 0x0000) { } else if (z->cur_reg == 0x10 && val == 0x0000) {
z->enabled = 0; z->enabled = 0;
printf("%s: LCD disabled\n", __func__); trace_z2_lcd_enable_disable_result("disabled");
} }
break; break;
default: default:
DPRINTF("%s: unknown command!\n", __func__);
break; break;
} }
z->pos = 0; z->pos = 0;
@ -211,14 +204,12 @@ static int aer915_send(I2CSlave *i2c, uint8_t data)
s->buf[s->len] = data; s->buf[s->len] = data;
if (s->len++ > 2) { if (s->len++ > 2) {
DPRINTF("%s: message too long (%i bytes)\n", trace_z2_aer915_send_too_long(s->len);
__func__, s->len);
return 1; return 1;
} }
if (s->len == 2) { if (s->len == 2) {
DPRINTF("%s: reg %d value 0x%02x\n", __func__, trace_z2_aer915_send(s->buf[0], s->buf[1]);
s->buf[0], s->buf[1]);
} }
return 0; return 0;
@ -228,14 +219,12 @@ static int aer915_event(I2CSlave *i2c, enum i2c_event event)
{ {
AER915State *s = AER915(i2c); AER915State *s = AER915(i2c);
trace_z2_aer915_event(s->len, event);
switch (event) { switch (event) {
case I2C_START_SEND: case I2C_START_SEND:
s->len = 0; s->len = 0;
break; break;
case I2C_START_RECV: case I2C_START_RECV:
if (s->len != 1) {
DPRINTF("%s: short message!?\n", __func__);
}
break; break;
case I2C_FINISH: case I2C_FINISH:
break; break;

View File

@ -232,57 +232,6 @@ static char *default_bus_get_fw_dev_path(DeviceState *dev)
return g_strdup(object_get_typename(OBJECT(dev))); return g_strdup(object_get_typename(OBJECT(dev)));
} }
/**
* bus_phases_reset:
* Transition reset method for buses to allow moving
* smoothly from legacy reset method to multi-phases
*/
static void bus_phases_reset(BusState *bus)
{
ResettableClass *rc = RESETTABLE_GET_CLASS(bus);
if (rc->phases.enter) {
rc->phases.enter(OBJECT(bus), RESET_TYPE_COLD);
}
if (rc->phases.hold) {
rc->phases.hold(OBJECT(bus));
}
if (rc->phases.exit) {
rc->phases.exit(OBJECT(bus));
}
}
static void bus_transitional_reset(Object *obj)
{
BusClass *bc = BUS_GET_CLASS(obj);
/*
* This will call either @bus_phases_reset (for multi-phases transitioned
* buses) or a bus's specific method for not-yet transitioned buses.
* In both case, it does not reset children.
*/
if (bc->reset) {
bc->reset(BUS(obj));
}
}
/**
* bus_get_transitional_reset:
* check if the bus's class is ready for multi-phase
*/
static ResettableTrFunction bus_get_transitional_reset(Object *obj)
{
BusClass *dc = BUS_GET_CLASS(obj);
if (dc->reset != bus_phases_reset) {
/*
* dc->reset has been overridden by a subclass,
* the bus is not ready for multi phase yet.
*/
return bus_transitional_reset;
}
return NULL;
}
static void bus_class_init(ObjectClass *class, void *data) static void bus_class_init(ObjectClass *class, void *data)
{ {
BusClass *bc = BUS_CLASS(class); BusClass *bc = BUS_CLASS(class);
@ -293,22 +242,6 @@ static void bus_class_init(ObjectClass *class, void *data)
rc->get_state = bus_get_reset_state; rc->get_state = bus_get_reset_state;
rc->child_foreach = bus_reset_child_foreach; rc->child_foreach = bus_reset_child_foreach;
/*
* @bus_phases_reset is put as the default reset method below, allowing
* to do the multi-phase transition from base classes to leaf classes. It
* allows a legacy-reset Bus class to extend a multi-phases-reset
* Bus class for the following reason:
* + If a base class B has been moved to multi-phase, then it does not
* override this default reset method and may have defined phase methods.
* + A child class C (extending class B) which uses
* bus_class_set_parent_reset() (or similar means) to override the
* reset method will still work as expected. @bus_phases_reset function
* will be registered as the parent reset method and effectively call
* parent reset phases.
*/
bc->reset = bus_phases_reset;
rc->get_transitional_function = bus_get_transitional_reset;
} }
static void qbus_finalize(Object *obj) static void qbus_finalize(Object *obj)

View File

@ -2453,9 +2453,9 @@ static void vmbus_unrealize(BusState *bus)
qemu_mutex_destroy(&vmbus->rx_queue_lock); qemu_mutex_destroy(&vmbus->rx_queue_lock);
} }
static void vmbus_reset(BusState *bus) static void vmbus_reset_hold(Object *obj)
{ {
vmbus_deinit(VMBUS(bus)); vmbus_deinit(VMBUS(obj));
} }
static char *vmbus_get_dev_path(DeviceState *dev) static char *vmbus_get_dev_path(DeviceState *dev)
@ -2476,12 +2476,13 @@ static char *vmbus_get_fw_dev_path(DeviceState *dev)
static void vmbus_class_init(ObjectClass *klass, void *data) static void vmbus_class_init(ObjectClass *klass, void *data)
{ {
BusClass *k = BUS_CLASS(klass); BusClass *k = BUS_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
k->get_dev_path = vmbus_get_dev_path; k->get_dev_path = vmbus_get_dev_path;
k->get_fw_dev_path = vmbus_get_fw_dev_path; k->get_fw_dev_path = vmbus_get_fw_dev_path;
k->realize = vmbus_realize; k->realize = vmbus_realize;
k->unrealize = vmbus_unrealize; k->unrealize = vmbus_unrealize;
k->reset = vmbus_reset; rc->phases.hold = vmbus_reset_hold;
} }
static int vmbus_pre_load(void *opaque) static int vmbus_pre_load(void *opaque)

View File

@ -231,9 +231,9 @@ static const VMStateDescription vmstate_adb_bus = {
} }
}; };
static void adb_bus_reset(BusState *qbus) static void adb_bus_reset_hold(Object *obj)
{ {
ADBBusState *adb_bus = ADB_BUS(qbus); ADBBusState *adb_bus = ADB_BUS(obj);
adb_bus->autopoll_enabled = false; adb_bus->autopoll_enabled = false;
adb_bus->autopoll_mask = 0xffff; adb_bus->autopoll_mask = 0xffff;
@ -262,10 +262,11 @@ static void adb_bus_unrealize(BusState *qbus)
static void adb_bus_class_init(ObjectClass *klass, void *data) static void adb_bus_class_init(ObjectClass *klass, void *data)
{ {
BusClass *k = BUS_CLASS(klass); BusClass *k = BUS_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
k->realize = adb_bus_realize; k->realize = adb_bus_realize;
k->unrealize = adb_bus_unrealize; k->unrealize = adb_bus_unrealize;
k->reset = adb_bus_reset; rc->phases.hold = adb_bus_reset_hold;
} }
static const TypeInfo adb_bus_type_info = { static const TypeInfo adb_bus_type_info = {

View File

@ -38,7 +38,7 @@ system_ss.add(when: 'CONFIG_I82596_COMMON', if_true: files('i82596.c'))
system_ss.add(when: 'CONFIG_SUNHME', if_true: files('sunhme.c')) system_ss.add(when: 'CONFIG_SUNHME', if_true: files('sunhme.c'))
system_ss.add(when: 'CONFIG_FTGMAC100', if_true: files('ftgmac100.c')) system_ss.add(when: 'CONFIG_FTGMAC100', if_true: files('ftgmac100.c'))
system_ss.add(when: 'CONFIG_SUNGEM', if_true: files('sungem.c')) system_ss.add(when: 'CONFIG_SUNGEM', if_true: files('sungem.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c')) system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c', 'npcm_gmac.c'))
system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c')) system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c'))
system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c')) system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c'))

942
hw/net/npcm_gmac.c Normal file
View File

@ -0,0 +1,942 @@
/*
* Nuvoton NPCM7xx/8xx GMAC Module
*
* Copyright 2024 Google LLC
* Authors:
* Hao Wu <wuhaotsh@google.com>
* Nabih Estefan <nabihestefan@google.com>
*
* 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.
*
* Unsupported/unimplemented features:
* - MII is not implemented, MII_ADDR.BUSY and MII_DATA always return zero
* - Precision timestamp (PTP) is not implemented.
*/
#include "qemu/osdep.h"
#include "hw/registerfields.h"
#include "hw/net/mii.h"
#include "hw/net/npcm_gmac.h"
#include "migration/vmstate.h"
#include "net/checksum.h"
#include "net/eth.h"
#include "net/net.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "qemu/units.h"
#include "sysemu/dma.h"
#include "trace.h"
REG32(NPCM_DMA_BUS_MODE, 0x1000)
REG32(NPCM_DMA_XMT_POLL_DEMAND, 0x1004)
REG32(NPCM_DMA_RCV_POLL_DEMAND, 0x1008)
REG32(NPCM_DMA_RX_BASE_ADDR, 0x100c)
REG32(NPCM_DMA_TX_BASE_ADDR, 0x1010)
REG32(NPCM_DMA_STATUS, 0x1014)
REG32(NPCM_DMA_CONTROL, 0x1018)
REG32(NPCM_DMA_INTR_ENA, 0x101c)
REG32(NPCM_DMA_MISSED_FRAME_CTR, 0x1020)
REG32(NPCM_DMA_HOST_TX_DESC, 0x1048)
REG32(NPCM_DMA_HOST_RX_DESC, 0x104c)
REG32(NPCM_DMA_CUR_TX_BUF_ADDR, 0x1050)
REG32(NPCM_DMA_CUR_RX_BUF_ADDR, 0x1054)
REG32(NPCM_DMA_HW_FEATURE, 0x1058)
REG32(NPCM_GMAC_MAC_CONFIG, 0x0)
REG32(NPCM_GMAC_FRAME_FILTER, 0x4)
REG32(NPCM_GMAC_HASH_HIGH, 0x8)
REG32(NPCM_GMAC_HASH_LOW, 0xc)
REG32(NPCM_GMAC_MII_ADDR, 0x10)
REG32(NPCM_GMAC_MII_DATA, 0x14)
REG32(NPCM_GMAC_FLOW_CTRL, 0x18)
REG32(NPCM_GMAC_VLAN_FLAG, 0x1c)
REG32(NPCM_GMAC_VERSION, 0x20)
REG32(NPCM_GMAC_WAKEUP_FILTER, 0x28)
REG32(NPCM_GMAC_PMT, 0x2c)
REG32(NPCM_GMAC_LPI_CTRL, 0x30)
REG32(NPCM_GMAC_TIMER_CTRL, 0x34)
REG32(NPCM_GMAC_INT_STATUS, 0x38)
REG32(NPCM_GMAC_INT_MASK, 0x3c)
REG32(NPCM_GMAC_MAC0_ADDR_HI, 0x40)
REG32(NPCM_GMAC_MAC0_ADDR_LO, 0x44)
REG32(NPCM_GMAC_MAC1_ADDR_HI, 0x48)
REG32(NPCM_GMAC_MAC1_ADDR_LO, 0x4c)
REG32(NPCM_GMAC_MAC2_ADDR_HI, 0x50)
REG32(NPCM_GMAC_MAC2_ADDR_LO, 0x54)
REG32(NPCM_GMAC_MAC3_ADDR_HI, 0x58)
REG32(NPCM_GMAC_MAC3_ADDR_LO, 0x5c)
REG32(NPCM_GMAC_RGMII_STATUS, 0xd8)
REG32(NPCM_GMAC_WATCHDOG, 0xdc)
REG32(NPCM_GMAC_PTP_TCR, 0x700)
REG32(NPCM_GMAC_PTP_SSIR, 0x704)
REG32(NPCM_GMAC_PTP_STSR, 0x708)
REG32(NPCM_GMAC_PTP_STNSR, 0x70c)
REG32(NPCM_GMAC_PTP_STSUR, 0x710)
REG32(NPCM_GMAC_PTP_STNSUR, 0x714)
REG32(NPCM_GMAC_PTP_TAR, 0x718)
REG32(NPCM_GMAC_PTP_TTSR, 0x71c)
/* Register Fields */
#define NPCM_GMAC_MII_ADDR_BUSY BIT(0)
#define NPCM_GMAC_MII_ADDR_WRITE BIT(1)
#define NPCM_GMAC_MII_ADDR_GR(rv) extract16((rv), 6, 5)
#define NPCM_GMAC_MII_ADDR_PA(rv) extract16((rv), 11, 5)
#define NPCM_GMAC_INT_MASK_LPIIM BIT(10)
#define NPCM_GMAC_INT_MASK_PMTM BIT(3)
#define NPCM_GMAC_INT_MASK_RGIM BIT(0)
#define NPCM_DMA_BUS_MODE_SWR BIT(0)
static const uint32_t npcm_gmac_cold_reset_values[NPCM_GMAC_NR_REGS] = {
/* Reduce version to 3.2 so that the kernel can enable interrupt. */
[R_NPCM_GMAC_VERSION] = 0x00001032,
[R_NPCM_GMAC_TIMER_CTRL] = 0x03e80000,
[R_NPCM_GMAC_MAC0_ADDR_HI] = 0x8000ffff,
[R_NPCM_GMAC_MAC0_ADDR_LO] = 0xffffffff,
[R_NPCM_GMAC_MAC1_ADDR_HI] = 0x0000ffff,
[R_NPCM_GMAC_MAC1_ADDR_LO] = 0xffffffff,
[R_NPCM_GMAC_MAC2_ADDR_HI] = 0x0000ffff,
[R_NPCM_GMAC_MAC2_ADDR_LO] = 0xffffffff,
[R_NPCM_GMAC_MAC3_ADDR_HI] = 0x0000ffff,
[R_NPCM_GMAC_MAC3_ADDR_LO] = 0xffffffff,
[R_NPCM_GMAC_PTP_TCR] = 0x00002000,
[R_NPCM_DMA_BUS_MODE] = 0x00020101,
[R_NPCM_DMA_HW_FEATURE] = 0x100d4f37,
};
static const uint16_t phy_reg_init[] = {
[MII_BMCR] = MII_BMCR_AUTOEN | MII_BMCR_FD | MII_BMCR_SPEED1000,
[MII_BMSR] = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD |
MII_BMSR_10T_HD | MII_BMSR_EXTSTAT | MII_BMSR_AUTONEG |
MII_BMSR_LINK_ST | MII_BMSR_EXTCAP,
[MII_PHYID1] = 0x0362,
[MII_PHYID2] = 0x5e6a,
[MII_ANAR] = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD |
MII_ANAR_10 | MII_ANAR_CSMACD,
[MII_ANLPAR] = MII_ANLPAR_ACK | MII_ANLPAR_PAUSE |
MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD |
MII_ANLPAR_10 | MII_ANLPAR_CSMACD,
[MII_ANER] = 0x64 | MII_ANER_NWAY,
[MII_ANNP] = 0x2001,
[MII_CTRL1000] = MII_CTRL1000_FULL,
[MII_STAT1000] = MII_STAT1000_FULL,
[MII_EXTSTAT] = 0x3000, /* 1000BASTE_T full-duplex capable */
};
static void npcm_gmac_soft_reset(NPCMGMACState *gmac)
{
memcpy(gmac->regs, npcm_gmac_cold_reset_values,
NPCM_GMAC_NR_REGS * sizeof(uint32_t));
/* Clear reset bits */
gmac->regs[R_NPCM_DMA_BUS_MODE] &= ~NPCM_DMA_BUS_MODE_SWR;
}
static void gmac_phy_set_link(NPCMGMACState *gmac, bool active)
{
/* Autonegotiation status mirrors link status. */
if (active) {
gmac->phy_regs[0][MII_BMSR] |= (MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
} else {
gmac->phy_regs[0][MII_BMSR] &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
}
}
static bool gmac_can_receive(NetClientState *nc)
{
NPCMGMACState *gmac = NPCM_GMAC(qemu_get_nic_opaque(nc));
/* If GMAC receive is disabled. */
if (!(gmac->regs[R_NPCM_GMAC_MAC_CONFIG] & NPCM_GMAC_MAC_CONFIG_RX_EN)) {
return false;
}
/* If GMAC DMA RX is stopped. */
if (!(gmac->regs[R_NPCM_DMA_CONTROL] & NPCM_DMA_CONTROL_START_STOP_RX)) {
return false;
}
return true;
}
/*
* Function that updates the GMAC IRQ
* It find the logical OR of the enabled bits for NIS (if enabled)
* It find the logical OR of the enabled bits for AIS (if enabled)
*/
static void gmac_update_irq(NPCMGMACState *gmac)
{
/*
* Check if the normal interrupts summary is enabled
* if so, add the bits for the summary that are enabled
*/
if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] &
(NPCM_DMA_INTR_ENAB_NIE_BITS)) {
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_NIS;
}
/*
* Check if the abnormal interrupts summary is enabled
* if so, add the bits for the summary that are enabled
*/
if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] &
(NPCM_DMA_INTR_ENAB_AIE_BITS)) {
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_AIS;
}
/* Get the logical OR of both normal and abnormal interrupts */
int level = !!((gmac->regs[R_NPCM_DMA_STATUS] &
gmac->regs[R_NPCM_DMA_INTR_ENA] &
NPCM_DMA_STATUS_NIS) |
(gmac->regs[R_NPCM_DMA_STATUS] &
gmac->regs[R_NPCM_DMA_INTR_ENA] &
NPCM_DMA_STATUS_AIS));
/* Set the IRQ */
trace_npcm_gmac_update_irq(DEVICE(gmac)->canonical_path,
gmac->regs[R_NPCM_DMA_STATUS],
gmac->regs[R_NPCM_DMA_INTR_ENA],
level);
qemu_set_irq(gmac->irq, level);
}
static int gmac_read_rx_desc(dma_addr_t addr, struct NPCMGMACRxDesc *desc)
{
if (dma_memory_read(&address_space_memory, addr, desc,
sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
HWADDR_PRIx "\n", __func__, addr);
return -1;
}
desc->rdes0 = le32_to_cpu(desc->rdes0);
desc->rdes1 = le32_to_cpu(desc->rdes1);
desc->rdes2 = le32_to_cpu(desc->rdes2);
desc->rdes3 = le32_to_cpu(desc->rdes3);
return 0;
}
static int gmac_write_rx_desc(dma_addr_t addr, struct NPCMGMACRxDesc *desc)
{
struct NPCMGMACRxDesc le_desc;
le_desc.rdes0 = cpu_to_le32(desc->rdes0);
le_desc.rdes1 = cpu_to_le32(desc->rdes1);
le_desc.rdes2 = cpu_to_le32(desc->rdes2);
le_desc.rdes3 = cpu_to_le32(desc->rdes3);
if (dma_memory_write(&address_space_memory, addr, &le_desc,
sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
HWADDR_PRIx "\n", __func__, addr);
return -1;
}
return 0;
}
static int gmac_read_tx_desc(dma_addr_t addr, struct NPCMGMACTxDesc *desc)
{
if (dma_memory_read(&address_space_memory, addr, desc,
sizeof(*desc), MEMTXATTRS_UNSPECIFIED)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
HWADDR_PRIx "\n", __func__, addr);
return -1;
}
desc->tdes0 = le32_to_cpu(desc->tdes0);
desc->tdes1 = le32_to_cpu(desc->tdes1);
desc->tdes2 = le32_to_cpu(desc->tdes2);
desc->tdes3 = le32_to_cpu(desc->tdes3);
return 0;
}
static int gmac_write_tx_desc(dma_addr_t addr, struct NPCMGMACTxDesc *desc)
{
struct NPCMGMACTxDesc le_desc;
le_desc.tdes0 = cpu_to_le32(desc->tdes0);
le_desc.tdes1 = cpu_to_le32(desc->tdes1);
le_desc.tdes2 = cpu_to_le32(desc->tdes2);
le_desc.tdes3 = cpu_to_le32(desc->tdes3);
if (dma_memory_write(&address_space_memory, addr, &le_desc,
sizeof(le_desc), MEMTXATTRS_UNSPECIFIED)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
HWADDR_PRIx "\n", __func__, addr);
return -1;
}
return 0;
}
static int gmac_rx_transfer_frame_to_buffer(uint32_t rx_buf_len,
uint32_t *left_frame,
uint32_t rx_buf_addr,
bool *eof_transferred,
const uint8_t **frame_ptr,
uint16_t *transferred)
{
uint32_t to_transfer;
/*
* Check that buffer is bigger than the frame being transfered
* If bigger then transfer only whats left of frame
* Else, fill frame with all the content possible
*/
if (rx_buf_len >= *left_frame) {
to_transfer = *left_frame;
*eof_transferred = true;
} else {
to_transfer = rx_buf_len;
}
/* write frame part to memory */
if (dma_memory_write(&address_space_memory, (uint64_t) rx_buf_addr,
*frame_ptr, to_transfer, MEMTXATTRS_UNSPECIFIED)) {
return -1;
}
/* update frame pointer and size of whats left of frame */
*frame_ptr += to_transfer;
*left_frame -= to_transfer;
*transferred += to_transfer;
return 0;
}
static void gmac_dma_set_state(NPCMGMACState *gmac, int shift, uint32_t state)
{
gmac->regs[R_NPCM_DMA_STATUS] = deposit32(gmac->regs[R_NPCM_DMA_STATUS],
shift, 3, state);
}
static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf, size_t len)
{
/*
* Comments have steps that relate to the
* receiving process steps in pg 386
*/
NPCMGMACState *gmac = NPCM_GMAC(qemu_get_nic_opaque(nc));
uint32_t left_frame = len;
const uint8_t *frame_ptr = buf;
uint32_t desc_addr;
uint32_t rx_buf_len, rx_buf_addr;
struct NPCMGMACRxDesc rx_desc;
uint16_t transferred = 0;
bool eof_transferred = false;
trace_npcm_gmac_packet_receive(DEVICE(gmac)->canonical_path, len);
if (!gmac_can_receive(nc)) {
qemu_log_mask(LOG_GUEST_ERROR, "GMAC Currently is not able for Rx");
return -1;
}
if (!gmac->regs[R_NPCM_DMA_HOST_RX_DESC]) {
gmac->regs[R_NPCM_DMA_HOST_RX_DESC] =
NPCM_DMA_HOST_RX_DESC_MASK(gmac->regs[R_NPCM_DMA_RX_BASE_ADDR]);
}
desc_addr = NPCM_DMA_HOST_RX_DESC_MASK(gmac->regs[R_NPCM_DMA_HOST_RX_DESC]);
/* step 1 */
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_RUNNING_FETCHING_STATE);
trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path, desc_addr);
if (gmac_read_rx_desc(desc_addr, &rx_desc)) {
qemu_log_mask(LOG_GUEST_ERROR, "RX Descriptor @ 0x%x cant be read\n",
desc_addr);
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_SUSPENDED_STATE);
return -1;
}
/* step 2 */
if (!(rx_desc.rdes0 & RX_DESC_RDES0_OWN)) {
qemu_log_mask(LOG_GUEST_ERROR,
"RX Descriptor @ 0x%x is owned by software\n",
desc_addr);
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RU;
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RI;
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_SUSPENDED_STATE);
gmac_update_irq(gmac);
return len;
}
/* step 3 */
/*
* TODO --
* Implement all frame filtering and processing (with its own interrupts)
*/
trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc,
rx_desc.rdes0, rx_desc.rdes1, rx_desc.rdes2,
rx_desc.rdes3);
/* Clear rdes0 for the incoming descriptor and set FS in first descriptor.*/
rx_desc.rdes0 = RX_DESC_RDES0_FIRST_DESC_MASK;
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_RUNNING_TRANSFERRING_STATE);
/* Pad the frame with FCS as the kernel driver will strip it away. */
left_frame += ETH_FCS_LEN;
/* repeat while we still have frame to transfer to memory */
while (!eof_transferred) {
/* Return descriptor no matter what happens */
rx_desc.rdes0 &= ~RX_DESC_RDES0_OWN;
/* Set the frame to be an IPv4/IPv6 frame. */
rx_desc.rdes0 |= RX_DESC_RDES0_FRM_TYPE_MASK;
/* step 4 */
rx_buf_len = RX_DESC_RDES1_BFFR1_SZ_MASK(rx_desc.rdes1);
rx_buf_addr = rx_desc.rdes2;
gmac->regs[R_NPCM_DMA_CUR_RX_BUF_ADDR] = rx_buf_addr;
gmac_rx_transfer_frame_to_buffer(rx_buf_len, &left_frame, rx_buf_addr,
&eof_transferred, &frame_ptr,
&transferred);
trace_npcm_gmac_packet_receiving_buffer(DEVICE(gmac)->canonical_path,
rx_buf_len, rx_buf_addr);
/* if we still have frame left and the second buffer is not chained */
if (!(rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) && \
!eof_transferred) {
/* repeat process from above on buffer 2 */
rx_buf_len = RX_DESC_RDES1_BFFR2_SZ_MASK(rx_desc.rdes1);
rx_buf_addr = rx_desc.rdes3;
gmac->regs[R_NPCM_DMA_CUR_RX_BUF_ADDR] = rx_buf_addr;
gmac_rx_transfer_frame_to_buffer(rx_buf_len, &left_frame,
rx_buf_addr, &eof_transferred,
&frame_ptr, &transferred);
trace_npcm_gmac_packet_receiving_buffer( \
DEVICE(gmac)->canonical_path,
rx_buf_len, rx_buf_addr);
}
/* update address for descriptor */
gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = rx_buf_addr;
/* Return descriptor */
rx_desc.rdes0 &= ~RX_DESC_RDES0_OWN;
/* Update frame length transferred */
rx_desc.rdes0 |= ((uint32_t)transferred)
<< RX_DESC_RDES0_FRAME_LEN_SHIFT;
trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc,
rx_desc.rdes0, rx_desc.rdes1,
rx_desc.rdes2, rx_desc.rdes3);
/* step 5 */
gmac_write_rx_desc(desc_addr, &rx_desc);
trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path,
&rx_desc, rx_desc.rdes0,
rx_desc.rdes1, rx_desc.rdes2,
rx_desc.rdes3);
/* read new descriptor into rx_desc if needed*/
if (!eof_transferred) {
/* Get next descriptor address (chained or sequential) */
if (rx_desc.rdes1 & RX_DESC_RDES1_RC_END_RING_MASK) {
desc_addr = gmac->regs[R_NPCM_DMA_RX_BASE_ADDR];
} else if (rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) {
desc_addr = rx_desc.rdes3;
} else {
desc_addr += sizeof(rx_desc);
}
trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path,
desc_addr);
if (gmac_read_rx_desc(desc_addr, &rx_desc)) {
qemu_log_mask(LOG_GUEST_ERROR,
"RX Descriptor @ 0x%x cant be read\n",
desc_addr);
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RU;
gmac_update_irq(gmac);
return len;
}
/* step 6 */
if (!(rx_desc.rdes0 & RX_DESC_RDES0_OWN)) {
if (!(gmac->regs[R_NPCM_DMA_CONTROL] & \
NPCM_DMA_CONTROL_FLUSH_MASK)) {
rx_desc.rdes0 |= RX_DESC_RDES0_DESC_ERR_MASK;
}
eof_transferred = true;
}
/* Clear rdes0 for the incoming descriptor */
rx_desc.rdes0 = 0;
}
}
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_RUNNING_CLOSING_STATE);
rx_desc.rdes0 |= RX_DESC_RDES0_LAST_DESC_MASK;
if (!(rx_desc.rdes1 & RX_DESC_RDES1_DIS_INTR_COMP_MASK)) {
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_RI;
gmac_update_irq(gmac);
}
trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &rx_desc,
rx_desc.rdes0, rx_desc.rdes1, rx_desc.rdes2,
rx_desc.rdes3);
/* step 8 */
gmac->regs[R_NPCM_DMA_CONTROL] |= NPCM_DMA_CONTROL_FLUSH_MASK;
/* step 9 */
trace_npcm_gmac_packet_received(DEVICE(gmac)->canonical_path, left_frame);
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE);
gmac_write_rx_desc(desc_addr, &rx_desc);
/* Get next descriptor address (chained or sequential) */
if (rx_desc.rdes1 & RX_DESC_RDES1_RC_END_RING_MASK) {
desc_addr = gmac->regs[R_NPCM_DMA_RX_BASE_ADDR];
} else if (rx_desc.rdes1 & RX_DESC_RDES1_SEC_ADDR_CHND_MASK) {
desc_addr = rx_desc.rdes3;
} else {
desc_addr += sizeof(rx_desc);
}
gmac->regs[R_NPCM_DMA_HOST_RX_DESC] = desc_addr;
return len;
}
static int gmac_tx_get_csum(uint32_t tdes1)
{
uint32_t mask = TX_DESC_TDES1_CHKSM_INS_CTRL_MASK(tdes1);
int csum = 0;
if (likely(mask > 0)) {
csum |= CSUM_IP;
}
if (likely(mask > 1)) {
csum |= CSUM_TCP | CSUM_UDP;
}
return csum;
}
static void gmac_try_send_next_packet(NPCMGMACState *gmac)
{
/*
* Comments about steps refer to steps for
* transmitting in page 384 of datasheet
*/
uint16_t tx_buffer_size = 2048;
g_autofree uint8_t *tx_send_buffer = g_malloc(tx_buffer_size);
uint32_t desc_addr;
struct NPCMGMACTxDesc tx_desc;
uint32_t tx_buf_addr, tx_buf_len;
uint16_t length = 0;
uint8_t *buf = tx_send_buffer;
uint32_t prev_buf_size = 0;
int csum = 0;
/* steps 1&2 */
if (!gmac->regs[R_NPCM_DMA_HOST_TX_DESC]) {
gmac->regs[R_NPCM_DMA_HOST_TX_DESC] =
NPCM_DMA_HOST_TX_DESC_MASK(gmac->regs[R_NPCM_DMA_TX_BASE_ADDR]);
}
desc_addr = gmac->regs[R_NPCM_DMA_HOST_TX_DESC];
while (true) {
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_TX_RUNNING_FETCHING_STATE);
if (gmac_read_tx_desc(desc_addr, &tx_desc)) {
qemu_log_mask(LOG_GUEST_ERROR,
"TX Descriptor @ 0x%x can't be read\n",
desc_addr);
return;
}
/* step 3 */
trace_npcm_gmac_packet_desc_read(DEVICE(gmac)->canonical_path,
desc_addr);
trace_npcm_gmac_debug_desc_data(DEVICE(gmac)->canonical_path, &tx_desc,
tx_desc.tdes0, tx_desc.tdes1, tx_desc.tdes2, tx_desc.tdes3);
/* 1 = DMA Owned, 0 = Software Owned */
if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) {
qemu_log_mask(LOG_GUEST_ERROR,
"TX Descriptor @ 0x%x is owned by software\n",
desc_addr);
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU;
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_TX_SUSPENDED_STATE);
gmac_update_irq(gmac);
return;
}
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_TX_RUNNING_READ_STATE);
/* Give the descriptor back regardless of what happens. */
tx_desc.tdes0 &= ~TX_DESC_TDES0_OWN;
if (tx_desc.tdes1 & TX_DESC_TDES1_FIRST_SEG_MASK) {
csum = gmac_tx_get_csum(tx_desc.tdes1);
}
/* step 4 */
tx_buf_addr = tx_desc.tdes2;
gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr;
tx_buf_len = TX_DESC_TDES1_BFFR1_SZ_MASK(tx_desc.tdes1);
buf = &tx_send_buffer[prev_buf_size];
if ((prev_buf_size + tx_buf_len) > sizeof(buf)) {
tx_buffer_size = prev_buf_size + tx_buf_len;
tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size);
buf = &tx_send_buffer[prev_buf_size];
}
/* step 5 */
if (dma_memory_read(&address_space_memory, tx_buf_addr, buf,
tx_buf_len, MEMTXATTRS_UNSPECIFIED)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read packet @ 0x%x\n",
__func__, tx_buf_addr);
return;
}
length += tx_buf_len;
prev_buf_size += tx_buf_len;
/* If not chained we'll have a second buffer. */
if (!(tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK)) {
tx_buf_addr = tx_desc.tdes3;
gmac->regs[R_NPCM_DMA_CUR_TX_BUF_ADDR] = tx_buf_addr;
tx_buf_len = TX_DESC_TDES1_BFFR2_SZ_MASK(tx_desc.tdes1);
buf = &tx_send_buffer[prev_buf_size];
if ((prev_buf_size + tx_buf_len) > sizeof(buf)) {
tx_buffer_size = prev_buf_size + tx_buf_len;
tx_send_buffer = g_realloc(tx_send_buffer, tx_buffer_size);
buf = &tx_send_buffer[prev_buf_size];
}
if (dma_memory_read(&address_space_memory, tx_buf_addr, buf,
tx_buf_len, MEMTXATTRS_UNSPECIFIED)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Failed to read packet @ 0x%x\n",
__func__, tx_buf_addr);
return;
}
length += tx_buf_len;
prev_buf_size += tx_buf_len;
}
if (tx_desc.tdes1 & TX_DESC_TDES1_LAST_SEG_MASK) {
net_checksum_calculate(tx_send_buffer, length, csum);
qemu_send_packet(qemu_get_queue(gmac->nic), tx_send_buffer, length);
trace_npcm_gmac_packet_sent(DEVICE(gmac)->canonical_path, length);
buf = tx_send_buffer;
length = 0;
}
/* step 6 */
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_TX_RUNNING_CLOSING_STATE);
gmac_write_tx_desc(desc_addr, &tx_desc);
if (tx_desc.tdes1 & TX_DESC_TDES1_TX_END_RING_MASK) {
desc_addr = gmac->regs[R_NPCM_DMA_TX_BASE_ADDR];
} else if (tx_desc.tdes1 & TX_DESC_TDES1_SEC_ADDR_CHND_MASK) {
desc_addr = tx_desc.tdes3;
} else {
desc_addr += sizeof(tx_desc);
}
gmac->regs[R_NPCM_DMA_HOST_TX_DESC] = desc_addr;
/* step 7 */
if (tx_desc.tdes1 & TX_DESC_TDES1_INTERR_COMP_MASK) {
gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TI;
gmac_update_irq(gmac);
}
}
}
static void gmac_cleanup(NetClientState *nc)
{
/* Nothing to do yet. */
}
static void gmac_set_link(NetClientState *nc)
{
NPCMGMACState *gmac = qemu_get_nic_opaque(nc);
trace_npcm_gmac_set_link(!nc->link_down);
gmac_phy_set_link(gmac, !nc->link_down);
}
static void npcm_gmac_mdio_access(NPCMGMACState *gmac, uint16_t v)
{
bool busy = v & NPCM_GMAC_MII_ADDR_BUSY;
uint8_t is_write;
uint8_t pa, gr;
uint16_t data;
if (busy) {
is_write = v & NPCM_GMAC_MII_ADDR_WRITE;
pa = NPCM_GMAC_MII_ADDR_PA(v);
gr = NPCM_GMAC_MII_ADDR_GR(v);
/* Both pa and gr are 5 bits, so they are less than 32. */
g_assert(pa < NPCM_GMAC_MAX_PHYS);
g_assert(gr < NPCM_GMAC_MAX_PHY_REGS);
if (v & NPCM_GMAC_MII_ADDR_WRITE) {
data = gmac->regs[R_NPCM_GMAC_MII_DATA];
/* Clear reset bit for BMCR register */
switch (gr) {
case MII_BMCR:
data &= ~MII_BMCR_RESET;
/* Autonegotiation is a W1C bit*/
if (data & MII_BMCR_ANRESTART) {
/* Tells autonegotiation to not restart again */
data &= ~MII_BMCR_ANRESTART;
}
if ((data & MII_BMCR_AUTOEN) &&
!(gmac->phy_regs[pa][MII_BMSR] & MII_BMSR_AN_COMP)) {
/* sets autonegotiation as complete */
gmac->phy_regs[pa][MII_BMSR] |= MII_BMSR_AN_COMP;
/* Resolve AN automatically->need to set this */
gmac->phy_regs[0][MII_ANLPAR] = 0x0000;
}
}
gmac->phy_regs[pa][gr] = data;
} else {
data = gmac->phy_regs[pa][gr];
gmac->regs[R_NPCM_GMAC_MII_DATA] = data;
}
trace_npcm_gmac_mdio_access(DEVICE(gmac)->canonical_path, is_write, pa,
gr, data);
}
gmac->regs[R_NPCM_GMAC_MII_ADDR] = v & ~NPCM_GMAC_MII_ADDR_BUSY;
}
static uint64_t npcm_gmac_read(void *opaque, hwaddr offset, unsigned size)
{
NPCMGMACState *gmac = opaque;
uint32_t v = 0;
switch (offset) {
/* Write only registers */
case A_NPCM_DMA_XMT_POLL_DEMAND:
case A_NPCM_DMA_RCV_POLL_DEMAND:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Read of write-only reg: offset: 0x%04" HWADDR_PRIx
"\n", DEVICE(gmac)->canonical_path, offset);
break;
default:
v = gmac->regs[offset / sizeof(uint32_t)];
}
trace_npcm_gmac_reg_read(DEVICE(gmac)->canonical_path, offset, v);
return v;
}
static void npcm_gmac_write(void *opaque, hwaddr offset,
uint64_t v, unsigned size)
{
NPCMGMACState *gmac = opaque;
trace_npcm_gmac_reg_write(DEVICE(gmac)->canonical_path, offset, v);
switch (offset) {
/* Read only registers */
case A_NPCM_GMAC_VERSION:
case A_NPCM_GMAC_INT_STATUS:
case A_NPCM_GMAC_RGMII_STATUS:
case A_NPCM_GMAC_PTP_STSR:
case A_NPCM_GMAC_PTP_STNSR:
case A_NPCM_DMA_MISSED_FRAME_CTR:
case A_NPCM_DMA_HOST_TX_DESC:
case A_NPCM_DMA_HOST_RX_DESC:
case A_NPCM_DMA_CUR_TX_BUF_ADDR:
case A_NPCM_DMA_CUR_RX_BUF_ADDR:
case A_NPCM_DMA_HW_FEATURE:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Write of read-only reg: offset: 0x%04" HWADDR_PRIx
", value: 0x%04" PRIx64 "\n",
DEVICE(gmac)->canonical_path, offset, v);
break;
case A_NPCM_GMAC_MAC_CONFIG:
gmac->regs[offset / sizeof(uint32_t)] = v;
break;
case A_NPCM_GMAC_MII_ADDR:
npcm_gmac_mdio_access(gmac, v);
break;
case A_NPCM_GMAC_MAC0_ADDR_HI:
gmac->regs[offset / sizeof(uint32_t)] = v;
gmac->conf.macaddr.a[0] = v >> 8;
gmac->conf.macaddr.a[1] = v >> 0;
break;
case A_NPCM_GMAC_MAC0_ADDR_LO:
gmac->regs[offset / sizeof(uint32_t)] = v;
gmac->conf.macaddr.a[2] = v >> 24;
gmac->conf.macaddr.a[3] = v >> 16;
gmac->conf.macaddr.a[4] = v >> 8;
gmac->conf.macaddr.a[5] = v >> 0;
break;
case A_NPCM_GMAC_MAC1_ADDR_HI:
case A_NPCM_GMAC_MAC1_ADDR_LO:
case A_NPCM_GMAC_MAC2_ADDR_HI:
case A_NPCM_GMAC_MAC2_ADDR_LO:
case A_NPCM_GMAC_MAC3_ADDR_HI:
case A_NPCM_GMAC_MAC3_ADDR_LO:
gmac->regs[offset / sizeof(uint32_t)] = v;
qemu_log_mask(LOG_UNIMP,
"%s: Only MAC Address 0 is supported. This request "
"is ignored.\n", DEVICE(gmac)->canonical_path);
break;
case A_NPCM_DMA_BUS_MODE:
gmac->regs[offset / sizeof(uint32_t)] = v;
if (v & NPCM_DMA_BUS_MODE_SWR) {
npcm_gmac_soft_reset(gmac);
}
break;
case A_NPCM_DMA_RCV_POLL_DEMAND:
/* We dont actually care about the value */
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE);
break;
case A_NPCM_DMA_XMT_POLL_DEMAND:
/* We dont actually care about the value */
gmac_try_send_next_packet(gmac);
break;
case A_NPCM_DMA_CONTROL:
gmac->regs[offset / sizeof(uint32_t)] = v;
if (v & NPCM_DMA_CONTROL_START_STOP_TX) {
gmac_try_send_next_packet(gmac);
} else {
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_TX_STOPPED_STATE);
}
if (v & NPCM_DMA_CONTROL_START_STOP_RX) {
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE);
qemu_flush_queued_packets(qemu_get_queue(gmac->nic));
} else {
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_STOPPED_STATE);
}
break;
case A_NPCM_DMA_STATUS:
/* Check that RO bits are not written to */
if (NPCM_DMA_STATUS_RO_MASK(v)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Write of read-only bits of reg: offset: 0x%04"
HWADDR_PRIx ", value: 0x%04" PRIx64 "\n",
DEVICE(gmac)->canonical_path, offset, v);
}
/* for W1C bits, implement W1C */
gmac->regs[offset / sizeof(uint32_t)] &= ~NPCM_DMA_STATUS_W1C_MASK(v);
if (v & NPCM_DMA_STATUS_RU) {
/* Clearing RU bit indicates descriptor is owned by DMA again. */
gmac_dma_set_state(gmac, NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT,
NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE);
qemu_flush_queued_packets(qemu_get_queue(gmac->nic));
}
break;
default:
gmac->regs[offset / sizeof(uint32_t)] = v;
break;
}
gmac_update_irq(gmac);
}
static void npcm_gmac_reset(DeviceState *dev)
{
NPCMGMACState *gmac = NPCM_GMAC(dev);
npcm_gmac_soft_reset(gmac);
memcpy(gmac->phy_regs[0], phy_reg_init, sizeof(phy_reg_init));
trace_npcm_gmac_reset(DEVICE(gmac)->canonical_path,
gmac->phy_regs[0][MII_BMSR]);
}
static NetClientInfo net_npcm_gmac_info = {
.type = NET_CLIENT_DRIVER_NIC,
.size = sizeof(NICState),
.can_receive = gmac_can_receive,
.receive = gmac_receive,
.cleanup = gmac_cleanup,
.link_status_changed = gmac_set_link,
};
static const struct MemoryRegionOps npcm_gmac_ops = {
.read = npcm_gmac_read,
.write = npcm_gmac_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
.unaligned = false,
},
};
static void npcm_gmac_realize(DeviceState *dev, Error **errp)
{
NPCMGMACState *gmac = NPCM_GMAC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
memory_region_init_io(&gmac->iomem, OBJECT(gmac), &npcm_gmac_ops, gmac,
TYPE_NPCM_GMAC, 8 * KiB);
sysbus_init_mmio(sbd, &gmac->iomem);
sysbus_init_irq(sbd, &gmac->irq);
qemu_macaddr_default_if_unset(&gmac->conf.macaddr);
gmac->nic = qemu_new_nic(&net_npcm_gmac_info, &gmac->conf, TYPE_NPCM_GMAC,
dev->id, &dev->mem_reentrancy_guard, gmac);
qemu_format_nic_info_str(qemu_get_queue(gmac->nic), gmac->conf.macaddr.a);
gmac->regs[R_NPCM_GMAC_MAC0_ADDR_HI] = (gmac->conf.macaddr.a[0] << 8) + \
gmac->conf.macaddr.a[1];
gmac->regs[R_NPCM_GMAC_MAC0_ADDR_LO] = (gmac->conf.macaddr.a[2] << 24) + \
(gmac->conf.macaddr.a[3] << 16) + \
(gmac->conf.macaddr.a[4] << 8) + \
gmac->conf.macaddr.a[5];
}
static void npcm_gmac_unrealize(DeviceState *dev)
{
NPCMGMACState *gmac = NPCM_GMAC(dev);
qemu_del_nic(gmac->nic);
}
static const VMStateDescription vmstate_npcm_gmac = {
.name = TYPE_NPCM_GMAC,
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, NPCMGMACState, NPCM_GMAC_NR_REGS),
VMSTATE_END_OF_LIST(),
},
};
static Property npcm_gmac_properties[] = {
DEFINE_NIC_PROPERTIES(NPCMGMACState, conf),
DEFINE_PROP_END_OF_LIST(),
};
static void npcm_gmac_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "NPCM GMAC Controller";
dc->realize = npcm_gmac_realize;
dc->unrealize = npcm_gmac_unrealize;
dc->reset = npcm_gmac_reset;
dc->vmsd = &vmstate_npcm_gmac;
device_class_set_props(dc, npcm_gmac_properties);
}
static const TypeInfo npcm_gmac_types[] = {
{
.name = TYPE_NPCM_GMAC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(NPCMGMACState),
.class_init = npcm_gmac_class_init,
},
};
DEFINE_TYPES(npcm_gmac_types)

View File

@ -467,6 +467,25 @@ npcm7xx_emc_rx_done(uint32_t crxdsa) "RX done, CRXDSA=0x%x"
npcm7xx_emc_reg_read(int emc_num, uint32_t result, const char *name, int regno) "emc%d: 0x%x = reg[%s/%d]" npcm7xx_emc_reg_read(int emc_num, uint32_t result, const char *name, int regno) "emc%d: 0x%x = reg[%s/%d]"
npcm7xx_emc_reg_write(int emc_num, const char *name, int regno, uint32_t value) "emc%d: reg[%s/%d] = 0x%x" npcm7xx_emc_reg_write(int emc_num, const char *name, int regno, uint32_t value) "emc%d: reg[%s/%d] = 0x%x"
# npcm_gmac.c
npcm_gmac_reg_read(const char *name, uint64_t offset, uint32_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx32
npcm_gmac_reg_write(const char *name, uint64_t offset, uint32_t value) "%s: offset: 0x%04" PRIx64 " value: 0x%04" PRIx32
npcm_gmac_mdio_access(const char *name, uint8_t is_write, uint8_t pa, uint8_t gr, uint16_t val) "%s: is_write: %" PRIu8 " pa: %" PRIu8 " gr: %" PRIu8 " val: 0x%04" PRIx16
npcm_gmac_reset(const char *name, uint16_t value) "%s: phy_regs[0][1]: 0x%04" PRIx16
npcm_gmac_set_link(bool active) "Set link: active=%u"
npcm_gmac_update_irq(const char *name, uint32_t status, uint32_t intr_en, int level) "%s: Status Reg: 0x%04" PRIX32 " Interrupt Enable Reg: 0x%04" PRIX32 " IRQ Set: %d"
npcm_gmac_packet_desc_read(const char* name, uint32_t desc_addr) "%s: attempting to read descriptor @0x%04" PRIX32
npcm_gmac_packet_receive(const char* name, uint32_t len) "%s: RX packet length: 0x%04" PRIX32
npcm_gmac_packet_receiving_buffer(const char* name, uint32_t buf_len, uint32_t rx_buf_addr) "%s: Receiving into Buffer size: 0x%04" PRIX32 " at address 0x%04" PRIX32
npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception finished, packet left: 0x%04" PRIX32
npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16
npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32
npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32
# npcm_pcs.c
npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
npcm_pcs_reg_write(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
# dp8398x.c # dp8398x.c
dp8393x_raise_irq(int isr) "raise irq, isr is 0x%04x" dp8393x_raise_irq(int isr) "raise irq, isr is 0x%04x"
dp8393x_lower_irq(void) "lower irq" dp8393x_lower_irq(void) "lower irq"

View File

@ -340,6 +340,8 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
break; break;
case DESIGNWARE_PCIE_ATU_VIEWPORT: case DESIGNWARE_PCIE_ATU_VIEWPORT:
val &= DESIGNWARE_PCIE_ATU_REGION_INBOUND |
(DESIGNWARE_PCIE_NUM_VIEWPORTS - 1);
root->atu_viewport = val; root->atu_viewport = val;
break; break;

View File

@ -64,7 +64,7 @@ bool pci_available = true;
static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_dev_path(DeviceState *dev);
static char *pcibus_get_fw_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev);
static void pcibus_reset(BusState *qbus); static void pcibus_reset_hold(Object *obj);
static bool pcie_has_upstream_port(PCIDevice *dev); static bool pcie_has_upstream_port(PCIDevice *dev);
static Property pci_props[] = { static Property pci_props[] = {
@ -202,13 +202,15 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
{ {
BusClass *k = BUS_CLASS(klass); BusClass *k = BUS_CLASS(klass);
PCIBusClass *pbc = PCI_BUS_CLASS(klass); PCIBusClass *pbc = PCI_BUS_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
k->print_dev = pcibus_dev_print; k->print_dev = pcibus_dev_print;
k->get_dev_path = pcibus_get_dev_path; k->get_dev_path = pcibus_get_dev_path;
k->get_fw_dev_path = pcibus_get_fw_dev_path; k->get_fw_dev_path = pcibus_get_fw_dev_path;
k->realize = pci_bus_realize; k->realize = pci_bus_realize;
k->unrealize = pci_bus_unrealize; k->unrealize = pci_bus_unrealize;
k->reset = pcibus_reset;
rc->phases.hold = pcibus_reset_hold;
pbc->bus_num = pcibus_num; pbc->bus_num = pcibus_num;
pbc->numa_node = pcibus_numa_node; pbc->numa_node = pcibus_numa_node;
@ -424,9 +426,9 @@ void pci_device_reset(PCIDevice *dev)
* Called via bus_cold_reset on RST# assert, after the devices * Called via bus_cold_reset on RST# assert, after the devices
* have been reset device_cold_reset-ed already. * have been reset device_cold_reset-ed already.
*/ */
static void pcibus_reset(BusState *qbus) static void pcibus_reset_hold(Object *obj)
{ {
PCIBus *bus = DO_UPCAST(PCIBus, qbus, qbus); PCIBus *bus = PCI_BUS(obj);
int i; int i;
for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {

View File

@ -56,7 +56,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev,
qdev_unrealize(dev); qdev_unrealize(dev);
} }
static void virtual_css_bus_reset(BusState *qbus) static void virtual_css_bus_reset_hold(Object *obj)
{ {
/* This should actually be modelled via the generic css */ /* This should actually be modelled via the generic css */
css_reset(); css_reset();
@ -81,8 +81,9 @@ static char *virtual_css_bus_get_dev_path(DeviceState *dev)
static void virtual_css_bus_class_init(ObjectClass *klass, void *data) static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
{ {
BusClass *k = BUS_CLASS(klass); BusClass *k = BUS_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
k->reset = virtual_css_bus_reset; rc->phases.hold = virtual_css_bus_reset_hold;
k->get_dev_path = virtual_css_bus_get_dev_path; k->get_dev_path = virtual_css_bus_get_dev_path;
} }

View File

@ -20,3 +20,7 @@ config XILINX_SPIPS
config STM32F2XX_SPI config STM32F2XX_SPI
bool bool
select SSI select SSI
config BCM2835_SPI
bool
select SSI

288
hw/ssi/bcm2835_spi.c Normal file
View File

@ -0,0 +1,288 @@
/*
* BCM2835 SPI Master Controller
*
* Copyright (c) 2024 Rayhan Faizel <rayhan.faizel@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/fifo8.h"
#include "hw/ssi/bcm2835_spi.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
static void bcm2835_spi_update_int(BCM2835SPIState *s)
{
int do_interrupt = 0;
/* Interrupt on DONE */
if (s->cs & BCM2835_SPI_CS_INTD && s->cs & BCM2835_SPI_CS_DONE) {
do_interrupt = 1;
}
/* Interrupt on RXR */
if (s->cs & BCM2835_SPI_CS_INTR && s->cs & BCM2835_SPI_CS_RXR) {
do_interrupt = 1;
}
qemu_set_irq(s->irq, do_interrupt);
}
static void bcm2835_spi_update_rx_flags(BCM2835SPIState *s)
{
/* Set RXD if RX FIFO is non empty */
if (!fifo8_is_empty(&s->rx_fifo)) {
s->cs |= BCM2835_SPI_CS_RXD;
} else {
s->cs &= ~BCM2835_SPI_CS_RXD;
}
/* Set RXF if RX FIFO is full */
if (fifo8_is_full(&s->rx_fifo)) {
s->cs |= BCM2835_SPI_CS_RXF;
} else {
s->cs &= ~BCM2835_SPI_CS_RXF;
}
/* Set RXR if RX FIFO is 3/4th used or above */
if (fifo8_num_used(&s->rx_fifo) >= FIFO_SIZE_3_4) {
s->cs |= BCM2835_SPI_CS_RXR;
} else {
s->cs &= ~BCM2835_SPI_CS_RXR;
}
}
static void bcm2835_spi_update_tx_flags(BCM2835SPIState *s)
{
/* Set TXD if TX FIFO is not full */
if (fifo8_is_full(&s->tx_fifo)) {
s->cs &= ~BCM2835_SPI_CS_TXD;
} else {
s->cs |= BCM2835_SPI_CS_TXD;
}
/* Set DONE if in TA mode and TX FIFO is empty */
if (fifo8_is_empty(&s->tx_fifo) && s->cs & BCM2835_SPI_CS_TA) {
s->cs |= BCM2835_SPI_CS_DONE;
} else {
s->cs &= ~BCM2835_SPI_CS_DONE;
}
}
static void bcm2835_spi_flush_tx_fifo(BCM2835SPIState *s)
{
uint8_t tx_byte, rx_byte;
while (!fifo8_is_empty(&s->tx_fifo) && !fifo8_is_full(&s->rx_fifo)) {
tx_byte = fifo8_pop(&s->tx_fifo);
rx_byte = ssi_transfer(s->bus, tx_byte);
fifo8_push(&s->rx_fifo, rx_byte);
}
bcm2835_spi_update_tx_flags(s);
bcm2835_spi_update_rx_flags(s);
}
static uint64_t bcm2835_spi_read(void *opaque, hwaddr addr, unsigned size)
{
BCM2835SPIState *s = opaque;
uint32_t readval = 0;
switch (addr) {
case BCM2835_SPI_CS:
readval = s->cs & 0xffffffff;
break;
case BCM2835_SPI_FIFO:
bcm2835_spi_flush_tx_fifo(s);
if (s->cs & BCM2835_SPI_CS_RXD) {
readval = fifo8_pop(&s->rx_fifo);
bcm2835_spi_update_rx_flags(s);
}
bcm2835_spi_update_int(s);
break;
case BCM2835_SPI_CLK:
readval = s->clk & 0xffff;
break;
case BCM2835_SPI_DLEN:
readval = s->dlen & 0xffff;
break;
case BCM2835_SPI_LTOH:
readval = s->ltoh & 0xf;
break;
case BCM2835_SPI_DC:
readval = s->dc & 0xffffffff;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
}
return readval;
}
static void bcm2835_spi_write(void *opaque, hwaddr addr,
uint64_t value, unsigned int size)
{
BCM2835SPIState *s = opaque;
switch (addr) {
case BCM2835_SPI_CS:
s->cs = (value & ~RO_MASK) | (s->cs & RO_MASK);
if (!(s->cs & BCM2835_SPI_CS_TA)) {
/* Clear DONE and RXR if TA is off */
s->cs &= ~(BCM2835_SPI_CS_DONE);
s->cs &= ~(BCM2835_SPI_CS_RXR);
}
/* Clear RX FIFO */
if (s->cs & BCM2835_SPI_CLEAR_RX) {
fifo8_reset(&s->rx_fifo);
bcm2835_spi_update_rx_flags(s);
}
/* Clear TX FIFO*/
if (s->cs & BCM2835_SPI_CLEAR_TX) {
fifo8_reset(&s->tx_fifo);
bcm2835_spi_update_tx_flags(s);
}
/* Set Transfer Active */
if (s->cs & BCM2835_SPI_CS_TA) {
bcm2835_spi_update_tx_flags(s);
}
if (s->cs & BCM2835_SPI_CS_DMAEN) {
qemu_log_mask(LOG_UNIMP, "%s: " \
"DMA not supported\n", __func__);
}
if (s->cs & BCM2835_SPI_CS_LEN) {
qemu_log_mask(LOG_UNIMP, "%s: " \
"LoSSI not supported\n", __func__);
}
bcm2835_spi_update_int(s);
break;
case BCM2835_SPI_FIFO:
/*
* According to documentation, writes to FIFO without TA controls
* CS and DLEN registers. This is supposed to be used in DMA mode
* which is currently unimplemented. Moreover, Linux does not make
* use of this and directly modifies the CS and DLEN registers.
*/
if (s->cs & BCM2835_SPI_CS_TA) {
if (s->cs & BCM2835_SPI_CS_TXD) {
fifo8_push(&s->tx_fifo, value & 0xff);
bcm2835_spi_update_tx_flags(s);
}
bcm2835_spi_flush_tx_fifo(s);
bcm2835_spi_update_int(s);
}
break;
case BCM2835_SPI_CLK:
s->clk = value & 0xffff;
break;
case BCM2835_SPI_DLEN:
s->dlen = value & 0xffff;
break;
case BCM2835_SPI_LTOH:
s->ltoh = value & 0xf;
break;
case BCM2835_SPI_DC:
s->dc = value & 0xffffffff;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
}
}
static const MemoryRegionOps bcm2835_spi_ops = {
.read = bcm2835_spi_read,
.write = bcm2835_spi_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void bcm2835_spi_realize(DeviceState *dev, Error **errp)
{
BCM2835SPIState *s = BCM2835_SPI(dev);
s->bus = ssi_create_bus(dev, "spi");
memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_spi_ops, s,
TYPE_BCM2835_SPI, 0x18);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
fifo8_create(&s->tx_fifo, FIFO_SIZE);
fifo8_create(&s->rx_fifo, FIFO_SIZE);
}
static void bcm2835_spi_reset(DeviceState *dev)
{
BCM2835SPIState *s = BCM2835_SPI(dev);
fifo8_reset(&s->tx_fifo);
fifo8_reset(&s->rx_fifo);
/* Reset values according to BCM2835 Peripheral Documentation */
s->cs = BCM2835_SPI_CS_TXD | BCM2835_SPI_CS_REN;
s->clk = 0;
s->dlen = 0;
s->ltoh = 0x1;
s->dc = 0x30201020;
}
static const VMStateDescription vmstate_bcm2835_spi = {
.name = TYPE_BCM2835_SPI,
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_FIFO8(tx_fifo, BCM2835SPIState),
VMSTATE_FIFO8(rx_fifo, BCM2835SPIState),
VMSTATE_UINT32(cs, BCM2835SPIState),
VMSTATE_UINT32(clk, BCM2835SPIState),
VMSTATE_UINT32(dlen, BCM2835SPIState),
VMSTATE_UINT32(ltoh, BCM2835SPIState),
VMSTATE_UINT32(dc, BCM2835SPIState),
VMSTATE_END_OF_LIST()
}
};
static void bcm2835_spi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = bcm2835_spi_reset;
dc->realize = bcm2835_spi_realize;
dc->vmsd = &vmstate_bcm2835_spi;
}
static const TypeInfo bcm2835_spi_info = {
.name = TYPE_BCM2835_SPI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(BCM2835SPIState),
.class_init = bcm2835_spi_class_init,
};
static void bcm2835_spi_register_types(void)
{
type_register_static(&bcm2835_spi_info);
}
type_init(bcm2835_spi_register_types)

View File

@ -11,3 +11,4 @@ system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c')) system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c'))
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c')) system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c'))
system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c')) system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c'))
system_ss.add(when: 'CONFIG_BCM2835_SPI', if_true: files('bcm2835_spi.c'))

View File

@ -42,7 +42,7 @@ xs_node_vscanf(char *path, char *value) "%s %s"
xs_node_watch(char *path) "%s" xs_node_watch(char *path) "%s"
xs_node_unwatch(char *path) "%s" xs_node_unwatch(char *path) "%s"
# xen-hvm.c # xen-hvm-common.c
xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: 0x%lx, size 0x%lx" xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: 0x%lx, size 0x%lx"
xen_client_set_memory(uint64_t start_addr, unsigned long size, bool log_dirty) "0x%"PRIx64" size 0x%lx, log_dirty %i" xen_client_set_memory(uint64_t start_addr, unsigned long size, bool log_dirty) "0x%"PRIx64" size 0x%lx, log_dirty %i"
handle_ioreq(void *req, uint32_t type, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p type=%d dir=%d df=%d ptr=%d port=0x%"PRIx64" data=0x%"PRIx64" count=%d size=%d" handle_ioreq(void *req, uint32_t type, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O=%p type=%d dir=%d df=%d ptr=%d port=0x%"PRIx64" data=0x%"PRIx64" count=%d size=%d"
@ -55,8 +55,27 @@ cpu_ioreq_move(void *req, uint32_t dir, uint32_t df, uint32_t data_is_ptr, uint6
xen_map_resource_ioreq(uint32_t id, void *addr) "id: %u addr: %p" xen_map_resource_ioreq(uint32_t id, void *addr) "id: %u addr: %p"
cpu_ioreq_config_read(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x" cpu_ioreq_config_read(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x"
cpu_ioreq_config_write(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x" cpu_ioreq_config_write(void *req, uint32_t sbdf, uint32_t reg, uint32_t size, uint32_t data) "I/O=%p sbdf=0x%x reg=%u size=%u data=0x%x"
cpu_get_ioreq_from_shared_memory_req_not_ready(int state, int data_is_ptr, uint64_t addr, uint64_t data, uint32_t count, uint32_t size) "I/O request not ready: 0x%x, ptr: 0x%x, port: 0x%"PRIx64", data: 0x%"PRIx64", count: %u, size: %u"
xen_main_loop_prepare_init_cpu(int id, void *cpu) "cpu_by_vcpu_id[%d]=%p"
xen_map_ioreq_server_shared_page(long unsigned int ioreq_pfn) "shared page at pfn 0x%lx"
xen_map_ioreq_server_buffered_io_page(long unsigned int ioreq_pfn) "buffered io page at pfn 0x%lx"
xen_map_ioreq_server_buffered_io_evtchn(int bufioreq_evtchn) "buffered io evtchn is 0x%x"
destroy_hvm_domain_cannot_acquire_handle(void) "Cannot acquire xenctrl handle"
destroy_hvm_domain_failed_action(const char *action, int sts, char *errno_s) "xc_domain_shutdown failed to issue %s, sts %d, %s"
destroy_hvm_domain_action(int xen_domid, const char *action) "Issued domain %d %s"
# xen-mapcache.c # xen-mapcache.c
xen_map_cache(uint64_t phys_addr) "want 0x%"PRIx64 xen_map_cache(uint64_t phys_addr) "want 0x%"PRIx64
xen_remap_bucket(uint64_t index) "index 0x%"PRIx64 xen_remap_bucket(uint64_t index) "index 0x%"PRIx64
xen_map_cache_return(void* ptr) "%p" xen_map_cache_return(void* ptr) "%p"
xen_map_cache_init(uint64_t nr_buckets, uint64_t size) "nr_buckets = 0x%"PRIx64" size 0x%"PRIx64
xen_replace_cache_entry_dummy(uint64_t old_phys_addr, uint64_t new_phys_addr) "Replacing a dummy mapcache entry for 0x%"PRIx64" with 0x%"PRIx64
xen_invalidate_map_cache_entry_unlocked_not_found(void *p) "could not find %p"
xen_invalidate_map_cache_entry_unlocked_found(uint64_t addr, void *p) " 0x%"PRIx64" -> %p is present"
xen_invalidate_map_cache_entry_unlocked_miss(void *buffer) "Trying to unmap address %p that is not in the mapcache"
xen_replace_cache_entry_unlocked_could_not_update_entry(uint64_t old_phys_addr) "Unable to update a mapcache entry for 0x%"PRIx64
xen_ram_addr_from_mapcache_not_found(void *p) "could not find %p"
xen_ram_addr_from_mapcache_found(uint64_t addr, void *p) " 0x%"PRIx64" -> %p is present"
xen_ram_addr_from_mapcache_not_in_cache(void *p) "Trying to find address %p that is not in the mapcache"
xen_replace_cache_entry_unlocked(uint64_t old_phys_addr) "Trying to update an entry for 0x%"PRIx64" that is not in the mapcache"
xen_invalidate_map_cache(uint64_t paddr_index, void *vaddr_req) "Locked DMA mapping while invalidating mapcache 0x%"PRIx64" -> %p is present"

View File

@ -20,8 +20,8 @@ void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, MemoryRegion *mr,
if (runstate_check(RUN_STATE_INMIGRATE)) { if (runstate_check(RUN_STATE_INMIGRATE)) {
/* RAM already populated in Xen */ /* RAM already populated in Xen */
fprintf(stderr, "%s: do not alloc "RAM_ADDR_FMT warn_report("%s: do not alloc "RAM_ADDR_FMT
" bytes of ram at "RAM_ADDR_FMT" when runstate is INMIGRATE\n", " bytes of ram at "RAM_ADDR_FMT" when runstate is INMIGRATE",
__func__, size, ram_addr); __func__, size, ram_addr);
return; return;
} }
@ -169,11 +169,12 @@ static ioreq_t *cpu_get_ioreq_from_shared_memory(XenIOState *state, int vcpu)
ioreq_t *req = xen_vcpu_ioreq(state->shared_page, vcpu); ioreq_t *req = xen_vcpu_ioreq(state->shared_page, vcpu);
if (req->state != STATE_IOREQ_READY) { if (req->state != STATE_IOREQ_READY) {
DPRINTF("I/O request not ready: " trace_cpu_get_ioreq_from_shared_memory_req_not_ready(req->state,
"%x, ptr: %x, port: %"PRIx64", " req->data_is_ptr,
"data: %"PRIx64", count: %u, size: %u\n", req->addr,
req->state, req->data_is_ptr, req->addr, req->data,
req->data, req->count, req->size); req->count,
req->size);
return NULL; return NULL;
} }
@ -551,9 +552,9 @@ static void cpu_handle_ioreq(void *opaque)
req->data = copy.data; req->data = copy.data;
if (req->state != STATE_IOREQ_INPROCESS) { if (req->state != STATE_IOREQ_INPROCESS) {
fprintf(stderr, "Badness in I/O request ... not in service?!: " warn_report("Badness in I/O request ... not in service?!: "
"%x, ptr: %x, port: %"PRIx64", " "%x, ptr: %x, port: %"PRIx64", "
"data: %"PRIx64", count: %u, size: %u, type: %u\n", "data: %"PRIx64", count: %u, size: %u, type: %u",
req->state, req->data_is_ptr, req->addr, req->state, req->data_is_ptr, req->addr,
req->data, req->count, req->size, req->type); req->data, req->count, req->size, req->type);
destroy_hvm_domain(false); destroy_hvm_domain(false);
@ -601,10 +602,9 @@ static void xen_main_loop_prepare(XenIOState *state)
if (evtchn_fd != -1) { if (evtchn_fd != -1) {
CPUState *cpu_state; CPUState *cpu_state;
DPRINTF("%s: Init cpu_by_vcpu_id\n", __func__);
CPU_FOREACH(cpu_state) { CPU_FOREACH(cpu_state) {
DPRINTF("%s: cpu_by_vcpu_id[%d]=%p\n", trace_xen_main_loop_prepare_init_cpu(cpu_state->cpu_index,
__func__, cpu_state->cpu_index, cpu_state); cpu_state);
state->cpu_by_vcpu_id[cpu_state->cpu_index] = cpu_state; state->cpu_by_vcpu_id[cpu_state->cpu_index] = cpu_state;
} }
qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state); qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, state);
@ -681,7 +681,7 @@ static int xen_map_ioreq_server(XenIOState *state)
} }
if (state->shared_page == NULL) { if (state->shared_page == NULL) {
DPRINTF("shared page at pfn %lx\n", ioreq_pfn); trace_xen_map_ioreq_server_shared_page(ioreq_pfn);
state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid, state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
@ -693,7 +693,7 @@ static int xen_map_ioreq_server(XenIOState *state)
} }
if (state->buffered_io_page == NULL) { if (state->buffered_io_page == NULL) {
DPRINTF("buffered io page at pfn %lx\n", bufioreq_pfn); trace_xen_map_ioreq_server_buffered_io_page(bufioreq_pfn);
state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid, state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
@ -709,7 +709,7 @@ static int xen_map_ioreq_server(XenIOState *state)
return -1; return -1;
} }
DPRINTF("buffered io evtchn is %x\n", bufioreq_evtchn); trace_xen_map_ioreq_server_buffered_io_evtchn(bufioreq_evtchn);
state->bufioreq_remote_port = bufioreq_evtchn; state->bufioreq_remote_port = bufioreq_evtchn;
@ -737,16 +737,17 @@ void destroy_hvm_domain(bool reboot)
xc_handle = xc_interface_open(0, 0, 0); xc_handle = xc_interface_open(0, 0, 0);
if (xc_handle == NULL) { if (xc_handle == NULL) {
fprintf(stderr, "Cannot acquire xenctrl handle\n"); trace_destroy_hvm_domain_cannot_acquire_handle();
} else { } else {
sts = xc_domain_shutdown(xc_handle, xen_domid, reason); sts = xc_domain_shutdown(xc_handle, xen_domid, reason);
if (sts != 0) { if (sts != 0) {
fprintf(stderr, "xc_domain_shutdown failed to issue %s, " trace_destroy_hvm_domain_failed_action(
"sts %d, %s\n", reboot ? "reboot" : "poweroff", reboot ? "reboot" : "poweroff", sts, strerror(errno)
sts, strerror(errno)); );
} else { } else {
fprintf(stderr, "Issued domain %d %s\n", xen_domid, trace_destroy_hvm_domain_action(
reboot ? "reboot" : "poweroff"); xen_domid, reboot ? "reboot" : "poweroff"
);
} }
xc_interface_close(xc_handle); xc_interface_close(xc_handle);
} }
@ -757,9 +758,9 @@ void xen_shutdown_fatal_error(const char *fmt, ...)
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
vfprintf(stderr, fmt, ap); error_vreport(fmt, ap);
va_end(ap); va_end(ap);
fprintf(stderr, "Will destroy the domain.\n"); error_report("Will destroy the domain.");
/* destroy the domain */ /* destroy the domain */
qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR); qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR);
} }

View File

@ -22,16 +22,6 @@
#include "trace.h" #include "trace.h"
//#define MAPCACHE_DEBUG
#ifdef MAPCACHE_DEBUG
# define DPRINTF(fmt, ...) do { \
fprintf(stderr, "xen_mapcache: " fmt, ## __VA_ARGS__); \
} while (0)
#else
# define DPRINTF(fmt, ...) do { } while (0)
#endif
#if HOST_LONG_BITS == 32 #if HOST_LONG_BITS == 32
# define MCACHE_BUCKET_SHIFT 16 # define MCACHE_BUCKET_SHIFT 16
# define MCACHE_MAX_SIZE (1UL<<31) /* 2GB Cap */ # define MCACHE_MAX_SIZE (1UL<<31) /* 2GB Cap */
@ -145,8 +135,7 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
size = mapcache->nr_buckets * sizeof (MapCacheEntry); size = mapcache->nr_buckets * sizeof (MapCacheEntry);
size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1); size = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
DPRINTF("%s, nr_buckets = %lx size %lu\n", __func__, trace_xen_map_cache_init(mapcache->nr_buckets, size);
mapcache->nr_buckets, size);
mapcache->entry = g_malloc0(size); mapcache->entry = g_malloc0(size);
} }
@ -286,7 +275,9 @@ tryagain:
test_bits(address_offset >> XC_PAGE_SHIFT, test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT, test_bit_size >> XC_PAGE_SHIFT,
mapcache->last_entry->valid_mapping)) { mapcache->last_entry->valid_mapping)) {
trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset); trace_xen_map_cache_return(
mapcache->last_entry->vaddr_base + address_offset
);
return mapcache->last_entry->vaddr_base + address_offset; return mapcache->last_entry->vaddr_base + address_offset;
} }
@ -356,9 +347,8 @@ tryagain:
MapCacheRev *reventry = g_new0(MapCacheRev, 1); MapCacheRev *reventry = g_new0(MapCacheRev, 1);
entry->lock++; entry->lock++;
if (entry->lock == 0) { if (entry->lock == 0) {
fprintf(stderr, error_report("mapcache entry lock overflow: "HWADDR_FMT_plx" -> %p",
"mapcache entry lock overflow: "HWADDR_FMT_plx" -> %p\n", entry->paddr_index, entry->vaddr_base);
entry->paddr_index, entry->vaddr_base);
abort(); abort();
} }
reventry->dma = dma; reventry->dma = dma;
@ -368,7 +358,9 @@ tryagain:
QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next); QTAILQ_INSERT_HEAD(&mapcache->locked_entries, reventry, next);
} }
trace_xen_map_cache_return(mapcache->last_entry->vaddr_base + address_offset); trace_xen_map_cache_return(
mapcache->last_entry->vaddr_base + address_offset
);
return mapcache->last_entry->vaddr_base + address_offset; return mapcache->last_entry->vaddr_base + address_offset;
} }
@ -402,10 +394,10 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
} }
} }
if (!found) { if (!found) {
fprintf(stderr, "%s, could not find %p\n", __func__, ptr); trace_xen_ram_addr_from_mapcache_not_found(ptr);
QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
DPRINTF(" "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index, trace_xen_ram_addr_from_mapcache_found(reventry->paddr_index,
reventry->vaddr_req); reventry->vaddr_req);
} }
abort(); abort();
return 0; return 0;
@ -416,7 +408,7 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
entry = entry->next; entry = entry->next;
} }
if (!entry) { if (!entry) {
DPRINTF("Trying to find address %p that is not in the mapcache!\n", ptr); trace_xen_ram_addr_from_mapcache_not_in_cache(ptr);
raddr = 0; raddr = 0;
} else { } else {
raddr = (reventry->paddr_index << MCACHE_BUCKET_SHIFT) + raddr = (reventry->paddr_index << MCACHE_BUCKET_SHIFT) +
@ -443,9 +435,12 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
} }
} }
if (!found) { if (!found) {
DPRINTF("%s, could not find %p\n", __func__, buffer); trace_xen_invalidate_map_cache_entry_unlocked_not_found(buffer);
QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) { QTAILQ_FOREACH(reventry, &mapcache->locked_entries, next) {
DPRINTF(" "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index, reventry->vaddr_req); trace_xen_invalidate_map_cache_entry_unlocked_found(
reventry->paddr_index,
reventry->vaddr_req
);
} }
return; return;
} }
@ -463,7 +458,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
entry = entry->next; entry = entry->next;
} }
if (!entry) { if (!entry) {
DPRINTF("Trying to unmap address %p that is not in the mapcache!\n", buffer); trace_xen_invalidate_map_cache_entry_unlocked_miss(buffer);
return; return;
} }
entry->lock--; entry->lock--;
@ -502,9 +497,8 @@ void xen_invalidate_map_cache(void)
if (!reventry->dma) { if (!reventry->dma) {
continue; continue;
} }
fprintf(stderr, "Locked DMA mapping while invalidating mapcache!" trace_xen_invalidate_map_cache(reventry->paddr_index,
" "HWADDR_FMT_plx" -> %p is present\n", reventry->vaddr_req);
reventry->paddr_index, reventry->vaddr_req);
} }
for (i = 0; i < mapcache->nr_buckets; i++) { for (i = 0; i < mapcache->nr_buckets; i++) {
@ -562,24 +556,23 @@ static uint8_t *xen_replace_cache_entry_unlocked(hwaddr old_phys_addr,
entry = entry->next; entry = entry->next;
} }
if (!entry) { if (!entry) {
DPRINTF("Trying to update an entry for "HWADDR_FMT_plx \ trace_xen_replace_cache_entry_unlocked(old_phys_addr);
"that is not in the mapcache!\n", old_phys_addr);
return NULL; return NULL;
} }
address_index = new_phys_addr >> MCACHE_BUCKET_SHIFT; address_index = new_phys_addr >> MCACHE_BUCKET_SHIFT;
address_offset = new_phys_addr & (MCACHE_BUCKET_SIZE - 1); address_offset = new_phys_addr & (MCACHE_BUCKET_SIZE - 1);
fprintf(stderr, "Replacing a dummy mapcache entry for "HWADDR_FMT_plx \ trace_xen_replace_cache_entry_dummy(old_phys_addr, new_phys_addr);
" with "HWADDR_FMT_plx"\n", old_phys_addr, new_phys_addr);
xen_remap_bucket(entry, entry->vaddr_base, xen_remap_bucket(entry, entry->vaddr_base,
cache_size, address_index, false); cache_size, address_index, false);
if (!test_bits(address_offset >> XC_PAGE_SHIFT, if (!test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT, test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping)) { entry->valid_mapping)) {
DPRINTF("Unable to update a mapcache entry for "HWADDR_FMT_plx"!\n", trace_xen_replace_cache_entry_unlocked_could_not_update_entry(
old_phys_addr); old_phys_addr
);
return NULL; return NULL;
} }

View File

@ -31,6 +31,7 @@
#include "hw/gpio/bcm2835_gpio.h" #include "hw/gpio/bcm2835_gpio.h"
#include "hw/timer/bcm2835_systmr.h" #include "hw/timer/bcm2835_systmr.h"
#include "hw/usb/hcd-dwc2.h" #include "hw/usb/hcd-dwc2.h"
#include "hw/ssi/bcm2835_spi.h"
#include "hw/misc/unimp.h" #include "hw/misc/unimp.h"
#include "qom/object.h" #include "qom/object.h"
@ -66,7 +67,7 @@ struct BCM2835PeripheralState {
BCM2835GpioState gpio; BCM2835GpioState gpio;
Bcm2835ThermalState thermal; Bcm2835ThermalState thermal;
UnimplementedDeviceState i2s; UnimplementedDeviceState i2s;
UnimplementedDeviceState spi[1]; BCM2835SPIState spi[1];
UnimplementedDeviceState i2c[3]; UnimplementedDeviceState i2c[3];
UnimplementedDeviceState otp; UnimplementedDeviceState otp;
UnimplementedDeviceState dbus; UnimplementedDeviceState dbus;

View File

@ -47,13 +47,10 @@ OBJECT_DECLARE_SIMPLE_TYPE(MSF2State, MSF2_SOC)
#define MSF2_NUM_TIMERS 2 #define MSF2_NUM_TIMERS 2
struct MSF2State { struct MSF2State {
/*< private >*/
SysBusDevice parent_obj; SysBusDevice parent_obj;
/*< public >*/
ARMv7MState armv7m; ARMv7MState armv7m;
char *cpu_type;
char *part_name; char *part_name;
uint64_t envm_size; uint64_t envm_size;
uint64_t esram_size; uint64_t esram_size;

View File

@ -29,6 +29,7 @@
#include "hw/misc/npcm7xx_pwm.h" #include "hw/misc/npcm7xx_pwm.h"
#include "hw/misc/npcm7xx_rng.h" #include "hw/misc/npcm7xx_rng.h"
#include "hw/net/npcm7xx_emc.h" #include "hw/net/npcm7xx_emc.h"
#include "hw/net/npcm_gmac.h"
#include "hw/nvram/npcm7xx_otp.h" #include "hw/nvram/npcm7xx_otp.h"
#include "hw/timer/npcm7xx_timer.h" #include "hw/timer/npcm7xx_timer.h"
#include "hw/ssi/npcm7xx_fiu.h" #include "hw/ssi/npcm7xx_fiu.h"
@ -104,6 +105,7 @@ struct NPCM7xxState {
OHCISysBusState ohci; OHCISysBusState ohci;
NPCM7xxFIUState fiu[2]; NPCM7xxFIUState fiu[2];
NPCM7xxEMCState emc[2]; NPCM7xxEMCState emc[2];
NPCMGMACState gmac[2];
NPCM7xxSDHCIState mmc; NPCM7xxSDHCIState mmc;
NPCMPSPIState pspi[2]; NPCMPSPIState pspi[2];
}; };

343
include/hw/net/npcm_gmac.h Normal file
View File

@ -0,0 +1,343 @@
/*
* Nuvoton NPCM7xx/8xx GMAC Module
*
* Copyright 2024 Google LLC
* Authors:
* Hao Wu <wuhaotsh@google.com>
* Nabih Estefan <nabihestefan@google.com>
*
* 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.
*/
#ifndef NPCM_GMAC_H
#define NPCM_GMAC_H
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "net/net.h"
#define NPCM_GMAC_NR_REGS (0x1060 / sizeof(uint32_t))
#define NPCM_GMAC_MAX_PHYS 32
#define NPCM_GMAC_MAX_PHY_REGS 32
struct NPCMGMACRxDesc {
uint32_t rdes0;
uint32_t rdes1;
uint32_t rdes2;
uint32_t rdes3;
};
/* NPCMGMACRxDesc.flags values */
/* RDES2 and RDES3 are buffer addresses */
/* Owner: 0 = software, 1 = dma */
#define RX_DESC_RDES0_OWN BIT(31)
/* Destination Address Filter Fail */
#define RX_DESC_RDES0_DEST_ADDR_FILT_FAIL BIT(30)
/* Frame length */
#define RX_DESC_RDES0_FRAME_LEN_MASK(word) extract32(word, 16, 14)
/* Frame length Shift*/
#define RX_DESC_RDES0_FRAME_LEN_SHIFT 16
/* Error Summary */
#define RX_DESC_RDES0_ERR_SUMM_MASK BIT(15)
/* Descriptor Error */
#define RX_DESC_RDES0_DESC_ERR_MASK BIT(14)
/* Source Address Filter Fail */
#define RX_DESC_RDES0_SRC_ADDR_FILT_FAIL_MASK BIT(13)
/* Length Error */
#define RX_DESC_RDES0_LEN_ERR_MASK BIT(12)
/* Overflow Error */
#define RX_DESC_RDES0_OVRFLW_ERR_MASK BIT(11)
/* VLAN Tag */
#define RX_DESC_RDES0_VLAN_TAG_MASK BIT(10)
/* First Descriptor */
#define RX_DESC_RDES0_FIRST_DESC_MASK BIT(9)
/* Last Descriptor */
#define RX_DESC_RDES0_LAST_DESC_MASK BIT(8)
/* IPC Checksum Error/Giant Frame */
#define RX_DESC_RDES0_IPC_CHKSM_ERR_GNT_FRM_MASK BIT(7)
/* Late Collision */
#define RX_DESC_RDES0_LT_COLL_MASK BIT(6)
/* Frame Type */
#define RX_DESC_RDES0_FRM_TYPE_MASK BIT(5)
/* Receive Watchdog Timeout */
#define RX_DESC_RDES0_REC_WTCHDG_TMT_MASK BIT(4)
/* Receive Error */
#define RX_DESC_RDES0_RCV_ERR_MASK BIT(3)
/* Dribble Bit Error */
#define RX_DESC_RDES0_DRBL_BIT_ERR_MASK BIT(2)
/* Cyclcic Redundancy Check Error */
#define RX_DESC_RDES0_CRC_ERR_MASK BIT(1)
/* Rx MAC Address/Payload Checksum Error */
#define RC_DESC_RDES0_RCE_MASK BIT(0)
/* Disable Interrupt on Completion */
#define RX_DESC_RDES1_DIS_INTR_COMP_MASK BIT(31)
/* Recieve end of ring */
#define RX_DESC_RDES1_RC_END_RING_MASK BIT(25)
/* Second Address Chained */
#define RX_DESC_RDES1_SEC_ADDR_CHND_MASK BIT(24)
/* Receive Buffer 2 Size */
#define RX_DESC_RDES1_BFFR2_SZ_SHIFT 11
#define RX_DESC_RDES1_BFFR2_SZ_MASK(word) extract32(word, \
RX_DESC_RDES1_BFFR2_SZ_SHIFT, 11)
/* Receive Buffer 1 Size */
#define RX_DESC_RDES1_BFFR1_SZ_MASK(word) extract32(word, 0, 11)
struct NPCMGMACTxDesc {
uint32_t tdes0;
uint32_t tdes1;
uint32_t tdes2;
uint32_t tdes3;
};
/* NPCMGMACTxDesc.flags values */
/* TDES2 and TDES3 are buffer addresses */
/* Owner: 0 = software, 1 = gmac */
#define TX_DESC_TDES0_OWN BIT(31)
/* Tx Time Stamp Status */
#define TX_DESC_TDES0_TTSS_MASK BIT(17)
/* IP Header Error */
#define TX_DESC_TDES0_IP_HEAD_ERR_MASK BIT(16)
/* Error Summary */
#define TX_DESC_TDES0_ERR_SUMM_MASK BIT(15)
/* Jabber Timeout */
#define TX_DESC_TDES0_JBBR_TMT_MASK BIT(14)
/* Frame Flushed */
#define TX_DESC_TDES0_FRM_FLSHD_MASK BIT(13)
/* Payload Checksum Error */
#define TX_DESC_TDES0_PYLD_CHKSM_ERR_MASK BIT(12)
/* Loss of Carrier */
#define TX_DESC_TDES0_LSS_CARR_MASK BIT(11)
/* No Carrier */
#define TX_DESC_TDES0_NO_CARR_MASK BIT(10)
/* Late Collision */
#define TX_DESC_TDES0_LATE_COLL_MASK BIT(9)
/* Excessive Collision */
#define TX_DESC_TDES0_EXCS_COLL_MASK BIT(8)
/* VLAN Frame */
#define TX_DESC_TDES0_VLAN_FRM_MASK BIT(7)
/* Collision Count */
#define TX_DESC_TDES0_COLL_CNT_MASK(word) extract32(word, 3, 4)
/* Excessive Deferral */
#define TX_DESC_TDES0_EXCS_DEF_MASK BIT(2)
/* Underflow Error */
#define TX_DESC_TDES0_UNDRFLW_ERR_MASK BIT(1)
/* Deferred Bit */
#define TX_DESC_TDES0_DFRD_BIT_MASK BIT(0)
/* Interrupt of Completion */
#define TX_DESC_TDES1_INTERR_COMP_MASK BIT(31)
/* Last Segment */
#define TX_DESC_TDES1_LAST_SEG_MASK BIT(30)
/* First Segment */
#define TX_DESC_TDES1_FIRST_SEG_MASK BIT(29)
/* Checksum Insertion Control */
#define TX_DESC_TDES1_CHKSM_INS_CTRL_MASK(word) extract32(word, 27, 2)
/* Disable Cyclic Redundancy Check */
#define TX_DESC_TDES1_DIS_CDC_MASK BIT(26)
/* Transmit End of Ring */
#define TX_DESC_TDES1_TX_END_RING_MASK BIT(25)
/* Secondary Address Chained */
#define TX_DESC_TDES1_SEC_ADDR_CHND_MASK BIT(24)
/* Transmit Buffer 2 Size */
#define TX_DESC_TDES1_BFFR2_SZ_MASK(word) extract32(word, 11, 11)
/* Transmit Buffer 1 Size */
#define TX_DESC_TDES1_BFFR1_SZ_MASK(word) extract32(word, 0, 11)
typedef struct NPCMGMACState {
SysBusDevice parent;
MemoryRegion iomem;
qemu_irq irq;
NICState *nic;
NICConf conf;
uint32_t regs[NPCM_GMAC_NR_REGS];
uint16_t phy_regs[NPCM_GMAC_MAX_PHYS][NPCM_GMAC_MAX_PHY_REGS];
} NPCMGMACState;
#define TYPE_NPCM_GMAC "npcm-gmac"
OBJECT_DECLARE_SIMPLE_TYPE(NPCMGMACState, NPCM_GMAC)
/* Mask for RO bits in Status */
#define NPCM_DMA_STATUS_RO_MASK(word) (word & 0xfffe0000)
/* Mask for RO bits in Status */
#define NPCM_DMA_STATUS_W1C_MASK(word) (word & 0x1e7ff)
/* Transmit Process State */
#define NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT 20
/* Transmit States */
#define NPCM_DMA_STATUS_TX_STOPPED_STATE \
(0b000)
#define NPCM_DMA_STATUS_TX_RUNNING_FETCHING_STATE \
(0b001)
#define NPCM_DMA_STATUS_TX_RUNNING_WAITING_STATE \
(0b010)
#define NPCM_DMA_STATUS_TX_RUNNING_READ_STATE \
(0b011)
#define NPCM_DMA_STATUS_TX_SUSPENDED_STATE \
(0b110)
#define NPCM_DMA_STATUS_TX_RUNNING_CLOSING_STATE \
(0b111)
/* Transmit Process State */
#define NPCM_DMA_STATUS_RX_PROCESS_STATE_SHIFT 17
/* Receive States */
#define NPCM_DMA_STATUS_RX_STOPPED_STATE \
(0b000)
#define NPCM_DMA_STATUS_RX_RUNNING_FETCHING_STATE \
(0b001)
#define NPCM_DMA_STATUS_RX_RUNNING_WAITING_STATE \
(0b011)
#define NPCM_DMA_STATUS_RX_SUSPENDED_STATE \
(0b100)
#define NPCM_DMA_STATUS_RX_RUNNING_CLOSING_STATE \
(0b101)
#define NPCM_DMA_STATUS_RX_RUNNING_TRANSFERRING_STATE \
(0b111)
/* Early Receive Interrupt */
#define NPCM_DMA_STATUS_ERI BIT(14)
/* Fatal Bus Error Interrupt */
#define NPCM_DMA_STATUS_FBI BIT(13)
/* Early transmit Interrupt */
#define NPCM_DMA_STATUS_ETI BIT(10)
/* Receive Watchdog Timout */
#define NPCM_DMA_STATUS_RWT BIT(9)
/* Receive Process Stopped */
#define NPCM_DMA_STATUS_RPS BIT(8)
/* Receive Buffer Unavailable */
#define NPCM_DMA_STATUS_RU BIT(7)
/* Receive Interrupt */
#define NPCM_DMA_STATUS_RI BIT(6)
/* Transmit Underflow */
#define NPCM_DMA_STATUS_UNF BIT(5)
/* Receive Overflow */
#define NPCM_DMA_STATUS_OVF BIT(4)
/* Transmit Jabber Timeout */
#define NPCM_DMA_STATUS_TJT BIT(3)
/* Transmit Buffer Unavailable */
#define NPCM_DMA_STATUS_TU BIT(2)
/* Transmit Process Stopped */
#define NPCM_DMA_STATUS_TPS BIT(1)
/* Transmit Interrupt */
#define NPCM_DMA_STATUS_TI BIT(0)
/* Normal Interrupt Summary */
#define NPCM_DMA_STATUS_NIS BIT(16)
/* Interrupts enabled by NIE */
#define NPCM_DMA_STATUS_NIS_BITS (NPCM_DMA_STATUS_TI | \
NPCM_DMA_STATUS_TU | \
NPCM_DMA_STATUS_RI | \
NPCM_DMA_STATUS_ERI)
/* Abnormal Interrupt Summary */
#define NPCM_DMA_STATUS_AIS BIT(15)
/* Interrupts enabled by AIE */
#define NPCM_DMA_STATUS_AIS_BITS (NPCM_DMA_STATUS_TPS | \
NPCM_DMA_STATUS_TJT | \
NPCM_DMA_STATUS_OVF | \
NPCM_DMA_STATUS_UNF | \
NPCM_DMA_STATUS_RU | \
NPCM_DMA_STATUS_RPS | \
NPCM_DMA_STATUS_RWT | \
NPCM_DMA_STATUS_ETI | \
NPCM_DMA_STATUS_FBI)
/* Early Receive Interrupt Enable */
#define NPCM_DMA_INTR_ENAB_ERE BIT(14)
/* Fatal Bus Error Interrupt Enable */
#define NPCM_DMA_INTR_ENAB_FBE BIT(13)
/* Early transmit Interrupt Enable */
#define NPCM_DMA_INTR_ENAB_ETE BIT(10)
/* Receive Watchdog Timout Enable */
#define NPCM_DMA_INTR_ENAB_RWE BIT(9)
/* Receive Process Stopped Enable */
#define NPCM_DMA_INTR_ENAB_RSE BIT(8)
/* Receive Buffer Unavailable Enable */
#define NPCM_DMA_INTR_ENAB_RUE BIT(7)
/* Receive Interrupt Enable */
#define NPCM_DMA_INTR_ENAB_RIE BIT(6)
/* Transmit Underflow Enable */
#define NPCM_DMA_INTR_ENAB_UNE BIT(5)
/* Receive Overflow Enable */
#define NPCM_DMA_INTR_ENAB_OVE BIT(4)
/* Transmit Jabber Timeout Enable */
#define NPCM_DMA_INTR_ENAB_TJE BIT(3)
/* Transmit Buffer Unavailable Enable */
#define NPCM_DMA_INTR_ENAB_TUE BIT(2)
/* Transmit Process Stopped Enable */
#define NPCM_DMA_INTR_ENAB_TSE BIT(1)
/* Transmit Interrupt Enable */
#define NPCM_DMA_INTR_ENAB_TIE BIT(0)
/* Normal Interrupt Summary Enable */
#define NPCM_DMA_INTR_ENAB_NIE BIT(16)
/* Interrupts enabled by NIE Enable */
#define NPCM_DMA_INTR_ENAB_NIE_BITS (NPCM_DMA_INTR_ENAB_TIE | \
NPCM_DMA_INTR_ENAB_TUE | \
NPCM_DMA_INTR_ENAB_RIE | \
NPCM_DMA_INTR_ENAB_ERE)
/* Abnormal Interrupt Summary Enable */
#define NPCM_DMA_INTR_ENAB_AIE BIT(15)
/* Interrupts enabled by AIE Enable */
#define NPCM_DMA_INTR_ENAB_AIE_BITS (NPCM_DMA_INTR_ENAB_TSE | \
NPCM_DMA_INTR_ENAB_TJE | \
NPCM_DMA_INTR_ENAB_OVE | \
NPCM_DMA_INTR_ENAB_UNE | \
NPCM_DMA_INTR_ENAB_RUE | \
NPCM_DMA_INTR_ENAB_RSE | \
NPCM_DMA_INTR_ENAB_RWE | \
NPCM_DMA_INTR_ENAB_ETE | \
NPCM_DMA_INTR_ENAB_FBE)
/* Flushing Disabled */
#define NPCM_DMA_CONTROL_FLUSH_MASK BIT(24)
/* Start/stop Transmit */
#define NPCM_DMA_CONTROL_START_STOP_TX BIT(13)
/* Start/stop Receive */
#define NPCM_DMA_CONTROL_START_STOP_RX BIT(1)
/* Next receive descriptor start address */
#define NPCM_DMA_HOST_RX_DESC_MASK(word) ((uint32_t) (word) & ~3u)
/* Next transmit descriptor start address */
#define NPCM_DMA_HOST_TX_DESC_MASK(word) ((uint32_t) (word) & ~3u)
/* Receive enable */
#define NPCM_GMAC_MAC_CONFIG_RX_EN BIT(2)
/* Transmit enable */
#define NPCM_GMAC_MAC_CONFIG_TX_EN BIT(3)
/* Frame Receive All */
#define NPCM_GMAC_FRAME_FILTER_REC_ALL_MASK BIT(31)
/* Frame HPF Filter*/
#define NPCM_GMAC_FRAME_FILTER_HPF_MASK BIT(10)
/* Frame SAF Filter*/
#define NPCM_GMAC_FRAME_FILTER_SAF_MASK BIT(9)
/* Frame SAIF Filter*/
#define NPCM_GMAC_FRAME_FILTER_SAIF_MASK BIT(8)
/* Frame PCF Filter*/
#define NPCM_GMAC_FRAME_FILTER_PCF_MASK BIT(word) extract32((word), 6, 2)
/* Frame DBF Filter*/
#define NPCM_GMAC_FRAME_FILTER_DBF_MASK BIT(5)
/* Frame PM Filter*/
#define NPCM_GMAC_FRAME_FILTER_PM_MASK BIT(4)
/* Frame DAIF Filter*/
#define NPCM_GMAC_FRAME_FILTER_DAIF_MASK BIT(3)
/* Frame HMC Filter*/
#define NPCM_GMAC_FRAME_FILTER_HMC_MASK BIT(2)
/* Frame HUC Filter*/
#define NPCM_GMAC_FRAME_FILTER_HUC_MASK BIT(1)
/* Frame PR Filter*/
#define NPCM_GMAC_FRAME_FILTER_PR_MASK BIT(0)
#endif /* NPCM_GMAC_H */

View File

@ -329,8 +329,6 @@ struct BusClass {
*/ */
char *(*get_fw_dev_path)(DeviceState *dev); char *(*get_fw_dev_path)(DeviceState *dev);
void (*reset)(BusState *bus);
/* /*
* Return whether the device can be added to @bus, * Return whether the device can be added to @bus,
* based on the address that was set (via device properties) * based on the address that was set (via device properties)

View File

@ -0,0 +1,81 @@
/*
* BCM2835 SPI Master Controller
*
* Copyright (c) 2024 Rayhan Faizel <rayhan.faizel@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw/sysbus.h"
#include "hw/ssi/ssi.h"
#include "qom/object.h"
#include "qemu/fifo8.h"
#define TYPE_BCM2835_SPI "bcm2835-spi"
OBJECT_DECLARE_SIMPLE_TYPE(BCM2835SPIState, BCM2835_SPI)
/*
* Though BCM2835 documentation says FIFOs have a capacity of 16,
* FIFOs are actually 16 words in size or effectively 64 bytes when operating
* in non DMA mode.
*/
#define FIFO_SIZE 64
#define FIFO_SIZE_3_4 48
#define RO_MASK 0x1f0000
#define BCM2835_SPI_CS 0x00
#define BCM2835_SPI_FIFO 0x04
#define BCM2835_SPI_CLK 0x08
#define BCM2835_SPI_DLEN 0x0c
#define BCM2835_SPI_LTOH 0x10
#define BCM2835_SPI_DC 0x14
#define BCM2835_SPI_CS_RXF BIT(20)
#define BCM2835_SPI_CS_RXR BIT(19)
#define BCM2835_SPI_CS_TXD BIT(18)
#define BCM2835_SPI_CS_RXD BIT(17)
#define BCM2835_SPI_CS_DONE BIT(16)
#define BCM2835_SPI_CS_LEN BIT(13)
#define BCM2835_SPI_CS_REN BIT(12)
#define BCM2835_SPI_CS_INTR BIT(10)
#define BCM2835_SPI_CS_INTD BIT(9)
#define BCM2835_SPI_CS_DMAEN BIT(8)
#define BCM2835_SPI_CS_TA BIT(7)
#define BCM2835_SPI_CLEAR_RX BIT(5)
#define BCM2835_SPI_CLEAR_TX BIT(4)
struct BCM2835SPIState {
/* <private> */
SysBusDevice parent_obj;
/* <public> */
SSIBus *bus;
MemoryRegion iomem;
qemu_irq irq;
uint32_t cs;
uint32_t clk;
uint32_t dlen;
uint32_t ltoh;
uint32_t dc;
Fifo8 tx_fifo;
Fifo8 rx_fifo;
};

View File

@ -3994,7 +3994,7 @@ ERST
DEF("initrd", HAS_ARG, QEMU_OPTION_initrd, \ DEF("initrd", HAS_ARG, QEMU_OPTION_initrd, \
"-initrd file use 'file' as initial ram disk\n", QEMU_ARCH_ALL) "-initrd file use 'file' as initial ram disk\n", QEMU_ARCH_ALL)
SRST SRST(initrd)
``-initrd file`` ``-initrd file``
Use file as initial ram disk. Use file as initial ram disk.
@ -4129,7 +4129,8 @@ SRST
This option can be used several times to simulate up to 4 serial This option can be used several times to simulate up to 4 serial
ports. ports.
Use ``-serial none`` to disable all serial ports. You can use ``-serial none`` to suppress the creation of default
serial devices.
Available character devices are: Available character devices are:
@ -4151,10 +4152,17 @@ SRST
[Linux only] Pseudo TTY (a new PTY is automatically allocated) [Linux only] Pseudo TTY (a new PTY is automatically allocated)
``none`` ``none``
No device is allocated. No device is allocated. Note that for machine types which
emulate systems where a serial device is always present in
real hardware, this may be equivalent to the ``null`` option,
in that the serial device is still present but all output
is discarded. For boards where the number of serial ports is
truly variable, this suppresses the creation of the device.
``null`` ``null``
void device A guest will see the UART or serial device as present in the
machine, but all output is discarded, and there is no input.
Conceptually equivalent to redirecting the output to ``/dev/null``.
``chardev:id`` ``chardev:id``
Use a named character device defined with the ``-chardev`` Use a named character device defined with the ``-chardev``

View File

@ -1439,18 +1439,22 @@ static void qemu_create_default_devices(void)
static int serial_parse(const char *devname) static int serial_parse(const char *devname)
{ {
int index = num_serial_hds; int index = num_serial_hds;
char label[32];
if (strcmp(devname, "none") == 0)
return 0;
snprintf(label, sizeof(label), "serial%d", index);
serial_hds = g_renew(Chardev *, serial_hds, index + 1); serial_hds = g_renew(Chardev *, serial_hds, index + 1);
serial_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL); if (strcmp(devname, "none") == 0) {
if (!serial_hds[index]) { /* Don't allocate a serial device for this index */
error_report("could not connect serial device" serial_hds[index] = NULL;
" to character backend '%s'", devname); } else {
return -1; char label[32];
snprintf(label, sizeof(label), "serial%d", index);
serial_hds[index] = qemu_chr_new_mux_mon(label, devname, NULL);
if (!serial_hds[index]) {
error_report("could not connect serial device"
" to character backend '%s'", devname);
return -1;
}
} }
num_serial_hds++; num_serial_hds++;
return 0; return 0;

View File

@ -1627,6 +1627,10 @@ void arm_cpu_post_init(Object *obj)
} }
} else if (cpu_isar_feature(aa32_vfp, cpu)) { } else if (cpu_isar_feature(aa32_vfp, cpu)) {
cpu->has_vfp = true; cpu->has_vfp = true;
if (tcg_enabled() || qtest_enabled()) {
qdev_property_add_static(DEVICE(obj),
&arm_cpu_has_vfp_property);
}
if (cpu_isar_feature(aa32_simd_r32, cpu)) { if (cpu_isar_feature(aa32_simd_r32, cpu)) {
cpu->has_vfp_d32 = true; cpu->has_vfp_d32 = true;
/* /*

View File

@ -8897,6 +8897,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
R_ID_AA64ZFR0_AES_MASK | R_ID_AA64ZFR0_AES_MASK |
R_ID_AA64ZFR0_BITPERM_MASK | R_ID_AA64ZFR0_BITPERM_MASK |
R_ID_AA64ZFR0_BFLOAT16_MASK | R_ID_AA64ZFR0_BFLOAT16_MASK |
R_ID_AA64ZFR0_B16B16_MASK |
R_ID_AA64ZFR0_SHA3_MASK | R_ID_AA64ZFR0_SHA3_MASK |
R_ID_AA64ZFR0_SM4_MASK | R_ID_AA64ZFR0_SM4_MASK |
R_ID_AA64ZFR0_I8MM_MASK | R_ID_AA64ZFR0_I8MM_MASK |
@ -11015,6 +11016,24 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
} }
if (env->exception.target_el == 2) { if (env->exception.target_el == 2) {
/* Debug exceptions are reported differently on AArch32 */
switch (syn_get_ec(env->exception.syndrome)) {
case EC_BREAKPOINT:
case EC_BREAKPOINT_SAME_EL:
case EC_AA32_BKPT:
case EC_VECTORCATCH:
env->exception.syndrome = syn_insn_abort(arm_current_el(env) == 2,
0, 0, 0x22);
break;
case EC_WATCHPOINT:
env->exception.syndrome = syn_set_ec(env->exception.syndrome,
EC_DATAABORT);
break;
case EC_WATCHPOINT_SAME_EL:
env->exception.syndrome = syn_set_ec(env->exception.syndrome,
EC_DATAABORT_SAME_EL);
break;
}
arm_cpu_do_interrupt_aarch32_hyp(cs); arm_cpu_do_interrupt_aarch32_hyp(cs);
return; return;
} }

View File

@ -25,6 +25,8 @@
#ifndef TARGET_ARM_SYNDROME_H #ifndef TARGET_ARM_SYNDROME_H
#define TARGET_ARM_SYNDROME_H #define TARGET_ARM_SYNDROME_H
#include "qemu/bitops.h"
/* Valid Syndrome Register EC field values */ /* Valid Syndrome Register EC field values */
enum arm_exception_class { enum arm_exception_class {
EC_UNCATEGORIZED = 0x00, EC_UNCATEGORIZED = 0x00,
@ -80,6 +82,7 @@ typedef enum {
SME_ET_InactiveZA, SME_ET_InactiveZA,
} SMEExceptionType; } SMEExceptionType;
#define ARM_EL_EC_LENGTH 6
#define ARM_EL_EC_SHIFT 26 #define ARM_EL_EC_SHIFT 26
#define ARM_EL_IL_SHIFT 25 #define ARM_EL_IL_SHIFT 25
#define ARM_EL_ISV_SHIFT 24 #define ARM_EL_ISV_SHIFT 24
@ -94,6 +97,11 @@ static inline uint32_t syn_get_ec(uint32_t syn)
return syn >> ARM_EL_EC_SHIFT; return syn >> ARM_EL_EC_SHIFT;
} }
static inline uint32_t syn_set_ec(uint32_t syn, uint32_t ec)
{
return deposit32(syn, ARM_EL_EC_SHIFT, ARM_EL_EC_LENGTH, ec);
}
/* /*
* Utility functions for constructing various kinds of syndrome value. * Utility functions for constructing various kinds of syndrome value.
* Note that in general we follow the AArch64 syndrome values; in a * Note that in general we follow the AArch64 syndrome values; in a

View File

@ -231,6 +231,7 @@ qtests_aarch64 = \
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \ (config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \
(config_all_accel.has_key('CONFIG_TCG') and \ (config_all_accel.has_key('CONFIG_TCG') and \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \ config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
['arm-cpu-features', ['arm-cpu-features',
'numa-test', 'numa-test',
'boot-serial-test', 'boot-serial-test',

View File

@ -0,0 +1,344 @@
/*
* QTests for Nuvoton NPCM7xx/8xx GMAC Modules.
*
* Copyright 2024 Google LLC
* Authors:
* Hao Wu <wuhaotsh@google.com>
* Nabih Estefan <nabihestefan@google.com>
*
* 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 "libqos/libqos.h"
/* Name of the GMAC Device */
#define TYPE_NPCM_GMAC "npcm-gmac"
/* Address of the PCS Module */
#define PCS_BASE_ADDRESS 0xf0780000
#define NPCM_PCS_IND_AC_BA 0x1fe
typedef struct GMACModule {
int irq;
uint64_t base_addr;
} GMACModule;
typedef struct TestData {
const GMACModule *module;
} TestData;
/* Values extracted from hw/arm/npcm8xx.c */
static const GMACModule gmac_module_list[] = {
{
.irq = 14,
.base_addr = 0xf0802000
},
{
.irq = 15,
.base_addr = 0xf0804000
},
{
.irq = 16,
.base_addr = 0xf0806000
},
{
.irq = 17,
.base_addr = 0xf0808000
}
};
/* Returns the index of the GMAC module. */
static int gmac_module_index(const GMACModule *mod)
{
ptrdiff_t diff = mod - gmac_module_list;
g_assert_true(diff >= 0 && diff < ARRAY_SIZE(gmac_module_list));
return diff;
}
/* 32-bit register indices. Taken from npcm_gmac.c */
typedef enum NPCMRegister {
/* DMA Registers */
NPCM_DMA_BUS_MODE = 0x1000,
NPCM_DMA_XMT_POLL_DEMAND = 0x1004,
NPCM_DMA_RCV_POLL_DEMAND = 0x1008,
NPCM_DMA_RCV_BASE_ADDR = 0x100c,
NPCM_DMA_TX_BASE_ADDR = 0x1010,
NPCM_DMA_STATUS = 0x1014,
NPCM_DMA_CONTROL = 0x1018,
NPCM_DMA_INTR_ENA = 0x101c,
NPCM_DMA_MISSED_FRAME_CTR = 0x1020,
NPCM_DMA_HOST_TX_DESC = 0x1048,
NPCM_DMA_HOST_RX_DESC = 0x104c,
NPCM_DMA_CUR_TX_BUF_ADDR = 0x1050,
NPCM_DMA_CUR_RX_BUF_ADDR = 0x1054,
NPCM_DMA_HW_FEATURE = 0x1058,
/* GMAC Registers */
NPCM_GMAC_MAC_CONFIG = 0x0,
NPCM_GMAC_FRAME_FILTER = 0x4,
NPCM_GMAC_HASH_HIGH = 0x8,
NPCM_GMAC_HASH_LOW = 0xc,
NPCM_GMAC_MII_ADDR = 0x10,
NPCM_GMAC_MII_DATA = 0x14,
NPCM_GMAC_FLOW_CTRL = 0x18,
NPCM_GMAC_VLAN_FLAG = 0x1c,
NPCM_GMAC_VERSION = 0x20,
NPCM_GMAC_WAKEUP_FILTER = 0x28,
NPCM_GMAC_PMT = 0x2c,
NPCM_GMAC_LPI_CTRL = 0x30,
NPCM_GMAC_TIMER_CTRL = 0x34,
NPCM_GMAC_INT_STATUS = 0x38,
NPCM_GMAC_INT_MASK = 0x3c,
NPCM_GMAC_MAC0_ADDR_HI = 0x40,
NPCM_GMAC_MAC0_ADDR_LO = 0x44,
NPCM_GMAC_MAC1_ADDR_HI = 0x48,
NPCM_GMAC_MAC1_ADDR_LO = 0x4c,
NPCM_GMAC_MAC2_ADDR_HI = 0x50,
NPCM_GMAC_MAC2_ADDR_LO = 0x54,
NPCM_GMAC_MAC3_ADDR_HI = 0x58,
NPCM_GMAC_MAC3_ADDR_LO = 0x5c,
NPCM_GMAC_RGMII_STATUS = 0xd8,
NPCM_GMAC_WATCHDOG = 0xdc,
NPCM_GMAC_PTP_TCR = 0x700,
NPCM_GMAC_PTP_SSIR = 0x704,
NPCM_GMAC_PTP_STSR = 0x708,
NPCM_GMAC_PTP_STNSR = 0x70c,
NPCM_GMAC_PTP_STSUR = 0x710,
NPCM_GMAC_PTP_STNSUR = 0x714,
NPCM_GMAC_PTP_TAR = 0x718,
NPCM_GMAC_PTP_TTSR = 0x71c,
/* PCS Registers */
NPCM_PCS_SR_CTL_ID1 = 0x3c0008,
NPCM_PCS_SR_CTL_ID2 = 0x3c000a,
NPCM_PCS_SR_CTL_STS = 0x3c0010,
NPCM_PCS_SR_MII_CTRL = 0x3e0000,
NPCM_PCS_SR_MII_STS = 0x3e0002,
NPCM_PCS_SR_MII_DEV_ID1 = 0x3e0004,
NPCM_PCS_SR_MII_DEV_ID2 = 0x3e0006,
NPCM_PCS_SR_MII_AN_ADV = 0x3e0008,
NPCM_PCS_SR_MII_LP_BABL = 0x3e000a,
NPCM_PCS_SR_MII_AN_EXPN = 0x3e000c,
NPCM_PCS_SR_MII_EXT_STS = 0x3e001e,
NPCM_PCS_SR_TIM_SYNC_ABL = 0x3e0e10,
NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR = 0x3e0e12,
NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_UPR = 0x3e0e14,
NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR = 0x3e0e16,
NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_UPR = 0x3e0e18,
NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR = 0x3e0e1a,
NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_UPR = 0x3e0e1c,
NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR = 0x3e0e1e,
NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_UPR = 0x3e0e20,
NPCM_PCS_VR_MII_MMD_DIG_CTRL1 = 0x3f0000,
NPCM_PCS_VR_MII_AN_CTRL = 0x3f0002,
NPCM_PCS_VR_MII_AN_INTR_STS = 0x3f0004,
NPCM_PCS_VR_MII_TC = 0x3f0006,
NPCM_PCS_VR_MII_DBG_CTRL = 0x3f000a,
NPCM_PCS_VR_MII_EEE_MCTRL0 = 0x3f000c,
NPCM_PCS_VR_MII_EEE_TXTIMER = 0x3f0010,
NPCM_PCS_VR_MII_EEE_RXTIMER = 0x3f0012,
NPCM_PCS_VR_MII_LINK_TIMER_CTRL = 0x3f0014,
NPCM_PCS_VR_MII_EEE_MCTRL1 = 0x3f0016,
NPCM_PCS_VR_MII_DIG_STS = 0x3f0020,
NPCM_PCS_VR_MII_ICG_ERRCNT1 = 0x3f0022,
NPCM_PCS_VR_MII_MISC_STS = 0x3f0030,
NPCM_PCS_VR_MII_RX_LSTS = 0x3f0040,
NPCM_PCS_VR_MII_MP_TX_BSTCTRL0 = 0x3f0070,
NPCM_PCS_VR_MII_MP_TX_LVLCTRL0 = 0x3f0074,
NPCM_PCS_VR_MII_MP_TX_GENCTRL0 = 0x3f007a,
NPCM_PCS_VR_MII_MP_TX_GENCTRL1 = 0x3f007c,
NPCM_PCS_VR_MII_MP_TX_STS = 0x3f0090,
NPCM_PCS_VR_MII_MP_RX_GENCTRL0 = 0x3f00b0,
NPCM_PCS_VR_MII_MP_RX_GENCTRL1 = 0x3f00b2,
NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0 = 0x3f00ba,
NPCM_PCS_VR_MII_MP_MPLL_CTRL0 = 0x3f00f0,
NPCM_PCS_VR_MII_MP_MPLL_CTRL1 = 0x3f00f2,
NPCM_PCS_VR_MII_MP_MPLL_STS = 0x3f0110,
NPCM_PCS_VR_MII_MP_MISC_CTRL2 = 0x3f0126,
NPCM_PCS_VR_MII_MP_LVL_CTRL = 0x3f0130,
NPCM_PCS_VR_MII_MP_MISC_CTRL0 = 0x3f0132,
NPCM_PCS_VR_MII_MP_MISC_CTRL1 = 0x3f0134,
NPCM_PCS_VR_MII_DIG_CTRL2 = 0x3f01c2,
NPCM_PCS_VR_MII_DIG_ERRCNT_SEL = 0x3f01c4,
} NPCMRegister;
static uint32_t gmac_read(QTestState *qts, const GMACModule *mod,
NPCMRegister regno)
{
return qtest_readl(qts, mod->base_addr + regno);
}
static uint16_t pcs_read(QTestState *qts, const GMACModule *mod,
NPCMRegister regno)
{
uint32_t write_value = (regno & 0x3ffe00) >> 9;
qtest_writel(qts, PCS_BASE_ADDRESS + NPCM_PCS_IND_AC_BA, write_value);
uint32_t read_offset = regno & 0x1ff;
return qtest_readl(qts, PCS_BASE_ADDRESS + read_offset);
}
/* Check that GMAC registers are reset to default value */
static void test_init(gconstpointer test_data)
{
const TestData *td = test_data;
const GMACModule *mod = td->module;
QTestState *qts = qtest_init("-machine npcm845-evb");
#define CHECK_REG32(regno, value) \
do { \
g_assert_cmphex(gmac_read(qts, mod, (regno)), ==, (value)); \
} while (0)
#define CHECK_REG_PCS(regno, value) \
do { \
g_assert_cmphex(pcs_read(qts, mod, (regno)), ==, (value)); \
} while (0)
CHECK_REG32(NPCM_DMA_BUS_MODE, 0x00020100);
CHECK_REG32(NPCM_DMA_XMT_POLL_DEMAND, 0);
CHECK_REG32(NPCM_DMA_RCV_POLL_DEMAND, 0);
CHECK_REG32(NPCM_DMA_RCV_BASE_ADDR, 0);
CHECK_REG32(NPCM_DMA_TX_BASE_ADDR, 0);
CHECK_REG32(NPCM_DMA_STATUS, 0);
CHECK_REG32(NPCM_DMA_CONTROL, 0);
CHECK_REG32(NPCM_DMA_INTR_ENA, 0);
CHECK_REG32(NPCM_DMA_MISSED_FRAME_CTR, 0);
CHECK_REG32(NPCM_DMA_HOST_TX_DESC, 0);
CHECK_REG32(NPCM_DMA_HOST_RX_DESC, 0);
CHECK_REG32(NPCM_DMA_CUR_TX_BUF_ADDR, 0);
CHECK_REG32(NPCM_DMA_CUR_RX_BUF_ADDR, 0);
CHECK_REG32(NPCM_DMA_HW_FEATURE, 0x100d4f37);
CHECK_REG32(NPCM_GMAC_MAC_CONFIG, 0);
CHECK_REG32(NPCM_GMAC_FRAME_FILTER, 0);
CHECK_REG32(NPCM_GMAC_HASH_HIGH, 0);
CHECK_REG32(NPCM_GMAC_HASH_LOW, 0);
CHECK_REG32(NPCM_GMAC_MII_ADDR, 0);
CHECK_REG32(NPCM_GMAC_MII_DATA, 0);
CHECK_REG32(NPCM_GMAC_FLOW_CTRL, 0);
CHECK_REG32(NPCM_GMAC_VLAN_FLAG, 0);
CHECK_REG32(NPCM_GMAC_VERSION, 0x00001032);
CHECK_REG32(NPCM_GMAC_WAKEUP_FILTER, 0);
CHECK_REG32(NPCM_GMAC_PMT, 0);
CHECK_REG32(NPCM_GMAC_LPI_CTRL, 0);
CHECK_REG32(NPCM_GMAC_TIMER_CTRL, 0x03e80000);
CHECK_REG32(NPCM_GMAC_INT_STATUS, 0);
CHECK_REG32(NPCM_GMAC_INT_MASK, 0);
CHECK_REG32(NPCM_GMAC_MAC0_ADDR_HI, 0x8000ffff);
CHECK_REG32(NPCM_GMAC_MAC0_ADDR_LO, 0xffffffff);
CHECK_REG32(NPCM_GMAC_MAC1_ADDR_HI, 0x0000ffff);
CHECK_REG32(NPCM_GMAC_MAC1_ADDR_LO, 0xffffffff);
CHECK_REG32(NPCM_GMAC_MAC2_ADDR_HI, 0x0000ffff);
CHECK_REG32(NPCM_GMAC_MAC2_ADDR_LO, 0xffffffff);
CHECK_REG32(NPCM_GMAC_MAC3_ADDR_HI, 0x0000ffff);
CHECK_REG32(NPCM_GMAC_MAC3_ADDR_LO, 0xffffffff);
CHECK_REG32(NPCM_GMAC_RGMII_STATUS, 0);
CHECK_REG32(NPCM_GMAC_WATCHDOG, 0);
CHECK_REG32(NPCM_GMAC_PTP_TCR, 0x00002000);
CHECK_REG32(NPCM_GMAC_PTP_SSIR, 0);
CHECK_REG32(NPCM_GMAC_PTP_STSR, 0);
CHECK_REG32(NPCM_GMAC_PTP_STNSR, 0);
CHECK_REG32(NPCM_GMAC_PTP_STSUR, 0);
CHECK_REG32(NPCM_GMAC_PTP_STNSUR, 0);
CHECK_REG32(NPCM_GMAC_PTP_TAR, 0);
CHECK_REG32(NPCM_GMAC_PTP_TTSR, 0);
/* TODO Add registers PCS */
if (mod->base_addr == 0xf0802000) {
CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID1, 0x699e);
CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID2, 0);
CHECK_REG_PCS(NPCM_PCS_SR_CTL_STS, 0x8000);
CHECK_REG_PCS(NPCM_PCS_SR_MII_CTRL, 0x1140);
CHECK_REG_PCS(NPCM_PCS_SR_MII_STS, 0x0109);
CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID1, 0x699e);
CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID2, 0x0ced0);
CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_ADV, 0x0020);
CHECK_REG_PCS(NPCM_PCS_SR_MII_LP_BABL, 0);
CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_EXPN, 0);
CHECK_REG_PCS(NPCM_PCS_SR_MII_EXT_STS, 0xc000);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_ABL, 0x0003);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR, 0x0038);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_UPR, 0);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR, 0x0038);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_UPR, 0);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR, 0x0058);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_UPR, 0);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR, 0x0048);
CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_UPR, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MMD_DIG_CTRL1, 0x2400);
CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_CTRL, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_INTR_STS, 0x000a);
CHECK_REG_PCS(NPCM_PCS_VR_MII_TC, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_DBG_CTRL, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL0, 0x899c);
CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_TXTIMER, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_RXTIMER, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_LINK_TIMER_CTRL, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL1, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_STS, 0x0010);
CHECK_REG_PCS(NPCM_PCS_VR_MII_ICG_ERRCNT1, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MISC_STS, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_RX_LSTS, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_BSTCTRL0, 0x00a);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_LVLCTRL0, 0x007f);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL0, 0x0001);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL1, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_STS, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL0, 0x0100);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL1, 0x1100);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0, 0x000e);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL0, 0x0100);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL1, 0x0032);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_STS, 0x0001);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL2, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_LVL_CTRL, 0x0019);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL0, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL1, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_CTRL2, 0);
CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_ERRCNT_SEL, 0);
}
qtest_quit(qts);
}
static void gmac_add_test(const char *name, const TestData* td,
GTestDataFunc fn)
{
g_autofree char *full_name = g_strdup_printf(
"npcm7xx_gmac/gmac[%d]/%s", gmac_module_index(td->module), name);
qtest_add_data_func(full_name, td, fn);
}
int main(int argc, char **argv)
{
TestData test_data_list[ARRAY_SIZE(gmac_module_list)];
g_test_init(&argc, &argv, NULL);
for (int i = 0; i < ARRAY_SIZE(gmac_module_list); ++i) {
TestData *td = &test_data_list[i];
td->module = &gmac_module_list[i];
gmac_add_test("init", td, test_init);
}
return g_test_run();
}

View File

@ -298,10 +298,13 @@ static size_t trng_collect(uint32_t *rnd, size_t cnt)
return i; return i;
} }
/* These tests all generate 512 bits of random data with the device */
#define TEST_DATA_WORDS (512 / 32)
static void trng_test_autogen(void) static void trng_test_autogen(void)
{ {
const size_t cnt = 512 / 32; const size_t cnt = TEST_DATA_WORDS;
uint32_t rng[cnt], prng[cnt]; uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
size_t n; size_t n;
trng_reset(); trng_reset();
@ -343,8 +346,8 @@ static void trng_test_autogen(void)
static void trng_test_oneshot(void) static void trng_test_oneshot(void)
{ {
const size_t cnt = 512 / 32; const size_t cnt = TEST_DATA_WORDS;
uint32_t rng[cnt]; uint32_t rng[TEST_DATA_WORDS];
size_t n; size_t n;
trng_reset(); trng_reset();
@ -370,8 +373,8 @@ static void trng_test_oneshot(void)
static void trng_test_per_str(void) static void trng_test_per_str(void)
{ {
const size_t cnt = 512 / 32; const size_t cnt = TEST_DATA_WORDS;
uint32_t rng[cnt], prng[cnt]; uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
size_t n; size_t n;
trng_reset(); trng_reset();
@ -415,8 +418,8 @@ static void trng_test_forced_prng(void)
const char *prop = "forced-prng"; const char *prop = "forced-prng";
const uint64_t seed = 0xdeadbeefbad1bad0ULL; const uint64_t seed = 0xdeadbeefbad1bad0ULL;
const size_t cnt = 512 / 32; const size_t cnt = TEST_DATA_WORDS;
uint32_t rng[cnt], prng[cnt]; uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
size_t n; size_t n;
trng_reset(); trng_reset();

View File

@ -137,7 +137,7 @@ int main(void)
/* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */ /* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */
get_cpu_reg_check_mask(id_aa64dfr0_el1, _m(0000,0000,0000,0006)); get_cpu_reg_check_mask(id_aa64dfr0_el1, _m(0000,0000,0000,0006));
get_cpu_reg_check_zero(id_aa64dfr1_el1); get_cpu_reg_check_zero(id_aa64dfr1_el1);
get_cpu_reg_check_mask(SYS_ID_AA64ZFR0_EL1, _m(0ff0,ff0f,00ff,00ff)); get_cpu_reg_check_mask(SYS_ID_AA64ZFR0_EL1, _m(0ff0,ff0f,0fff,00ff));
get_cpu_reg_check_mask(SYS_ID_AA64SMFR0_EL1, _m(8ff1,fcff,0000,0000)); get_cpu_reg_check_mask(SYS_ID_AA64SMFR0_EL1, _m(8ff1,fcff,0000,0000));
get_cpu_reg_check_zero(id_aa64afr0_el1); get_cpu_reg_check_zero(id_aa64afr0_el1);