mirror of https://github.com/xemu-project/xemu.git
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:
commit
4f2fdb10b5
|
@ -30,6 +30,13 @@ nor the documentation output.
|
|||
|
||||
``SRST`` starts a reStructuredText section. Following lines
|
||||
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``,
|
||||
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
|
||||
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
|
||||
is included into two separate Sphinx documents, and some
|
||||
versions of Sphinx will complain about the duplicate label
|
||||
that results.
|
||||
that results. Use the ``SRST()`` directive documented above, to
|
||||
emit an unambiguous label.
|
||||
|
|
|
@ -78,6 +78,14 @@ def parse_archheading(file, lnum, line):
|
|||
serror(file, lnum, "Invalid ARCHHEADING line")
|
||||
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):
|
||||
"""Extract rST fragments from the specified .hx file"""
|
||||
required_argument = 1
|
||||
|
@ -113,6 +121,14 @@ class HxtoolDocDirective(Directive):
|
|||
serror(hxfile, lnum, 'expected ERST, found SRST')
|
||||
else:
|
||||
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':
|
||||
if state == HxState.CTEXT:
|
||||
serror(hxfile, lnum, 'expected SRST, found ERST')
|
||||
|
|
|
@ -33,11 +33,11 @@ Implemented devices
|
|||
* USB2 host controller (DWC2 and MPHI)
|
||||
* MailBox controller (MBOX)
|
||||
* VideoCore firmware (property)
|
||||
* Peripheral SPI controller (SPI)
|
||||
|
||||
|
||||
Missing devices
|
||||
---------------
|
||||
|
||||
* Peripheral SPI controller (SPI)
|
||||
* Analog to Digital Converter (ADC)
|
||||
* Pulse Width Modulation (PWM)
|
||||
|
|
|
@ -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
|
||||
with an actual initramfs, which would need to listed as a second multiboot
|
||||
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
|
||||
--------------------
|
||||
|
|
|
@ -429,6 +429,7 @@ config RASPI
|
|||
select PL011 # UART
|
||||
select SDHCI
|
||||
select USB_DWC2
|
||||
select BCM2835_SPI
|
||||
|
||||
config STM32F100_SOC
|
||||
bool
|
||||
|
|
|
@ -144,6 +144,10 @@ static void bcm2835_peripherals_init(Object *obj)
|
|||
/* Power Management */
|
||||
object_initialize_child(obj, "powermgt", &s->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)
|
||||
|
@ -402,11 +406,22 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
|
|||
memory_region_add_subregion(&s->peri_mr, PM_OFFSET,
|
||||
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->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
|
||||
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_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->i2c[0], "bcm2835-i2c0", BSC0_OFFSET, 0x20);
|
||||
create_unimp(s, &s->i2c[1], "bcm2835-i2c1", BSC1_OFFSET, 0x20);
|
||||
|
|
|
@ -556,6 +556,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
|
|||
for (n = 0; n < EXYNOS4210_NCPUS; n++) {
|
||||
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
|
||||
* support EL3 so the CPU EL3 property is disabled before realization.
|
||||
*/
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "hw/qdev-properties.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/irq.h"
|
||||
#include "target/arm/cpu-qom.h"
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
static const char * const valid_cpu_types[] = {
|
||||
ARM_CPU_TYPE_NAME("cortex-a9"),
|
||||
NULL
|
||||
};
|
||||
|
||||
static void nuri_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Samsung NURI board (Exynos4210)";
|
||||
mc->init = nuri_init;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->max_cpus = EXYNOS4210_NCPUS;
|
||||
mc->min_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->init = smdkc210_init;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->max_cpus = EXYNOS4210_NCPUS;
|
||||
mc->min_cpus = EXYNOS4210_NCPUS;
|
||||
mc->default_cpus = EXYNOS4210_NCPUS;
|
||||
|
|
|
@ -209,6 +209,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
|
|||
cpuobj = object_new(machine->cpu_type);
|
||||
cpu = ARM_CPU(cpuobj);
|
||||
|
||||
object_property_add_child(OBJECT(machine), "cpu[*]", cpuobj);
|
||||
object_property_set_int(cpuobj, "psci-conduit", QEMU_PSCI_CONDUIT_SMC,
|
||||
&error_abort);
|
||||
|
||||
|
@ -342,10 +343,15 @@ static void midway_init(MachineState *machine)
|
|||
|
||||
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);
|
||||
|
||||
mc->desc = "Calxeda Highbank (ECX-1000)";
|
||||
mc->init = highbank_init;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->units_per_default_bus = 1;
|
||||
mc->max_cpus = 4;
|
||||
|
@ -361,10 +367,15 @@ static const TypeInfo highbank_type = {
|
|||
|
||||
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);
|
||||
|
||||
mc->desc = "Calxeda Midway (ECX-2000)";
|
||||
mc->init = midway_init;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->units_per_default_bus = 1;
|
||||
mc->max_cpus = 4;
|
||||
|
|
|
@ -134,7 +134,7 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
|
||||
armv7m = DEVICE(&s->armv7m);
|
||||
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_connect_clock_in(armv7m, "cpuclk", s->m3clk);
|
||||
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
|
||||
* property is for information purpose only.
|
||||
*/
|
||||
DEFINE_PROP_STRING("cpu-type", MSF2State, cpu_type),
|
||||
DEFINE_PROP_STRING("part-name", MSF2State, part_name),
|
||||
DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE),
|
||||
DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size,
|
||||
|
|
|
@ -47,7 +47,6 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
|
|||
DeviceState *dev;
|
||||
DeviceState *spi_flash;
|
||||
MSF2State *soc;
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
|
||||
qemu_irq cs_line;
|
||||
BusState *spi_bus;
|
||||
|
@ -62,8 +61,6 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
|
|||
dev = qdev_new(TYPE_MSF2_SOC);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(dev));
|
||||
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, "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->init = emcraft_sf2_s2s010_init;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
}
|
||||
|
||||
|
|
|
@ -605,7 +605,6 @@ static void musca_class_init(ObjectClass *oc, void *data)
|
|||
mc->default_cpus = 2;
|
||||
mc->min_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->init = musca_init;
|
||||
}
|
||||
|
|
|
@ -84,8 +84,10 @@ enum NPCM7xxInterrupt {
|
|||
NPCM7XX_UART1_IRQ,
|
||||
NPCM7XX_UART2_IRQ,
|
||||
NPCM7XX_UART3_IRQ,
|
||||
NPCM7XX_GMAC1_IRQ = 14,
|
||||
NPCM7XX_EMC1RX_IRQ = 15,
|
||||
NPCM7XX_EMC1TX_IRQ,
|
||||
NPCM7XX_GMAC2_IRQ,
|
||||
NPCM7XX_MMC_IRQ = 26,
|
||||
NPCM7XX_PSPI2_IRQ = 28,
|
||||
NPCM7XX_PSPI1_IRQ = 31,
|
||||
|
@ -229,6 +231,12 @@ static const hwaddr npcm7xx_pspi_addr[] = {
|
|||
0xf0201000,
|
||||
};
|
||||
|
||||
/* Register base address for each GMAC Module */
|
||||
static const hwaddr npcm7xx_gmac_addr[] = {
|
||||
0xf0802000,
|
||||
0xf0804000,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
hwaddr regs_addr;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -690,6 +702,29 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
|||
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
|
||||
* 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.ahbpci", 0xf0400000, 1 * MiB);
|
||||
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.ece", 0xf0820000, 8 * KiB);
|
||||
create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB);
|
||||
|
|
|
@ -465,7 +465,6 @@ static void npcm7xx_machine_class_init(ObjectClass *oc, void *data)
|
|||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
mc->default_ram_id = "ram";
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9");
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,8 +46,7 @@
|
|||
#include "qemu/log.h"
|
||||
#include "qom/object.h"
|
||||
#include "target/arm/cpu-qom.h"
|
||||
|
||||
//#define DEBUG
|
||||
#include "trace.h"
|
||||
|
||||
/*
|
||||
TODO
|
||||
|
@ -66,12 +65,6 @@
|
|||
- Enhance UART with modem signals
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__)
|
||||
#else
|
||||
# define DPRINTF(format, ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
hwaddr io_base;
|
||||
int irq;
|
||||
|
@ -151,8 +144,9 @@ static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset,
|
|||
case ICPR:
|
||||
return s->pending;
|
||||
default:
|
||||
printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n",
|
||||
__func__, offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad register offset 0x"HWADDR_FMT_plx"\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -173,8 +167,9 @@ static void strongarm_pic_mem_write(void *opaque, hwaddr offset,
|
|||
s->int_idle = (value & 1) ? 0 : ~0;
|
||||
break;
|
||||
default:
|
||||
printf("%s: Bad register offset 0x" HWADDR_FMT_plx "\n",
|
||||
__func__, offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad register offset 0x"HWADDR_FMT_plx"\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
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) /
|
||||
(1000 * ((s->rttr & 0xffff) + 1));
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +372,9 @@ static void strongarm_rtc_write(void *opaque, hwaddr addr,
|
|||
break;
|
||||
|
||||
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 */
|
||||
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;
|
||||
|
||||
case GPCR: /* GPIO Pin-Output Clear registers */
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
@ -626,7 +627,9 @@ static void strongarm_gpio_write(void *opaque, hwaddr offset,
|
|||
break;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
@ -817,7 +822,9 @@ static void strongarm_ppc_write(void *opaque, hwaddr offset,
|
|||
break;
|
||||
|
||||
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;
|
||||
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,
|
||||
speed, parity, data_bits, stop_bits);
|
||||
trace_strongarm_uart_update_parameters((s->chr.chr ?
|
||||
s->chr.chr->label : "NULL") ?:
|
||||
"NULL",
|
||||
speed,
|
||||
parity,
|
||||
data_bits,
|
||||
stop_bits);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1221,7 +1235,9 @@ static void strongarm_uart_write(void *opaque, hwaddr addr,
|
|||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
if (s->rx_level < 1) {
|
||||
printf("%s: SSP Rx Underrun\n", __func__);
|
||||
trace_strongarm_ssp_read_underrun();
|
||||
return 0xffffffff;
|
||||
}
|
||||
s->rx_level--;
|
||||
|
@ -1443,7 +1459,9 @@ static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr,
|
|||
strongarm_ssp_fifo_update(s);
|
||||
return retval;
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1458,8 +1476,8 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr,
|
|||
case SSCR0:
|
||||
s->sscr[0] = value & 0xffbf;
|
||||
if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
|
||||
printf("%s: Wrong data size: %i bits\n", __func__,
|
||||
(int)SSCR0_DSS(value));
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Wrong data size: %i bits\n",
|
||||
__func__, (int)SSCR0_DSS(value));
|
||||
}
|
||||
if (!(value & SSCR0_SSE)) {
|
||||
s->sssr = 0;
|
||||
|
@ -1471,7 +1489,9 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr,
|
|||
case SSCR1:
|
||||
s->sscr[1] = value & 0x2f;
|
||||
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);
|
||||
break;
|
||||
|
@ -1509,7 +1529,9 @@ static void strongarm_ssp_write(void *opaque, hwaddr addr,
|
|||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_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
|
||||
|
|
|
@ -783,22 +783,30 @@ static void vexpress_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);
|
||||
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc);
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "hw/xen/xen-hvm-common.h"
|
||||
#include "sysemu/tpm.h"
|
||||
#include "hw/xen/arch_hvm.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh")
|
||||
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);
|
||||
|
||||
DPRINTF("Created virtio-mmio device %d: irq %d base 0x%lx\n",
|
||||
i, GUEST_VIRTIO_MMIO_SPI_FIRST + i, base);
|
||||
trace_xen_create_virtio_mmio_devices(i,
|
||||
GUEST_VIRTIO_MMIO_SPI_FIRST + i,
|
||||
base);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +103,7 @@ static void xen_init_ram(MachineState *machine)
|
|||
MemoryRegion *sysmem = get_system_memory();
|
||||
ram_addr_t block_len, ram_size[GUEST_RAM_BANKS];
|
||||
|
||||
trace_xen_init_ram(machine->ram_size);
|
||||
if (machine->ram_size <= GUEST_RAM0_SIZE) {
|
||||
ram_size[0] = machine->ram_size;
|
||||
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,
|
||||
GUEST_RAM0_BASE, ram_size[0]);
|
||||
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) {
|
||||
memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &ram_memory,
|
||||
GUEST_RAM1_BASE, ram_size[1]);
|
||||
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");
|
||||
if (be == NULL) {
|
||||
DPRINTF("Couldn't fine the backend for tpm0\n");
|
||||
error_report("Couldn't find tmp0 backend");
|
||||
return;
|
||||
}
|
||||
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_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
|
||||
|
||||
|
@ -179,8 +177,9 @@ static void xen_arm_init(MachineState *machine)
|
|||
xam->state = g_new0(XenIOState, 1);
|
||||
|
||||
if (machine->ram_size == 0) {
|
||||
DPRINTF("ram_size not specified. QEMU machine started without IOREQ"
|
||||
"(no emulated devices including Virtio)\n");
|
||||
warn_report("%s non-zero ram size not specified. QEMU machine started"
|
||||
" without IOREQ (no emulated devices including virtio)",
|
||||
MACHINE_CLASS(object_get_class(OBJECT(machine)))->desc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -194,7 +193,7 @@ static void xen_arm_init(MachineState *machine)
|
|||
if (xam->cfg.tpm_base_addr) {
|
||||
xen_enable_tpm(xam);
|
||||
} 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
|
||||
}
|
||||
|
|
|
@ -352,13 +352,17 @@ static void zynq_init(MachineState *machine)
|
|||
|
||||
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);
|
||||
mc->desc = "Xilinx Zynq Platform Baseboard for Cortex-A9";
|
||||
mc->init = zynq_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_sdcard = 1;
|
||||
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";
|
||||
}
|
||||
|
||||
|
|
27
hw/arm/z2.c
27
hw/arm/z2.c
|
@ -27,13 +27,7 @@
|
|||
#include "exec/address-spaces.h"
|
||||
#include "qom/object.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#ifdef DEBUG_Z2
|
||||
#define DPRINTF(fmt, ...) \
|
||||
printf(fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...)
|
||||
#endif
|
||||
#include "trace.h"
|
||||
|
||||
static const struct keymap map[0x100] = {
|
||||
[0 ... 0xff] = { -1, -1 },
|
||||
|
@ -119,6 +113,8 @@ static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value)
|
|||
{
|
||||
ZipitLCD *z = ZIPIT_LCD(dev);
|
||||
uint16_t val;
|
||||
|
||||
trace_z2_lcd_reg_update(z->cur_reg, z->buf[0], z->buf[1], z->buf[2], value);
|
||||
if (z->selected) {
|
||||
z->buf[z->pos] = value & 0xff;
|
||||
z->pos++;
|
||||
|
@ -126,22 +122,19 @@ static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value)
|
|||
if (z->pos == 3) {
|
||||
switch (z->buf[0]) {
|
||||
case 0x74:
|
||||
DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]);
|
||||
z->cur_reg = z->buf[2];
|
||||
break;
|
||||
case 0x76:
|
||||
val = z->buf[1] << 8 | z->buf[2];
|
||||
DPRINTF("%s: value: 0x%.4x\n", __func__, val);
|
||||
if (z->cur_reg == 0x22 && val == 0x0000) {
|
||||
z->enabled = 1;
|
||||
printf("%s: LCD enabled\n", __func__);
|
||||
trace_z2_lcd_enable_disable_result("enabled");
|
||||
} else if (z->cur_reg == 0x10 && val == 0x0000) {
|
||||
z->enabled = 0;
|
||||
printf("%s: LCD disabled\n", __func__);
|
||||
trace_z2_lcd_enable_disable_result("disabled");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DPRINTF("%s: unknown command!\n", __func__);
|
||||
break;
|
||||
}
|
||||
z->pos = 0;
|
||||
|
@ -211,14 +204,12 @@ static int aer915_send(I2CSlave *i2c, uint8_t data)
|
|||
|
||||
s->buf[s->len] = data;
|
||||
if (s->len++ > 2) {
|
||||
DPRINTF("%s: message too long (%i bytes)\n",
|
||||
__func__, s->len);
|
||||
trace_z2_aer915_send_too_long(s->len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (s->len == 2) {
|
||||
DPRINTF("%s: reg %d value 0x%02x\n", __func__,
|
||||
s->buf[0], s->buf[1]);
|
||||
trace_z2_aer915_send(s->buf[0], s->buf[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -228,14 +219,12 @@ static int aer915_event(I2CSlave *i2c, enum i2c_event event)
|
|||
{
|
||||
AER915State *s = AER915(i2c);
|
||||
|
||||
trace_z2_aer915_event(s->len, event);
|
||||
switch (event) {
|
||||
case I2C_START_SEND:
|
||||
s->len = 0;
|
||||
break;
|
||||
case I2C_START_RECV:
|
||||
if (s->len != 1) {
|
||||
DPRINTF("%s: short message!?\n", __func__);
|
||||
}
|
||||
break;
|
||||
case I2C_FINISH:
|
||||
break;
|
||||
|
|
|
@ -232,57 +232,6 @@ static char *default_bus_get_fw_dev_path(DeviceState *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)
|
||||
{
|
||||
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->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)
|
||||
|
|
|
@ -2453,9 +2453,9 @@ static void vmbus_unrealize(BusState *bus)
|
|||
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)
|
||||
|
@ -2476,12 +2476,13 @@ static char *vmbus_get_fw_dev_path(DeviceState *dev)
|
|||
static void vmbus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
BusClass *k = BUS_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
k->get_dev_path = vmbus_get_dev_path;
|
||||
k->get_fw_dev_path = vmbus_get_fw_dev_path;
|
||||
k->realize = vmbus_realize;
|
||||
k->unrealize = vmbus_unrealize;
|
||||
k->reset = vmbus_reset;
|
||||
rc->phases.hold = vmbus_reset_hold;
|
||||
}
|
||||
|
||||
static int vmbus_pre_load(void *opaque)
|
||||
|
|
|
@ -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_mask = 0xffff;
|
||||
|
@ -262,10 +262,11 @@ static void adb_bus_unrealize(BusState *qbus)
|
|||
static void adb_bus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
BusClass *k = BUS_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
k->realize = adb_bus_realize;
|
||||
k->unrealize = adb_bus_unrealize;
|
||||
k->reset = adb_bus_reset;
|
||||
rc->phases.hold = adb_bus_reset_hold;
|
||||
}
|
||||
|
||||
static const TypeInfo adb_bus_type_info = {
|
||||
|
|
|
@ -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_FTGMAC100', if_true: files('ftgmac100.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_COLDFIRE', if_true: files('mcf_fec.c'))
|
||||
|
|
|
@ -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)
|
|
@ -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_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
|
||||
dp8393x_raise_irq(int isr) "raise irq, isr is 0x%04x"
|
||||
dp8393x_lower_irq(void) "lower irq"
|
||||
|
|
|
@ -340,6 +340,8 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
|
|||
break;
|
||||
|
||||
case DESIGNWARE_PCIE_ATU_VIEWPORT:
|
||||
val &= DESIGNWARE_PCIE_ATU_REGION_INBOUND |
|
||||
(DESIGNWARE_PCIE_NUM_VIEWPORTS - 1);
|
||||
root->atu_viewport = val;
|
||||
break;
|
||||
|
||||
|
|
10
hw/pci/pci.c
10
hw/pci/pci.c
|
@ -64,7 +64,7 @@ bool pci_available = true;
|
|||
|
||||
static char *pcibus_get_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 Property pci_props[] = {
|
||||
|
@ -202,13 +202,15 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
|
|||
{
|
||||
BusClass *k = BUS_CLASS(klass);
|
||||
PCIBusClass *pbc = PCI_BUS_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
k->print_dev = pcibus_dev_print;
|
||||
k->get_dev_path = pcibus_get_dev_path;
|
||||
k->get_fw_dev_path = pcibus_get_fw_dev_path;
|
||||
k->realize = pci_bus_realize;
|
||||
k->unrealize = pci_bus_unrealize;
|
||||
k->reset = pcibus_reset;
|
||||
|
||||
rc->phases.hold = pcibus_reset_hold;
|
||||
|
||||
pbc->bus_num = pcibus_num;
|
||||
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
|
||||
* 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;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) {
|
||||
|
|
|
@ -56,7 +56,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_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 */
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,3 +20,7 @@ config XILINX_SPIPS
|
|||
config STM32F2XX_SPI
|
||||
bool
|
||||
select SSI
|
||||
|
||||
config BCM2835_SPI
|
||||
bool
|
||||
select SSI
|
||||
|
|
|
@ -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)
|
|
@ -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_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_BCM2835_SPI', if_true: files('bcm2835_spi.c'))
|
||||
|
|
|
@ -42,7 +42,7 @@ xs_node_vscanf(char *path, char *value) "%s %s"
|
|||
xs_node_watch(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_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"
|
||||
|
@ -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"
|
||||
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_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_map_cache(uint64_t phys_addr) "want 0x%"PRIx64
|
||||
xen_remap_bucket(uint64_t index) "index 0x%"PRIx64
|
||||
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"
|
||||
|
|
|
@ -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)) {
|
||||
/* RAM already populated in Xen */
|
||||
fprintf(stderr, "%s: do not alloc "RAM_ADDR_FMT
|
||||
" bytes of ram at "RAM_ADDR_FMT" when runstate is INMIGRATE\n",
|
||||
warn_report("%s: do not alloc "RAM_ADDR_FMT
|
||||
" bytes of ram at "RAM_ADDR_FMT" when runstate is INMIGRATE",
|
||||
__func__, size, ram_addr);
|
||||
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);
|
||||
|
||||
if (req->state != STATE_IOREQ_READY) {
|
||||
DPRINTF("I/O request not ready: "
|
||||
"%x, ptr: %x, port: %"PRIx64", "
|
||||
"data: %"PRIx64", count: %u, size: %u\n",
|
||||
req->state, req->data_is_ptr, req->addr,
|
||||
req->data, req->count, req->size);
|
||||
trace_cpu_get_ioreq_from_shared_memory_req_not_ready(req->state,
|
||||
req->data_is_ptr,
|
||||
req->addr,
|
||||
req->data,
|
||||
req->count,
|
||||
req->size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -551,9 +552,9 @@ static void cpu_handle_ioreq(void *opaque)
|
|||
req->data = copy.data;
|
||||
|
||||
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", "
|
||||
"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->data, req->count, req->size, req->type);
|
||||
destroy_hvm_domain(false);
|
||||
|
@ -601,10 +602,9 @@ static void xen_main_loop_prepare(XenIOState *state)
|
|||
if (evtchn_fd != -1) {
|
||||
CPUState *cpu_state;
|
||||
|
||||
DPRINTF("%s: Init cpu_by_vcpu_id\n", __func__);
|
||||
CPU_FOREACH(cpu_state) {
|
||||
DPRINTF("%s: cpu_by_vcpu_id[%d]=%p\n",
|
||||
__func__, cpu_state->cpu_index, cpu_state);
|
||||
trace_xen_main_loop_prepare_init_cpu(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);
|
||||
|
@ -681,7 +681,7 @@ static int xen_map_ioreq_server(XenIOState *state)
|
|||
}
|
||||
|
||||
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,
|
||||
PROT_READ | PROT_WRITE,
|
||||
|
@ -693,7 +693,7 @@ static int xen_map_ioreq_server(XenIOState *state)
|
|||
}
|
||||
|
||||
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,
|
||||
PROT_READ | PROT_WRITE,
|
||||
|
@ -709,7 +709,7 @@ static int xen_map_ioreq_server(XenIOState *state)
|
|||
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;
|
||||
|
||||
|
@ -737,16 +737,17 @@ void destroy_hvm_domain(bool reboot)
|
|||
|
||||
xc_handle = xc_interface_open(0, 0, 0);
|
||||
if (xc_handle == NULL) {
|
||||
fprintf(stderr, "Cannot acquire xenctrl handle\n");
|
||||
trace_destroy_hvm_domain_cannot_acquire_handle();
|
||||
} else {
|
||||
sts = xc_domain_shutdown(xc_handle, xen_domid, reason);
|
||||
if (sts != 0) {
|
||||
fprintf(stderr, "xc_domain_shutdown failed to issue %s, "
|
||||
"sts %d, %s\n", reboot ? "reboot" : "poweroff",
|
||||
sts, strerror(errno));
|
||||
trace_destroy_hvm_domain_failed_action(
|
||||
reboot ? "reboot" : "poweroff", sts, strerror(errno)
|
||||
);
|
||||
} else {
|
||||
fprintf(stderr, "Issued domain %d %s\n", xen_domid,
|
||||
reboot ? "reboot" : "poweroff");
|
||||
trace_destroy_hvm_domain_action(
|
||||
xen_domid, reboot ? "reboot" : "poweroff"
|
||||
);
|
||||
}
|
||||
xc_interface_close(xc_handle);
|
||||
}
|
||||
|
@ -757,9 +758,9 @@ void xen_shutdown_fatal_error(const char *fmt, ...)
|
|||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
error_vreport(fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "Will destroy the domain.\n");
|
||||
error_report("Will destroy the domain.");
|
||||
/* destroy the domain */
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR);
|
||||
}
|
||||
|
|
|
@ -22,16 +22,6 @@
|
|||
#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
|
||||
# define MCACHE_BUCKET_SHIFT 16
|
||||
# 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 = (size + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1);
|
||||
DPRINTF("%s, nr_buckets = %lx size %lu\n", __func__,
|
||||
mapcache->nr_buckets, size);
|
||||
trace_xen_map_cache_init(mapcache->nr_buckets, size);
|
||||
mapcache->entry = g_malloc0(size);
|
||||
}
|
||||
|
||||
|
@ -286,7 +275,9 @@ tryagain:
|
|||
test_bits(address_offset >> XC_PAGE_SHIFT,
|
||||
test_bit_size >> XC_PAGE_SHIFT,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -356,9 +347,8 @@ tryagain:
|
|||
MapCacheRev *reventry = g_new0(MapCacheRev, 1);
|
||||
entry->lock++;
|
||||
if (entry->lock == 0) {
|
||||
fprintf(stderr,
|
||||
"mapcache entry lock overflow: "HWADDR_FMT_plx" -> %p\n",
|
||||
entry->paddr_index, entry->vaddr_base);
|
||||
error_report("mapcache entry lock overflow: "HWADDR_FMT_plx" -> %p",
|
||||
entry->paddr_index, entry->vaddr_base);
|
||||
abort();
|
||||
}
|
||||
reventry->dma = dma;
|
||||
|
@ -368,7 +358,9 @@ tryagain:
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -402,10 +394,10 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
|
|||
}
|
||||
}
|
||||
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) {
|
||||
DPRINTF(" "HWADDR_FMT_plx" -> %p is present\n", reventry->paddr_index,
|
||||
reventry->vaddr_req);
|
||||
trace_xen_ram_addr_from_mapcache_found(reventry->paddr_index,
|
||||
reventry->vaddr_req);
|
||||
}
|
||||
abort();
|
||||
return 0;
|
||||
|
@ -416,7 +408,7 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
|
|||
entry = entry->next;
|
||||
}
|
||||
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;
|
||||
} else {
|
||||
raddr = (reventry->paddr_index << MCACHE_BUCKET_SHIFT) +
|
||||
|
@ -443,9 +435,12 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
|
|||
}
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
@ -463,7 +458,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
|
|||
entry = entry->next;
|
||||
}
|
||||
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;
|
||||
}
|
||||
entry->lock--;
|
||||
|
@ -502,9 +497,8 @@ void xen_invalidate_map_cache(void)
|
|||
if (!reventry->dma) {
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "Locked DMA mapping while invalidating mapcache!"
|
||||
" "HWADDR_FMT_plx" -> %p is present\n",
|
||||
reventry->paddr_index, reventry->vaddr_req);
|
||||
trace_xen_invalidate_map_cache(reventry->paddr_index,
|
||||
reventry->vaddr_req);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (!entry) {
|
||||
DPRINTF("Trying to update an entry for "HWADDR_FMT_plx \
|
||||
"that is not in the mapcache!\n", old_phys_addr);
|
||||
trace_xen_replace_cache_entry_unlocked(old_phys_addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
address_index = new_phys_addr >> MCACHE_BUCKET_SHIFT;
|
||||
address_offset = new_phys_addr & (MCACHE_BUCKET_SIZE - 1);
|
||||
|
||||
fprintf(stderr, "Replacing a dummy mapcache entry for "HWADDR_FMT_plx \
|
||||
" with "HWADDR_FMT_plx"\n", old_phys_addr, new_phys_addr);
|
||||
trace_xen_replace_cache_entry_dummy(old_phys_addr, new_phys_addr);
|
||||
|
||||
xen_remap_bucket(entry, entry->vaddr_base,
|
||||
cache_size, address_index, false);
|
||||
if (!test_bits(address_offset >> XC_PAGE_SHIFT,
|
||||
test_bit_size >> XC_PAGE_SHIFT,
|
||||
entry->valid_mapping)) {
|
||||
DPRINTF("Unable to update a mapcache entry for "HWADDR_FMT_plx"!\n",
|
||||
old_phys_addr);
|
||||
trace_xen_replace_cache_entry_unlocked_could_not_update_entry(
|
||||
old_phys_addr
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "hw/gpio/bcm2835_gpio.h"
|
||||
#include "hw/timer/bcm2835_systmr.h"
|
||||
#include "hw/usb/hcd-dwc2.h"
|
||||
#include "hw/ssi/bcm2835_spi.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
|
@ -66,7 +67,7 @@ struct BCM2835PeripheralState {
|
|||
BCM2835GpioState gpio;
|
||||
Bcm2835ThermalState thermal;
|
||||
UnimplementedDeviceState i2s;
|
||||
UnimplementedDeviceState spi[1];
|
||||
BCM2835SPIState spi[1];
|
||||
UnimplementedDeviceState i2c[3];
|
||||
UnimplementedDeviceState otp;
|
||||
UnimplementedDeviceState dbus;
|
||||
|
|
|
@ -47,13 +47,10 @@ OBJECT_DECLARE_SIMPLE_TYPE(MSF2State, MSF2_SOC)
|
|||
#define MSF2_NUM_TIMERS 2
|
||||
|
||||
struct MSF2State {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
ARMv7MState armv7m;
|
||||
|
||||
char *cpu_type;
|
||||
char *part_name;
|
||||
uint64_t envm_size;
|
||||
uint64_t esram_size;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "hw/misc/npcm7xx_pwm.h"
|
||||
#include "hw/misc/npcm7xx_rng.h"
|
||||
#include "hw/net/npcm7xx_emc.h"
|
||||
#include "hw/net/npcm_gmac.h"
|
||||
#include "hw/nvram/npcm7xx_otp.h"
|
||||
#include "hw/timer/npcm7xx_timer.h"
|
||||
#include "hw/ssi/npcm7xx_fiu.h"
|
||||
|
@ -104,6 +105,7 @@ struct NPCM7xxState {
|
|||
OHCISysBusState ohci;
|
||||
NPCM7xxFIUState fiu[2];
|
||||
NPCM7xxEMCState emc[2];
|
||||
NPCMGMACState gmac[2];
|
||||
NPCM7xxSDHCIState mmc;
|
||||
NPCMPSPIState pspi[2];
|
||||
};
|
||||
|
|
|
@ -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 */
|
|
@ -329,8 +329,6 @@ struct BusClass {
|
|||
*/
|
||||
char *(*get_fw_dev_path)(DeviceState *dev);
|
||||
|
||||
void (*reset)(BusState *bus);
|
||||
|
||||
/*
|
||||
* Return whether the device can be added to @bus,
|
||||
* based on the address that was set (via device properties)
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -3994,7 +3994,7 @@ ERST
|
|||
|
||||
DEF("initrd", HAS_ARG, QEMU_OPTION_initrd, \
|
||||
"-initrd file use 'file' as initial ram disk\n", QEMU_ARCH_ALL)
|
||||
SRST
|
||||
SRST(initrd)
|
||||
|
||||
``-initrd file``
|
||||
Use file as initial ram disk.
|
||||
|
@ -4129,7 +4129,8 @@ SRST
|
|||
This option can be used several times to simulate up to 4 serial
|
||||
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:
|
||||
|
||||
|
@ -4151,10 +4152,17 @@ SRST
|
|||
[Linux only] Pseudo TTY (a new PTY is automatically allocated)
|
||||
|
||||
``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``
|
||||
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``
|
||||
Use a named character device defined with the ``-chardev``
|
||||
|
|
22
system/vl.c
22
system/vl.c
|
@ -1439,18 +1439,22 @@ static void qemu_create_default_devices(void)
|
|||
static int serial_parse(const char *devname)
|
||||
{
|
||||
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[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;
|
||||
if (strcmp(devname, "none") == 0) {
|
||||
/* Don't allocate a serial device for this index */
|
||||
serial_hds[index] = NULL;
|
||||
} else {
|
||||
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++;
|
||||
return 0;
|
||||
|
|
|
@ -1627,6 +1627,10 @@ void arm_cpu_post_init(Object *obj)
|
|||
}
|
||||
} else if (cpu_isar_feature(aa32_vfp, cpu)) {
|
||||
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)) {
|
||||
cpu->has_vfp_d32 = true;
|
||||
/*
|
||||
|
|
|
@ -8897,6 +8897,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
|||
R_ID_AA64ZFR0_AES_MASK |
|
||||
R_ID_AA64ZFR0_BITPERM_MASK |
|
||||
R_ID_AA64ZFR0_BFLOAT16_MASK |
|
||||
R_ID_AA64ZFR0_B16B16_MASK |
|
||||
R_ID_AA64ZFR0_SHA3_MASK |
|
||||
R_ID_AA64ZFR0_SM4_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) {
|
||||
/* 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);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef TARGET_ARM_SYNDROME_H
|
||||
#define TARGET_ARM_SYNDROME_H
|
||||
|
||||
#include "qemu/bitops.h"
|
||||
|
||||
/* Valid Syndrome Register EC field values */
|
||||
enum arm_exception_class {
|
||||
EC_UNCATEGORIZED = 0x00,
|
||||
|
@ -80,6 +82,7 @@ typedef enum {
|
|||
SME_ET_InactiveZA,
|
||||
} SMEExceptionType;
|
||||
|
||||
#define ARM_EL_EC_LENGTH 6
|
||||
#define ARM_EL_EC_SHIFT 26
|
||||
#define ARM_EL_IL_SHIFT 25
|
||||
#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;
|
||||
}
|
||||
|
||||
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.
|
||||
* Note that in general we follow the AArch64 syndrome values; in a
|
||||
|
|
|
@ -231,6 +231,7 @@ qtests_aarch64 = \
|
|||
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \
|
||||
(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_NPCM7XX') ? qtests_npcm7xx : []) + \
|
||||
['arm-cpu-features',
|
||||
'numa-test',
|
||||
'boot-serial-test',
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -298,10 +298,13 @@ static size_t trng_collect(uint32_t *rnd, size_t cnt)
|
|||
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)
|
||||
{
|
||||
const size_t cnt = 512 / 32;
|
||||
uint32_t rng[cnt], prng[cnt];
|
||||
const size_t cnt = TEST_DATA_WORDS;
|
||||
uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
|
||||
size_t n;
|
||||
|
||||
trng_reset();
|
||||
|
@ -343,8 +346,8 @@ static void trng_test_autogen(void)
|
|||
|
||||
static void trng_test_oneshot(void)
|
||||
{
|
||||
const size_t cnt = 512 / 32;
|
||||
uint32_t rng[cnt];
|
||||
const size_t cnt = TEST_DATA_WORDS;
|
||||
uint32_t rng[TEST_DATA_WORDS];
|
||||
size_t n;
|
||||
|
||||
trng_reset();
|
||||
|
@ -370,8 +373,8 @@ static void trng_test_oneshot(void)
|
|||
|
||||
static void trng_test_per_str(void)
|
||||
{
|
||||
const size_t cnt = 512 / 32;
|
||||
uint32_t rng[cnt], prng[cnt];
|
||||
const size_t cnt = TEST_DATA_WORDS;
|
||||
uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
|
||||
size_t n;
|
||||
|
||||
trng_reset();
|
||||
|
@ -415,8 +418,8 @@ static void trng_test_forced_prng(void)
|
|||
const char *prop = "forced-prng";
|
||||
const uint64_t seed = 0xdeadbeefbad1bad0ULL;
|
||||
|
||||
const size_t cnt = 512 / 32;
|
||||
uint32_t rng[cnt], prng[cnt];
|
||||
const size_t cnt = TEST_DATA_WORDS;
|
||||
uint32_t rng[TEST_DATA_WORDS], prng[TEST_DATA_WORDS];
|
||||
size_t n;
|
||||
|
||||
trng_reset();
|
||||
|
|
|
@ -137,7 +137,7 @@ int main(void)
|
|||
/* 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_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_zero(id_aa64afr0_el1);
|
||||
|
|
Loading…
Reference in New Issue