mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
+11
@@ -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
@@ -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
@@ -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()``).
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
@@ -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
@@ -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,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
@@ -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
@@ -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++) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) },
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user