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

target-arm queue:
 * Handle atomic updates of page tables entries in MMIO during PTW
 * Advertise Cortex-A53 erratum #843419 fix via REVIDR
 * MAINTAINERS: Cover hw/ide/ahci-allwinner.c with AllWinner A10 machine
 * misc: m48t59: replace qemu_system_reset_request() call with watchdog_perform_action()
 * misc: pxa2xx_timer: replace qemu_system_reset_request() call with watchdog_perform_action()
 * xlnx-versal-ospi: disable reentrancy detection for iomem_dac
 * sbsa-ref: Simplify init since PCIe is always enabled
 * stm32l4x5: Use TYPE_OR_IRQ when connecting STM32L4x5 EXTI fan-in IRQs
 * pl031: Update last RTCLR value on write in case it's read back
 * block: m25p80: Add support of mt35xu02gbba
 * xlnx-versal-virt: Add machine property ospi-flash
 * reset: refactor system reset to be three-phase aware
 * new board model raspi4b

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmXeAMEZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3syyD/4lJzzstbDIAsu94Z4Hi0So
# CFLAMJFsPy3fMsU2IqVP+TDTyhUeMPebwfj7sQHUtQcXVh5i1/HlYgdUgXsnjGWQ
# pc6BxycpW6uJWYb7Ma3CdSGS+hxEpQ+U8Qeijwqg0kAqhjNtrSIkTRQ4u8p8T+kN
# dWtQzp7D15BpEVhWl/2dLWWJwV3H6TThmr1FbK5wl/c7hJzy2uaXqmmCvercU0Zo
# 6ab3SnGyhaujdd/FsDvhnVEYqcmcO2p9UtSnGAbdfw0zsf4p8cS2Q6M9q4DHBFYn
# 6Bt51DFP5D+114VpqRSXF2Lv9K8swjTgqhDld9vCoios6pS3LMwcTAcONUxE8JU+
# uD7kXTN/lv3atNEy4MTFkTeNtKgbYJJuPwWrDRNdbVXPwrEHGWN3+ZYISmuYb+p+
# XL2/7HeP7/qEVMW2d18+7OCriZwKiBRZRKUrtG7mQSBZEMetbhpA+mLcxAZT0FAl
# 18O/mcvEJrrE7x6Bqyv96b8PE0/er5cVg/b/wrkKS8DL4NWU9bJSjJNRrvt9bvvl
# jSzPGo4ngHlfO0OpurLoFOZCVxKWVXgaKkQ3pOz301nsDyhEndNLeCxrITac8G2Q
# C/WQuMaeOoV1x7N2MzaCQmyRzy8yGkG9av0aI/8feobfV/Yg4wPsfhcEn/XQWXKv
# NUJ4/z78FbJlI2JeDP2QSA==
# =xaMv
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 27 Feb 2024 15:33:21 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-20240227-1' of https://git.linaro.org/people/pmaydell/qemu-arm: (36 commits)
  docs/system/arm: Add RPi4B to raspi.rst
  hw/misc/bcm2835_property: Add missed BCM2835 properties
  tests/avocado/boot_linux_console.py: Add Rpi4b boot tests
  hw/arm/bcm2838_peripherals: Add clock_isp stub
  hw/arm: Add memory region for BCM2837 RPiVid ASB
  hw/arm/raspi4b: Temporarily disable unimplemented rpi4b devices
  hw/arm: Introduce Raspberry PI 4 machine
  hw/arm: Add GPIO and SD to BCM2838 periph
  hw/gpio: Connect SD controller to BCM2838 GPIO
  hw/gpio: Implement BCM2838 GPIO functionality
  hw/gpio: Add BCM2838 GPIO stub
  hw/arm/bcm2838: Add GIC-400 to BCM2838 SoC
  hw/arm: Introduce BCM2838 SoC
  hw/arm/raspi: Split out raspi machine common part
  hw/arm/bcm2853_peripherals: Split out common part of peripherals
  hw/arm/bcm2836: Split out common part of BCM283X classes
  docs/devel/reset: Update to discuss system reset
  hw/core/machine: Use qemu_register_resettable for sysbus reset
  hw/core/reset: Implement qemu_register_reset via qemu_register_resettable
  hw/core/reset: Add qemu_{register, unregister}_resettable()
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2024-02-27 15:34:41 +00:00
46 changed files with 2503 additions and 305 deletions
+11
View File
@@ -642,6 +642,7 @@ R: Strahinja Jankovic <strahinja.p.jankovic@gmail.com>
L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/*/allwinner*
F: hw/ide/ahci-allwinner.c
F: include/hw/*/allwinner*
F: hw/arm/cubieboard.c
F: docs/system/arm/cubieboard.rst
@@ -3675,6 +3676,16 @@ F: hw/core/clock-vmstate.c
F: hw/core/qdev-clock.c
F: docs/devel/clocks.rst
Reset framework
M: Peter Maydell <peter.maydell@linaro.org>
S: Maintained
F: include/hw/resettable.h
F: include/hw/core/resetcontainer.h
F: include/sysemu/reset.h
F: hw/core/reset.c
F: hw/core/resettable.c
F: hw/core/resetcontainer.c
Usermode Emulation
------------------
Overall usermode emulation
+29 -5
View File
@@ -348,12 +348,14 @@ used. This does the same as OBJECT_DECLARE_SIMPLE_TYPE(), but without
the 'struct MyDeviceClass' definition.
To implement the type, the OBJECT_DEFINE macro family is available.
In the simple case the OBJECT_DEFINE_TYPE macro is suitable:
For the simplest case of a leaf class which doesn't need any of its
own virtual functions (i.e. which was declared with OBJECT_DECLARE_SIMPLE_TYPE)
the OBJECT_DEFINE_SIMPLE_TYPE macro is suitable:
.. code-block:: c
:caption: Defining a simple type
OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
OBJECT_DEFINE_SIMPLE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
This is equivalent to the following:
@@ -370,7 +372,6 @@ This is equivalent to the following:
.instance_size = sizeof(MyDevice),
.instance_init = my_device_init,
.instance_finalize = my_device_finalize,
.class_size = sizeof(MyDeviceClass),
.class_init = my_device_class_init,
};
@@ -385,13 +386,36 @@ This is sufficient to get the type registered with the type
system, and the three standard methods now need to be implemented
along with any other logic required for the type.
If the class needs its own virtual methods, or has some other
per-class state it needs to store in its own class struct,
then you can use the OBJECT_DEFINE_TYPE macro. This does the
same thing as OBJECT_DEFINE_SIMPLE_TYPE, but it also sets the
class_size of the type to the size of the class struct.
.. code-block:: c
:caption: Defining a type which needs a class struct
OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
If the type needs to implement one or more interfaces, then the
OBJECT_DEFINE_TYPE_WITH_INTERFACES() macro can be used instead.
This accepts an array of interface type names.
OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES() and
OBJECT_DEFINE_TYPE_WITH_INTERFACES() macros can be used instead.
These accept an array of interface type names. The difference between
them is that the former is for simple leaf classes that don't need
a class struct, and the latter is for when you will be defining
a class struct.
.. code-block:: c
:caption: Defining a simple type implementing interfaces
OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(MyDevice, my_device,
MY_DEVICE, DEVICE,
{ TYPE_USER_CREATABLE },
{ NULL })
.. code-block:: c
:caption: Defining a type implementing interfaces
OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device,
MY_DEVICE, DEVICE,
{ TYPE_USER_CREATABLE },
+42 -2
View File
@@ -11,8 +11,8 @@ whole group can be reset consistently. Each individual member object does not
have to care about others; in particular, problems of order (which object is
reset first) are addressed.
As of now DeviceClass and BusClass implement this interface.
The main object types which implement this interface are DeviceClass
and BusClass.
Triggering reset
----------------
@@ -288,3 +288,43 @@ There is currently 2 cases where this function is used:
2. *hot bus change*; it means an existing live device is added, moved or
removed in the bus hierarchy. At the moment, it occurs only in the raspi
machines for changing the sdbus used by sd card.
Reset of the complete system
----------------------------
Reset of the complete system is a little complicated. The typical
flow is:
1. Code which wishes to reset the entire system does so by calling
``qemu_system_reset_request()``. This schedules a reset, but the
reset will happen asynchronously after the function returns.
That makes this safe to call from, for example, device models.
2. The function which is called to make the reset happen is
``qemu_system_reset()``. Generally only core system code should
call this directly.
3. ``qemu_system_reset()`` calls the ``MachineClass::reset`` method of
the current machine, if it has one. That method must call
``qemu_devices_reset()``. If the machine has no reset method,
``qemu_system_reset()`` calls ``qemu_devices_reset()`` directly.
4. ``qemu_devices_reset()`` performs a reset of the system, using
the three-phase mechanism listed above. It resets all objects
that were registered with it using ``qemu_register_resettable()``.
It also calls all the functions registered with it using
``qemu_register_reset()``. Those functions are called during the
"hold" phase of this reset.
5. The most important object that this reset resets is the
'sysbus' bus. The sysbus bus is the root of the qbus tree. This
means that all devices on the sysbus are reset, and all their
child buses, and all the devices on those child buses.
6. Devices which are not on the qbus tree are *not* automatically
reset! (The most obvious example of this is CPU objects, but
anything that directly inherits from ``TYPE_OBJECT`` or ``TYPE_DEVICE``
rather than from ``TYPE_SYS_BUS_DEVICE`` or some other plugs-into-a-bus
type will be in this category.) You need to therefore arrange for these
to be reset in some other way (e.g. using ``qemu_register_resettable()``
or ``qemu_register_reset()``).
+7 -5
View File
@@ -1,5 +1,5 @@
Raspberry Pi boards (``raspi0``, ``raspi1ap``, ``raspi2b``, ``raspi3ap``, ``raspi3b``)
======================================================================================
Raspberry Pi boards (``raspi0``, ``raspi1ap``, ``raspi2b``, ``raspi3ap``, ``raspi3b``, ``raspi4b``)
===================================================================================================
QEMU provides models of the following Raspberry Pi boards:
@@ -12,12 +12,13 @@ QEMU provides models of the following Raspberry Pi boards:
Cortex-A53 (4 cores), 512 MiB of RAM
``raspi3b``
Cortex-A53 (4 cores), 1 GiB of RAM
``raspi4b``
Cortex-A72 (4 cores), 2 GiB of RAM
Implemented devices
-------------------
* ARM1176JZF-S, Cortex-A7 or Cortex-A53 CPU
* ARM1176JZF-S, Cortex-A7, Cortex-A53 or Cortex-A72 CPU
* Interrupt controller
* DMA controller
* Clock and reset controller (CPRMAN)
@@ -35,9 +36,10 @@ Implemented devices
* VideoCore firmware (property)
* Peripheral SPI controller (SPI)
Missing devices
---------------
* Analog to Digital Converter (ADC)
* Pulse Width Modulation (PWM)
* PCIE Root Port (raspi4b)
* GENET Ethernet Controller (raspi4b)
+128 -87
View File
@@ -30,9 +30,9 @@
#define SEPARATE_DMA_IRQ_MAX 10
#define ORGATED_DMA_IRQ_COUNT 4
static void create_unimp(BCM2835PeripheralState *ps,
UnimplementedDeviceState *uds,
const char *name, hwaddr ofs, hwaddr size)
void create_unimp(BCMSocPeripheralBaseState *ps,
UnimplementedDeviceState *uds,
const char *name, hwaddr ofs, hwaddr size)
{
object_initialize_child(OBJECT(ps), name, uds, TYPE_UNIMPLEMENTED_DEVICE);
qdev_prop_set_string(DEVICE(uds), "name", name);
@@ -45,9 +45,36 @@ static void create_unimp(BCM2835PeripheralState *ps,
static void bcm2835_peripherals_init(Object *obj)
{
BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj);
BCMSocPeripheralBaseState *s_base = BCM_SOC_PERIPHERALS_BASE(obj);
/* Random Number Generator */
object_initialize_child(obj, "rng", &s->rng, TYPE_BCM2835_RNG);
/* Thermal */
object_initialize_child(obj, "thermal", &s->thermal, TYPE_BCM2835_THERMAL);
/* GPIO */
object_initialize_child(obj, "gpio", &s->gpio, TYPE_BCM2835_GPIO);
object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhci",
OBJECT(&s_base->sdhci.sdbus));
object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost",
OBJECT(&s_base->sdhost.sdbus));
/* Gated DMA interrupts */
object_initialize_child(obj, "orgated-dma-irq",
&s_base->orgated_dma_irq, TYPE_OR_IRQ);
object_property_set_int(OBJECT(&s_base->orgated_dma_irq), "num-lines",
ORGATED_DMA_IRQ_COUNT, &error_abort);
}
static void raspi_peripherals_base_init(Object *obj)
{
BCMSocPeripheralBaseState *s = BCM_SOC_PERIPHERALS_BASE(obj);
BCMSocPeripheralBaseClass *bc = BCM_SOC_PERIPHERALS_BASE_GET_CLASS(obj);
/* Memory region for peripheral devices, which we export to our parent */
memory_region_init(&s->peri_mr, obj,"bcm2835-peripherals", 0x1000000);
memory_region_init(&s->peri_mr, obj, "bcm2835-peripherals", bc->peri_size);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_mr);
/* Internal memory region for peripheral bus addresses (not exported) */
@@ -81,6 +108,7 @@ static void bcm2835_peripherals_init(Object *obj)
/* Framebuffer */
object_initialize_child(obj, "fb", &s->fb, TYPE_BCM2835_FB);
object_property_add_alias(obj, "vcram-size", OBJECT(&s->fb), "vcram-size");
object_property_add_alias(obj, "vcram-base", OBJECT(&s->fb), "vcram-base");
object_property_add_const_link(OBJECT(&s->fb), "dma-mr",
OBJECT(&s->gpu_bus_mr));
@@ -98,9 +126,6 @@ static void bcm2835_peripherals_init(Object *obj)
object_property_add_const_link(OBJECT(&s->property), "dma-mr",
OBJECT(&s->gpu_bus_mr));
/* Random Number Generator */
object_initialize_child(obj, "rng", &s->rng, TYPE_BCM2835_RNG);
/* Extended Mass Media Controller */
object_initialize_child(obj, "sdhci", &s->sdhci, TYPE_SYSBUS_SDHCI);
@@ -110,25 +135,9 @@ static void bcm2835_peripherals_init(Object *obj)
/* DMA Channels */
object_initialize_child(obj, "dma", &s->dma, TYPE_BCM2835_DMA);
object_initialize_child(obj, "orgated-dma-irq",
&s->orgated_dma_irq, TYPE_OR_IRQ);
object_property_set_int(OBJECT(&s->orgated_dma_irq), "num-lines",
ORGATED_DMA_IRQ_COUNT, &error_abort);
object_property_add_const_link(OBJECT(&s->dma), "dma-mr",
OBJECT(&s->gpu_bus_mr));
/* Thermal */
object_initialize_child(obj, "thermal", &s->thermal, TYPE_BCM2835_THERMAL);
/* GPIO */
object_initialize_child(obj, "gpio", &s->gpio, TYPE_BCM2835_GPIO);
object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhci",
OBJECT(&s->sdhci.sdbus));
object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost",
OBJECT(&s->sdhost.sdbus));
/* Mphi */
object_initialize_child(obj, "mphi", &s->mphi, TYPE_BCM2835_MPHI);
@@ -152,11 +161,76 @@ static void bcm2835_peripherals_init(Object *obj)
static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
{
MemoryRegion *mphi_mr;
BCM2835PeripheralState *s = BCM2835_PERIPHERALS(dev);
BCMSocPeripheralBaseState *s_base = BCM_SOC_PERIPHERALS_BASE(dev);
int n;
bcm_soc_peripherals_common_realize(dev, errp);
/* Extended Mass Media Controller */
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->sdhci), 0,
qdev_get_gpio_in_named(DEVICE(&s_base->ic), BCM2835_IC_GPU_IRQ,
INTERRUPT_ARASANSDIO));
/* Connect DMA 0-12 to the interrupt controller */
for (n = 0; n <= SEPARATE_DMA_IRQ_MAX; n++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->dma), n,
qdev_get_gpio_in_named(DEVICE(&s_base->ic),
BCM2835_IC_GPU_IRQ,
INTERRUPT_DMA0 + n));
}
if (!qdev_realize(DEVICE(&s_base->orgated_dma_irq), NULL, errp)) {
return;
}
for (n = 0; n < ORGATED_DMA_IRQ_COUNT; n++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->dma),
SEPARATE_DMA_IRQ_MAX + 1 + n,
qdev_get_gpio_in(DEVICE(&s_base->orgated_dma_irq), n));
}
qdev_connect_gpio_out(DEVICE(&s_base->orgated_dma_irq), 0,
qdev_get_gpio_in_named(DEVICE(&s_base->ic),
BCM2835_IC_GPU_IRQ,
INTERRUPT_DMA0 + SEPARATE_DMA_IRQ_MAX + 1));
/* Random Number Generator */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->rng), errp)) {
return;
}
memory_region_add_subregion(
&s_base->peri_mr, RNG_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rng), 0));
/* THERMAL */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->thermal), errp)) {
return;
}
memory_region_add_subregion(&s_base->peri_mr, THERMAL_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->thermal), 0));
/* Map MPHI to the peripherals memory map */
mphi_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s_base->mphi), 0);
memory_region_add_subregion(&s_base->peri_mr, MPHI_OFFSET, mphi_mr);
/* GPIO */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
return;
}
memory_region_add_subregion(
&s_base->peri_mr, GPIO_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0));
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus");
}
void bcm_soc_peripherals_common_realize(DeviceState *dev, Error **errp)
{
BCMSocPeripheralBaseState *s = BCM_SOC_PERIPHERALS_BASE(dev);
Object *obj;
MemoryRegion *ram;
Error *err = NULL;
uint64_t ram_size, vcram_size;
uint64_t ram_size, vcram_size, vcram_base;
int n;
obj = object_property_get_link(OBJECT(dev), "ram", &error_abort);
@@ -260,11 +334,21 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
return;
}
if (!object_property_set_uint(OBJECT(&s->fb), "vcram-base",
ram_size - vcram_size, errp)) {
vcram_base = object_property_get_uint(OBJECT(s), "vcram-base", &err);
if (err) {
error_propagate(errp, err);
return;
}
if (vcram_base == 0) {
vcram_base = ram_size - vcram_size;
}
vcram_base = MIN(vcram_base, UPPER_RAM_BASE - vcram_size);
if (!object_property_set_uint(OBJECT(&s->fb), "vcram-base", vcram_base,
errp)) {
return;
}
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fb), errp)) {
return;
}
@@ -285,14 +369,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->property), 0,
qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY));
/* Random Number Generator */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->rng), errp)) {
return;
}
memory_region_add_subregion(&s->peri_mr, RNG_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rng), 0));
/* Extended Mass Media Controller
*
* Compatible with:
@@ -315,9 +391,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->peri_mr, EMMC1_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sdhci), 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
INTERRUPT_ARASANSDIO));
/* SDHOST */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhost), errp)) {
@@ -340,49 +413,11 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->peri_mr, DMA15_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dma), 1));
for (n = 0; n <= SEPARATE_DMA_IRQ_MAX; n++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), n,
qdev_get_gpio_in_named(DEVICE(&s->ic),
BCM2835_IC_GPU_IRQ,
INTERRUPT_DMA0 + n));
}
if (!qdev_realize(DEVICE(&s->orgated_dma_irq), NULL, errp)) {
return;
}
for (n = 0; n < ORGATED_DMA_IRQ_COUNT; n++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma),
SEPARATE_DMA_IRQ_MAX + 1 + n,
qdev_get_gpio_in(DEVICE(&s->orgated_dma_irq), n));
}
qdev_connect_gpio_out(DEVICE(&s->orgated_dma_irq), 0,
qdev_get_gpio_in_named(DEVICE(&s->ic),
BCM2835_IC_GPU_IRQ,
INTERRUPT_DMA0 + SEPARATE_DMA_IRQ_MAX + 1));
/* THERMAL */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->thermal), errp)) {
return;
}
memory_region_add_subregion(&s->peri_mr, THERMAL_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->thermal), 0));
/* GPIO */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
return;
}
memory_region_add_subregion(&s->peri_mr, GPIO_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0));
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus");
/* Mphi */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->mphi), errp)) {
return;
}
memory_region_add_subregion(&s->peri_mr, MPHI_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mphi), 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->mphi), 0,
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ,
INTERRUPT_HOSTPORT));
@@ -436,21 +471,27 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCMSocPeripheralBaseClass *bc = BCM_SOC_PERIPHERALS_BASE_CLASS(oc);
bc->peri_size = 0x1000000;
dc->realize = bcm2835_peripherals_realize;
}
static const TypeInfo bcm2835_peripherals_type_info = {
.name = TYPE_BCM2835_PERIPHERALS,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(BCM2835PeripheralState),
.instance_init = bcm2835_peripherals_init,
.class_init = bcm2835_peripherals_class_init,
static const TypeInfo bcm2835_peripherals_types[] = {
{
.name = TYPE_BCM2835_PERIPHERALS,
.parent = TYPE_BCM_SOC_PERIPHERALS_BASE,
.instance_size = sizeof(BCM2835PeripheralState),
.instance_init = bcm2835_peripherals_init,
.class_init = bcm2835_peripherals_class_init,
}, {
.name = TYPE_BCM_SOC_PERIPHERALS_BASE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(BCMSocPeripheralBaseState),
.instance_init = raspi_peripherals_base_init,
.class_size = sizeof(BCMSocPeripheralBaseClass),
.abstract = true,
}
};
static void bcm2835_peripherals_register_types(void)
{
type_register_static(&bcm2835_peripherals_type_info);
}
type_init(bcm2835_peripherals_register_types)
DEFINE_TYPES(bcm2835_peripherals_types)
+68 -49
View File
@@ -31,12 +31,12 @@ struct BCM283XClass {
};
static Property bcm2836_enabled_cores_property =
DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 0);
DEFINE_PROP_UINT32("enabled-cpus", BCM283XBaseState, enabled_cpus, 0);
static void bcm2836_init(Object *obj)
static void bcm283x_base_init(Object *obj)
{
BCM283XState *s = BCM283X(obj);
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
BCM283XBaseState *s = BCM283X_BASE(obj);
BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(obj);
int n;
for (n = 0; n < bc->core_count; n++) {
@@ -52,6 +52,11 @@ static void bcm2836_init(Object *obj)
object_initialize_child(obj, "control", &s->control,
TYPE_BCM2836_CONTROL);
}
}
static void bcm283x_init(Object *obj)
{
BCM283XState *s = BCM283X(obj);
object_initialize_child(obj, "peripherals", &s->peripherals,
TYPE_BCM2835_PERIPHERALS);
@@ -61,108 +66,116 @@ static void bcm2836_init(Object *obj)
"command-line");
object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
"vcram-size");
object_property_add_alias(obj, "vcram-base", OBJECT(&s->peripherals),
"vcram-base");
}
static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
bool bcm283x_common_realize(DeviceState *dev, BCMSocPeripheralBaseState *ps,
Error **errp)
{
BCM283XState *s = BCM283X(dev);
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
BCM283XBaseState *s = BCM283X_BASE(dev);
BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(dev);
Object *obj;
/* common peripherals from bcm2835 */
obj = object_property_get_link(OBJECT(dev), "ram", &error_abort);
object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj);
object_property_add_const_link(OBJECT(ps), "ram", obj);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), errp)) {
if (!sysbus_realize(SYS_BUS_DEVICE(ps), errp)) {
return false;
}
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
"sd-bus");
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(ps), "sd-bus");
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
bc->peri_base, 1);
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(ps), 0, bc->peri_base, 1);
return true;
}
static void bcm2835_realize(DeviceState *dev, Error **errp)
{
BCM283XState *s = BCM283X(dev);
BCM283XBaseState *s_base = BCM283X_BASE(dev);
BCMSocPeripheralBaseState *ps_base
= BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
if (!bcm283x_common_realize(dev, errp)) {
if (!bcm283x_common_realize(dev, ps_base, errp)) {
return;
}
if (!qdev_realize(DEVICE(&s->cpu[0].core), NULL, errp)) {
if (!qdev_realize(DEVICE(&s_base->cpu[0].core), NULL, errp)) {
return;
}
/* Connect irq/fiq outputs from the interrupt controller. */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_IRQ));
qdev_get_gpio_in(DEVICE(&s_base->cpu[0].core), ARM_CPU_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_FIQ));
qdev_get_gpio_in(DEVICE(&s_base->cpu[0].core), ARM_CPU_FIQ));
}
static void bcm2836_realize(DeviceState *dev, Error **errp)
{
BCM283XState *s = BCM283X(dev);
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
int n;
BCM283XState *s = BCM283X(dev);
BCM283XBaseState *s_base = BCM283X_BASE(dev);
BCM283XBaseClass *bc = BCM283X_BASE_GET_CLASS(dev);
BCMSocPeripheralBaseState *ps_base
= BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
if (!bcm283x_common_realize(dev, errp)) {
if (!bcm283x_common_realize(dev, ps_base, errp)) {
return;
}
/* bcm2836 interrupt controller (and mailboxes, etc.) */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
if (!sysbus_realize(SYS_BUS_DEVICE(&s_base->control), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, bc->ctrl_base);
sysbus_mmio_map(SYS_BUS_DEVICE(&s_base->control), 0, bc->ctrl_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
qdev_get_gpio_in_named(DEVICE(&s_base->control), "gpu-irq", 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
qdev_get_gpio_in_named(DEVICE(&s_base->control), "gpu-fiq", 0));
for (n = 0; n < BCM283X_NCPUS; n++) {
object_property_set_int(OBJECT(&s->cpu[n].core), "mp-affinity",
object_property_set_int(OBJECT(&s_base->cpu[n].core), "mp-affinity",
(bc->clusterid << 8) | n, &error_abort);
/* set periphbase/CBAR value for CPU-local registers */
object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar",
object_property_set_int(OBJECT(&s_base->cpu[n].core), "reset-cbar",
bc->peri_base, &error_abort);
/* start powered off if not enabled */
object_property_set_bool(OBJECT(&s->cpu[n].core), "start-powered-off",
n >= s->enabled_cpus, &error_abort);
object_property_set_bool(OBJECT(&s_base->cpu[n].core),
"start-powered-off",
n >= s_base->enabled_cpus, &error_abort);
if (!qdev_realize(DEVICE(&s->cpu[n].core), NULL, errp)) {
if (!qdev_realize(DEVICE(&s_base->cpu[n].core), NULL, errp)) {
return;
}
/* Connect irq/fiq outputs from the interrupt controller. */
qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_IRQ));
qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n,
qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_FIQ));
qdev_connect_gpio_out_named(DEVICE(&s_base->control), "irq", n,
qdev_get_gpio_in(DEVICE(&s_base->cpu[n].core), ARM_CPU_IRQ));
qdev_connect_gpio_out_named(DEVICE(&s_base->control), "fiq", n,
qdev_get_gpio_in(DEVICE(&s_base->cpu[n].core), ARM_CPU_FIQ));
/* Connect timers from the CPU to the interrupt controller */
qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_PHYS,
qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n));
qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_VIRT,
qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n));
qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_HYP,
qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n));
qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_SEC,
qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n));
qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_PHYS,
qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntpnsirq", n));
qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_VIRT,
qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntvirq", n));
qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_HYP,
qdev_get_gpio_in_named(DEVICE(&s_base->control), "cnthpirq", n));
qdev_connect_gpio_out(DEVICE(&s_base->cpu[n].core), GTIMER_SEC,
qdev_get_gpio_in_named(DEVICE(&s_base->control), "cntpsirq", n));
}
}
static void bcm283x_class_init(ObjectClass *oc, void *data)
static void bcm283x_base_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -173,7 +186,7 @@ static void bcm283x_class_init(ObjectClass *oc, void *data)
static void bcm2835_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XClass *bc = BCM283X_CLASS(oc);
BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
bc->core_count = 1;
@@ -184,7 +197,7 @@ static void bcm2835_class_init(ObjectClass *oc, void *data)
static void bcm2836_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XClass *bc = BCM283X_CLASS(oc);
BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
bc->core_count = BCM283X_NCPUS;
@@ -198,7 +211,7 @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
static void bcm2837_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XClass *bc = BCM283X_CLASS(oc);
BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc);
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
bc->core_count = BCM283X_NCPUS;
@@ -226,11 +239,17 @@ static const TypeInfo bcm283x_types[] = {
#endif
}, {
.name = TYPE_BCM283X,
.parent = TYPE_DEVICE,
.parent = TYPE_BCM283X_BASE,
.instance_size = sizeof(BCM283XState),
.instance_init = bcm2836_init,
.class_size = sizeof(BCM283XClass),
.class_init = bcm283x_class_init,
.instance_init = bcm283x_init,
.abstract = true,
}, {
.name = TYPE_BCM283X_BASE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(BCM283XBaseState),
.instance_init = bcm283x_base_init,
.class_size = sizeof(BCM283XBaseClass),
.class_init = bcm283x_base_class_init,
.abstract = true,
}
};
+263
View File
@@ -0,0 +1,263 @@
/*
* BCM2838 SoC emulation
*
* Copyright (C) 2022 Ovchinnikov Vitalii <vitalii.ovchinnikov@auriga.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "hw/arm/raspi_platform.h"
#include "hw/sysbus.h"
#include "hw/arm/bcm2838.h"
#include "trace.h"
#define GIC400_MAINTENANCE_IRQ 9
#define GIC400_TIMER_NS_EL2_IRQ 10
#define GIC400_TIMER_VIRT_IRQ 11
#define GIC400_LEGACY_FIQ 12
#define GIC400_TIMER_S_EL1_IRQ 13
#define GIC400_TIMER_NS_EL1_IRQ 14
#define GIC400_LEGACY_IRQ 15
/* Number of external interrupt lines to configure the GIC with */
#define GIC_NUM_IRQS 192
#define PPI(cpu, irq) (GIC_NUM_IRQS + (cpu) * GIC_INTERNAL + GIC_NR_SGIS + irq)
#define GIC_BASE_OFS 0x0000
#define GIC_DIST_OFS 0x1000
#define GIC_CPU_OFS 0x2000
#define GIC_VIFACE_THIS_OFS 0x4000
#define GIC_VIFACE_OTHER_OFS(cpu) (0x5000 + (cpu) * 0x200)
#define GIC_VCPU_OFS 0x6000
#define VIRTUAL_PMU_IRQ 7
static void bcm2838_gic_set_irq(void *opaque, int irq, int level)
{
BCM2838State *s = (BCM2838State *)opaque;
trace_bcm2838_gic_set_irq(irq, level);
qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
}
static void bcm2838_init(Object *obj)
{
BCM2838State *s = BCM2838(obj);
object_initialize_child(obj, "peripherals", &s->peripherals,
TYPE_BCM2838_PERIPHERALS);
object_property_add_alias(obj, "board-rev", OBJECT(&s->peripherals),
"board-rev");
object_property_add_alias(obj, "vcram-size", OBJECT(&s->peripherals),
"vcram-size");
object_property_add_alias(obj, "vcram-base", OBJECT(&s->peripherals),
"vcram-base");
object_property_add_alias(obj, "command-line", OBJECT(&s->peripherals),
"command-line");
object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC);
}
static void bcm2838_realize(DeviceState *dev, Error **errp)
{
BCM2838State *s = BCM2838(dev);
BCM283XBaseState *s_base = BCM283X_BASE(dev);
BCM283XBaseClass *bc_base = BCM283X_BASE_GET_CLASS(dev);
BCM2838PeripheralState *ps = BCM2838_PERIPHERALS(&s->peripherals);
BCMSocPeripheralBaseState *ps_base =
BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
DeviceState *gicdev = NULL;
if (!bcm283x_common_realize(dev, ps_base, errp)) {
return;
}
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(ps), 1, BCM2838_PERI_LOW_BASE, 1);
/* bcm2836 interrupt controller (and mailboxes, etc.) */
if (!sysbus_realize(SYS_BUS_DEVICE(&s_base->control), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s_base->control), 0, bc_base->ctrl_base);
/* Create cores */
for (int n = 0; n < bc_base->core_count; n++) {
object_property_set_int(OBJECT(&s_base->cpu[n].core), "mp-affinity",
(bc_base->clusterid << 8) | n, &error_abort);
/* set periphbase/CBAR value for CPU-local registers */
object_property_set_int(OBJECT(&s_base->cpu[n].core), "reset-cbar",
bc_base->peri_base, &error_abort);
/* start powered off if not enabled */
object_property_set_bool(OBJECT(&s_base->cpu[n].core),
"start-powered-off",
n >= s_base->enabled_cpus, &error_abort);
if (!qdev_realize(DEVICE(&s_base->cpu[n].core), NULL, errp)) {
return;
}
}
if (!object_property_set_uint(OBJECT(&s->gic), "revision", 2, errp)) {
return;
}
if (!object_property_set_uint(OBJECT(&s->gic), "num-cpu", BCM283X_NCPUS,
errp)) {
return;
}
if (!object_property_set_uint(OBJECT(&s->gic), "num-irq",
GIC_NUM_IRQS + GIC_INTERNAL, errp)) {
return;
}
if (!object_property_set_bool(OBJECT(&s->gic),
"has-virtualization-extensions", true,
errp)) {
return;
}
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0,
bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_DIST_OFS);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1,
bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_CPU_OFS);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 2,
bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_VIFACE_THIS_OFS);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 3,
bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_VCPU_OFS);
for (int n = 0; n < BCM283X_NCPUS; n++) {
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 4 + n,
bc_base->ctrl_base + BCM2838_GIC_BASE
+ GIC_VIFACE_OTHER_OFS(n));
}
gicdev = DEVICE(&s->gic);
for (int n = 0; n < BCM283X_NCPUS; n++) {
DeviceState *cpudev = DEVICE(&s_base->cpu[n]);
/* Connect the GICv2 outputs to the CPU */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n,
qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + BCM283X_NCPUS,
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + 2 * BCM283X_NCPUS,
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + 3 * BCM283X_NCPUS,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), n + 4 * BCM283X_NCPUS,
qdev_get_gpio_in(gicdev,
PPI(n, GIC400_MAINTENANCE_IRQ)));
/* Connect timers from the CPU to the interrupt controller */
qdev_connect_gpio_out(cpudev, GTIMER_PHYS,
qdev_get_gpio_in(gicdev, PPI(n, GIC400_TIMER_NS_EL1_IRQ)));
qdev_connect_gpio_out(cpudev, GTIMER_VIRT,
qdev_get_gpio_in(gicdev, PPI(n, GIC400_TIMER_VIRT_IRQ)));
qdev_connect_gpio_out(cpudev, GTIMER_HYP,
qdev_get_gpio_in(gicdev, PPI(n, GIC400_TIMER_NS_EL2_IRQ)));
qdev_connect_gpio_out(cpudev, GTIMER_SEC,
qdev_get_gpio_in(gicdev, PPI(n, GIC400_TIMER_S_EL1_IRQ)));
/* PMU interrupt */
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
qdev_get_gpio_in(gicdev, PPI(n, VIRTUAL_PMU_IRQ)));
}
/* Connect UART0 to the interrupt controller */
sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->uart0), 0,
qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_UART0));
/* Connect AUX / UART1 to the interrupt controller */
sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->aux), 0,
qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_AUX_UART1));
/* Connect VC mailbox to the interrupt controller */
sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->mboxes), 0,
qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_MBOX));
/* Connect SD host to the interrupt controller */
sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->sdhost), 0,
qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_SDHOST));
/* According to DTS, EMMC and EMMC2 share one irq */
DeviceState *mmc_irq_orgate = DEVICE(&ps->mmc_irq_orgate);
/* Connect EMMC and EMMC2 to the interrupt controller */
qdev_connect_gpio_out(mmc_irq_orgate, 0,
qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_EMMC_EMMC2));
/* Connect USB OTG and MPHI to the interrupt controller */
sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->mphi), 0,
qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_MPHI));
sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->dwc2), 0,
qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_DWC2));
/* Connect DMA 0-6 to the interrupt controller */
for (int n = GIC_SPI_INTERRUPT_DMA_0; n <= GIC_SPI_INTERRUPT_DMA_6; n++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&ps_base->dma),
n - GIC_SPI_INTERRUPT_DMA_0,
qdev_get_gpio_in(gicdev, n));
}
/* According to DTS, DMA 7 and 8 share one irq */
DeviceState *dma_7_8_irq_orgate = DEVICE(&ps->dma_7_8_irq_orgate);
/* Connect DMA 7-8 to the interrupt controller */
qdev_connect_gpio_out(dma_7_8_irq_orgate, 0,
qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_DMA_7_8));
/* According to DTS, DMA 9 and 10 share one irq */
DeviceState *dma_9_10_irq_orgate = DEVICE(&ps->dma_9_10_irq_orgate);
/* Connect DMA 9-10 to the interrupt controller */
qdev_connect_gpio_out(dma_9_10_irq_orgate, 0,
qdev_get_gpio_in(gicdev, GIC_SPI_INTERRUPT_DMA_9_10));
/* Pass through inbound GPIO lines to the GIC */
qdev_init_gpio_in(dev, bcm2838_gic_set_irq, GIC_NUM_IRQS);
/* Pass through outbound IRQ lines from the GIC */
qdev_pass_gpios(DEVICE(&s->gic), DEVICE(&s->peripherals), NULL);
}
static void bcm2838_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XBaseClass *bc_base = BCM283X_BASE_CLASS(oc);
bc_base->cpu_type = ARM_CPU_TYPE_NAME("cortex-a72");
bc_base->core_count = BCM283X_NCPUS;
bc_base->peri_base = 0xfe000000;
bc_base->ctrl_base = 0xff800000;
bc_base->clusterid = 0x0;
dc->realize = bcm2838_realize;
}
static const TypeInfo bcm2838_type = {
.name = TYPE_BCM2838,
.parent = TYPE_BCM283X_BASE,
.instance_size = sizeof(BCM2838State),
.instance_init = bcm2838_init,
.class_size = sizeof(BCM283XBaseClass),
.class_init = bcm2838_class_init,
};
static void bcm2838_register_types(void)
{
type_register_static(&bcm2838_type);
}
type_init(bcm2838_register_types);
+224
View File
@@ -0,0 +1,224 @@
/*
* BCM2838 peripherals emulation
*
* Copyright (C) 2022 Ovchinnikov Vitalii <vitalii.ovchinnikov@auriga.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "hw/arm/raspi_platform.h"
#include "hw/arm/bcm2838_peripherals.h"
#define CLOCK_ISP_OFFSET 0xc11000
#define CLOCK_ISP_SIZE 0x100
/* Lower peripheral base address on the VC (GPU) system bus */
#define BCM2838_VC_PERI_LOW_BASE 0x7c000000
/* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */
#define BCM2835_SDHC_CAPAREG 0x52134b4
static void bcm2838_peripherals_init(Object *obj)
{
BCM2838PeripheralState *s = BCM2838_PERIPHERALS(obj);
BCM2838PeripheralClass *bc = BCM2838_PERIPHERALS_GET_CLASS(obj);
BCMSocPeripheralBaseState *s_base = BCM_SOC_PERIPHERALS_BASE(obj);
/* Lower memory region for peripheral devices (exported to the Soc) */
memory_region_init(&s->peri_low_mr, obj, "bcm2838-peripherals",
bc->peri_low_size);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->peri_low_mr);
/* Extended Mass Media Controller 2 */
object_initialize_child(obj, "emmc2", &s->emmc2, TYPE_SYSBUS_SDHCI);
/* GPIO */
object_initialize_child(obj, "gpio", &s->gpio, TYPE_BCM2838_GPIO);
object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhci",
OBJECT(&s_base->sdhci.sdbus));
object_property_add_const_link(OBJECT(&s->gpio), "sdbus-sdhost",
OBJECT(&s_base->sdhost.sdbus));
object_initialize_child(obj, "mmc_irq_orgate", &s->mmc_irq_orgate,
TYPE_OR_IRQ);
object_property_set_int(OBJECT(&s->mmc_irq_orgate), "num-lines", 2,
&error_abort);
object_initialize_child(obj, "dma_7_8_irq_orgate", &s->dma_7_8_irq_orgate,
TYPE_OR_IRQ);
object_property_set_int(OBJECT(&s->dma_7_8_irq_orgate), "num-lines", 2,
&error_abort);
object_initialize_child(obj, "dma_9_10_irq_orgate", &s->dma_9_10_irq_orgate,
TYPE_OR_IRQ);
object_property_set_int(OBJECT(&s->dma_9_10_irq_orgate), "num-lines", 2,
&error_abort);
}
static void bcm2838_peripherals_realize(DeviceState *dev, Error **errp)
{
DeviceState *mmc_irq_orgate;
DeviceState *dma_7_8_irq_orgate;
DeviceState *dma_9_10_irq_orgate;
MemoryRegion *mphi_mr;
BCM2838PeripheralState *s = BCM2838_PERIPHERALS(dev);
BCMSocPeripheralBaseState *s_base = BCM_SOC_PERIPHERALS_BASE(dev);
int n;
bcm_soc_peripherals_common_realize(dev, errp);
/* Map lower peripherals into the GPU address space */
memory_region_init_alias(&s->peri_low_mr_alias, OBJECT(s),
"bcm2838-peripherals", &s->peri_low_mr, 0,
memory_region_size(&s->peri_low_mr));
memory_region_add_subregion_overlap(&s_base->gpu_bus_mr,
BCM2838_VC_PERI_LOW_BASE,
&s->peri_low_mr_alias, 1);
/* Extended Mass Media Controller 2 */
object_property_set_uint(OBJECT(&s->emmc2), "sd-spec-version", 3,
&error_abort);
object_property_set_uint(OBJECT(&s->emmc2), "capareg",
BCM2835_SDHC_CAPAREG, &error_abort);
object_property_set_bool(OBJECT(&s->emmc2), "pending-insert-quirk", true,
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc2), errp)) {
return;
}
memory_region_add_subregion(&s_base->peri_mr, EMMC2_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->emmc2),
0));
/* According to DTS, EMMC and EMMC2 share one irq */
if (!qdev_realize(DEVICE(&s->mmc_irq_orgate), NULL, errp)) {
return;
}
mmc_irq_orgate = DEVICE(&s->mmc_irq_orgate);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc2), 0,
qdev_get_gpio_in(mmc_irq_orgate, 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->sdhci), 0,
qdev_get_gpio_in(mmc_irq_orgate, 1));
/* Connect EMMC and EMMC2 to the interrupt controller */
qdev_connect_gpio_out(mmc_irq_orgate, 0,
qdev_get_gpio_in_named(DEVICE(&s_base->ic),
BCM2835_IC_GPU_IRQ,
INTERRUPT_ARASANSDIO));
/* Connect DMA 0-6 to the interrupt controller */
for (n = 0; n < 7; n++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->dma), n,
qdev_get_gpio_in_named(DEVICE(&s_base->ic),
BCM2835_IC_GPU_IRQ,
GPU_INTERRUPT_DMA0 + n));
}
/* According to DTS, DMA 7 and 8 share one irq */
if (!qdev_realize(DEVICE(&s->dma_7_8_irq_orgate), NULL, errp)) {
return;
}
dma_7_8_irq_orgate = DEVICE(&s->dma_7_8_irq_orgate);
/* Connect DMA 7-8 to the interrupt controller */
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->dma), 7,
qdev_get_gpio_in(dma_7_8_irq_orgate, 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->dma), 8,
qdev_get_gpio_in(dma_7_8_irq_orgate, 1));
qdev_connect_gpio_out(dma_7_8_irq_orgate, 0,
qdev_get_gpio_in_named(DEVICE(&s_base->ic),
BCM2835_IC_GPU_IRQ,
GPU_INTERRUPT_DMA7_8));
/* According to DTS, DMA 9 and 10 share one irq */
if (!qdev_realize(DEVICE(&s->dma_9_10_irq_orgate), NULL, errp)) {
return;
}
dma_9_10_irq_orgate = DEVICE(&s->dma_9_10_irq_orgate);
/* Connect DMA 9-10 to the interrupt controller */
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->dma), 9,
qdev_get_gpio_in(dma_9_10_irq_orgate, 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->dma), 10,
qdev_get_gpio_in(dma_9_10_irq_orgate, 1));
qdev_connect_gpio_out(dma_9_10_irq_orgate, 0,
qdev_get_gpio_in_named(DEVICE(&s_base->ic),
BCM2835_IC_GPU_IRQ,
GPU_INTERRUPT_DMA9_10));
/* Connect DMA 11-14 to the interrupt controller */
for (n = 11; n < 15; n++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->dma), n,
qdev_get_gpio_in_named(DEVICE(&s_base->ic),
BCM2835_IC_GPU_IRQ,
GPU_INTERRUPT_DMA11 + n
- 11));
}
/*
* Connect DMA 15 to the interrupt controller, it is physically removed
* from other DMA channels and exclusively used by the GPU
*/
sysbus_connect_irq(SYS_BUS_DEVICE(&s_base->dma), 15,
qdev_get_gpio_in_named(DEVICE(&s_base->ic),
BCM2835_IC_GPU_IRQ,
GPU_INTERRUPT_DMA15));
/* Map MPHI to BCM2838 memory map */
mphi_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s_base->mphi), 0);
memory_region_init_alias(&s->mphi_mr_alias, OBJECT(s), "mphi", mphi_mr, 0,
BCM2838_MPHI_SIZE);
memory_region_add_subregion(&s_base->peri_mr, BCM2838_MPHI_OFFSET,
&s->mphi_mr_alias);
create_unimp(s_base, &s->clkisp, "bcm2835-clkisp", CLOCK_ISP_OFFSET,
CLOCK_ISP_SIZE);
/* GPIO */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
return;
}
memory_region_add_subregion(
&s_base->peri_mr, GPIO_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0));
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->gpio), "sd-bus");
/* BCM2838 RPiVid ASB must be mapped to prevent kernel crash */
create_unimp(s_base, &s->asb, "bcm2838-asb", BRDG_OFFSET, 0x24);
}
static void bcm2838_peripherals_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM2838PeripheralClass *bc = BCM2838_PERIPHERALS_CLASS(oc);
BCMSocPeripheralBaseClass *bc_base = BCM_SOC_PERIPHERALS_BASE_CLASS(oc);
bc->peri_low_size = 0x2000000;
bc_base->peri_size = 0x1800000;
dc->realize = bcm2838_peripherals_realize;
}
static const TypeInfo bcm2838_peripherals_type_info = {
.name = TYPE_BCM2838_PERIPHERALS,
.parent = TYPE_BCM_SOC_PERIPHERALS_BASE,
.instance_size = sizeof(BCM2838PeripheralState),
.instance_init = bcm2838_peripherals_init,
.class_size = sizeof(BCM2838PeripheralClass),
.class_init = bcm2838_peripherals_class_init,
};
static void bcm2838_peripherals_register_types(void)
{
type_register_static(&bcm2838_peripherals_type_info);
}
type_init(bcm2838_peripherals_register_types)
+2
View File
@@ -30,6 +30,7 @@ arm_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubi
arm_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c'))
arm_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40.c', 'bananapi_m2u.c'))
arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2836.c', 'raspi.c'))
arm_ss.add(when: ['CONFIG_RASPI', 'TARGET_AARCH64'], if_true: files('bcm2838.c', 'raspi4b.c'))
arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c'))
arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c'))
arm_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c'))
@@ -67,6 +68,7 @@ system_ss.add(when: 'CONFIG_GUMSTIX', if_true: files('gumstix.c'))
system_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c'))
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap2.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2838_peripherals.c'))
system_ss.add(when: 'CONFIG_SPITZ', if_true: files('spitz.c'))
system_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c'))
system_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c'))
+75 -55
View File
@@ -18,6 +18,8 @@
#include "qapi/error.h"
#include "hw/arm/boot.h"
#include "hw/arm/bcm2836.h"
#include "hw/arm/bcm2838.h"
#include "hw/arm/raspi_platform.h"
#include "hw/registerfields.h"
#include "qemu/error-report.h"
#include "hw/boards.h"
@@ -25,6 +27,9 @@
#include "hw/arm/boot.h"
#include "qom/object.h"
#define TYPE_RASPI_MACHINE MACHINE_TYPE_NAME("raspi-common")
OBJECT_DECLARE_SIMPLE_TYPE(RaspiMachineState, RASPI_MACHINE)
#define SMPBOOT_ADDR 0x300 /* this should leave enough space for ATAGS */
#define MVBAR_ADDR 0x400 /* secure vectors */
#define BOARDSETUP_ADDR (MVBAR_ADDR + 0x20) /* board setup code */
@@ -32,30 +37,12 @@
#define FIRMWARE_ADDR_3 0x80000 /* Pi 3 loads kernel.img here by default */
#define SPINTABLE_ADDR 0xd8 /* Pi 3 bootloader spintable */
/* Registered machine type (matches RPi Foundation bootloader and U-Boot) */
#define MACH_TYPE_BCM2708 3138
struct RaspiMachineState {
/*< private >*/
MachineState parent_obj;
RaspiBaseMachineState parent_obj;
/*< public >*/
BCM283XState soc;
struct arm_boot_info binfo;
};
typedef struct RaspiMachineState RaspiMachineState;
struct RaspiMachineClass {
/*< private >*/
MachineClass parent_obj;
/*< public >*/
uint32_t board_rev;
};
typedef struct RaspiMachineClass RaspiMachineClass;
#define TYPE_RASPI_MACHINE MACHINE_TYPE_NAME("raspi-common")
DECLARE_OBJ_CHECKERS(RaspiMachineState, RaspiMachineClass,
RASPI_MACHINE, TYPE_RASPI_MACHINE)
/*
* Board revision codes:
@@ -72,6 +59,7 @@ typedef enum RaspiProcessorId {
PROCESSOR_ID_BCM2835 = 0,
PROCESSOR_ID_BCM2836 = 1,
PROCESSOR_ID_BCM2837 = 2,
PROCESSOR_ID_BCM2838 = 3,
} RaspiProcessorId;
static const struct {
@@ -81,9 +69,10 @@ static const struct {
[PROCESSOR_ID_BCM2835] = {TYPE_BCM2835, 1},
[PROCESSOR_ID_BCM2836] = {TYPE_BCM2836, BCM283X_NCPUS},
[PROCESSOR_ID_BCM2837] = {TYPE_BCM2837, BCM283X_NCPUS},
[PROCESSOR_ID_BCM2838] = {TYPE_BCM2838, BCM283X_NCPUS},
};
static uint64_t board_ram_size(uint32_t board_rev)
uint64_t board_ram_size(uint32_t board_rev)
{
assert(FIELD_EX32(board_rev, REV_CODE, STYLE)); /* Only new style */
return 256 * MiB << FIELD_EX32(board_rev, REV_CODE, MEMORY_SIZE);
@@ -99,7 +88,7 @@ static RaspiProcessorId board_processor_id(uint32_t board_rev)
return proc_id;
}
static const char *board_soc_type(uint32_t board_rev)
const char *board_soc_type(uint32_t board_rev)
{
return soc_property[board_processor_id(board_rev)].type;
}
@@ -200,13 +189,12 @@ static void reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
cpu_set_pc(cs, info->smp_loader_start);
}
static void setup_boot(MachineState *machine, RaspiProcessorId processor_id,
size_t ram_size)
static void setup_boot(MachineState *machine, ARMCPU *cpu,
RaspiProcessorId processor_id, size_t ram_size)
{
RaspiMachineState *s = RASPI_MACHINE(machine);
RaspiBaseMachineState *s = RASPI_BASE_MACHINE(machine);
int r;
s->binfo.board_id = MACH_TYPE_BCM2708;
s->binfo.ram_size = ram_size;
if (processor_id <= PROCESSOR_ID_BCM2836) {
@@ -252,16 +240,17 @@ static void setup_boot(MachineState *machine, RaspiProcessorId processor_id,
s->binfo.firmware_loaded = true;
}
arm_load_kernel(&s->soc.cpu[0].core, machine, &s->binfo);
arm_load_kernel(cpu, machine, &s->binfo);
}
static void raspi_machine_init(MachineState *machine)
void raspi_base_machine_init(MachineState *machine,
BCM283XBaseState *soc)
{
RaspiMachineClass *mc = RASPI_MACHINE_GET_CLASS(machine);
RaspiMachineState *s = RASPI_MACHINE(machine);
RaspiBaseMachineClass *mc = RASPI_BASE_MACHINE_GET_CLASS(machine);
uint32_t board_rev = mc->board_rev;
uint64_t ram_size = board_ram_size(board_rev);
uint32_t vcram_size;
uint32_t vcram_base, vcram_size;
size_t boot_ram_size;
DriveInfo *di;
BlockBackend *blk;
BusState *bus;
@@ -279,19 +268,17 @@ static void raspi_machine_init(MachineState *machine)
machine->ram, 0);
/* Setup the SOC */
object_initialize_child(OBJECT(machine), "soc", &s->soc,
board_soc_type(board_rev));
object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(machine->ram));
object_property_set_int(OBJECT(&s->soc), "board-rev", board_rev,
object_property_add_const_link(OBJECT(soc), "ram", OBJECT(machine->ram));
object_property_set_int(OBJECT(soc), "board-rev", board_rev,
&error_abort);
object_property_set_str(OBJECT(&s->soc), "command-line",
object_property_set_str(OBJECT(soc), "command-line",
machine->kernel_cmdline, &error_abort);
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
qdev_realize(DEVICE(soc), NULL, &error_fatal);
/* Create and plug in the SD cards */
di = drive_get(IF_SD, 0, 0);
blk = di ? blk_by_legacy_dinfo(di) : NULL;
bus = qdev_get_child_bus(DEVICE(&s->soc), "sd-bus");
bus = qdev_get_child_bus(DEVICE(soc), "sd-bus");
if (bus == NULL) {
error_report("No SD bus found in SOC object");
exit(1);
@@ -300,19 +287,40 @@ static void raspi_machine_init(MachineState *machine)
qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
qdev_realize_and_unref(carddev, bus, &error_fatal);
vcram_size = object_property_get_uint(OBJECT(&s->soc), "vcram-size",
vcram_size = object_property_get_uint(OBJECT(soc), "vcram-size",
&error_abort);
setup_boot(machine, board_processor_id(mc->board_rev),
machine->ram_size - vcram_size);
vcram_base = object_property_get_uint(OBJECT(soc), "vcram-base",
&error_abort);
if (vcram_base == 0) {
vcram_base = ram_size - vcram_size;
}
boot_ram_size = MIN(vcram_base, UPPER_RAM_BASE - vcram_size);
setup_boot(machine, &soc->cpu[0].core, board_processor_id(board_rev),
boot_ram_size);
}
static void raspi_machine_class_common_init(MachineClass *mc,
uint32_t board_rev)
void raspi_machine_init(MachineState *machine)
{
RaspiMachineState *s = RASPI_MACHINE(machine);
RaspiBaseMachineState *s_base = RASPI_BASE_MACHINE(machine);
RaspiBaseMachineClass *mc = RASPI_BASE_MACHINE_GET_CLASS(machine);
BCM283XState *soc = &s->soc;
s_base->binfo.board_id = MACH_TYPE_BCM2708;
object_initialize_child(OBJECT(machine), "soc", soc,
board_soc_type(mc->board_rev));
raspi_base_machine_init(machine, &soc->parent_obj);
}
void raspi_machine_class_common_init(MachineClass *mc,
uint32_t board_rev)
{
mc->desc = g_strdup_printf("Raspberry Pi %s (revision 1.%u)",
board_type(board_rev),
FIELD_EX32(board_rev, REV_CODE, REVISION));
mc->init = raspi_machine_init;
mc->block_default_type = IF_SD;
mc->no_parallel = 1;
mc->no_floppy = 1;
@@ -322,50 +330,57 @@ static void raspi_machine_class_common_init(MachineClass *mc,
mc->default_ram_id = "ram";
};
static void raspi_machine_class_init(MachineClass *mc,
uint32_t board_rev)
{
raspi_machine_class_common_init(mc, board_rev);
mc->init = raspi_machine_init;
};
static void raspi0_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
rmc->board_rev = 0x920092; /* Revision 1.2 */
raspi_machine_class_common_init(mc, rmc->board_rev);
raspi_machine_class_init(mc, rmc->board_rev);
};
static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
rmc->board_rev = 0x900021; /* Revision 1.1 */
raspi_machine_class_common_init(mc, rmc->board_rev);
raspi_machine_class_init(mc, rmc->board_rev);
};
static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
rmc->board_rev = 0xa21041;
raspi_machine_class_common_init(mc, rmc->board_rev);
raspi_machine_class_init(mc, rmc->board_rev);
};
#ifdef TARGET_AARCH64
static void raspi3ap_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
rmc->board_rev = 0x9020e0; /* Revision 1.0 */
raspi_machine_class_common_init(mc, rmc->board_rev);
raspi_machine_class_init(mc, rmc->board_rev);
};
static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
rmc->board_rev = 0xa02082;
raspi_machine_class_common_init(mc, rmc->board_rev);
raspi_machine_class_init(mc, rmc->board_rev);
};
#endif /* TARGET_AARCH64 */
@@ -394,9 +409,14 @@ static const TypeInfo raspi_machine_types[] = {
#endif
}, {
.name = TYPE_RASPI_MACHINE,
.parent = TYPE_MACHINE,
.parent = TYPE_RASPI_BASE_MACHINE,
.instance_size = sizeof(RaspiMachineState),
.class_size = sizeof(RaspiMachineClass),
.abstract = true,
}, {
.name = TYPE_RASPI_BASE_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(RaspiBaseMachineState),
.class_size = sizeof(RaspiBaseMachineClass),
.abstract = true,
}
};
+132
View File
@@ -0,0 +1,132 @@
/*
* Raspberry Pi 4B emulation
*
* Copyright (C) 2022 Ovchinnikov Vitalii <vitalii.ovchinnikov@auriga.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "hw/arm/raspi_platform.h"
#include "hw/display/bcm2835_fb.h"
#include "hw/registerfields.h"
#include "qemu/error-report.h"
#include "sysemu/device_tree.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/arm/boot.h"
#include "qom/object.h"
#include "hw/arm/bcm2838.h"
#include <libfdt.h>
#define TYPE_RASPI4B_MACHINE MACHINE_TYPE_NAME("raspi4b")
OBJECT_DECLARE_SIMPLE_TYPE(Raspi4bMachineState, RASPI4B_MACHINE)
struct Raspi4bMachineState {
RaspiBaseMachineState parent_obj;
BCM2838State soc;
};
/*
* Add second memory region if board RAM amount exceeds VC base address
* (see https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf
* 1.2 Address Map)
*/
static int raspi_add_memory_node(void *fdt, hwaddr mem_base, hwaddr mem_len)
{
int ret;
uint32_t acells, scells;
char *nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);
acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells",
NULL, &error_fatal);
scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells",
NULL, &error_fatal);
if (acells == 0 || scells == 0) {
fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
ret = -1;
} else {
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
ret = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
acells, mem_base,
scells, mem_len);
}
g_free(nodename);
return ret;
}
static void raspi4_modify_dtb(const struct arm_boot_info *info, void *fdt)
{
uint64_t ram_size;
/* Temporarily disable following devices until they are implemented */
const char *nodes_to_remove[] = {
"brcm,bcm2711-pcie",
"brcm,bcm2711-rng200",
"brcm,bcm2711-thermal",
"brcm,bcm2711-genet-v5",
};
for (int i = 0; i < ARRAY_SIZE(nodes_to_remove); i++) {
const char *dev_str = nodes_to_remove[i];
int offset = fdt_node_offset_by_compatible(fdt, -1, dev_str);
if (offset >= 0) {
if (!fdt_nop_node(fdt, offset)) {
warn_report("bcm2711 dtc: %s has been disabled!", dev_str);
}
}
}
ram_size = board_ram_size(info->board_id);
if (info->ram_size > UPPER_RAM_BASE) {
raspi_add_memory_node(fdt, UPPER_RAM_BASE, ram_size - UPPER_RAM_BASE);
}
}
static void raspi4b_machine_init(MachineState *machine)
{
Raspi4bMachineState *s = RASPI4B_MACHINE(machine);
RaspiBaseMachineState *s_base = RASPI_BASE_MACHINE(machine);
RaspiBaseMachineClass *mc = RASPI_BASE_MACHINE_GET_CLASS(machine);
BCM2838State *soc = &s->soc;
s_base->binfo.modify_dtb = raspi4_modify_dtb;
s_base->binfo.board_id = mc->board_rev;
object_initialize_child(OBJECT(machine), "soc", soc,
board_soc_type(mc->board_rev));
raspi_base_machine_init(machine, &soc->parent_obj);
}
static void raspi4b_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc);
rmc->board_rev = 0xb03115; /* Revision 1.5, 2 Gb RAM */
raspi_machine_class_common_init(mc, rmc->board_rev);
mc->init = raspi4b_machine_init;
}
static const TypeInfo raspi4b_machine_type = {
.name = TYPE_RASPI4B_MACHINE,
.parent = TYPE_RASPI_BASE_MACHINE,
.instance_size = sizeof(Raspi4bMachineState),
.class_init = raspi4b_machine_class_init,
};
static void raspi4b_machine_register_type(void)
{
type_register_static(&raspi4b_machine_type);
}
type_init(raspi4b_machine_register_type)
+2 -3
View File
@@ -664,9 +664,8 @@ static void create_pcie(SBSAMachineState *sms)
}
pci = PCI_HOST_BRIDGE(dev);
if (pci->bus) {
pci_init_nic_devices(pci->bus, mc->default_nic);
}
pci_init_nic_devices(pci->bus, mc->default_nic);
pci_create_simple(pci->bus, -1, "bochs-display");
+70 -10
View File
@@ -26,6 +26,7 @@
#include "qapi/error.h"
#include "exec/address-spaces.h"
#include "sysemu/sysemu.h"
#include "hw/or-irq.h"
#include "hw/arm/stm32l4x5_soc.h"
#include "hw/qdev-clock.h"
#include "hw/misc/unimp.h"
@@ -42,21 +43,24 @@
#define NUM_EXTI_IRQ 40
/* Match exti line connections with their CPU IRQ number */
/* See Vector Table (Reference Manual p.396) */
/*
* Some IRQs are connected to the same CPU IRQ (denoted by -1)
* and require an intermediary OR gate to function correctly.
*/
static const int exti_irq[NUM_EXTI_IRQ] = {
6, /* GPIO[0] */
7, /* GPIO[1] */
8, /* GPIO[2] */
9, /* GPIO[3] */
10, /* GPIO[4] */
23, 23, 23, 23, 23, /* GPIO[5..9] */
40, 40, 40, 40, 40, 40, /* GPIO[10..15] */
1, /* PVD */
-1, -1, -1, -1, -1, /* GPIO[5..9] OR gate 23 */
-1, -1, -1, -1, -1, -1, /* GPIO[10..15] OR gate 40 */
-1, /* PVD OR gate 1 */
67, /* OTG_FS_WKUP, Direct */
41, /* RTC_ALARM */
2, /* RTC_TAMP_STAMP2/CSS_LSE */
3, /* RTC wakeup timer */
63, /* COMP1 */
63, /* COMP2 */
-1, -1, /* COMP[1..2] OR gate 63 */
31, /* I2C1 wakeup, Direct */
33, /* I2C2 wakeup, Direct */
72, /* I2C3 wakeup, Direct */
@@ -69,18 +73,39 @@ static const int exti_irq[NUM_EXTI_IRQ] = {
65, /* LPTIM1, Direct */
66, /* LPTIM2, Direct */
76, /* SWPMI1 wakeup, Direct */
1, /* PVM1 wakeup */
1, /* PVM2 wakeup */
1, /* PVM3 wakeup */
1, /* PVM4 wakeup */
-1, -1, -1, -1, /* PVM[1..4] OR gate 1 */
78 /* LCD wakeup, Direct */
};
static const int exti_or_gates_out[NUM_EXTI_OR_GATES] = {
23, 40, 63, 1,
};
static const int exti_or_gates_num_lines_in[NUM_EXTI_OR_GATES] = {
5, 6, 2, 5,
};
/* 3 OR gates with consecutive inputs */
#define NUM_EXTI_SIMPLE_OR_GATES 3
static const int exti_or_gates_first_line_in[NUM_EXTI_SIMPLE_OR_GATES] = {
5, 10, 21,
};
/* 1 OR gate with non-consecutive inputs */
#define EXTI_OR_GATE1_NUM_LINES_IN 5
static const int exti_or_gate1_lines_in[EXTI_OR_GATE1_NUM_LINES_IN] = {
16, 35, 36, 37, 38,
};
static void stm32l4x5_soc_initfn(Object *obj)
{
Stm32l4x5SocState *s = STM32L4X5_SOC(obj);
object_initialize_child(obj, "exti", &s->exti, TYPE_STM32L4X5_EXTI);
for (unsigned i = 0; i < NUM_EXTI_OR_GATES; i++) {
object_initialize_child(obj, "exti_or_gates[*]", &s->exti_or_gates[i],
TYPE_OR_IRQ);
}
object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSCFG);
s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
@@ -175,8 +200,43 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
return;
}
sysbus_mmio_map(busdev, 0, EXTI_ADDR);
/* IRQs with fan-in that require an OR gate */
for (unsigned i = 0; i < NUM_EXTI_OR_GATES; i++) {
if (!object_property_set_int(OBJECT(&s->exti_or_gates[i]), "num-lines",
exti_or_gates_num_lines_in[i], errp)) {
return;
}
if (!qdev_realize(DEVICE(&s->exti_or_gates[i]), NULL, errp)) {
return;
}
qdev_connect_gpio_out(DEVICE(&s->exti_or_gates[i]), 0,
qdev_get_gpio_in(armv7m, exti_or_gates_out[i]));
if (i < NUM_EXTI_SIMPLE_OR_GATES) {
/* consecutive inputs for OR gates 23, 40, 63 */
for (unsigned j = 0; j < exti_or_gates_num_lines_in[i]; j++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s->exti),
exti_or_gates_first_line_in[i] + j,
qdev_get_gpio_in(DEVICE(&s->exti_or_gates[i]), j));
}
} else {
/* non-consecutive inputs for OR gate 1 */
for (unsigned j = 0; j < EXTI_OR_GATE1_NUM_LINES_IN; j++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s->exti),
exti_or_gate1_lines_in[j],
qdev_get_gpio_in(DEVICE(&s->exti_or_gates[i]), j));
}
}
}
/* IRQs that don't require fan-in */
for (unsigned i = 0; i < NUM_EXTI_IRQ; i++) {
sysbus_connect_irq(busdev, i, qdev_get_gpio_in(armv7m, exti_irq[i]));
if (exti_irq[i] != -1) {
sysbus_connect_irq(busdev, i,
qdev_get_gpio_in(armv7m, exti_irq[i]));
}
}
for (unsigned i = 0; i < 16; i++) {
+3
View File
@@ -70,3 +70,6 @@ z2_aer915_event(int8_t event, int8_t len) "i2c event =0x%x len=%d bytes"
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
# bcm2838.c
bcm2838_gic_set_irq(int irq, int level) "gic irq:%d lvl:%d"
+43 -1
View File
@@ -49,6 +49,7 @@ struct VersalVirt {
struct {
bool secure;
} cfg;
char *ospi_model;
};
static void fdt_create(VersalVirt *s)
@@ -638,6 +639,22 @@ static void sd_plugin_card(SDHCIState *sd, DriveInfo *di)
&error_fatal);
}
static char *versal_get_ospi_model(Object *obj, Error **errp)
{
VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj);
return g_strdup(s->ospi_model);
}
static void versal_set_ospi_model(Object *obj, const char *value, Error **errp)
{
VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj);
g_free(s->ospi_model);
s->ospi_model = g_strdup(value);
}
static void versal_virt_init(MachineState *machine)
{
VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(machine);
@@ -732,12 +749,25 @@ static void versal_virt_init(MachineState *machine)
for (i = 0; i < XLNX_VERSAL_NUM_OSPI_FLASH; i++) {
BusState *spi_bus;
DeviceState *flash_dev;
ObjectClass *flash_klass;
qemu_irq cs_line;
DriveInfo *dinfo = drive_get(IF_MTD, 0, i);
spi_bus = qdev_get_child_bus(DEVICE(&s->soc.pmc.iou.ospi), "spi0");
flash_dev = qdev_new("mt35xu01g");
if (s->ospi_model) {
flash_klass = object_class_by_name(s->ospi_model);
if (!flash_klass ||
object_class_is_abstract(flash_klass) ||
!object_class_dynamic_cast(flash_klass, "m25p80-generic")) {
error_setg(&error_fatal, "'%s' is either abstract or"
" not a subtype of m25p80", s->ospi_model);
return;
}
}
flash_dev = qdev_new(s->ospi_model ? s->ospi_model : "mt35xu01g");
if (dinfo) {
qdev_prop_set_drive_err(flash_dev, "drive",
blk_by_legacy_dinfo(dinfo), &error_fatal);
@@ -770,6 +800,13 @@ static void versal_virt_machine_instance_init(Object *obj)
0);
}
static void versal_virt_machine_finalize(Object *obj)
{
VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj);
g_free(s->ospi_model);
}
static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -781,6 +818,10 @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
mc->default_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS;
mc->no_cdrom = true;
mc->default_ram_id = "ddr";
object_class_property_add_str(oc, "ospi-flash", versal_get_ospi_model,
versal_set_ospi_model);
object_class_property_set_description(oc, "ospi-flash",
"Change the OSPI Flash model");
}
static const TypeInfo versal_virt_machine_init_typeinfo = {
@@ -789,6 +830,7 @@ static const TypeInfo versal_virt_machine_init_typeinfo = {
.class_init = versal_virt_machine_class_init,
.instance_init = versal_virt_machine_instance_init,
.instance_size = sizeof(VersalVirt),
.instance_finalize = versal_virt_machine_finalize,
};
static void versal_virt_machine_init_register_types(void)
+3
View File
@@ -267,6 +267,9 @@ static const FlashPartInfo known_devices[] = {
{ INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
{ INFO_STACKED("mt35xu01g", 0x2c5b1b, 0x104100, 128 << 10, 1024,
ER_4K | ER_32K, 2) },
{ INFO_STACKED("mt35xu02gbba", 0x2c5b1c, 0x104100, 128 << 10, 2048,
ER_4K | ER_32K, 4),
.sfdp_read = m25p80_sfdp_mt35xu02g },
{ INFO_STACKED("n25q00", 0x20ba21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
+36
View File
@@ -57,6 +57,42 @@ static const uint8_t sfdp_n25q256a[] = {
};
define_sfdp_read(n25q256a);
static const uint8_t sfdp_mt35xu02g[] = {
0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff,
0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff,
0x84, 0x00, 0x01, 0x02, 0x80, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xe5, 0x20, 0x8a, 0xff, 0xff, 0xff, 0xff, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x11, 0xd8,
0x0f, 0x52, 0x00, 0x00, 0x24, 0x5a, 0x99, 0x00,
0x8b, 0x8e, 0x03, 0xe1, 0xac, 0x01, 0x27, 0x38,
0x7a, 0x75, 0x7a, 0x75, 0xfb, 0xbd, 0xd5, 0x5c,
0x00, 0x00, 0x70, 0xff, 0x81, 0xb0, 0x38, 0x36,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x43, 0x0e, 0xff, 0xff, 0x21, 0xdc, 0x5c, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
define_sfdp_read(mt35xu02g);
/*
* Matronix
+1
View File
@@ -16,6 +16,7 @@
#define M25P80_SFDP_MAX_SIZE (1 << 24)
uint8_t m25p80_sfdp_n25q256a(uint32_t addr);
uint8_t m25p80_sfdp_mt35xu02g(uint32_t addr);
uint8_t m25p80_sfdp_mx25l25635e(uint32_t addr);
uint8_t m25p80_sfdp_mx25l25635f(uint32_t addr);
+3 -4
View File
@@ -1577,14 +1577,13 @@ void qdev_machine_creation_done(void)
/* TODO: once all bus devices are qdevified, this should be done
* when bus is created by qdev.c */
/*
* TODO: If we had a main 'reset container' that the whole system
* lived in, we could reset that using the multi-phase reset
* APIs. For the moment, we just reset the sysbus, which will cause
* This is where we arrange for the sysbus to be reset when the
* whole simulation is reset. In turn, resetting the sysbus will cause
* all devices hanging off it (and all their child buses, recursively)
* to be reset. Note that this will *not* reset any Device objects
* which are not attached to some part of the qbus tree!
*/
qemu_register_reset(resettable_cold_reset_fn, sysbus_get_default());
qemu_register_resettable(OBJECT(sysbus_get_default()));
notifier_list_notify(&machine_init_done_notifiers, NULL);
+1
View File
@@ -4,6 +4,7 @@ hwcore_ss.add(files(
'qdev-properties.c',
'qdev.c',
'reset.c',
'resetcontainer.c',
'resettable.c',
'vmstate-if.c',
# irq.c needed for qdev GPIO handling:

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