* [PATCH v2 01/18] hw/usb/hcd-dwc3: Align global registers size with Linux
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
@ 2025-02-23 11:46 ` Bernhard Beschow
2025-02-23 11:46 ` [PATCH v2 02/18] hw/pci-host/designware: Prevent device attachment on internal PCIe root bus Bernhard Beschow
` (17 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:46 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
While at it add missing GUSB2RHBCTL register as found in i.MX 8M Plus reference
manual.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
include/hw/usb/hcd-dwc3.h | 2 +-
hw/usb/hcd-dwc3.c | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/include/hw/usb/hcd-dwc3.h b/include/hw/usb/hcd-dwc3.h
index f752a27e94..dbdf12b21d 100644
--- a/include/hw/usb/hcd-dwc3.h
+++ b/include/hw/usb/hcd-dwc3.h
@@ -35,7 +35,7 @@
#define USB_DWC3(obj) \
OBJECT_CHECK(USBDWC3, (obj), TYPE_USB_DWC3)
-#define USB_DWC3_R_MAX ((0x530 / 4) + 1)
+#define USB_DWC3_R_MAX (0x600 / 4)
#define DWC3_SIZE 0x10000
typedef struct USBDWC3 {
diff --git a/hw/usb/hcd-dwc3.c b/hw/usb/hcd-dwc3.c
index 9ce9ba0b04..0bceee2712 100644
--- a/hw/usb/hcd-dwc3.c
+++ b/hw/usb/hcd-dwc3.c
@@ -343,6 +343,8 @@ REG32(GFLADJ, 0x530)
FIELD(GFLADJ, GFLADJ_REFCLK_FLADJ, 8, 14)
FIELD(GFLADJ, GFLADJ_30MHZ_SDBND_SEL, 7, 1)
FIELD(GFLADJ, GFLADJ_30MHZ, 0, 6)
+REG32(GUSB2RHBCTL, 0x540)
+ FIELD(GUSB2RHBCTL, OVRD_L1TIMEOUT, 0, 4)
#define DWC3_GLOBAL_OFFSET 0xC100
static void reset_csr(USBDWC3 * s)
@@ -560,6 +562,9 @@ static const RegisterAccessInfo usb_dwc3_regs_info[] = {
.rsvd = 0x40,
.ro = 0x400040,
.unimp = 0xffffffff,
+ },{ .name = "GUSB2RHBCTL", .addr = A_GUSB2RHBCTL,
+ .rsvd = 0xfffffff0,
+ .unimp = 0xffffffff,
}
};
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 02/18] hw/pci-host/designware: Prevent device attachment on internal PCIe root bus
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
2025-02-23 11:46 ` [PATCH v2 01/18] hw/usb/hcd-dwc3: Align global registers size with Linux Bernhard Beschow
@ 2025-02-23 11:46 ` Bernhard Beschow
2025-02-23 11:46 ` [PATCH v2 03/18] hw/gpio/pca955*: Move Kconfig switches next to implementations Bernhard Beschow
` (16 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:46 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
On the real device, the PCIe root bus is only connected to a PCIe bridge and
does not allow for direct attachment of devices. Doing so in QEMU results in no
PCI devices being detected by Linux. Instead, PCI devices should plug into the
secondary PCIe bus spawned by the internal PCIe bridge.
Unfortunately, QEMU defaults to plugging devices into the PCIe root bus. To work
around this, every PCI device created on the command line needs an extra
`bus=dw-pcie` option which is error prone. Fix that by marking the PCIe root bus
as full which makes QEMU decend into the child PCIe bus.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
include/hw/pci-host/designware.h | 7 +++++++
hw/pci-host/designware.c | 18 +++++++++++++++++-
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/include/hw/pci-host/designware.h b/include/hw/pci-host/designware.h
index bf8b278978..a35a3bd06c 100644
--- a/include/hw/pci-host/designware.h
+++ b/include/hw/pci-host/designware.h
@@ -25,12 +25,19 @@
#include "hw/pci/pci_bridge.h"
#include "qom/object.h"
+#define TYPE_DESIGNWARE_PCIE_ROOT_BUS "designware-pcie-root-BUS"
+OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIERootBus, DESIGNWARE_PCIE_ROOT_BUS)
+
#define TYPE_DESIGNWARE_PCIE_HOST "designware-pcie-host"
OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIEHost, DESIGNWARE_PCIE_HOST)
#define TYPE_DESIGNWARE_PCIE_ROOT "designware-pcie-root"
OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIERoot, DESIGNWARE_PCIE_ROOT)
+struct DesignwarePCIERootBus {
+ PCIBus parent;
+};
+
typedef struct DesignwarePCIEViewport {
DesignwarePCIERoot *root;
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
index 3e8c36e6a7..c07740bfaa 100644
--- a/hw/pci-host/designware.c
+++ b/hw/pci-host/designware.c
@@ -55,6 +55,17 @@
#define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff)
#define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C
+static void designware_pcie_root_bus_class_init(ObjectClass *klass, void *data)
+{
+ BusClass *k = BUS_CLASS(klass);
+
+ /*
+ * Designware has only a single root complex. Enforce the limit on the
+ * parent bus
+ */
+ k->max_dev = 1;
+}
+
static DesignwarePCIEHost *
designware_pcie_root_to_host(DesignwarePCIERoot *root)
{
@@ -699,7 +710,7 @@ static void designware_pcie_host_realize(DeviceState *dev, Error **errp)
&s->pci.memory,
&s->pci.io,
0, 4,
- TYPE_PCIE_BUS);
+ TYPE_DESIGNWARE_PCIE_ROOT_BUS);
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
memory_region_init(&s->pci.address_space_root,
@@ -754,6 +765,11 @@ static void designware_pcie_host_init(Object *obj)
static const TypeInfo designware_pcie_types[] = {
{
+ .name = TYPE_DESIGNWARE_PCIE_ROOT_BUS,
+ .parent = TYPE_PCIE_BUS,
+ .instance_size = sizeof(DesignwarePCIERootBus),
+ .class_init = designware_pcie_root_bus_class_init,
+ }, {
.name = TYPE_DESIGNWARE_PCIE_HOST,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(DesignwarePCIEHost),
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 03/18] hw/gpio/pca955*: Move Kconfig switches next to implementations
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
2025-02-23 11:46 ` [PATCH v2 01/18] hw/usb/hcd-dwc3: Align global registers size with Linux Bernhard Beschow
2025-02-23 11:46 ` [PATCH v2 02/18] hw/pci-host/designware: Prevent device attachment on internal PCIe root bus Bernhard Beschow
@ 2025-02-23 11:46 ` Bernhard Beschow
2025-02-25 14:15 ` Peter Maydell
2025-02-23 11:46 ` [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board Bernhard Beschow
` (15 subsequent siblings)
18 siblings, 1 reply; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:46 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
The move of the Kconfig bits to hw/gpio is fixing a bug in 6328d8ffa6cb9d
("misc/pca955*: Move models under hw/gpio"), which moved the code but forgot to
move the Kconfig sections.
Fixes: 6328d8ffa6cb9d "misc/pca955*: Move models under hw/gpio"
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
hw/gpio/Kconfig | 8 ++++++++
hw/misc/Kconfig | 8 --------
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
index c423e10f59..a209294c20 100644
--- a/hw/gpio/Kconfig
+++ b/hw/gpio/Kconfig
@@ -16,6 +16,14 @@ config SIFIVE_GPIO
config STM32L4X5_GPIO
bool
+config PCA9552
+ bool
+ depends on I2C
+
+config PCA9554
+ bool
+ depends on I2C
+
config PCF8574
bool
depends on I2C
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 8f9ce2f68c..4271e2f4ac 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -30,14 +30,6 @@ config EDU
default y if TEST_DEVICES
depends on PCI && MSI_NONBROKEN
-config PCA9552
- bool
- depends on I2C
-
-config PCA9554
- bool
- depends on I2C
-
config I2C_ECHO
bool
default y if TEST_DEVICES
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* Re: [PATCH v2 03/18] hw/gpio/pca955*: Move Kconfig switches next to implementations
2025-02-23 11:46 ` [PATCH v2 03/18] hw/gpio/pca955*: Move Kconfig switches next to implementations Bernhard Beschow
@ 2025-02-25 14:15 ` Peter Maydell
0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2025-02-25 14:15 UTC (permalink / raw)
To: Bernhard Beschow
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
On Sun, 23 Feb 2025 at 11:47, Bernhard Beschow <shentey@gmail.com> wrote:
>
> The move of the Kconfig bits to hw/gpio is fixing a bug in 6328d8ffa6cb9d
> ("misc/pca955*: Move models under hw/gpio"), which moved the code but forgot to
> move the Kconfig sections.
>
> Fixes: 6328d8ffa6cb9d "misc/pca955*: Move models under hw/gpio"
> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (2 preceding siblings ...)
2025-02-23 11:46 ` [PATCH v2 03/18] hw/gpio/pca955*: Move Kconfig switches next to implementations Bernhard Beschow
@ 2025-02-23 11:46 ` Bernhard Beschow
2025-02-25 14:19 ` Peter Maydell
2025-02-25 15:42 ` Peter Maydell
2025-02-23 11:46 ` [PATCH v2 05/18] hw/arm/fsl-imx8mp: Implement clock tree Bernhard Beschow
` (14 subsequent siblings)
18 siblings, 2 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:46 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
As a first step, implement the bare minimum: CPUs, RAM, interrupt controller,
serial. All other devices of the A53 memory map are represented as
TYPE_UNIMPLEMENTED_DEVICE, i.e. the whole memory map is provided. This allows
for running Linux without it crashing due to invalid memory accesses.
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
MAINTAINERS | 9 +
docs/system/arm/imx8mp-evk.rst | 54 +++++
docs/system/target-arm.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 189 +++++++++++++++++
hw/arm/fsl-imx8mp.c | 367 +++++++++++++++++++++++++++++++++
hw/arm/imx8mp-evk.c | 55 +++++
hw/arm/Kconfig | 12 ++
hw/arm/meson.build | 2 +
8 files changed, 689 insertions(+)
create mode 100644 docs/system/arm/imx8mp-evk.rst
create mode 100644 include/hw/arm/fsl-imx8mp.h
create mode 100644 hw/arm/fsl-imx8mp.c
create mode 100644 hw/arm/imx8mp-evk.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 1911949526..374fe98724 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -820,6 +820,15 @@ F: hw/pci-host/designware.c
F: include/hw/pci-host/designware.h
F: docs/system/arm/mcimx7d-sabre.rst
+MCIMX8MP-EVK / i.MX8MP
+M: Bernhard Beschow <shentey@gmail.com>
+L: qemu-arm@nongnu.org
+S: Maintained
+F: hw/arm/imx8mp-evk.c
+F: hw/arm/fsl-imx8mp.c
+F: include/hw/arm/fsl-imx8mp.h
+F: docs/system/arm/imx8mp-evk.rst
+
MPS2 / MPS3
M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
new file mode 100644
index 0000000000..b23fdcc743
--- /dev/null
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -0,0 +1,54 @@
+NXP i.MX 8M Plus Evaluation Kit (``imx8mp-evk``)
+================================================
+
+The ``imx8mp-evk`` machine models the i.MX 8M Plus Evaluation Kit, based on an
+i.MX 8M Plus SoC.
+
+Supported devices
+-----------------
+
+The ``imx8mp-evk`` machine implements the following devices:
+
+ * Up to 4 Cortex-A53 cores
+ * Generic Interrupt Controller (GICv3)
+ * 4 UARTs
+
+Boot options
+------------
+
+The ``imx8mp-evk`` machine can start a Linux kernel directly using the standard
+``-kernel`` functionality.
+
+Direct Linux Kernel Boot
+''''''''''''''''''''''''
+
+Probably the easiest way to get started with a whole Linux system on the machine
+is to generate an image with Buildroot. Version 2024.11.1 is tested at the time
+of writing and involves two steps. First run the following commands in the
+toplevel directory of the Buildroot source tree:
+
+.. code-block:: bash
+
+ $ echo "BR2_TARGET_ROOTFS_CPIO=y" >> configs/freescale_imx8mpevk_defconfig
+ $ make freescale_imx8mpevk_defconfig
+ $ make
+
+Once finished successfully there is an ``output/image`` subfolder. Navigate into
+it and patch the device tree with the following commands which will remove the
+``cpu-idle-states`` properties from CPU nodes:
+
+.. code-block:: bash
+
+ $ dtc imx8mp-evk.dtb | sed '/cpu-idle-states/d' > imx8mp-evk-patched.dts
+ $ dtc imx8mp-evk-patched.dts -o imx8mp-evk-patched.dtb
+
+Now that everything is prepared the machine can be started as follows:
+
+.. code-block:: bash
+
+ $ qemu-system-aarch64 -M imx8mp-evk -smp 4 -m 3G \
+ -display none -serial null -serial stdio \
+ -kernel Image \
+ -dtb imx8mp-evk-patched.dtb \
+ -initrd rootfs.cpio \
+ -append "root=/dev/ram"
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
index 9aaa9c414c..a43ec8f10e 100644
--- a/docs/system/target-arm.rst
+++ b/docs/system/target-arm.rst
@@ -95,6 +95,7 @@ Board-specific documentation
arm/imx25-pdk
arm/mcimx6ul-evk
arm/mcimx7d-sabre
+ arm/imx8mp-evk
arm/orangepi
arm/raspi
arm/collie
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
new file mode 100644
index 0000000000..57e23d1b69
--- /dev/null
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -0,0 +1,189 @@
+/*
+ * i.MX 8M Plus SoC Definitions
+ *
+ * Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef FSL_IMX8MP_H
+#define FSL_IMX8MP_H
+
+#include "cpu.h"
+#include "hw/char/imx_serial.h"
+#include "hw/intc/arm_gicv3_common.h"
+#include "qom/object.h"
+#include "qemu/units.h"
+
+#define TYPE_FSL_IMX8MP "fsl-imx8mp"
+OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
+
+#define FSL_IMX8MP_RAM_START 0x40000000
+#define FSL_IMX8MP_RAM_SIZE_MAX (8 * GiB)
+
+enum FslImx8mpConfiguration {
+ FSL_IMX8MP_NUM_CPUS = 4,
+ FSL_IMX8MP_NUM_IRQS = 160,
+ FSL_IMX8MP_NUM_UARTS = 4,
+};
+
+struct FslImx8mpState {
+ DeviceState parent_obj;
+
+ ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
+ GICv3State gic;
+ IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
+};
+
+enum FslImx8mpMemoryRegions {
+ FSL_IMX8MP_A53_DAP,
+ FSL_IMX8MP_AIPS1_CONFIGURATION,
+ FSL_IMX8MP_AIPS2_CONFIGURATION,
+ FSL_IMX8MP_AIPS3_CONFIGURATION,
+ FSL_IMX8MP_AIPS4_CONFIGURATION,
+ FSL_IMX8MP_AIPS5_CONFIGURATION,
+ FSL_IMX8MP_ANA_OSC,
+ FSL_IMX8MP_ANA_PLL,
+ FSL_IMX8MP_ANA_TSENSOR,
+ FSL_IMX8MP_APBH_DMA,
+ FSL_IMX8MP_ASRC,
+ FSL_IMX8MP_AUDIO_BLK_CTRL,
+ FSL_IMX8MP_AUDIO_DSP,
+ FSL_IMX8MP_AUDIO_XCVR_RX,
+ FSL_IMX8MP_AUD_IRQ_STEER,
+ FSL_IMX8MP_BOOT_ROM,
+ FSL_IMX8MP_BOOT_ROM_PROTECTED,
+ FSL_IMX8MP_CAAM,
+ FSL_IMX8MP_CAAM_MEM,
+ FSL_IMX8MP_CCM,
+ FSL_IMX8MP_CSU,
+ FSL_IMX8MP_DDR_BLK_CTRL,
+ FSL_IMX8MP_DDR_CTL,
+ FSL_IMX8MP_DDR_PERF_MON,
+ FSL_IMX8MP_DDR_PHY,
+ FSL_IMX8MP_DDR_PHY_BROADCAST,
+ FSL_IMX8MP_ECSPI1,
+ FSL_IMX8MP_ECSPI2,
+ FSL_IMX8MP_ECSPI3,
+ FSL_IMX8MP_EDMA_CHANNELS,
+ FSL_IMX8MP_EDMA_MANAGEMENT_PAGE,
+ FSL_IMX8MP_ENET1,
+ FSL_IMX8MP_ENET2_TSN,
+ FSL_IMX8MP_FLEXCAN1,
+ FSL_IMX8MP_FLEXCAN2,
+ FSL_IMX8MP_GIC_DIST,
+ FSL_IMX8MP_GIC_REDIST,
+ FSL_IMX8MP_GPC,
+ FSL_IMX8MP_GPIO1,
+ FSL_IMX8MP_GPIO2,
+ FSL_IMX8MP_GPIO3,
+ FSL_IMX8MP_GPIO4,
+ FSL_IMX8MP_GPIO5,
+ FSL_IMX8MP_GPT1,
+ FSL_IMX8MP_GPT2,
+ FSL_IMX8MP_GPT3,
+ FSL_IMX8MP_GPT4,
+ FSL_IMX8MP_GPT5,
+ FSL_IMX8MP_GPT6,
+ FSL_IMX8MP_GPU2D,
+ FSL_IMX8MP_GPU3D,
+ FSL_IMX8MP_HDMI_TX,
+ FSL_IMX8MP_HDMI_TX_AUDLNK_MSTR,
+ FSL_IMX8MP_HSIO_BLK_CTL,
+ FSL_IMX8MP_I2C1,
+ FSL_IMX8MP_I2C2,
+ FSL_IMX8MP_I2C3,
+ FSL_IMX8MP_I2C4,
+ FSL_IMX8MP_I2C5,
+ FSL_IMX8MP_I2C6,
+ FSL_IMX8MP_INTERCONNECT,
+ FSL_IMX8MP_IOMUXC,
+ FSL_IMX8MP_IOMUXC_GPR,
+ FSL_IMX8MP_IPS_DEWARP,
+ FSL_IMX8MP_ISI,
+ FSL_IMX8MP_ISP1,
+ FSL_IMX8MP_ISP2,
+ FSL_IMX8MP_LCDIF1,
+ FSL_IMX8MP_LCDIF2,
+ FSL_IMX8MP_MEDIA_BLK_CTL,
+ FSL_IMX8MP_MIPI_CSI1,
+ FSL_IMX8MP_MIPI_CSI2,
+ FSL_IMX8MP_MIPI_DSI1,
+ FSL_IMX8MP_MU_1_A,
+ FSL_IMX8MP_MU_1_B,
+ FSL_IMX8MP_MU_2_A,
+ FSL_IMX8MP_MU_2_B,
+ FSL_IMX8MP_MU_3_A,
+ FSL_IMX8MP_MU_3_B,
+ FSL_IMX8MP_NPU,
+ FSL_IMX8MP_OCOTP_CTRL,
+ FSL_IMX8MP_OCRAM,
+ FSL_IMX8MP_OCRAM_S,
+ FSL_IMX8MP_PCIE1,
+ FSL_IMX8MP_PCIE1_MEM,
+ FSL_IMX8MP_PCIE_PHY1,
+ FSL_IMX8MP_PDM,
+ FSL_IMX8MP_PERFMON1,
+ FSL_IMX8MP_PERFMON2,
+ FSL_IMX8MP_PWM1,
+ FSL_IMX8MP_PWM2,
+ FSL_IMX8MP_PWM3,
+ FSL_IMX8MP_PWM4,
+ FSL_IMX8MP_QOSC,
+ FSL_IMX8MP_QSPI,
+ FSL_IMX8MP_QSPI1_RX_BUFFER,
+ FSL_IMX8MP_QSPI1_TX_BUFFER,
+ FSL_IMX8MP_QSPI_MEM,
+ FSL_IMX8MP_RAM,
+ FSL_IMX8MP_RDC,
+ FSL_IMX8MP_SAI1,
+ FSL_IMX8MP_SAI2,
+ FSL_IMX8MP_SAI3,
+ FSL_IMX8MP_SAI5,
+ FSL_IMX8MP_SAI6,
+ FSL_IMX8MP_SAI7,
+ FSL_IMX8MP_SDMA1,
+ FSL_IMX8MP_SDMA2,
+ FSL_IMX8MP_SDMA3,
+ FSL_IMX8MP_SEMAPHORE1,
+ FSL_IMX8MP_SEMAPHORE2,
+ FSL_IMX8MP_SEMAPHORE_HS,
+ FSL_IMX8MP_SNVS_HP,
+ FSL_IMX8MP_SPBA1,
+ FSL_IMX8MP_SPBA2,
+ FSL_IMX8MP_SRC,
+ FSL_IMX8MP_SYSCNT_CMP,
+ FSL_IMX8MP_SYSCNT_CTRL,
+ FSL_IMX8MP_SYSCNT_RD,
+ FSL_IMX8MP_TCM_DTCM,
+ FSL_IMX8MP_TCM_ITCM,
+ FSL_IMX8MP_TZASC,
+ FSL_IMX8MP_UART1,
+ FSL_IMX8MP_UART2,
+ FSL_IMX8MP_UART3,
+ FSL_IMX8MP_UART4,
+ FSL_IMX8MP_USB1,
+ FSL_IMX8MP_USB2,
+ FSL_IMX8MP_USDHC1,
+ FSL_IMX8MP_USDHC2,
+ FSL_IMX8MP_USDHC3,
+ FSL_IMX8MP_VPU,
+ FSL_IMX8MP_VPU_BLK_CTRL,
+ FSL_IMX8MP_VPU_G1_DECODER,
+ FSL_IMX8MP_VPU_G2_DECODER,
+ FSL_IMX8MP_VPU_VC8000E_ENCODER,
+ FSL_IMX8MP_WDOG1,
+ FSL_IMX8MP_WDOG2,
+ FSL_IMX8MP_WDOG3,
+};
+
+enum FslImx8mpIrqs {
+ FSL_IMX8MP_UART1_IRQ = 26,
+ FSL_IMX8MP_UART2_IRQ = 27,
+ FSL_IMX8MP_UART3_IRQ = 28,
+ FSL_IMX8MP_UART4_IRQ = 29,
+ FSL_IMX8MP_UART5_IRQ = 30,
+ FSL_IMX8MP_UART6_IRQ = 16,
+};
+
+#endif /* FSL_IMX8MP_H */
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
new file mode 100644
index 0000000000..484b45c0d8
--- /dev/null
+++ b/hw/arm/fsl-imx8mp.c
@@ -0,0 +1,367 @@
+/*
+ * i.MX 8M Plus SoC Implementation
+ *
+ * Based on hw/arm/fsl-imx6.c
+ *
+ * Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "exec/address-spaces.h"
+#include "hw/arm/bsa.h"
+#include "hw/arm/fsl-imx8mp.h"
+#include "hw/intc/arm_gicv3.h"
+#include "hw/misc/unimp.h"
+#include "hw/boards.h"
+#include "system/system.h"
+#include "target/arm/cpu-qom.h"
+#include "qapi/error.h"
+#include "qobject/qlist.h"
+
+static const struct {
+ hwaddr addr;
+ size_t size;
+ const char *name;
+} fsl_imx8mp_memmap[] = {
+ [FSL_IMX8MP_RAM] = { FSL_IMX8MP_RAM_START, FSL_IMX8MP_RAM_SIZE_MAX, "ram" },
+ [FSL_IMX8MP_DDR_PHY_BROADCAST] = { 0x3dc00000, 4 * MiB, "ddr_phy_broadcast" },
+ [FSL_IMX8MP_DDR_PERF_MON] = { 0x3d800000, 4 * MiB, "ddr_perf_mon" },
+ [FSL_IMX8MP_DDR_CTL] = { 0x3d400000, 4 * MiB, "ddr_ctl" },
+ [FSL_IMX8MP_DDR_BLK_CTRL] = { 0x3d000000, 1 * MiB, "ddr_blk_ctrl" },
+ [FSL_IMX8MP_DDR_PHY] = { 0x3c000000, 16 * MiB, "ddr_phy" },
+ [FSL_IMX8MP_AUDIO_DSP] = { 0x3b000000, 16 * MiB, "audio_dsp" },
+ [FSL_IMX8MP_GIC_DIST] = { 0x38800000, 512 * KiB, "gic_dist" },
+ [FSL_IMX8MP_GIC_REDIST] = { 0x38880000, 512 * KiB, "gic_redist" },
+ [FSL_IMX8MP_NPU] = { 0x38500000, 2 * MiB, "npu" },
+ [FSL_IMX8MP_VPU] = { 0x38340000, 2 * MiB, "vpu" },
+ [FSL_IMX8MP_VPU_BLK_CTRL] = { 0x38330000, 2 * MiB, "vpu_blk_ctrl" },
+ [FSL_IMX8MP_VPU_VC8000E_ENCODER] = { 0x38320000, 2 * MiB, "vpu_vc8000e_encoder" },
+ [FSL_IMX8MP_VPU_G2_DECODER] = { 0x38310000, 2 * MiB, "vpu_g2_decoder" },
+ [FSL_IMX8MP_VPU_G1_DECODER] = { 0x38300000, 2 * MiB, "vpu_g1_decoder" },
+ [FSL_IMX8MP_USB2] = { 0x38200000, 1 * MiB, "usb2" },
+ [FSL_IMX8MP_USB1] = { 0x38100000, 1 * MiB, "usb1" },
+ [FSL_IMX8MP_GPU2D] = { 0x38008000, 32 * KiB, "gpu2d" },
+ [FSL_IMX8MP_GPU3D] = { 0x38000000, 32 * KiB, "gpu3d" },
+ [FSL_IMX8MP_QSPI1_RX_BUFFER] = { 0x34000000, 32 * MiB, "qspi1_rx_buffer" },
+ [FSL_IMX8MP_PCIE1] = { 0x33800000, 4 * MiB, "pcie1" },
+ [FSL_IMX8MP_QSPI1_TX_BUFFER] = { 0x33008000, 32 * KiB, "qspi1_tx_buffer" },
+ [FSL_IMX8MP_APBH_DMA] = { 0x33000000, 32 * KiB, "apbh_dma" },
+
+ /* AIPS-5 Begin */
+ [FSL_IMX8MP_MU_3_B] = { 0x30e90000, 64 * KiB, "mu_3_b" },
+ [FSL_IMX8MP_MU_3_A] = { 0x30e80000, 64 * KiB, "mu_3_a" },
+ [FSL_IMX8MP_MU_2_B] = { 0x30e70000, 64 * KiB, "mu_2_b" },
+ [FSL_IMX8MP_MU_2_A] = { 0x30e60000, 64 * KiB, "mu_2_a" },
+ [FSL_IMX8MP_EDMA_CHANNELS] = { 0x30e40000, 128 * KiB, "edma_channels" },
+ [FSL_IMX8MP_EDMA_MANAGEMENT_PAGE] = { 0x30e30000, 64 * KiB, "edma_management_page" },
+ [FSL_IMX8MP_AUDIO_BLK_CTRL] = { 0x30e20000, 64 * KiB, "audio_blk_ctrl" },
+ [FSL_IMX8MP_SDMA2] = { 0x30e10000, 64 * KiB, "sdma2" },
+ [FSL_IMX8MP_SDMA3] = { 0x30e00000, 64 * KiB, "sdma3" },
+ [FSL_IMX8MP_AIPS5_CONFIGURATION] = { 0x30df0000, 64 * KiB, "aips5_configuration" },
+ [FSL_IMX8MP_SPBA2] = { 0x30cf0000, 64 * KiB, "spba2" },
+ [FSL_IMX8MP_AUDIO_XCVR_RX] = { 0x30cc0000, 64 * KiB, "audio_xcvr_rx" },
+ [FSL_IMX8MP_HDMI_TX_AUDLNK_MSTR] = { 0x30cb0000, 64 * KiB, "hdmi_tx_audlnk_mstr" },
+ [FSL_IMX8MP_PDM] = { 0x30ca0000, 64 * KiB, "pdm" },
+ [FSL_IMX8MP_ASRC] = { 0x30c90000, 64 * KiB, "asrc" },
+ [FSL_IMX8MP_SAI7] = { 0x30c80000, 64 * KiB, "sai7" },
+ [FSL_IMX8MP_SAI6] = { 0x30c60000, 64 * KiB, "sai6" },
+ [FSL_IMX8MP_SAI5] = { 0x30c50000, 64 * KiB, "sai5" },
+ [FSL_IMX8MP_SAI3] = { 0x30c30000, 64 * KiB, "sai3" },
+ [FSL_IMX8MP_SAI2] = { 0x30c20000, 64 * KiB, "sai2" },
+ [FSL_IMX8MP_SAI1] = { 0x30c10000, 64 * KiB, "sai1" },
+ /* AIPS-5 End */
+
+ /* AIPS-4 Begin */
+ [FSL_IMX8MP_HDMI_TX] = { 0x32fc0000, 128 * KiB, "hdmi_tx" },
+ [FSL_IMX8MP_TZASC] = { 0x32f80000, 64 * KiB, "tzasc" },
+ [FSL_IMX8MP_HSIO_BLK_CTL] = { 0x32f10000, 64 * KiB, "hsio_blk_ctl" },
+ [FSL_IMX8MP_PCIE_PHY1] = { 0x32f00000, 64 * KiB, "pcie_phy1" },
+ [FSL_IMX8MP_MEDIA_BLK_CTL] = { 0x32ec0000, 64 * KiB, "media_blk_ctl" },
+ [FSL_IMX8MP_LCDIF2] = { 0x32e90000, 64 * KiB, "lcdif2" },
+ [FSL_IMX8MP_LCDIF1] = { 0x32e80000, 64 * KiB, "lcdif1" },
+ [FSL_IMX8MP_MIPI_DSI1] = { 0x32e60000, 64 * KiB, "mipi_dsi1" },
+ [FSL_IMX8MP_MIPI_CSI2] = { 0x32e50000, 64 * KiB, "mipi_csi2" },
+ [FSL_IMX8MP_MIPI_CSI1] = { 0x32e40000, 64 * KiB, "mipi_csi1" },
+ [FSL_IMX8MP_IPS_DEWARP] = { 0x32e30000, 64 * KiB, "ips_dewarp" },
+ [FSL_IMX8MP_ISP2] = { 0x32e20000, 64 * KiB, "isp2" },
+ [FSL_IMX8MP_ISP1] = { 0x32e10000, 64 * KiB, "isp1" },
+ [FSL_IMX8MP_ISI] = { 0x32e00000, 64 * KiB, "isi" },
+ [FSL_IMX8MP_AIPS4_CONFIGURATION] = { 0x32df0000, 64 * KiB, "aips4_configuration" },
+ /* AIPS-4 End */
+
+ [FSL_IMX8MP_INTERCONNECT] = { 0x32700000, 1 * MiB, "interconnect" },
+
+ /* AIPS-3 Begin */
+ [FSL_IMX8MP_ENET2_TSN] = { 0x30bf0000, 64 * KiB, "enet2_tsn" },
+ [FSL_IMX8MP_ENET1] = { 0x30be0000, 64 * KiB, "enet1" },
+ [FSL_IMX8MP_SDMA1] = { 0x30bd0000, 64 * KiB, "sdma1" },
+ [FSL_IMX8MP_QSPI] = { 0x30bb0000, 64 * KiB, "qspi" },
+ [FSL_IMX8MP_USDHC3] = { 0x30b60000, 64 * KiB, "usdhc3" },
+ [FSL_IMX8MP_USDHC2] = { 0x30b50000, 64 * KiB, "usdhc2" },
+ [FSL_IMX8MP_USDHC1] = { 0x30b40000, 64 * KiB, "usdhc1" },
+ [FSL_IMX8MP_I2C6] = { 0x30ae0000, 64 * KiB, "i2c6" },
+ [FSL_IMX8MP_I2C5] = { 0x30ad0000, 64 * KiB, "i2c5" },
+ [FSL_IMX8MP_SEMAPHORE_HS] = { 0x30ac0000, 64 * KiB, "semaphore_hs" },
+ [FSL_IMX8MP_MU_1_B] = { 0x30ab0000, 64 * KiB, "mu_1_b" },
+ [FSL_IMX8MP_MU_1_A] = { 0x30aa0000, 64 * KiB, "mu_1_a" },
+ [FSL_IMX8MP_AUD_IRQ_STEER] = { 0x30a80000, 64 * KiB, "aud_irq_steer" },
+ [FSL_IMX8MP_UART4] = { 0x30a60000, 64 * KiB, "uart4" },
+ [FSL_IMX8MP_I2C4] = { 0x30a50000, 64 * KiB, "i2c4" },
+ [FSL_IMX8MP_I2C3] = { 0x30a40000, 64 * KiB, "i2c3" },
+ [FSL_IMX8MP_I2C2] = { 0x30a30000, 64 * KiB, "i2c2" },
+ [FSL_IMX8MP_I2C1] = { 0x30a20000, 64 * KiB, "i2c1" },
+ [FSL_IMX8MP_AIPS3_CONFIGURATION] = { 0x309f0000, 64 * KiB, "aips3_configuration" },
+ [FSL_IMX8MP_CAAM] = { 0x30900000, 256 * KiB, "caam" },
+ [FSL_IMX8MP_SPBA1] = { 0x308f0000, 64 * KiB, "spba1" },
+ [FSL_IMX8MP_FLEXCAN2] = { 0x308d0000, 64 * KiB, "flexcan2" },
+ [FSL_IMX8MP_FLEXCAN1] = { 0x308c0000, 64 * KiB, "flexcan1" },
+ [FSL_IMX8MP_UART2] = { 0x30890000, 64 * KiB, "uart2" },
+ [FSL_IMX8MP_UART3] = { 0x30880000, 64 * KiB, "uart3" },
+ [FSL_IMX8MP_UART1] = { 0x30860000, 64 * KiB, "uart1" },
+ [FSL_IMX8MP_ECSPI3] = { 0x30840000, 64 * KiB, "ecspi3" },
+ [FSL_IMX8MP_ECSPI2] = { 0x30830000, 64 * KiB, "ecspi2" },
+ [FSL_IMX8MP_ECSPI1] = { 0x30820000, 64 * KiB, "ecspi1" },
+ /* AIPS-3 End */
+
+ /* AIPS-2 Begin */
+ [FSL_IMX8MP_QOSC] = { 0x307f0000, 64 * KiB, "qosc" },
+ [FSL_IMX8MP_PERFMON2] = { 0x307d0000, 64 * KiB, "perfmon2" },
+ [FSL_IMX8MP_PERFMON1] = { 0x307c0000, 64 * KiB, "perfmon1" },
+ [FSL_IMX8MP_GPT4] = { 0x30700000, 64 * KiB, "gpt4" },
+ [FSL_IMX8MP_GPT5] = { 0x306f0000, 64 * KiB, "gpt5" },
+ [FSL_IMX8MP_GPT6] = { 0x306e0000, 64 * KiB, "gpt6" },
+ [FSL_IMX8MP_SYSCNT_CTRL] = { 0x306c0000, 64 * KiB, "syscnt_ctrl" },
+ [FSL_IMX8MP_SYSCNT_CMP] = { 0x306b0000, 64 * KiB, "syscnt_cmp" },
+ [FSL_IMX8MP_SYSCNT_RD] = { 0x306a0000, 64 * KiB, "syscnt_rd" },
+ [FSL_IMX8MP_PWM4] = { 0x30690000, 64 * KiB, "pwm4" },
+ [FSL_IMX8MP_PWM3] = { 0x30680000, 64 * KiB, "pwm3" },
+ [FSL_IMX8MP_PWM2] = { 0x30670000, 64 * KiB, "pwm2" },
+ [FSL_IMX8MP_PWM1] = { 0x30660000, 64 * KiB, "pwm1" },
+ [FSL_IMX8MP_AIPS2_CONFIGURATION] = { 0x305f0000, 64 * KiB, "aips2_configuration" },
+ /* AIPS-2 End */
+
+ /* AIPS-1 Begin */
+ [FSL_IMX8MP_CSU] = { 0x303e0000, 64 * KiB, "csu" },
+ [FSL_IMX8MP_RDC] = { 0x303d0000, 64 * KiB, "rdc" },
+ [FSL_IMX8MP_SEMAPHORE2] = { 0x303c0000, 64 * KiB, "semaphore2" },
+ [FSL_IMX8MP_SEMAPHORE1] = { 0x303b0000, 64 * KiB, "semaphore1" },
+ [FSL_IMX8MP_GPC] = { 0x303a0000, 64 * KiB, "gpc" },
+ [FSL_IMX8MP_SRC] = { 0x30390000, 64 * KiB, "src" },
+ [FSL_IMX8MP_CCM] = { 0x30380000, 64 * KiB, "ccm" },
+ [FSL_IMX8MP_SNVS_HP] = { 0x30370000, 64 * KiB, "snvs_hp" },
+ [FSL_IMX8MP_ANA_PLL] = { 0x30360000, 64 * KiB, "ana_pll" },
+ [FSL_IMX8MP_OCOTP_CTRL] = { 0x30350000, 64 * KiB, "ocotp_ctrl" },
+ [FSL_IMX8MP_IOMUXC_GPR] = { 0x30340000, 64 * KiB, "iomuxc_gpr" },
+ [FSL_IMX8MP_IOMUXC] = { 0x30330000, 64 * KiB, "iomuxc" },
+ [FSL_IMX8MP_GPT3] = { 0x302f0000, 64 * KiB, "gpt3" },
+ [FSL_IMX8MP_GPT2] = { 0x302e0000, 64 * KiB, "gpt2" },
+ [FSL_IMX8MP_GPT1] = { 0x302d0000, 64 * KiB, "gpt1" },
+ [FSL_IMX8MP_WDOG3] = { 0x302a0000, 64 * KiB, "wdog3" },
+ [FSL_IMX8MP_WDOG2] = { 0x30290000, 64 * KiB, "wdog2" },
+ [FSL_IMX8MP_WDOG1] = { 0x30280000, 64 * KiB, "wdog1" },
+ [FSL_IMX8MP_ANA_OSC] = { 0x30270000, 64 * KiB, "ana_osc" },
+ [FSL_IMX8MP_ANA_TSENSOR] = { 0x30260000, 64 * KiB, "ana_tsensor" },
+ [FSL_IMX8MP_GPIO5] = { 0x30240000, 64 * KiB, "gpio5" },
+ [FSL_IMX8MP_GPIO4] = { 0x30230000, 64 * KiB, "gpio4" },
+ [FSL_IMX8MP_GPIO3] = { 0x30220000, 64 * KiB, "gpio3" },
+ [FSL_IMX8MP_GPIO2] = { 0x30210000, 64 * KiB, "gpio2" },
+ [FSL_IMX8MP_GPIO1] = { 0x30200000, 64 * KiB, "gpio1" },
+ [FSL_IMX8MP_AIPS1_CONFIGURATION] = { 0x301f0000, 64 * KiB, "aips1_configuration" },
+ /* AIPS-1 End */
+
+ [FSL_IMX8MP_A53_DAP] = { 0x28000000, 16 * MiB, "a53_dap" },
+ [FSL_IMX8MP_PCIE1_MEM] = { 0x18000000, 128 * MiB, "pcie1_mem" },
+ [FSL_IMX8MP_QSPI_MEM] = { 0x08000000, 256 * MiB, "qspi_mem" },
+ [FSL_IMX8MP_OCRAM] = { 0x00900000, 576 * KiB, "ocram" },
+ [FSL_IMX8MP_TCM_DTCM] = { 0x00800000, 128 * KiB, "tcm_dtcm" },
+ [FSL_IMX8MP_TCM_ITCM] = { 0x007e0000, 128 * KiB, "tcm_itcm" },
+ [FSL_IMX8MP_OCRAM_S] = { 0x00180000, 36 * KiB, "ocram_s" },
+ [FSL_IMX8MP_CAAM_MEM] = { 0x00100000, 32 * KiB, "caam_mem" },
+ [FSL_IMX8MP_BOOT_ROM_PROTECTED] = { 0x0003f000, 4 * KiB, "boot_rom_protected" },
+ [FSL_IMX8MP_BOOT_ROM] = { 0x00000000, 252 * KiB, "boot_rom" },
+};
+
+static void fsl_imx8mp_init(Object *obj)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ FslImx8mpState *s = FSL_IMX8MP(obj);
+ int i;
+
+ for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MP_NUM_CPUS); i++) {
+ g_autofree char *name = g_strdup_printf("cpu%d", i);
+ object_initialize_child(obj, name, &s->cpu[i],
+ ARM_CPU_TYPE_NAME("cortex-a53"));
+ }
+
+ object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GICV3);
+
+ for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
+ g_autofree char *name = g_strdup_printf("uart%d", i + 1);
+ object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
+ }
+}
+
+static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ FslImx8mpState *s = FSL_IMX8MP(dev);
+ DeviceState *gicdev = DEVICE(&s->gic);
+ int i;
+
+ if (ms->smp.cpus > FSL_IMX8MP_NUM_CPUS) {
+ error_setg(errp, "%s: Only %d CPUs are supported (%d requested)",
+ TYPE_FSL_IMX8MP, FSL_IMX8MP_NUM_CPUS, ms->smp.cpus);
+ return;
+ }
+
+ /* CPUs */
+ for (i = 0; i < ms->smp.cpus; i++) {
+ /* On uniprocessor, the CBAR is set to 0 */
+ if (ms->smp.cpus > 1) {
+ object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
+ fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr,
+ &error_abort);
+ }
+
+ /*
+ * CNTFID0 base frequency in Hz of system counter
+ */
+ object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000,
+ &error_abort);
+
+ if (i) {
+ /*
+ * Secondary CPUs start in powered-down state (and can be
+ * powered up via the SRC system reset controller)
+ */
+ object_property_set_bool(OBJECT(&s->cpu[i]), "start-powered-off",
+ true, &error_abort);
+ }
+
+ if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
+ return;
+ }
+ }
+
+ /* GIC */
+ {
+ SysBusDevice *gicsbd = SYS_BUS_DEVICE(&s->gic);
+ QList *redist_region_count;
+
+ qdev_prop_set_uint32(gicdev, "num-cpu", ms->smp.cpus);
+ qdev_prop_set_uint32(gicdev, "num-irq",
+ FSL_IMX8MP_NUM_IRQS + GIC_INTERNAL);
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, ms->smp.cpus);
+ qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count);
+ object_property_set_link(OBJECT(&s->gic), "sysmem",
+ OBJECT(get_system_memory()), &error_fatal);
+ if (!sysbus_realize(gicsbd, errp)) {
+ return;
+ }
+ sysbus_mmio_map(gicsbd, 0, fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr);
+ sysbus_mmio_map(gicsbd, 1, fsl_imx8mp_memmap[FSL_IMX8MP_GIC_REDIST].addr);
+
+ /*
+ * Wire the outputs from each CPU's generic timer and the GICv3
+ * maintenance interrupt signal to the appropriate GIC PPI inputs, and
+ * the GIC's IRQ/FIQ interrupt outputs to the CPU's inputs.
+ */
+ for (i = 0; i < ms->smp.cpus; i++) {
+ DeviceState *cpudev = DEVICE(&s->cpu[i]);
+ int intidbase = FSL_IMX8MP_NUM_IRQS + i * GIC_INTERNAL;
+ qemu_irq irq;
+
+ /*
+ * Mapping from the output timer irq lines from the CPU to the
+ * GIC PPI inputs.
+ */
+ static const int timer_irqs[] = {
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
+ };
+
+ for (int j = 0; j < ARRAY_SIZE(timer_irqs); j++) {
+ irq = qdev_get_gpio_in(gicdev, intidbase + timer_irqs[j]);
+ qdev_connect_gpio_out(cpudev, j, irq);
+ }
+
+ irq = qdev_get_gpio_in(gicdev, intidbase + ARCH_GIC_MAINT_IRQ);
+ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
+ 0, irq);
+
+ irq = qdev_get_gpio_in(gicdev, intidbase + VIRTUAL_PMU_IRQ);
+ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, irq);
+
+ sysbus_connect_irq(gicsbd, i,
+ qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
+ sysbus_connect_irq(gicsbd, i + ms->smp.cpus,
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
+ }
+ }
+
+ /* UARTs */
+ for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } serial_table[FSL_IMX8MP_NUM_UARTS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART3].addr, FSL_IMX8MP_UART3_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART4].addr, FSL_IMX8MP_UART4_IRQ },
+ };
+
+ qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i));
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
+ qdev_get_gpio_in(gicdev, serial_table[i].irq));
+ }
+
+ /* Unimplemented devices */
+ for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
+ switch (i) {
+ case FSL_IMX8MP_GIC_DIST:
+ case FSL_IMX8MP_GIC_REDIST:
+ case FSL_IMX8MP_RAM:
+ case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
+ /* device implemented and treated above */
+ break;
+
+ default:
+ create_unimplemented_device(fsl_imx8mp_memmap[i].name,
+ fsl_imx8mp_memmap[i].addr,
+ fsl_imx8mp_memmap[i].size);
+ break;
+ }
+ }
+}
+
+static void fsl_imx8mp_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = fsl_imx8mp_realize;
+
+ dc->desc = "i.MX 8M Plus SoC";
+}
+
+static const TypeInfo fsl_imx8mp_types[] = {
+ {
+ .name = TYPE_FSL_IMX8MP,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(FslImx8mpState),
+ .instance_init = fsl_imx8mp_init,
+ .class_init = fsl_imx8mp_class_init,
+ },
+};
+
+DEFINE_TYPES(fsl_imx8mp_types)
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
new file mode 100644
index 0000000000..2756d4c21c
--- /dev/null
+++ b/hw/arm/imx8mp-evk.c
@@ -0,0 +1,55 @@
+/*
+ * NXP i.MX 8M Plus Evaluation Kit System Emulation
+ *
+ * Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "exec/address-spaces.h"
+#include "hw/arm/boot.h"
+#include "hw/arm/fsl-imx8mp.h"
+#include "hw/boards.h"
+#include "system/qtest.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+static void imx8mp_evk_init(MachineState *machine)
+{
+ static struct arm_boot_info boot_info;
+ FslImx8mpState *s;
+
+ if (machine->ram_size > FSL_IMX8MP_RAM_SIZE_MAX) {
+ error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" PRIx64 ")",
+ machine->ram_size, FSL_IMX8MP_RAM_SIZE_MAX);
+ exit(1);
+ }
+
+ boot_info = (struct arm_boot_info) {
+ .loader_start = FSL_IMX8MP_RAM_START,
+ .board_id = -1,
+ .ram_size = machine->ram_size,
+ .psci_conduit = QEMU_PSCI_CONDUIT_SMC,
+ };
+
+ s = FSL_IMX8MP(object_new(TYPE_FSL_IMX8MP));
+ object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
+ qdev_realize(DEVICE(s), NULL, &error_fatal);
+
+ memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
+ machine->ram);
+
+ if (!qtest_enabled()) {
+ arm_load_kernel(&s->cpu[0], machine, &boot_info);
+ }
+}
+
+static void imx8mp_evk_machine_init(MachineClass *mc)
+{
+ mc->desc = "NXP i.MX 8M Plus EVK Board";
+ mc->init = imx8mp_evk_init;
+ mc->max_cpus = FSL_IMX8MP_NUM_CPUS;
+ mc->default_ram_id = "imx8mp-evk.ram";
+}
+DEFINE_MACHINE("imx8mp-evk", imx8mp_evk_machine_init)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 504841ccab..0a7de40861 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -593,6 +593,18 @@ config FSL_IMX7
select UNIMP
select USB_CHIPIDEA
+config FSL_IMX8MP
+ bool
+ select ARM_GIC
+ select IMX
+ select UNIMP
+
+config FSL_IMX8MP_EVK
+ bool
+ default y
+ depends on TCG && AARCH64
+ select FSL_IMX8MP
+
config ARM_SMMUV3
bool
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index 465c757f97..ac473ce7cd 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -54,6 +54,8 @@ arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c'))
arm_ss.add(when: 'CONFIG_MUSCA', if_true: files('musca.c'))
arm_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c'))
+arm_ss.add(when: 'CONFIG_FSL_IMX8MP', if_true: files('fsl-imx8mp.c'))
+arm_ss.add(when: 'CONFIG_FSL_IMX8MP_EVK', if_true: files('imx8mp-evk.c'))
arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* Re: [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board
2025-02-23 11:46 ` [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board Bernhard Beschow
@ 2025-02-25 14:19 ` Peter Maydell
2025-02-25 15:42 ` Peter Maydell
1 sibling, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2025-02-25 14:19 UTC (permalink / raw)
To: Bernhard Beschow
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
On Sun, 23 Feb 2025 at 11:47, Bernhard Beschow <shentey@gmail.com> wrote:
>
> As a first step, implement the bare minimum: CPUs, RAM, interrupt controller,
> serial. All other devices of the A53 memory map are represented as
> TYPE_UNIMPLEMENTED_DEVICE, i.e. the whole memory map is provided. This allows
> for running Linux without it crashing due to invalid memory accesses.
>
> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board
2025-02-23 11:46 ` [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board Bernhard Beschow
2025-02-25 14:19 ` Peter Maydell
@ 2025-02-25 15:42 ` Peter Maydell
2025-02-25 17:00 ` Peter Maydell
1 sibling, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2025-02-25 15:42 UTC (permalink / raw)
To: Bernhard Beschow
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
On Sun, 23 Feb 2025 at 11:47, Bernhard Beschow <shentey@gmail.com> wrote:
>
> As a first step, implement the bare minimum: CPUs, RAM, interrupt controller,
> serial. All other devices of the A53 memory map are represented as
> TYPE_UNIMPLEMENTED_DEVICE, i.e. the whole memory map is provided. This allows
> for running Linux without it crashing due to invalid memory accesses.
> +static const struct {
> + hwaddr addr;
> + size_t size;
> + const char *name;
> +} fsl_imx8mp_memmap[] = {
> + [FSL_IMX8MP_UART2] = { 0x30890000, 64 * KiB, "uart2" },
> + [FSL_IMX8MP_UART3] = { 0x30880000, 64 * KiB, "uart3" },
> + [FSL_IMX8MP_UART1] = { 0x30860000, 64 * KiB, "uart1" },
> + /* UARTs */
> + for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
> + static const struct {
> + hwaddr addr;
> + unsigned int irq;
> + } serial_table[FSL_IMX8MP_NUM_UARTS] = {
> + { fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
> + { fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
> + { fsl_imx8mp_memmap[FSL_IMX8MP_UART3].addr, FSL_IMX8MP_UART3_IRQ },
> + { fsl_imx8mp_memmap[FSL_IMX8MP_UART4].addr, FSL_IMX8MP_UART4_IRQ },
> + };
The C compiler for the OpenSUSE CI job doesn't seem to like this:
https://gitlab.com/pm215/qemu/-/jobs/9239416833
../hw/arm/fsl-imx8mp.c: In function ‘fsl_imx8mp_realize’:
../hw/arm/fsl-imx8mp.c:382:15: error: initializer element is not constant
{ fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
^~~~~~~~~~~~~~~~~
../hw/arm/fsl-imx8mp.c:382:15: note: (near initialization for
‘serial_table[0].addr’)
../hw/arm/fsl-imx8mp.c:383:15: error: initializer element is not constant
{ fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
^~~~~~~~~~~~~~~~~
This is (gcc 7.5.0 "cc (SUSE Linux) 7.5.0") apparently. That's
a pretty old compiler, only just within the bounds of our
version requirements (which are 7.4 or better), so I'm guessing
it's just not as smart about figuring out that the
initializer here really is a constant value.
I'll fix this up by dropping the "const" from the serial_table[]
etc definitions.
-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board
2025-02-25 15:42 ` Peter Maydell
@ 2025-02-25 17:00 ` Peter Maydell
2025-02-26 6:36 ` Bernhard Beschow
2025-02-26 6:55 ` Bernhard Beschow
0 siblings, 2 replies; 45+ messages in thread
From: Peter Maydell @ 2025-02-25 17:00 UTC (permalink / raw)
To: Bernhard Beschow
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
On Tue, 25 Feb 2025 at 15:42, Peter Maydell <peter.maydell@linaro.org> wrote:
> The C compiler for the OpenSUSE CI job doesn't seem to like this:
> https://gitlab.com/pm215/qemu/-/jobs/9239416833
>
> ../hw/arm/fsl-imx8mp.c: In function ‘fsl_imx8mp_realize’:
> ../hw/arm/fsl-imx8mp.c:382:15: error: initializer element is not constant
> { fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
> ^~~~~~~~~~~~~~~~~
> ../hw/arm/fsl-imx8mp.c:382:15: note: (near initialization for
> ‘serial_table[0].addr’)
> ../hw/arm/fsl-imx8mp.c:383:15: error: initializer element is not constant
> { fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
> ^~~~~~~~~~~~~~~~~
>
> This is (gcc 7.5.0 "cc (SUSE Linux) 7.5.0") apparently. That's
> a pretty old compiler, only just within the bounds of our
> version requirements (which are 7.4 or better), so I'm guessing
> it's just not as smart about figuring out that the
> initializer here really is a constant value.
>
> I'll fix this up by dropping the "const" from the serial_table[]
> etc definitions.
More specifically, you have to drop 'static const', leaving just 'struct'.
Minimal repro: https://godbolt.org/z/5css4hv67
-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board
2025-02-25 17:00 ` Peter Maydell
@ 2025-02-26 6:36 ` Bernhard Beschow
2025-02-26 11:53 ` Peter Maydell
2025-02-26 6:55 ` Bernhard Beschow
1 sibling, 1 reply; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-26 6:36 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
Am 25. Februar 2025 17:00:53 UTC schrieb Peter Maydell <peter.maydell@linaro.org>:
>On Tue, 25 Feb 2025 at 15:42, Peter Maydell <peter.maydell@linaro.org> wrote:
>> The C compiler for the OpenSUSE CI job doesn't seem to like this:
>> https://gitlab.com/pm215/qemu/-/jobs/9239416833
>>
>> ../hw/arm/fsl-imx8mp.c: In function ‘fsl_imx8mp_realize’:
>> ../hw/arm/fsl-imx8mp.c:382:15: error: initializer element is not constant
>> { fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
>> ^~~~~~~~~~~~~~~~~
>> ../hw/arm/fsl-imx8mp.c:382:15: note: (near initialization for
>> ‘serial_table[0].addr’)
>> ../hw/arm/fsl-imx8mp.c:383:15: error: initializer element is not constant
>> { fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
>> ^~~~~~~~~~~~~~~~~
>>
>> This is (gcc 7.5.0 "cc (SUSE Linux) 7.5.0") apparently. That's
>> a pretty old compiler, only just within the bounds of our
>> version requirements (which are 7.4 or better), so I'm guessing
>> it's just not as smart about figuring out that the
>> initializer here really is a constant value.
>>
>> I'll fix this up by dropping the "const" from the serial_table[]
>> etc definitions.
>
>More specifically, you have to drop 'static const', leaving just 'struct'.
>Minimal repro: https://godbolt.org/z/5css4hv67
I haven't checked, but this might be caused by the multiplications (... * KiB) which the old compiler might not perform at compile time. Thanks for looking into it without another iteration of the series!
Best regards,
Bernhard
>
>-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board
2025-02-26 6:36 ` Bernhard Beschow
@ 2025-02-26 11:53 ` Peter Maydell
0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2025-02-26 11:53 UTC (permalink / raw)
To: Bernhard Beschow
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
On Wed, 26 Feb 2025 at 06:36, Bernhard Beschow <shentey@gmail.com> wrote:
>
>
>
> Am 25. Februar 2025 17:00:53 UTC schrieb Peter Maydell <peter.maydell@linaro.org>:
> >On Tue, 25 Feb 2025 at 15:42, Peter Maydell <peter.maydell@linaro.org> wrote:
> >> The C compiler for the OpenSUSE CI job doesn't seem to like this:
> >> https://gitlab.com/pm215/qemu/-/jobs/9239416833
> >>
> >> ../hw/arm/fsl-imx8mp.c: In function ‘fsl_imx8mp_realize’:
> >> ../hw/arm/fsl-imx8mp.c:382:15: error: initializer element is not constant
> >> { fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
> >> ^~~~~~~~~~~~~~~~~
> >> ../hw/arm/fsl-imx8mp.c:382:15: note: (near initialization for
> >> ‘serial_table[0].addr’)
> >> ../hw/arm/fsl-imx8mp.c:383:15: error: initializer element is not constant
> >> { fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
> >> ^~~~~~~~~~~~~~~~~
> >>
> >> This is (gcc 7.5.0 "cc (SUSE Linux) 7.5.0") apparently. That's
> >> a pretty old compiler, only just within the bounds of our
> >> version requirements (which are 7.4 or better), so I'm guessing
> >> it's just not as smart about figuring out that the
> >> initializer here really is a constant value.
> >>
> >> I'll fix this up by dropping the "const" from the serial_table[]
> >> etc definitions.
> >
> >More specifically, you have to drop 'static const', leaving just 'struct'.
> >Minimal repro: https://godbolt.org/z/5css4hv67
>
> I haven't checked, but this might be caused by the multiplications (... * KiB)
The godbolt repro case just uses plain constant values in the memmap
array, so it's not the multiplication that's at fault.
-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board
2025-02-25 17:00 ` Peter Maydell
2025-02-26 6:36 ` Bernhard Beschow
@ 2025-02-26 6:55 ` Bernhard Beschow
1 sibling, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-26 6:55 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
Am 25. Februar 2025 17:00:53 UTC schrieb Peter Maydell <peter.maydell@linaro.org>:
>On Tue, 25 Feb 2025 at 15:42, Peter Maydell <peter.maydell@linaro.org> wrote:
>> The C compiler for the OpenSUSE CI job doesn't seem to like this:
>> https://gitlab.com/pm215/qemu/-/jobs/9239416833
>>
>> ../hw/arm/fsl-imx8mp.c: In function ‘fsl_imx8mp_realize’:
>> ../hw/arm/fsl-imx8mp.c:382:15: error: initializer element is not constant
>> { fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
>> ^~~~~~~~~~~~~~~~~
>> ../hw/arm/fsl-imx8mp.c:382:15: note: (near initialization for
>> ‘serial_table[0].addr’)
>> ../hw/arm/fsl-imx8mp.c:383:15: error: initializer element is not constant
>> { fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
>> ^~~~~~~~~~~~~~~~~
>>
>> This is (gcc 7.5.0 "cc (SUSE Linux) 7.5.0") apparently. That's
>> a pretty old compiler, only just within the bounds of our
>> version requirements (which are 7.4 or better), so I'm guessing
>> it's just not as smart about figuring out that the
>> initializer here really is a constant value.
>>
>> I'll fix this up by dropping the "const" from the serial_table[]
>> etc definitions.
>
>More specifically, you have to drop 'static const', leaving just 'struct'.
>Minimal repro: https://godbolt.org/z/5css4hv67
I haven't checked, but this is probably caused by the multiplications (... * KiB) which the old compiler might not perform at compile time. Thanks for looking into it without another iteration of the series!
Best regards,
Bernhard
>
>-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 05/18] hw/arm/fsl-imx8mp: Implement clock tree
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (3 preceding siblings ...)
2025-02-23 11:46 ` [PATCH v2 04/18] hw/arm: Add i.MX 8M Plus EVK board Bernhard Beschow
@ 2025-02-23 11:46 ` Bernhard Beschow
2025-02-25 14:21 ` Peter Maydell
2025-02-23 11:46 ` [PATCH v2 06/18] hw/arm/fsl-imx8mp: Add SNVS Bernhard Beschow
` (13 subsequent siblings)
18 siblings, 1 reply; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:46 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
Fixes quite a few stack traces during the Linux boot process. Also provides the
clocks for devices added later, e.g. enet1.
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
MAINTAINERS | 2 +
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 4 +
include/hw/misc/imx8mp_analog.h | 81 +++++++++++++++
include/hw/misc/imx8mp_ccm.h | 30 ++++++
hw/arm/fsl-imx8mp.c | 20 ++++
hw/misc/imx8mp_analog.c | 160 +++++++++++++++++++++++++++++
hw/misc/imx8mp_ccm.c | 175 ++++++++++++++++++++++++++++++++
hw/arm/Kconfig | 2 +
hw/misc/Kconfig | 6 ++
hw/misc/meson.build | 2 +
11 files changed, 483 insertions(+)
create mode 100644 include/hw/misc/imx8mp_analog.h
create mode 100644 include/hw/misc/imx8mp_ccm.h
create mode 100644 hw/misc/imx8mp_analog.c
create mode 100644 hw/misc/imx8mp_ccm.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 374fe98724..8ea7fb4c7a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -826,7 +826,9 @@ L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/imx8mp-evk.c
F: hw/arm/fsl-imx8mp.c
+F: hw/misc/imx8mp_*.c
F: include/hw/arm/fsl-imx8mp.h
+F: include/hw/misc/imx8mp_*.h
F: docs/system/arm/imx8mp-evk.rst
MPS2 / MPS3
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index b23fdcc743..f0df346113 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -12,6 +12,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* Up to 4 Cortex-A53 cores
* Generic Interrupt Controller (GICv3)
* 4 UARTs
+ * Clock Tree
Boot options
------------
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 57e23d1b69..ce5188e7f2 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -12,6 +12,8 @@
#include "cpu.h"
#include "hw/char/imx_serial.h"
#include "hw/intc/arm_gicv3_common.h"
+#include "hw/misc/imx8mp_analog.h"
+#include "hw/misc/imx8mp_ccm.h"
#include "qom/object.h"
#include "qemu/units.h"
@@ -32,6 +34,8 @@ struct FslImx8mpState {
ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
GICv3State gic;
+ IMX8MPCCMState ccm;
+ IMX8MPAnalogState analog;
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
};
diff --git a/include/hw/misc/imx8mp_analog.h b/include/hw/misc/imx8mp_analog.h
new file mode 100644
index 0000000000..955f03215a
--- /dev/null
+++ b/include/hw/misc/imx8mp_analog.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * i.MX8MP ANALOG IP block emulation code
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef IMX8MP_ANALOG_H
+#define IMX8MP_ANALOG_H
+
+#include "qom/object.h"
+#include "hw/sysbus.h"
+
+enum IMX8MPAnalogRegisters {
+ ANALOG_AUDIO_PLL1_GEN_CTRL = 0x000 / 4,
+ ANALOG_AUDIO_PLL1_FDIV_CTL0 = 0x004 / 4,
+ ANALOG_AUDIO_PLL1_FDIV_CTL1 = 0x008 / 4,
+ ANALOG_AUDIO_PLL1_SSCG_CTRL = 0x00c / 4,
+ ANALOG_AUDIO_PLL1_MNIT_CTRL = 0x010 / 4,
+ ANALOG_AUDIO_PLL2_GEN_CTRL = 0x014 / 4,
+ ANALOG_AUDIO_PLL2_FDIV_CTL0 = 0x018 / 4,
+ ANALOG_AUDIO_PLL2_FDIV_CTL1 = 0x01c / 4,
+ ANALOG_AUDIO_PLL2_SSCG_CTRL = 0x020 / 4,
+ ANALOG_AUDIO_PLL2_MNIT_CTRL = 0x024 / 4,
+ ANALOG_VIDEO_PLL1_GEN_CTRL = 0x028 / 4,
+ ANALOG_VIDEO_PLL1_FDIV_CTL0 = 0x02c / 4,
+ ANALOG_VIDEO_PLL1_FDIV_CTL1 = 0x030 / 4,
+ ANALOG_VIDEO_PLL1_SSCG_CTRL = 0x034 / 4,
+ ANALOG_VIDEO_PLL1_MNIT_CTRL = 0x038 / 4,
+ ANALOG_DRAM_PLL_GEN_CTRL = 0x050 / 4,
+ ANALOG_DRAM_PLL_FDIV_CTL0 = 0x054 / 4,
+ ANALOG_DRAM_PLL_FDIV_CTL1 = 0x058 / 4,
+ ANALOG_DRAM_PLL_SSCG_CTRL = 0x05c / 4,
+ ANALOG_DRAM_PLL_MNIT_CTRL = 0x060 / 4,
+ ANALOG_GPU_PLL_GEN_CTRL = 0x064 / 4,
+ ANALOG_GPU_PLL_FDIV_CTL0 = 0x068 / 4,
+ ANALOG_GPU_PLL_LOCKD_CTRL = 0x06c / 4,
+ ANALOG_GPU_PLL_MNIT_CTRL = 0x070 / 4,
+ ANALOG_VPU_PLL_GEN_CTRL = 0x074 / 4,
+ ANALOG_VPU_PLL_FDIV_CTL0 = 0x078 / 4,
+ ANALOG_VPU_PLL_LOCKD_CTRL = 0x07c / 4,
+ ANALOG_VPU_PLL_MNIT_CTRL = 0x080 / 4,
+ ANALOG_ARM_PLL_GEN_CTRL = 0x084 / 4,
+ ANALOG_ARM_PLL_FDIV_CTL0 = 0x088 / 4,
+ ANALOG_ARM_PLL_LOCKD_CTRL = 0x08c / 4,
+ ANALOG_ARM_PLL_MNIT_CTRL = 0x090 / 4,
+ ANALOG_SYS_PLL1_GEN_CTRL = 0x094 / 4,
+ ANALOG_SYS_PLL1_FDIV_CTL0 = 0x098 / 4,
+ ANALOG_SYS_PLL1_LOCKD_CTRL = 0x09c / 4,
+ ANALOG_SYS_PLL1_MNIT_CTRL = 0x100 / 4,
+ ANALOG_SYS_PLL2_GEN_CTRL = 0x104 / 4,
+ ANALOG_SYS_PLL2_FDIV_CTL0 = 0x108 / 4,
+ ANALOG_SYS_PLL2_LOCKD_CTRL = 0x10c / 4,
+ ANALOG_SYS_PLL2_MNIT_CTRL = 0x110 / 4,
+ ANALOG_SYS_PLL3_GEN_CTRL = 0x114 / 4,
+ ANALOG_SYS_PLL3_FDIV_CTL0 = 0x118 / 4,
+ ANALOG_SYS_PLL3_LOCKD_CTRL = 0x11c / 4,
+ ANALOG_SYS_PLL3_MNIT_CTRL = 0x120 / 4,
+ ANALOG_OSC_MISC_CFG = 0x124 / 4,
+ ANALOG_ANAMIX_PLL_MNIT_CTL = 0x128 / 4,
+
+ ANALOG_DIGPROG = 0x800 / 4,
+ ANALOG_MAX,
+};
+
+#define TYPE_IMX8MP_ANALOG "imx8mp.analog"
+OBJECT_DECLARE_SIMPLE_TYPE(IMX8MPAnalogState, IMX8MP_ANALOG)
+
+struct IMX8MPAnalogState {
+ SysBusDevice parent_obj;
+
+ struct {
+ MemoryRegion container;
+ MemoryRegion analog;
+ } mmio;
+
+ uint32_t analog[ANALOG_MAX];
+};
+
+#endif /* IMX8MP_ANALOG_H */
diff --git a/include/hw/misc/imx8mp_ccm.h b/include/hw/misc/imx8mp_ccm.h
new file mode 100644
index 0000000000..685c8582ff
--- /dev/null
+++ b/include/hw/misc/imx8mp_ccm.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * i.MX 8M Plus CCM IP block emulation code
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef IMX8MP_CCM_H
+#define IMX8MP_CCM_H
+
+#include "hw/misc/imx_ccm.h"
+#include "qom/object.h"
+
+enum IMX8MPCCMRegisters {
+ CCM_MAX = 0xc6fc / sizeof(uint32_t) + 1,
+};
+
+#define TYPE_IMX8MP_CCM "imx8mp.ccm"
+OBJECT_DECLARE_SIMPLE_TYPE(IMX8MPCCMState, IMX8MP_CCM)
+
+struct IMX8MPCCMState {
+ IMXCCMState parent_obj;
+
+ MemoryRegion iomem;
+
+ uint32_t ccm[CCM_MAX];
+};
+
+#endif /* IMX8MP_CCM_H */
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 484b45c0d8..2b86de45a0 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -197,6 +197,10 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GICV3);
+ object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX8MP_CCM);
+
+ object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG);
+
for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
g_autofree char *name = g_strdup_printf("uart%d", i + 1);
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
@@ -304,6 +308,20 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
}
}
+ /* CCM */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_CCM].addr);
+
+ /* Analog */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->analog), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->analog), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_ANA_PLL].addr);
+
/* UARTs */
for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
static const struct {
@@ -329,6 +347,8 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
/* Unimplemented devices */
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
switch (i) {
+ case FSL_IMX8MP_ANA_PLL:
+ case FSL_IMX8MP_CCM:
case FSL_IMX8MP_GIC_DIST:
case FSL_IMX8MP_GIC_REDIST:
case FSL_IMX8MP_RAM:
diff --git a/hw/misc/imx8mp_analog.c b/hw/misc/imx8mp_analog.c
new file mode 100644
index 0000000000..f7e7c83cc4
--- /dev/null
+++ b/hw/misc/imx8mp_analog.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * i.MX 8M Plus ANALOG IP block emulation code
+ *
+ * Based on hw/misc/imx7_ccm.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+
+#include "hw/misc/imx8mp_analog.h"
+#include "migration/vmstate.h"
+
+#define ANALOG_PLL_LOCK BIT(31)
+
+static void imx8mp_analog_reset(DeviceState *dev)
+{
+ IMX8MPAnalogState *s = IMX8MP_ANALOG(dev);
+
+ memset(s->analog, 0, sizeof(s->analog));
+
+ s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] = 0x00002010;
+ s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL0] = 0x00145032;
+ s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL1] = 0x00000000;
+ s->analog[ANALOG_AUDIO_PLL1_SSCG_CTRL] = 0x00000000;
+ s->analog[ANALOG_AUDIO_PLL1_MNIT_CTRL] = 0x00100103;
+ s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] = 0x00002010;
+ s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL0] = 0x00145032;
+ s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL1] = 0x00000000;
+ s->analog[ANALOG_AUDIO_PLL2_SSCG_CTRL] = 0x00000000;
+ s->analog[ANALOG_AUDIO_PLL2_MNIT_CTRL] = 0x00100103;
+ s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] = 0x00002010;
+ s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL0] = 0x00145032;
+ s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL1] = 0x00000000;
+ s->analog[ANALOG_VIDEO_PLL1_SSCG_CTRL] = 0x00000000;
+ s->analog[ANALOG_VIDEO_PLL1_MNIT_CTRL] = 0x00100103;
+ s->analog[ANALOG_DRAM_PLL_GEN_CTRL] = 0x00002010;
+ s->analog[ANALOG_DRAM_PLL_FDIV_CTL0] = 0x0012c032;
+ s->analog[ANALOG_DRAM_PLL_FDIV_CTL1] = 0x00000000;
+ s->analog[ANALOG_DRAM_PLL_SSCG_CTRL] = 0x00000000;
+ s->analog[ANALOG_DRAM_PLL_MNIT_CTRL] = 0x00100103;
+ s->analog[ANALOG_GPU_PLL_GEN_CTRL] = 0x00000810;
+ s->analog[ANALOG_GPU_PLL_FDIV_CTL0] = 0x000c8031;
+ s->analog[ANALOG_GPU_PLL_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_GPU_PLL_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_VPU_PLL_GEN_CTRL] = 0x00000810;
+ s->analog[ANALOG_VPU_PLL_FDIV_CTL0] = 0x0012c032;
+ s->analog[ANALOG_VPU_PLL_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_VPU_PLL_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_ARM_PLL_GEN_CTRL] = 0x00000810;
+ s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = 0x000fa031;
+ s->analog[ANALOG_ARM_PLL_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_ARM_PLL_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_SYS_PLL1_GEN_CTRL] = 0x0aaaa810;
+ s->analog[ANALOG_SYS_PLL1_FDIV_CTL0] = 0x00190032;
+ s->analog[ANALOG_SYS_PLL1_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_SYS_PLL1_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_SYS_PLL2_GEN_CTRL] = 0x0aaaa810;
+ s->analog[ANALOG_SYS_PLL2_FDIV_CTL0] = 0x000fa031;
+ s->analog[ANALOG_SYS_PLL2_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_SYS_PLL2_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_SYS_PLL3_GEN_CTRL] = 0x00000810;
+ s->analog[ANALOG_SYS_PLL3_FDIV_CTL0] = 0x000fa031;
+ s->analog[ANALOG_SYS_PLL3_LOCKD_CTRL] = 0x0010003f;
+ s->analog[ANALOG_SYS_PLL3_MNIT_CTRL] = 0x00280081;
+ s->analog[ANALOG_OSC_MISC_CFG] = 0x00000000;
+ s->analog[ANALOG_ANAMIX_PLL_MNIT_CTL] = 0x00000000;
+ s->analog[ANALOG_DIGPROG] = 0x00824010;
+
+ /* all PLLs need to be locked */
+ s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_DRAM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_GPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_VPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_ARM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_SYS_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_SYS_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
+ s->analog[ANALOG_SYS_PLL3_GEN_CTRL] |= ANALOG_PLL_LOCK;
+}
+
+static uint64_t imx8mp_analog_read(void *opaque, hwaddr offset, unsigned size)
+{
+ IMX8MPAnalogState *s = opaque;
+
+ return s->analog[offset >> 2];
+}
+
+static void imx8mp_analog_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ IMX8MPAnalogState *s = opaque;
+
+ if (offset >> 2 == ANALOG_DIGPROG) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Guest write to read-only ANALOG_DIGPROG register\n");
+ } else {
+ s->analog[offset >> 2] = value;
+ }
+}
+
+static const struct MemoryRegionOps imx8mp_analog_ops = {
+ .read = imx8mp_analog_read,
+ .write = imx8mp_analog_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+};
+
+static void imx8mp_analog_init(Object *obj)
+{
+ IMX8MPAnalogState *s = IMX8MP_ANALOG(obj);
+ SysBusDevice *sd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init(&s->mmio.container, obj, TYPE_IMX8MP_ANALOG, 0x10000);
+
+ memory_region_init_io(&s->mmio.analog, obj, &imx8mp_analog_ops, s,
+ TYPE_IMX8MP_ANALOG, sizeof(s->analog));
+ memory_region_add_subregion(&s->mmio.container, 0, &s->mmio.analog);
+
+ sysbus_init_mmio(sd, &s->mmio.container);
+}
+
+static const VMStateDescription imx8mp_analog_vmstate = {
+ .name = TYPE_IMX8MP_ANALOG,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(analog, IMX8MPAnalogState, ANALOG_MAX),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void imx8mp_analog_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ device_class_set_legacy_reset(dc, imx8mp_analog_reset);
+ dc->vmsd = &imx8mp_analog_vmstate;
+ dc->desc = "i.MX 8M Plus Analog Module";
+}
+
+static const TypeInfo imx8mp_analog_types[] = {
+ {
+ .name = TYPE_IMX8MP_ANALOG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMX8MPAnalogState),
+ .instance_init = imx8mp_analog_init,
+ .class_init = imx8mp_analog_class_init,
+ }
+};
+
+DEFINE_TYPES(imx8mp_analog_types);
diff --git a/hw/misc/imx8mp_ccm.c b/hw/misc/imx8mp_ccm.c
new file mode 100644
index 0000000000..1a1c932427
--- /dev/null
+++ b/hw/misc/imx8mp_ccm.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * i.MX 8M Plus CCM IP block emulation code
+ *
+ * Based on hw/misc/imx7_ccm.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+
+#include "hw/misc/imx8mp_ccm.h"
+#include "migration/vmstate.h"
+
+#include "trace.h"
+
+#define CKIH_FREQ 16000000 /* 16MHz crystal input */
+
+static void imx8mp_ccm_reset(DeviceState *dev)
+{
+ IMX8MPCCMState *s = IMX8MP_CCM(dev);
+
+ memset(s->ccm, 0, sizeof(s->ccm));
+}
+
+#define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t))
+#define CCM_BITOP(offset) ((offset) & (hwaddr)0xF)
+
+enum {
+ CCM_BITOP_NONE = 0x00,
+ CCM_BITOP_SET = 0x04,
+ CCM_BITOP_CLR = 0x08,
+ CCM_BITOP_TOG = 0x0C,
+};
+
+static uint64_t imx8mp_set_clr_tog_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ const uint32_t *mmio = opaque;
+
+ return mmio[CCM_INDEX(offset)];
+}
+
+static void imx8mp_set_clr_tog_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ const uint8_t bitop = CCM_BITOP(offset);
+ const uint32_t index = CCM_INDEX(offset);
+ uint32_t *mmio = opaque;
+
+ switch (bitop) {
+ case CCM_BITOP_NONE:
+ mmio[index] = value;
+ break;
+ case CCM_BITOP_SET:
+ mmio[index] |= value;
+ break;
+ case CCM_BITOP_CLR:
+ mmio[index] &= ~value;
+ break;
+ case CCM_BITOP_TOG:
+ mmio[index] ^= value;
+ break;
+ };
+}
+
+static const struct MemoryRegionOps imx8mp_set_clr_tog_ops = {
+ .read = imx8mp_set_clr_tog_read,
+ .write = imx8mp_set_clr_tog_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ /*
+ * Our device would not work correctly if the guest was doing
+ * unaligned access. This might not be a limitation on the real
+ * device but in practice there is no reason for a guest to access
+ * this device unaligned.
+ */
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+};
+
+static void imx8mp_ccm_init(Object *obj)
+{
+ SysBusDevice *sd = SYS_BUS_DEVICE(obj);
+ IMX8MPCCMState *s = IMX8MP_CCM(obj);
+
+ memory_region_init_io(&s->iomem,
+ obj,
+ &imx8mp_set_clr_tog_ops,
+ s->ccm,
+ TYPE_IMX8MP_CCM ".ccm",
+ sizeof(s->ccm));
+
+ sysbus_init_mmio(sd, &s->iomem);
+}
+
+static const VMStateDescription imx8mp_ccm_vmstate = {
+ .name = TYPE_IMX8MP_CCM,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(ccm, IMX8MPCCMState, CCM_MAX),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static uint32_t imx8mp_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
+{
+ /*
+ * This function is "consumed" by GPT emulation code. Some clocks
+ * have fixed frequencies and we can provide requested frequency
+ * easily. However for CCM provided clocks (like IPG) each GPT
+ * timer can have its own clock root.
+ * This means we need additional information when calling this
+ * function to know the requester's identity.
+ */
+ uint32_t freq = 0;
+
+ switch (clock) {
+ case CLK_NONE:
+ break;
+ case CLK_32k:
+ freq = CKIL_FREQ;
+ break;
+ case CLK_HIGH:
+ freq = CKIH_FREQ;
+ break;
+ case CLK_IPG:
+ case CLK_IPG_HIGH:
+ /*
+ * For now we don't have a way to figure out the device this
+ * function is called for. Until then the IPG derived clocks
+ * are left unimplemented.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Clock %d Not implemented\n",
+ TYPE_IMX8MP_CCM, __func__, clock);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
+ TYPE_IMX8MP_CCM, __func__, clock);
+ break;
+ }
+
+ trace_ccm_clock_freq(clock, freq);
+
+ return freq;
+}
+
+static void imx8mp_ccm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
+
+ device_class_set_legacy_reset(dc, imx8mp_ccm_reset);
+ dc->vmsd = &imx8mp_ccm_vmstate;
+ dc->desc = "i.MX 8M Plus Clock Control Module";
+
+ ccm->get_clock_frequency = imx8mp_ccm_get_clock_frequency;
+}
+
+static const TypeInfo imx8mp_ccm_types[] = {
+ {
+ .name = TYPE_IMX8MP_CCM,
+ .parent = TYPE_IMX_CCM,
+ .instance_size = sizeof(IMX8MPCCMState),
+ .instance_init = imx8mp_ccm_init,
+ .class_init = imx8mp_ccm_class_init,
+ },
+};
+
+DEFINE_TYPES(imx8mp_ccm_types);
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 0a7de40861..f77c451ba3 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -596,6 +596,8 @@ config FSL_IMX7
config FSL_IMX8MP
bool
select ARM_GIC
+ select FSL_IMX8MP_ANALOG
+ select FSL_IMX8MP_CCM
select IMX
select UNIMP
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 4271e2f4ac..82bd68b4bb 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -78,6 +78,12 @@ config IMX
select SSI
select USB_EHCI_SYSBUS
+config FSL_IMX8MP_ANALOG
+ bool
+
+config FSL_IMX8MP_CCM
+ bool
+
config STM32_RCC
bool
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index edd36a334d..0b5187a2f7 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -55,6 +55,8 @@ system_ss.add(when: 'CONFIG_AXP2XX_PMU', if_true: files('axp2xx.c'))
system_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
system_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pmu.c', 'exynos4210_clk.c', 'exynos4210_rng.c'))
+system_ss.add(when: 'CONFIG_FSL_IMX8MP_ANALOG', if_true: files('imx8mp_analog.c'))
+system_ss.add(when: 'CONFIG_FSL_IMX8MP_CCM', if_true: files('imx8mp_ccm.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx25_ccm.c',
'imx31_ccm.c',
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* Re: [PATCH v2 05/18] hw/arm/fsl-imx8mp: Implement clock tree
2025-02-23 11:46 ` [PATCH v2 05/18] hw/arm/fsl-imx8mp: Implement clock tree Bernhard Beschow
@ 2025-02-25 14:21 ` Peter Maydell
0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2025-02-25 14:21 UTC (permalink / raw)
To: Bernhard Beschow
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
On Sun, 23 Feb 2025 at 11:47, Bernhard Beschow <shentey@gmail.com> wrote:
>
> Fixes quite a few stack traces during the Linux boot process. Also provides the
> clocks for devices added later, e.g. enet1.
>
> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
> ---
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 06/18] hw/arm/fsl-imx8mp: Add SNVS
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (4 preceding siblings ...)
2025-02-23 11:46 ` [PATCH v2 05/18] hw/arm/fsl-imx8mp: Implement clock tree Bernhard Beschow
@ 2025-02-23 11:46 ` Bernhard Beschow
2025-02-23 11:46 ` [PATCH v2 07/18] hw/arm/fsl-imx8mp: Add USDHC storage controllers Bernhard Beschow
` (12 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:46 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
SNVS contains an RTC which allows Linux to deal correctly with time. This is
particularly useful when handling persistent storage which will be done in the
next patch.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 2 ++
hw/arm/fsl-imx8mp.c | 10 ++++++++++
3 files changed, 13 insertions(+)
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index f0df346113..22541c5442 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -12,6 +12,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* Up to 4 Cortex-A53 cores
* Generic Interrupt Controller (GICv3)
* 4 UARTs
+ * Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
Boot options
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index ce5188e7f2..26e24e99a1 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -12,6 +12,7 @@
#include "cpu.h"
#include "hw/char/imx_serial.h"
#include "hw/intc/arm_gicv3_common.h"
+#include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mp_analog.h"
#include "hw/misc/imx8mp_ccm.h"
#include "qom/object.h"
@@ -36,6 +37,7 @@ struct FslImx8mpState {
GICv3State gic;
IMX8MPCCMState ccm;
IMX8MPAnalogState analog;
+ IMX7SNVSState snvs;
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
};
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 2b86de45a0..de47ac1804 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -201,6 +201,8 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG);
+ object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS);
+
for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
g_autofree char *name = g_strdup_printf("uart%d", i + 1);
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
@@ -344,6 +346,13 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, serial_table[i].irq));
}
+ /* SNVS */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_SNVS_HP].addr);
+
/* Unimplemented devices */
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
switch (i) {
@@ -352,6 +361,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_GIC_DIST:
case FSL_IMX8MP_GIC_REDIST:
case FSL_IMX8MP_RAM:
+ case FSL_IMX8MP_SNVS_HP:
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
/* device implemented and treated above */
break;
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 07/18] hw/arm/fsl-imx8mp: Add USDHC storage controllers
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (5 preceding siblings ...)
2025-02-23 11:46 ` [PATCH v2 06/18] hw/arm/fsl-imx8mp: Add SNVS Bernhard Beschow
@ 2025-02-23 11:46 ` Bernhard Beschow
2025-02-23 11:46 ` [PATCH v2 08/18] hw/arm/fsl-imx8mp: Add PCIe support Bernhard Beschow
` (11 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:46 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
The USDHC emulation allows for running real-world images such as those generated
by Buildroot. Convert the board documentation accordingly instead of running a
Linux kernel with ephemeral storage.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
docs/system/arm/imx8mp-evk.rst | 18 ++++++++++++------
include/hw/arm/fsl-imx8mp.h | 7 +++++++
hw/arm/fsl-imx8mp.c | 28 ++++++++++++++++++++++++++++
hw/arm/imx8mp-evk.c | 18 ++++++++++++++++++
hw/arm/Kconfig | 1 +
5 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index 22541c5442..879c822356 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -12,6 +12,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* Up to 4 Cortex-A53 cores
* Generic Interrupt Controller (GICv3)
* 4 UARTs
+ * 3 USDHC Storage Controllers
* Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
@@ -26,18 +27,23 @@ Direct Linux Kernel Boot
Probably the easiest way to get started with a whole Linux system on the machine
is to generate an image with Buildroot. Version 2024.11.1 is tested at the time
-of writing and involves two steps. First run the following commands in the
+of writing and involves three steps. First run the following commands in the
toplevel directory of the Buildroot source tree:
.. code-block:: bash
- $ echo "BR2_TARGET_ROOTFS_CPIO=y" >> configs/freescale_imx8mpevk_defconfig
$ make freescale_imx8mpevk_defconfig
$ make
Once finished successfully there is an ``output/image`` subfolder. Navigate into
-it and patch the device tree with the following commands which will remove the
-``cpu-idle-states`` properties from CPU nodes:
+it and resize the SD card image to a power of two:
+
+.. code-block:: bash
+
+ $ qemu-img resize sdcard.img 256M
+
+Finally, the device tree needs to be patched with the following commands which
+will remove the ``cpu-idle-states`` properties from CPU nodes:
.. code-block:: bash
@@ -52,5 +58,5 @@ Now that everything is prepared the machine can be started as follows:
-display none -serial null -serial stdio \
-kernel Image \
-dtb imx8mp-evk-patched.dtb \
- -initrd rootfs.cpio \
- -append "root=/dev/ram"
+ -append "root=/dev/mmcblk2p2" \
+ -drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 26e24e99a1..349d55ca88 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -15,6 +15,7 @@
#include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mp_analog.h"
#include "hw/misc/imx8mp_ccm.h"
+#include "hw/sd/sdhci.h"
#include "qom/object.h"
#include "qemu/units.h"
@@ -28,6 +29,7 @@ enum FslImx8mpConfiguration {
FSL_IMX8MP_NUM_CPUS = 4,
FSL_IMX8MP_NUM_IRQS = 160,
FSL_IMX8MP_NUM_UARTS = 4,
+ FSL_IMX8MP_NUM_USDHCS = 3,
};
struct FslImx8mpState {
@@ -39,6 +41,7 @@ struct FslImx8mpState {
IMX8MPAnalogState analog;
IMX7SNVSState snvs;
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
+ SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
};
enum FslImx8mpMemoryRegions {
@@ -184,6 +187,10 @@ enum FslImx8mpMemoryRegions {
};
enum FslImx8mpIrqs {
+ FSL_IMX8MP_USDHC1_IRQ = 22,
+ FSL_IMX8MP_USDHC2_IRQ = 23,
+ FSL_IMX8MP_USDHC3_IRQ = 24,
+
FSL_IMX8MP_UART1_IRQ = 26,
FSL_IMX8MP_UART2_IRQ = 27,
FSL_IMX8MP_UART3_IRQ = 28,
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index de47ac1804..ad26c1e2f0 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -207,6 +207,11 @@ static void fsl_imx8mp_init(Object *obj)
g_autofree char *name = g_strdup_printf("uart%d", i + 1);
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
}
+
+ for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
+ g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
+ object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
+ }
}
static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
@@ -346,6 +351,28 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, serial_table[i].irq));
}
+ /* USDHCs */
+ for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } usdhc_table[FSL_IMX8MP_NUM_USDHCS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC1].addr, FSL_IMX8MP_USDHC1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC2].addr, FSL_IMX8MP_USDHC2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC3].addr, FSL_IMX8MP_USDHC3_IRQ },
+ };
+
+ object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
+ SDHCI_VENDOR_IMX, &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
+ qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
+ }
+
/* SNVS */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
return;
@@ -363,6 +390,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_RAM:
case FSL_IMX8MP_SNVS_HP:
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
+ case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
/* device implemented and treated above */
break;
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
index 2756d4c21c..27d9e9e8ee 100644
--- a/hw/arm/imx8mp-evk.c
+++ b/hw/arm/imx8mp-evk.c
@@ -11,6 +11,7 @@
#include "hw/arm/boot.h"
#include "hw/arm/fsl-imx8mp.h"
#include "hw/boards.h"
+#include "hw/qdev-properties.h"
#include "system/qtest.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
@@ -40,6 +41,23 @@ static void imx8mp_evk_init(MachineState *machine)
memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
machine->ram);
+ for (int i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
+ BusState *bus;
+ DeviceState *carddev;
+ BlockBackend *blk;
+ DriveInfo *di = drive_get(IF_SD, i, 0);
+
+ if (!di) {
+ continue;
+ }
+
+ blk = blk_by_legacy_dinfo(di);
+ bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
+ carddev = qdev_new(TYPE_SD_CARD);
+ qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
+ qdev_realize_and_unref(carddev, bus, &error_fatal);
+ }
+
if (!qtest_enabled()) {
arm_load_kernel(&s->cpu[0], machine, &boot_info);
}
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index f77c451ba3..d2dda3213d 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -599,6 +599,7 @@ config FSL_IMX8MP
select FSL_IMX8MP_ANALOG
select FSL_IMX8MP_CCM
select IMX
+ select SDHCI
select UNIMP
config FSL_IMX8MP_EVK
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 08/18] hw/arm/fsl-imx8mp: Add PCIe support
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (6 preceding siblings ...)
2025-02-23 11:46 ` [PATCH v2 07/18] hw/arm/fsl-imx8mp: Add USDHC storage controllers Bernhard Beschow
@ 2025-02-23 11:46 ` Bernhard Beschow
2025-02-25 14:22 ` Peter Maydell
2025-02-23 11:46 ` [PATCH v2 09/18] hw/arm/fsl-imx8mp: Add GPIO controllers Bernhard Beschow
` (10 subsequent siblings)
18 siblings, 1 reply; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:46 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
Linux checks for the PLLs in the PHY to be locked, so implement a model
emulating that.
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
MAINTAINERS | 2 +
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 10 +++
include/hw/pci-host/fsl_imx8m_phy.h | 28 +++++++++
hw/arm/fsl-imx8mp.c | 30 +++++++++
hw/pci-host/fsl_imx8m_phy.c | 98 +++++++++++++++++++++++++++++
hw/arm/Kconfig | 3 +
hw/pci-host/Kconfig | 3 +
hw/pci-host/meson.build | 1 +
9 files changed, 176 insertions(+)
create mode 100644 include/hw/pci-host/fsl_imx8m_phy.h
create mode 100644 hw/pci-host/fsl_imx8m_phy.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 8ea7fb4c7a..2e7fc6fa91 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -827,8 +827,10 @@ S: Maintained
F: hw/arm/imx8mp-evk.c
F: hw/arm/fsl-imx8mp.c
F: hw/misc/imx8mp_*.c
+F: hw/pci-host/fsl_imx8m_phy.c
F: include/hw/arm/fsl-imx8mp.h
F: include/hw/misc/imx8mp_*.h
+F: include/hw/pci-host/fsl_imx8m_phy.h
F: docs/system/arm/imx8mp-evk.rst
MPS2 / MPS3
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index 879c822356..18a8fdd278 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -13,6 +13,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* Generic Interrupt Controller (GICv3)
* 4 UARTs
* 3 USDHC Storage Controllers
+ * 1 Designware PCI Express Controller
* Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 349d55ca88..4c70c887a8 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -15,6 +15,8 @@
#include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mp_analog.h"
#include "hw/misc/imx8mp_ccm.h"
+#include "hw/pci-host/designware.h"
+#include "hw/pci-host/fsl_imx8m_phy.h"
#include "hw/sd/sdhci.h"
#include "qom/object.h"
#include "qemu/units.h"
@@ -42,6 +44,8 @@ struct FslImx8mpState {
IMX7SNVSState snvs;
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
+ DesignwarePCIEHost pcie;
+ FslImx8mPciePhyState pcie_phy;
};
enum FslImx8mpMemoryRegions {
@@ -197,6 +201,12 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_UART4_IRQ = 29,
FSL_IMX8MP_UART5_IRQ = 30,
FSL_IMX8MP_UART6_IRQ = 16,
+
+ FSL_IMX8MP_PCI_INTA_IRQ = 126,
+ FSL_IMX8MP_PCI_INTB_IRQ = 125,
+ FSL_IMX8MP_PCI_INTC_IRQ = 124,
+ FSL_IMX8MP_PCI_INTD_IRQ = 123,
+ FSL_IMX8MP_PCI_MSI_IRQ = 140,
};
#endif /* FSL_IMX8MP_H */
diff --git a/include/hw/pci-host/fsl_imx8m_phy.h b/include/hw/pci-host/fsl_imx8m_phy.h
new file mode 100644
index 0000000000..4f4875b37d
--- /dev/null
+++ b/include/hw/pci-host/fsl_imx8m_phy.h
@@ -0,0 +1,28 @@
+/*
+ * i.MX8 PCIe PHY emulation
+ *
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_PCIHOST_FSLIMX8MPCIEPHY_H
+#define HW_PCIHOST_FSLIMX8MPCIEPHY_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+#include "exec/memory.h"
+
+#define TYPE_FSL_IMX8M_PCIE_PHY "fsl-imx8m-pcie-phy"
+OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mPciePhyState, FSL_IMX8M_PCIE_PHY)
+
+#define FSL_IMX8M_PCIE_PHY_DATA_SIZE 0x800
+
+struct FslImx8mPciePhyState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ uint8_t data[FSL_IMX8M_PCIE_PHY_DATA_SIZE];
+};
+
+#endif
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index ad26c1e2f0..791d24eec9 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -212,6 +212,10 @@ static void fsl_imx8mp_init(Object *obj)
g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
}
+
+ object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
+ object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
+ TYPE_FSL_IMX8M_PCIE_PHY);
}
static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
@@ -380,6 +384,30 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0,
fsl_imx8mp_memmap[FSL_IMX8MP_SNVS_HP].addr);
+ /* PCIe */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_PCIE1].addr);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 0,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTA_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 1,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTB_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 2,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTC_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 3,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTD_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 4,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_MSI_IRQ));
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_PCIE_PHY1].addr);
+
/* Unimplemented devices */
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
switch (i) {
@@ -387,6 +415,8 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_CCM:
case FSL_IMX8MP_GIC_DIST:
case FSL_IMX8MP_GIC_REDIST:
+ case FSL_IMX8MP_PCIE1:
+ case FSL_IMX8MP_PCIE_PHY1:
case FSL_IMX8MP_RAM:
case FSL_IMX8MP_SNVS_HP:
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
diff --git a/hw/pci-host/fsl_imx8m_phy.c b/hw/pci-host/fsl_imx8m_phy.c
new file mode 100644
index 0000000000..aa304b102b
--- /dev/null
+++ b/hw/pci-host/fsl_imx8m_phy.c
@@ -0,0 +1,98 @@
+/*
+ * i.MX8 PCIe PHY emulation
+ *
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci-host/fsl_imx8m_phy.h"
+#include "hw/resettable.h"
+#include "migration/vmstate.h"
+
+#define CMN_REG075 0x1d4
+#define ANA_PLL_LOCK_DONE BIT(1)
+#define ANA_PLL_AFC_DONE BIT(0)
+
+static uint64_t fsl_imx8m_pcie_phy_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ FslImx8mPciePhyState *s = opaque;
+
+ if (offset == CMN_REG075) {
+ return s->data[offset] | ANA_PLL_LOCK_DONE | ANA_PLL_AFC_DONE;
+ }
+
+ return s->data[offset];
+}
+
+static void fsl_imx8m_pcie_phy_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ FslImx8mPciePhyState *s = opaque;
+
+ s->data[offset] = value;
+}
+
+static const MemoryRegionOps fsl_imx8m_pcie_phy_ops = {
+ .read = fsl_imx8m_pcie_phy_read,
+ .write = fsl_imx8m_pcie_phy_write,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void fsl_imx8m_pcie_phy_realize(DeviceState *dev, Error **errp)
+{
+ FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &fsl_imx8m_pcie_phy_ops, s,
+ TYPE_FSL_IMX8M_PCIE_PHY, ARRAY_SIZE(s->data));
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+}
+
+static void fsl_imx8m_pcie_phy_reset_hold(Object *obj, ResetType type)
+{
+ FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(obj);
+
+ memset(s->data, 0, sizeof(s->data));
+}
+
+static const VMStateDescription fsl_imx8m_pcie_phy_vmstate = {
+ .name = "fsl-imx8m-pcie-phy",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT8_ARRAY(data, FslImx8mPciePhyState,
+ FSL_IMX8M_PCIE_PHY_DATA_SIZE),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void fsl_imx8m_pcie_phy_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = fsl_imx8m_pcie_phy_realize;
+ dc->vmsd = &fsl_imx8m_pcie_phy_vmstate;
+ rc->phases.hold = fsl_imx8m_pcie_phy_reset_hold;
+}
+
+static const TypeInfo fsl_imx8m_pcie_phy_types[] = {
+ {
+ .name = TYPE_FSL_IMX8M_PCIE_PHY,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FslImx8mPciePhyState),
+ .class_init = fsl_imx8m_pcie_phy_class_init,
+ }
+};
+
+DEFINE_TYPES(fsl_imx8m_pcie_phy_types)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index d2dda3213d..be5a2c02b7 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -595,10 +595,13 @@ config FSL_IMX7
config FSL_IMX8MP
bool
+ imply PCI_DEVICES
select ARM_GIC
select FSL_IMX8MP_ANALOG
select FSL_IMX8MP_CCM
select IMX
+ select PCI_EXPRESS_DESIGNWARE
+ select PCI_EXPRESS_FSL_IMX8M_PHY
select SDHCI
select UNIMP
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
index c91880b237..35c0415242 100644
--- a/hw/pci-host/Kconfig
+++ b/hw/pci-host/Kconfig
@@ -99,6 +99,9 @@ config ASTRO
bool
select PCI
+config PCI_EXPRESS_FSL_IMX8M_PHY
+ bool
+
config GT64120
bool
select PCI
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
index 3001e93a43..937a0f72ac 100644
--- a/hw/pci-host/meson.build
+++ b/hw/pci-host/meson.build
@@ -28,6 +28,7 @@ pci_ss.add(when: 'CONFIG_ARTICIA', if_true: files('articia.c'))
pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c'))
# ARM devices
+pci_ss.add(when: 'CONFIG_PCI_EXPRESS_FSL_IMX8M_PHY', if_true: files('fsl_imx8m_phy.c'))
pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c'))
# HPPA devices
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* Re: [PATCH v2 08/18] hw/arm/fsl-imx8mp: Add PCIe support
2025-02-23 11:46 ` [PATCH v2 08/18] hw/arm/fsl-imx8mp: Add PCIe support Bernhard Beschow
@ 2025-02-25 14:22 ` Peter Maydell
0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2025-02-25 14:22 UTC (permalink / raw)
To: Bernhard Beschow
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
On Sun, 23 Feb 2025 at 11:47, Bernhard Beschow <shentey@gmail.com> wrote:
>
> Linux checks for the PLLs in the PHY to be locked, so implement a model
> emulating that.
>
> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 09/18] hw/arm/fsl-imx8mp: Add GPIO controllers
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (7 preceding siblings ...)
2025-02-23 11:46 ` [PATCH v2 08/18] hw/arm/fsl-imx8mp: Add PCIe support Bernhard Beschow
@ 2025-02-23 11:46 ` Bernhard Beschow
2025-02-23 11:47 ` [PATCH v2 10/18] hw/arm/fsl-imx8mp: Add I2C controllers Bernhard Beschow
` (9 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:46 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 14 +++++++++
hw/arm/fsl-imx8mp.c | 55 ++++++++++++++++++++++++++++++++++
3 files changed, 70 insertions(+)
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index 18a8fdd278..37d3630d09 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -14,6 +14,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* 4 UARTs
* 3 USDHC Storage Controllers
* 1 Designware PCI Express Controller
+ * 5 GPIO Controllers
* Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 4c70c887a8..18ea52d083 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -11,6 +11,7 @@
#include "cpu.h"
#include "hw/char/imx_serial.h"
+#include "hw/gpio/imx_gpio.h"
#include "hw/intc/arm_gicv3_common.h"
#include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mp_analog.h"
@@ -29,6 +30,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
enum FslImx8mpConfiguration {
FSL_IMX8MP_NUM_CPUS = 4,
+ FSL_IMX8MP_NUM_GPIOS = 5,
FSL_IMX8MP_NUM_IRQS = 160,
FSL_IMX8MP_NUM_UARTS = 4,
FSL_IMX8MP_NUM_USDHCS = 3,
@@ -39,6 +41,7 @@ struct FslImx8mpState {
ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
GICv3State gic;
+ IMXGPIOState gpio[FSL_IMX8MP_NUM_GPIOS];
IMX8MPCCMState ccm;
IMX8MPAnalogState analog;
IMX7SNVSState snvs;
@@ -202,6 +205,17 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_UART5_IRQ = 30,
FSL_IMX8MP_UART6_IRQ = 16,
+ FSL_IMX8MP_GPIO1_LOW_IRQ = 64,
+ FSL_IMX8MP_GPIO1_HIGH_IRQ = 65,
+ FSL_IMX8MP_GPIO2_LOW_IRQ = 66,
+ FSL_IMX8MP_GPIO2_HIGH_IRQ = 67,
+ FSL_IMX8MP_GPIO3_LOW_IRQ = 68,
+ FSL_IMX8MP_GPIO3_HIGH_IRQ = 69,
+ FSL_IMX8MP_GPIO4_LOW_IRQ = 70,
+ FSL_IMX8MP_GPIO4_HIGH_IRQ = 71,
+ FSL_IMX8MP_GPIO5_LOW_IRQ = 72,
+ FSL_IMX8MP_GPIO5_HIGH_IRQ = 73,
+
FSL_IMX8MP_PCI_INTA_IRQ = 126,
FSL_IMX8MP_PCI_INTB_IRQ = 125,
FSL_IMX8MP_PCI_INTC_IRQ = 124,
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 791d24eec9..456fa47dc7 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -208,6 +208,11 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
}
+ for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
+ g_autofree char *name = g_strdup_printf("gpio%d", i + 1);
+ object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO);
+ }
+
for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
@@ -355,6 +360,55 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, serial_table[i].irq));
}
+ /* GPIOs */
+ for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq_low;
+ unsigned int irq_high;
+ } gpio_table[FSL_IMX8MP_NUM_GPIOS] = {
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO1].addr,
+ FSL_IMX8MP_GPIO1_LOW_IRQ,
+ FSL_IMX8MP_GPIO1_HIGH_IRQ
+ },
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO2].addr,
+ FSL_IMX8MP_GPIO2_LOW_IRQ,
+ FSL_IMX8MP_GPIO2_HIGH_IRQ
+ },
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO3].addr,
+ FSL_IMX8MP_GPIO3_LOW_IRQ,
+ FSL_IMX8MP_GPIO3_HIGH_IRQ
+ },
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO4].addr,
+ FSL_IMX8MP_GPIO4_LOW_IRQ,
+ FSL_IMX8MP_GPIO4_HIGH_IRQ
+ },
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO5].addr,
+ FSL_IMX8MP_GPIO5_LOW_IRQ,
+ FSL_IMX8MP_GPIO5_HIGH_IRQ
+ },
+ };
+
+ object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", true,
+ &error_abort);
+ object_property_set_bool(OBJECT(&s->gpio[i]), "has-upper-pin-irq",
+ true, &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
+ qdev_get_gpio_in(gicdev, gpio_table[i].irq_low));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
+ qdev_get_gpio_in(gicdev, gpio_table[i].irq_high));
+ }
+
/* USDHCs */
for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
static const struct {
@@ -415,6 +469,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_CCM:
case FSL_IMX8MP_GIC_DIST:
case FSL_IMX8MP_GIC_REDIST:
+ case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
case FSL_IMX8MP_PCIE1:
case FSL_IMX8MP_PCIE_PHY1:
case FSL_IMX8MP_RAM:
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 10/18] hw/arm/fsl-imx8mp: Add I2C controllers
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (8 preceding siblings ...)
2025-02-23 11:46 ` [PATCH v2 09/18] hw/arm/fsl-imx8mp: Add GPIO controllers Bernhard Beschow
@ 2025-02-23 11:47 ` Bernhard Beschow
2025-02-23 11:47 ` [PATCH v2 11/18] hw/arm/fsl-imx8mp: Add SPI controllers Bernhard Beschow
` (8 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:47 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 11 +++++++++++
hw/arm/fsl-imx8mp.c | 29 +++++++++++++++++++++++++++++
hw/arm/Kconfig | 2 ++
4 files changed, 43 insertions(+)
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index 37d3630d09..ef0d997250 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -15,6 +15,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* 3 USDHC Storage Controllers
* 1 Designware PCI Express Controller
* 5 GPIO Controllers
+ * 6 I2C Controllers
* Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 18ea52d083..2590056627 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -12,6 +12,7 @@
#include "cpu.h"
#include "hw/char/imx_serial.h"
#include "hw/gpio/imx_gpio.h"
+#include "hw/i2c/imx_i2c.h"
#include "hw/intc/arm_gicv3_common.h"
#include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mp_analog.h"
@@ -31,6 +32,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
enum FslImx8mpConfiguration {
FSL_IMX8MP_NUM_CPUS = 4,
FSL_IMX8MP_NUM_GPIOS = 5,
+ FSL_IMX8MP_NUM_I2CS = 6,
FSL_IMX8MP_NUM_IRQS = 160,
FSL_IMX8MP_NUM_UARTS = 4,
FSL_IMX8MP_NUM_USDHCS = 3,
@@ -45,6 +47,7 @@ struct FslImx8mpState {
IMX8MPCCMState ccm;
IMX8MPAnalogState analog;
IMX7SNVSState snvs;
+ IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
DesignwarePCIEHost pcie;
@@ -205,6 +208,11 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_UART5_IRQ = 30,
FSL_IMX8MP_UART6_IRQ = 16,
+ FSL_IMX8MP_I2C1_IRQ = 35,
+ FSL_IMX8MP_I2C2_IRQ = 36,
+ FSL_IMX8MP_I2C3_IRQ = 37,
+ FSL_IMX8MP_I2C4_IRQ = 38,
+
FSL_IMX8MP_GPIO1_LOW_IRQ = 64,
FSL_IMX8MP_GPIO1_HIGH_IRQ = 65,
FSL_IMX8MP_GPIO2_LOW_IRQ = 66,
@@ -216,6 +224,9 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_GPIO5_LOW_IRQ = 72,
FSL_IMX8MP_GPIO5_HIGH_IRQ = 73,
+ FSL_IMX8MP_I2C5_IRQ = 76,
+ FSL_IMX8MP_I2C6_IRQ = 77,
+
FSL_IMX8MP_PCI_INTA_IRQ = 126,
FSL_IMX8MP_PCI_INTB_IRQ = 125,
FSL_IMX8MP_PCI_INTC_IRQ = 124,
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 456fa47dc7..3da81e28ca 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -208,6 +208,11 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
}
+ for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
+ g_autofree char *name = g_strdup_printf("i2c%d", i + 1);
+ object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C);
+ }
+
for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
g_autofree char *name = g_strdup_printf("gpio%d", i + 1);
object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO);
@@ -360,6 +365,29 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, serial_table[i].irq));
}
+ /* I2Cs */
+ for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } i2c_table[FSL_IMX8MP_NUM_I2CS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C1].addr, FSL_IMX8MP_I2C1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C2].addr, FSL_IMX8MP_I2C2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C3].addr, FSL_IMX8MP_I2C3_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C4].addr, FSL_IMX8MP_I2C4_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C5].addr, FSL_IMX8MP_I2C5_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C6].addr, FSL_IMX8MP_I2C6_IRQ },
+ };
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
+ qdev_get_gpio_in(gicdev, i2c_table[i].irq));
+ }
+
/* GPIOs */
for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
static const struct {
@@ -470,6 +498,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_GIC_DIST:
case FSL_IMX8MP_GIC_REDIST:
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
+ case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
case FSL_IMX8MP_PCIE1:
case FSL_IMX8MP_PCIE_PHY1:
case FSL_IMX8MP_RAM:
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index be5a2c02b7..28ae409c85 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -595,11 +595,13 @@ config FSL_IMX7
config FSL_IMX8MP
bool
+ imply I2C_DEVICES
imply PCI_DEVICES
select ARM_GIC
select FSL_IMX8MP_ANALOG
select FSL_IMX8MP_CCM
select IMX
+ select IMX_I2C
select PCI_EXPRESS_DESIGNWARE
select PCI_EXPRESS_FSL_IMX8M_PHY
select SDHCI
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 11/18] hw/arm/fsl-imx8mp: Add SPI controllers
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (9 preceding siblings ...)
2025-02-23 11:47 ` [PATCH v2 10/18] hw/arm/fsl-imx8mp: Add I2C controllers Bernhard Beschow
@ 2025-02-23 11:47 ` Bernhard Beschow
2025-02-23 11:47 ` [PATCH v2 12/18] hw/arm/fsl-imx8mp: Add watchdog support Bernhard Beschow
` (7 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:47 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 8 ++++++++
hw/arm/fsl-imx8mp.c | 26 ++++++++++++++++++++++++++
3 files changed, 35 insertions(+)
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index ef0d997250..66e5865107 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -16,6 +16,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* 1 Designware PCI Express Controller
* 5 GPIO Controllers
* 6 I2C Controllers
+ * 3 SPI Controllers
* Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 2590056627..296a87eb50 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -20,6 +20,7 @@
#include "hw/pci-host/designware.h"
#include "hw/pci-host/fsl_imx8m_phy.h"
#include "hw/sd/sdhci.h"
+#include "hw/ssi/imx_spi.h"
#include "qom/object.h"
#include "qemu/units.h"
@@ -31,6 +32,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
enum FslImx8mpConfiguration {
FSL_IMX8MP_NUM_CPUS = 4,
+ FSL_IMX8MP_NUM_ECSPIS = 3,
FSL_IMX8MP_NUM_GPIOS = 5,
FSL_IMX8MP_NUM_I2CS = 6,
FSL_IMX8MP_NUM_IRQS = 160,
@@ -47,6 +49,7 @@ struct FslImx8mpState {
IMX8MPCCMState ccm;
IMX8MPAnalogState analog;
IMX7SNVSState snvs;
+ IMXSPIState spi[FSL_IMX8MP_NUM_ECSPIS];
IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
@@ -208,6 +211,11 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_UART5_IRQ = 30,
FSL_IMX8MP_UART6_IRQ = 16,
+ FSL_IMX8MP_ECSPI1_IRQ = 31,
+ FSL_IMX8MP_ECSPI2_IRQ = 32,
+ FSL_IMX8MP_ECSPI3_IRQ = 33,
+ FSL_IMX8MP_ECSPI4_IRQ = 34,
+
FSL_IMX8MP_I2C1_IRQ = 35,
FSL_IMX8MP_I2C2_IRQ = 36,
FSL_IMX8MP_I2C3_IRQ = 37,
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 3da81e28ca..14f317be70 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -223,6 +223,11 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
}
+ for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
+ g_autofree char *name = g_strdup_printf("spi%d", i + 1);
+ object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
+ }
+
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
TYPE_FSL_IMX8M_PCIE_PHY);
@@ -459,6 +464,26 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
}
+ /* ECSPIs */
+ for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } spi_table[FSL_IMX8MP_NUM_ECSPIS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI1].addr, FSL_IMX8MP_ECSPI1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI2].addr, FSL_IMX8MP_ECSPI2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI3].addr, FSL_IMX8MP_ECSPI3_IRQ },
+ };
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
+ qdev_get_gpio_in(gicdev, spi_table[i].irq));
+ }
+
/* SNVS */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
return;
@@ -498,6 +523,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_GIC_DIST:
case FSL_IMX8MP_GIC_REDIST:
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
+ case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
case FSL_IMX8MP_PCIE1:
case FSL_IMX8MP_PCIE_PHY1:
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 12/18] hw/arm/fsl-imx8mp: Add watchdog support
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (10 preceding siblings ...)
2025-02-23 11:47 ` [PATCH v2 11/18] hw/arm/fsl-imx8mp: Add SPI controllers Bernhard Beschow
@ 2025-02-23 11:47 ` Bernhard Beschow
2025-02-23 11:47 ` [PATCH v2 13/18] hw/arm/fsl-imx8mp: Implement general purpose timers Bernhard Beschow
` (6 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:47 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 7 +++++++
hw/arm/fsl-imx8mp.c | 28 ++++++++++++++++++++++++++++
hw/arm/Kconfig | 1 +
4 files changed, 37 insertions(+)
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index 66e5865107..904de9aa7d 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -17,6 +17,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* 5 GPIO Controllers
* 6 I2C Controllers
* 3 SPI Controllers
+ * 3 Watchdogs
* Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 296a87eb50..dfbdc6ac7f 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -21,6 +21,7 @@
#include "hw/pci-host/fsl_imx8m_phy.h"
#include "hw/sd/sdhci.h"
#include "hw/ssi/imx_spi.h"
+#include "hw/watchdog/wdt_imx2.h"
#include "qom/object.h"
#include "qemu/units.h"
@@ -38,6 +39,7 @@ enum FslImx8mpConfiguration {
FSL_IMX8MP_NUM_IRQS = 160,
FSL_IMX8MP_NUM_UARTS = 4,
FSL_IMX8MP_NUM_USDHCS = 3,
+ FSL_IMX8MP_NUM_WDTS = 3,
};
struct FslImx8mpState {
@@ -53,6 +55,7 @@ struct FslImx8mpState {
IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
+ IMX2WdtState wdt[FSL_IMX8MP_NUM_WDTS];
DesignwarePCIEHost pcie;
FslImx8mPciePhyState pcie_phy;
};
@@ -235,6 +238,10 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_I2C5_IRQ = 76,
FSL_IMX8MP_I2C6_IRQ = 77,
+ FSL_IMX8MP_WDOG1_IRQ = 78,
+ FSL_IMX8MP_WDOG2_IRQ = 79,
+ FSL_IMX8MP_WDOG3_IRQ = 10,
+
FSL_IMX8MP_PCI_INTA_IRQ = 126,
FSL_IMX8MP_PCI_INTB_IRQ = 125,
FSL_IMX8MP_PCI_INTC_IRQ = 124,
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 14f317be70..0e031b8c5e 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -228,6 +228,11 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
}
+ for (i = 0; i < FSL_IMX8MP_NUM_WDTS; i++) {
+ g_autofree char *name = g_strdup_printf("wdt%d", i);
+ object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
+ }
+
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
TYPE_FSL_IMX8M_PCIE_PHY);
@@ -491,6 +496,28 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0,
fsl_imx8mp_memmap[FSL_IMX8MP_SNVS_HP].addr);
+ /* Watchdogs */
+ for (i = 0; i < FSL_IMX8MP_NUM_WDTS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } wdog_table[FSL_IMX8MP_NUM_WDTS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG1].addr, FSL_IMX8MP_WDOG1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG2].addr, FSL_IMX8MP_WDOG2_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG3].addr, FSL_IMX8MP_WDOG3_IRQ },
+ };
+
+ object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support",
+ true, &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, wdog_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
+ qdev_get_gpio_in(gicdev, wdog_table[i].irq));
+ }
+
/* PCIe */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) {
return;
@@ -531,6 +558,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_SNVS_HP:
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
+ case FSL_IMX8MP_WDOG1 ... FSL_IMX8MP_WDOG3:
/* device implemented and treated above */
break;
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 28ae409c85..98ac93a23f 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -606,6 +606,7 @@ config FSL_IMX8MP
select PCI_EXPRESS_FSL_IMX8M_PHY
select SDHCI
select UNIMP
+ select WDT_IMX2
config FSL_IMX8MP_EVK
bool
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 13/18] hw/arm/fsl-imx8mp: Implement general purpose timers
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (11 preceding siblings ...)
2025-02-23 11:47 ` [PATCH v2 12/18] hw/arm/fsl-imx8mp: Add watchdog support Bernhard Beschow
@ 2025-02-23 11:47 ` Bernhard Beschow
2025-02-23 11:47 ` [PATCH v2 14/18] hw/arm/fsl-imx8mp: Add Ethernet controller Bernhard Beschow
` (5 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:47 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 11 +++++++
include/hw/timer/imx_gpt.h | 1 +
hw/arm/fsl-imx8mp.c | 53 ++++++++++++++++++++++++++++++++++
hw/timer/imx_gpt.c | 25 ++++++++++++++++
hw/arm/Kconfig | 1 +
6 files changed, 92 insertions(+)
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index 904de9aa7d..4b195c917f 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -18,6 +18,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* 6 I2C Controllers
* 3 SPI Controllers
* 3 Watchdogs
+ * 6 General Purpose Timers
* Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index dfbdc6ac7f..975887751b 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -17,10 +17,12 @@
#include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mp_analog.h"
#include "hw/misc/imx8mp_ccm.h"
+#include "hw/or-irq.h"
#include "hw/pci-host/designware.h"
#include "hw/pci-host/fsl_imx8m_phy.h"
#include "hw/sd/sdhci.h"
#include "hw/ssi/imx_spi.h"
+#include "hw/timer/imx_gpt.h"
#include "hw/watchdog/wdt_imx2.h"
#include "qom/object.h"
#include "qemu/units.h"
@@ -35,6 +37,7 @@ enum FslImx8mpConfiguration {
FSL_IMX8MP_NUM_CPUS = 4,
FSL_IMX8MP_NUM_ECSPIS = 3,
FSL_IMX8MP_NUM_GPIOS = 5,
+ FSL_IMX8MP_NUM_GPTS = 6,
FSL_IMX8MP_NUM_I2CS = 6,
FSL_IMX8MP_NUM_IRQS = 160,
FSL_IMX8MP_NUM_UARTS = 4,
@@ -47,6 +50,7 @@ struct FslImx8mpState {
ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
GICv3State gic;
+ IMXGPTState gpt[FSL_IMX8MP_NUM_GPTS];
IMXGPIOState gpio[FSL_IMX8MP_NUM_GPIOS];
IMX8MPCCMState ccm;
IMX8MPAnalogState analog;
@@ -58,6 +62,7 @@ struct FslImx8mpState {
IMX2WdtState wdt[FSL_IMX8MP_NUM_WDTS];
DesignwarePCIEHost pcie;
FslImx8mPciePhyState pcie_phy;
+ OrIRQState gpt5_gpt6_irq;
};
enum FslImx8mpMemoryRegions {
@@ -224,6 +229,12 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_I2C3_IRQ = 37,
FSL_IMX8MP_I2C4_IRQ = 38,
+ FSL_IMX8MP_GPT1_IRQ = 55,
+ FSL_IMX8MP_GPT2_IRQ = 54,
+ FSL_IMX8MP_GPT3_IRQ = 53,
+ FSL_IMX8MP_GPT4_IRQ = 52,
+ FSL_IMX8MP_GPT5_GPT6_IRQ = 51,
+
FSL_IMX8MP_GPIO1_LOW_IRQ = 64,
FSL_IMX8MP_GPIO1_HIGH_IRQ = 65,
FSL_IMX8MP_GPIO2_LOW_IRQ = 66,
diff --git a/include/hw/timer/imx_gpt.h b/include/hw/timer/imx_gpt.h
index 5a1230da35..5488f7e4df 100644
--- a/include/hw/timer/imx_gpt.h
+++ b/include/hw/timer/imx_gpt.h
@@ -80,6 +80,7 @@
#define TYPE_IMX6_GPT "imx6.gpt"
#define TYPE_IMX6UL_GPT "imx6ul.gpt"
#define TYPE_IMX7_GPT "imx7.gpt"
+#define TYPE_IMX8MP_GPT "imx8mp.gpt"
#define TYPE_IMX_GPT TYPE_IMX25_GPT
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 0e031b8c5e..dcf67c5889 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -208,6 +208,13 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
}
+ for (i = 0; i < FSL_IMX8MP_NUM_GPTS; i++) {
+ g_autofree char *name = g_strdup_printf("gpt%d", i + 1);
+ object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX8MP_GPT);
+ }
+ object_initialize_child(obj, "gpt5-gpt6-irq", &s->gpt5_gpt6_irq,
+ TYPE_OR_IRQ);
+
for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
g_autofree char *name = g_strdup_printf("i2c%d", i + 1);
object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C);
@@ -375,6 +382,52 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, serial_table[i].irq));
}
+ /* GPTs */
+ object_property_set_int(OBJECT(&s->gpt5_gpt6_irq), "num-lines", 2,
+ &error_abort);
+ if (!qdev_realize(DEVICE(&s->gpt5_gpt6_irq), NULL, errp)) {
+ return;
+ }
+
+ qdev_connect_gpio_out(DEVICE(&s->gpt5_gpt6_irq), 0,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_GPT5_GPT6_IRQ));
+
+ for (i = 0; i < FSL_IMX8MP_NUM_GPTS; i++) {
+ static const hwaddr gpt_addrs[FSL_IMX8MP_NUM_GPTS] = {
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT1].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT2].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT3].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT4].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT5].addr,
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT6].addr,
+ };
+
+ s->gpt[i].ccm = IMX_CCM(&s->ccm);
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), errp)) {
+ return;
+ }
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_addrs[i]);
+
+ if (i < FSL_IMX8MP_NUM_GPTS - 2) {
+ static const unsigned int gpt_irqs[FSL_IMX8MP_NUM_GPTS - 2] = {
+ FSL_IMX8MP_GPT1_IRQ,
+ FSL_IMX8MP_GPT2_IRQ,
+ FSL_IMX8MP_GPT3_IRQ,
+ FSL_IMX8MP_GPT4_IRQ,
+ };
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
+ qdev_get_gpio_in(gicdev, gpt_irqs[i]));
+ } else {
+ int irq = i - FSL_IMX8MP_NUM_GPTS + 2;
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->gpt5_gpt6_irq), irq));
+ }
+ }
+
/* I2Cs */
for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
static const struct {
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 11eca9fa4d..200a89225b 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -126,6 +126,17 @@ static const IMXClk imx7_gpt_clocks[] = {
CLK_NONE, /* 111 not defined */
};
+static const IMXClk imx8mp_gpt_clocks[] = {
+ CLK_NONE, /* 000 No clock source */
+ CLK_IPG, /* 001 ipg_clk, 532MHz */
+ CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */
+ CLK_EXT, /* 011 External clock */
+ CLK_32k, /* 100 ipg_clk_32k */
+ CLK_HIGH, /* 101 ipg_clk_16M */
+ CLK_NONE, /* 110 not defined */
+ CLK_NONE, /* 111 not defined */
+};
+
/* Must be called from within ptimer_transaction_begin/commit block */
static void imx_gpt_set_freq(IMXGPTState *s)
{
@@ -552,6 +563,13 @@ static void imx7_gpt_init(Object *obj)
s->clocks = imx7_gpt_clocks;
}
+static void imx8mp_gpt_init(Object *obj)
+{
+ IMXGPTState *s = IMX_GPT(obj);
+
+ s->clocks = imx8mp_gpt_clocks;
+}
+
static const TypeInfo imx25_gpt_info = {
.name = TYPE_IMX25_GPT,
.parent = TYPE_SYS_BUS_DEVICE,
@@ -584,6 +602,12 @@ static const TypeInfo imx7_gpt_info = {
.instance_init = imx7_gpt_init,
};
+static const TypeInfo imx8mp_gpt_info = {
+ .name = TYPE_IMX8MP_GPT,
+ .parent = TYPE_IMX25_GPT,
+ .instance_init = imx8mp_gpt_init,
+};
+
static void imx_gpt_register_types(void)
{
type_register_static(&imx25_gpt_info);
@@ -591,6 +615,7 @@ static void imx_gpt_register_types(void)
type_register_static(&imx6_gpt_info);
type_register_static(&imx6ul_gpt_info);
type_register_static(&imx7_gpt_info);
+ type_register_static(&imx8mp_gpt_info);
}
type_init(imx_gpt_register_types)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 98ac93a23f..4e83895b91 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -602,6 +602,7 @@ config FSL_IMX8MP
select FSL_IMX8MP_CCM
select IMX
select IMX_I2C
+ select OR_IRQ
select PCI_EXPRESS_DESIGNWARE
select PCI_EXPRESS_FSL_IMX8M_PHY
select SDHCI
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 14/18] hw/arm/fsl-imx8mp: Add Ethernet controller
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (12 preceding siblings ...)
2025-02-23 11:47 ` [PATCH v2 13/18] hw/arm/fsl-imx8mp: Implement general purpose timers Bernhard Beschow
@ 2025-02-23 11:47 ` Bernhard Beschow
2025-02-23 11:47 ` [PATCH v2 15/18] hw/arm/fsl-imx8mp: Add USB support Bernhard Beschow
` (4 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:47 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
The i.MX 8M Plus SoC actually has two ethernet controllers, the usual ENET one
and a Designware one. There is no device model for the latter, so only add the
ENET one.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 8 ++++++++
hw/arm/fsl-imx8mp.c | 24 ++++++++++++++++++++++++
hw/arm/imx8mp-evk.c | 1 +
hw/arm/Kconfig | 1 +
5 files changed, 35 insertions(+)
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index 4b195c917f..917c1d5176 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -14,6 +14,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* 4 UARTs
* 3 USDHC Storage Controllers
* 1 Designware PCI Express Controller
+ * 1 Ethernet Controller
* 5 GPIO Controllers
* 6 I2C Controllers
* 3 SPI Controllers
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 975887751b..e292c31a3d 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -17,6 +17,7 @@
#include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mp_analog.h"
#include "hw/misc/imx8mp_ccm.h"
+#include "hw/net/imx_fec.h"
#include "hw/or-irq.h"
#include "hw/pci-host/designware.h"
#include "hw/pci-host/fsl_imx8m_phy.h"
@@ -58,11 +59,15 @@ struct FslImx8mpState {
IMXSPIState spi[FSL_IMX8MP_NUM_ECSPIS];
IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
+ IMXFECState enet;
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
IMX2WdtState wdt[FSL_IMX8MP_NUM_WDTS];
DesignwarePCIEHost pcie;
FslImx8mPciePhyState pcie_phy;
OrIRQState gpt5_gpt6_irq;
+
+ uint32_t phy_num;
+ bool phy_connected;
};
enum FslImx8mpMemoryRegions {
@@ -253,6 +258,9 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_WDOG2_IRQ = 79,
FSL_IMX8MP_WDOG3_IRQ = 10,
+ FSL_IMX8MP_ENET1_MAC_IRQ = 118,
+ FSL_IMX6_ENET1_MAC_1588_IRQ = 121,
+
FSL_IMX8MP_PCI_INTA_IRQ = 126,
FSL_IMX8MP_PCI_INTB_IRQ = 125,
FSL_IMX8MP_PCI_INTC_IRQ = 124,
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index dcf67c5889..935279ee68 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -240,6 +240,8 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
}
+ object_initialize_child(obj, "eth0", &s->enet, TYPE_IMX_ENET);
+
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
TYPE_FSL_IMX8M_PCIE_PHY);
@@ -542,6 +544,21 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, spi_table[i].irq));
}
+ /* ENET1 */
+ object_property_set_uint(OBJECT(&s->enet), "phy-num", s->phy_num,
+ &error_abort);
+ object_property_set_uint(OBJECT(&s->enet), "tx-ring-num", 3, &error_abort);
+ qemu_configure_nic_device(DEVICE(&s->enet), true, NULL);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->enet), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->enet), 0,
+ fsl_imx8mp_memmap[FSL_IMX8MP_ENET1].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 0,
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_ENET1_MAC_IRQ));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 1,
+ qdev_get_gpio_in(gicdev, FSL_IMX6_ENET1_MAC_1588_IRQ));
+
/* SNVS */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
return;
@@ -604,6 +621,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_GIC_REDIST:
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
+ case FSL_IMX8MP_ENET1:
case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
case FSL_IMX8MP_PCIE1:
case FSL_IMX8MP_PCIE_PHY1:
@@ -624,10 +642,16 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
}
}
+static const Property fsl_imx8mp_properties[] = {
+ DEFINE_PROP_UINT32("fec1-phy-num", FslImx8mpState, phy_num, 0),
+ DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mpState, phy_connected, true),
+};
+
static void fsl_imx8mp_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
+ device_class_set_props(dc, fsl_imx8mp_properties);
dc->realize = fsl_imx8mp_realize;
dc->desc = "i.MX 8M Plus SoC";
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
index 27d9e9e8ee..e1a7892fd7 100644
--- a/hw/arm/imx8mp-evk.c
+++ b/hw/arm/imx8mp-evk.c
@@ -36,6 +36,7 @@ static void imx8mp_evk_init(MachineState *machine)
s = FSL_IMX8MP(object_new(TYPE_FSL_IMX8MP));
object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
+ object_property_set_uint(OBJECT(s), "fec1-phy-num", 1, &error_fatal);
qdev_realize(DEVICE(s), NULL, &error_fatal);
memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 4e83895b91..4d642db970 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -601,6 +601,7 @@ config FSL_IMX8MP
select FSL_IMX8MP_ANALOG
select FSL_IMX8MP_CCM
select IMX
+ select IMX_FEC
select IMX_I2C
select OR_IRQ
select PCI_EXPRESS_DESIGNWARE
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 15/18] hw/arm/fsl-imx8mp: Add USB support
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (13 preceding siblings ...)
2025-02-23 11:47 ` [PATCH v2 14/18] hw/arm/fsl-imx8mp: Add Ethernet controller Bernhard Beschow
@ 2025-02-23 11:47 ` Bernhard Beschow
2025-02-23 11:47 ` [PATCH v2 16/18] hw/arm/fsl-imx8mp: Add boot ROM Bernhard Beschow
` (3 subsequent siblings)
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:47 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
Split the USB MMIO regions to better keep track of the implemented vs.
unimplemented regions.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
docs/system/arm/imx8mp-evk.rst | 1 +
include/hw/arm/fsl-imx8mp.h | 12 +++++++++++
hw/arm/fsl-imx8mp.c | 37 ++++++++++++++++++++++++++++++++--
hw/arm/Kconfig | 1 +
4 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
index 917c1d5176..00527b0cbe 100644
--- a/docs/system/arm/imx8mp-evk.rst
+++ b/docs/system/arm/imx8mp-evk.rst
@@ -15,6 +15,7 @@ The ``imx8mp-evk`` machine implements the following devices:
* 3 USDHC Storage Controllers
* 1 Designware PCI Express Controller
* 1 Ethernet Controller
+ * 2 Designware USB 3 Controllers
* 5 GPIO Controllers
* 6 I2C Controllers
* 3 SPI Controllers
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index e292c31a3d..5247e972b8 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -24,6 +24,7 @@
#include "hw/sd/sdhci.h"
#include "hw/ssi/imx_spi.h"
#include "hw/timer/imx_gpt.h"
+#include "hw/usb/hcd-dwc3.h"
#include "hw/watchdog/wdt_imx2.h"
#include "qom/object.h"
#include "qemu/units.h"
@@ -42,6 +43,7 @@ enum FslImx8mpConfiguration {
FSL_IMX8MP_NUM_I2CS = 6,
FSL_IMX8MP_NUM_IRQS = 160,
FSL_IMX8MP_NUM_UARTS = 4,
+ FSL_IMX8MP_NUM_USBS = 2,
FSL_IMX8MP_NUM_USDHCS = 3,
FSL_IMX8MP_NUM_WDTS = 3,
};
@@ -62,6 +64,7 @@ struct FslImx8mpState {
IMXFECState enet;
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
IMX2WdtState wdt[FSL_IMX8MP_NUM_WDTS];
+ USBDWC3 usb[FSL_IMX8MP_NUM_USBS];
DesignwarePCIEHost pcie;
FslImx8mPciePhyState pcie_phy;
OrIRQState gpt5_gpt6_irq;
@@ -199,6 +202,12 @@ enum FslImx8mpMemoryRegions {
FSL_IMX8MP_UART4,
FSL_IMX8MP_USB1,
FSL_IMX8MP_USB2,
+ FSL_IMX8MP_USB1_DEV,
+ FSL_IMX8MP_USB2_DEV,
+ FSL_IMX8MP_USB1_OTG,
+ FSL_IMX8MP_USB2_OTG,
+ FSL_IMX8MP_USB1_GLUE,
+ FSL_IMX8MP_USB2_GLUE,
FSL_IMX8MP_USDHC1,
FSL_IMX8MP_USDHC2,
FSL_IMX8MP_USDHC3,
@@ -234,6 +243,9 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_I2C3_IRQ = 37,
FSL_IMX8MP_I2C4_IRQ = 38,
+ FSL_IMX8MP_USB1_IRQ = 40,
+ FSL_IMX8MP_USB2_IRQ = 41,
+
FSL_IMX8MP_GPT1_IRQ = 55,
FSL_IMX8MP_GPT2_IRQ = 54,
FSL_IMX8MP_GPT3_IRQ = 53,
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 935279ee68..f0d5980300 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -40,8 +40,14 @@ static const struct {
[FSL_IMX8MP_VPU_VC8000E_ENCODER] = { 0x38320000, 2 * MiB, "vpu_vc8000e_encoder" },
[FSL_IMX8MP_VPU_G2_DECODER] = { 0x38310000, 2 * MiB, "vpu_g2_decoder" },
[FSL_IMX8MP_VPU_G1_DECODER] = { 0x38300000, 2 * MiB, "vpu_g1_decoder" },
- [FSL_IMX8MP_USB2] = { 0x38200000, 1 * MiB, "usb2" },
- [FSL_IMX8MP_USB1] = { 0x38100000, 1 * MiB, "usb1" },
+ [FSL_IMX8MP_USB2_GLUE] = { 0x382f0000, 0x100, "usb2_glue" },
+ [FSL_IMX8MP_USB2_OTG] = { 0x3820cc00, 0x100, "usb2_otg" },
+ [FSL_IMX8MP_USB2_DEV] = { 0x3820c700, 0x500, "usb2_dev" },
+ [FSL_IMX8MP_USB2] = { 0x38200000, 0xc700, "usb2" },
+ [FSL_IMX8MP_USB1_GLUE] = { 0x381f0000, 0x100, "usb1_glue" },
+ [FSL_IMX8MP_USB1_OTG] = { 0x3810cc00, 0x100, "usb1_otg" },
+ [FSL_IMX8MP_USB1_DEV] = { 0x3810c700, 0x500, "usb1_dev" },
+ [FSL_IMX8MP_USB1] = { 0x38100000, 0xc700, "usb1" },
[FSL_IMX8MP_GPU2D] = { 0x38008000, 32 * KiB, "gpu2d" },
[FSL_IMX8MP_GPU3D] = { 0x38000000, 32 * KiB, "gpu3d" },
[FSL_IMX8MP_QSPI1_RX_BUFFER] = { 0x34000000, 32 * MiB, "qspi1_rx_buffer" },
@@ -230,6 +236,11 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
}
+ for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
+ g_autofree char *name = g_strdup_printf("usb%d", i);
+ object_initialize_child(obj, name, &s->usb[i], TYPE_USB_DWC3);
+ }
+
for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
g_autofree char *name = g_strdup_printf("spi%d", i + 1);
object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
@@ -524,6 +535,27 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
}
+ /* USBs */
+ for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } usb_table[FSL_IMX8MP_NUM_USBS] = {
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USB1].addr, FSL_IMX8MP_USB1_IRQ },
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USB2].addr, FSL_IMX8MP_USB2_IRQ },
+ };
+
+ qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p2", 1);
+ qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p3", 1);
+ qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "slots", 2);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, usb_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 0,
+ qdev_get_gpio_in(gicdev, usb_table[i].irq));
+ }
+
/* ECSPIs */
for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
static const struct {
@@ -628,6 +660,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_RAM:
case FSL_IMX8MP_SNVS_HP:
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
+ case FSL_IMX8MP_USB1 ... FSL_IMX8MP_USB2:
case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
case FSL_IMX8MP_WDOG1 ... FSL_IMX8MP_WDOG3:
/* device implemented and treated above */
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 4d642db970..faa00d1db3 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -608,6 +608,7 @@ config FSL_IMX8MP
select PCI_EXPRESS_FSL_IMX8M_PHY
select SDHCI
select UNIMP
+ select USB_DWC3
select WDT_IMX2
config FSL_IMX8MP_EVK
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 16/18] hw/arm/fsl-imx8mp: Add boot ROM
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (14 preceding siblings ...)
2025-02-23 11:47 ` [PATCH v2 15/18] hw/arm/fsl-imx8mp: Add USB support Bernhard Beschow
@ 2025-02-23 11:47 ` Bernhard Beschow
2025-02-25 14:29 ` Peter Maydell
2025-02-23 11:47 ` [PATCH v2 17/18] hw/arm/fsl-imx8mp: Add on-chip RAM Bernhard Beschow
` (2 subsequent siblings)
18 siblings, 1 reply; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:47 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
On a real device, the boot ROM contains the very first instructions the CPU
executes. Also, U-Boot calls into the ROM to determine the boot device. While
we're not actually implementing this here, let's create the infrastructure and
add a dummy ROM with all zeros. This allows for implementing a ROM later without
touching the source code and even allows for users to provide their own ROMs.
The imx8mp-boot.rom was created with
`dd if=/dev/zero of=imx8mp-boot.rom bs=1 count=258048`.
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
MAINTAINERS | 1 +
include/hw/arm/fsl-imx8mp.h | 1 +
hw/arm/fsl-imx8mp.c | 18 ++++++++++++++++++
pc-bios/imx8mp-boot.rom | Bin 0 -> 258048 bytes
pc-bios/meson.build | 1 +
5 files changed, 21 insertions(+)
create mode 100644 pc-bios/imx8mp-boot.rom
diff --git a/MAINTAINERS b/MAINTAINERS
index 2e7fc6fa91..489e426d85 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -831,6 +831,7 @@ F: hw/pci-host/fsl_imx8m_phy.c
F: include/hw/arm/fsl-imx8mp.h
F: include/hw/misc/imx8mp_*.h
F: include/hw/pci-host/fsl_imx8m_phy.h
+F: pc-bios/imx8mp*
F: docs/system/arm/imx8mp-evk.rst
MPS2 / MPS3
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 5247e972b8..4dbe30f524 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -68,6 +68,7 @@ struct FslImx8mpState {
DesignwarePCIEHost pcie;
FslImx8mPciePhyState pcie_phy;
OrIRQState gpt5_gpt6_irq;
+ MemoryRegion boot_rom;
uint32_t phy_num;
bool phy_connected;
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index f0d5980300..f26cf5984e 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -9,12 +9,14 @@
*/
#include "qemu/osdep.h"
+#include "qemu/datadir.h"
#include "exec/address-spaces.h"
#include "hw/arm/bsa.h"
#include "hw/arm/fsl-imx8mp.h"
#include "hw/intc/arm_gicv3.h"
#include "hw/misc/unimp.h"
#include "hw/boards.h"
+#include "hw/loader.h"
#include "system/system.h"
#include "target/arm/cpu-qom.h"
#include "qapi/error.h"
@@ -263,6 +265,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
MachineState *ms = MACHINE(qdev_get_machine());
FslImx8mpState *s = FSL_IMX8MP(dev);
DeviceState *gicdev = DEVICE(&s->gic);
+ g_autofree char *filename = NULL;
int i;
if (ms->smp.cpus > FSL_IMX8MP_NUM_CPUS) {
@@ -644,10 +647,25 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0,
fsl_imx8mp_memmap[FSL_IMX8MP_PCIE_PHY1].addr);
+ /* ROM memory */
+ if (!memory_region_init_rom(&s->boot_rom, OBJECT(dev),
+ fsl_imx8mp_memmap[FSL_IMX8MP_BOOT_ROM].name,
+ fsl_imx8mp_memmap[FSL_IMX8MP_BOOT_ROM].size,
+ errp)) {
+ return;
+ }
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "imx8mp-boot.rom");
+ load_image_size(filename, memory_region_get_ram_ptr(&s->boot_rom),
+ memory_region_size(&s->boot_rom));
+ memory_region_add_subregion(get_system_memory(),
+ fsl_imx8mp_memmap[FSL_IMX8MP_BOOT_ROM].addr,
+ &s->boot_rom);
+
/* Unimplemented devices */
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
switch (i) {
case FSL_IMX8MP_ANA_PLL:
+ case FSL_IMX8MP_BOOT_ROM:
case FSL_IMX8MP_CCM:
case FSL_IMX8MP_GIC_DIST:
case FSL_IMX8MP_GIC_REDIST:
diff --git a/pc-bios/imx8mp-boot.rom b/pc-bios/imx8mp-boot.rom
new file mode 100644
index 0000000000000000000000000000000000000000..5324b5eed200e723d048f8476e4d96d45622fd4d
GIT binary patch
literal 258048
zcmeIuF#!Mo0K%a4Pi+Q&h(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM
z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*
z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd
z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA
zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj
zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r
z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@
z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK
zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5
zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM
z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*
z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd
z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA
zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj
zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r
z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@
z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK
zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5
zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM
z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*
z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd
z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>f$Z
E2JkHa0RR91
literal 0
HcmV?d00001
diff --git a/pc-bios/meson.build b/pc-bios/meson.build
index 51e95cc903..50506a7895 100644
--- a/pc-bios/meson.build
+++ b/pc-bios/meson.build
@@ -60,6 +60,7 @@ blobs = [
'efi-virtio.rom',
'efi-e1000e.rom',
'efi-vmxnet3.rom',
+ 'imx8mp-boot.rom',
'qemu-nsis.bmp',
'multiboot.bin',
'multiboot_dma.bin',
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* Re: [PATCH v2 16/18] hw/arm/fsl-imx8mp: Add boot ROM
2025-02-23 11:47 ` [PATCH v2 16/18] hw/arm/fsl-imx8mp: Add boot ROM Bernhard Beschow
@ 2025-02-25 14:29 ` Peter Maydell
2025-02-25 18:48 ` Bernhard Beschow
0 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2025-02-25 14:29 UTC (permalink / raw)
To: Bernhard Beschow
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
On Sun, 23 Feb 2025 at 11:47, Bernhard Beschow <shentey@gmail.com> wrote:
>
> On a real device, the boot ROM contains the very first instructions the CPU
> executes. Also, U-Boot calls into the ROM to determine the boot device. While
> we're not actually implementing this here, let's create the infrastructure and
> add a dummy ROM with all zeros. This allows for implementing a ROM later without
> touching the source code and even allows for users to provide their own ROMs.
>
> The imx8mp-boot.rom was created with
> `dd if=/dev/zero of=imx8mp-boot.rom bs=1 count=258048`.
>
> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Hi; I've thought about this a bit, and I think we should just
postpone having code to load a rom blob until we have an
actual rom blob that's not all zeroes. This makes this
board the same as e.g. imx7 which also doesn't try to load
a ROM blob. You can create a memory region for the ROM,
like imx7; just don't load anything into it, and that's
exactly the same as if there was an all-zeroes file that
got loaded.
This doesn't prevent users from experimenting with providing
their own ROM code, because they can do that with the
generic loader (passing it either an ELF file set up to
load to the ROM area or else a binary blob plus the
start address of 0).
That way we aren't carrying code we aren't using and an
awkward binary blob in git; we can add those when we need
them.
thanks
-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 16/18] hw/arm/fsl-imx8mp: Add boot ROM
2025-02-25 14:29 ` Peter Maydell
@ 2025-02-25 18:48 ` Bernhard Beschow
0 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-25 18:48 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
Am 25. Februar 2025 14:29:15 UTC schrieb Peter Maydell <peter.maydell@linaro.org>:
>On Sun, 23 Feb 2025 at 11:47, Bernhard Beschow <shentey@gmail.com> wrote:
>>
>> On a real device, the boot ROM contains the very first instructions the CPU
>> executes. Also, U-Boot calls into the ROM to determine the boot device. While
>> we're not actually implementing this here, let's create the infrastructure and
>> add a dummy ROM with all zeros. This allows for implementing a ROM later without
>> touching the source code and even allows for users to provide their own ROMs.
>>
>> The imx8mp-boot.rom was created with
>> `dd if=/dev/zero of=imx8mp-boot.rom bs=1 count=258048`.
>>
>> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>
>Hi; I've thought about this a bit, and I think we should just
>postpone having code to load a rom blob until we have an
>actual rom blob that's not all zeroes. This makes this
>board the same as e.g. imx7 which also doesn't try to load
>a ROM blob. You can create a memory region for the ROM,
>like imx7; just don't load anything into it, and that's
>exactly the same as if there was an all-zeroes file that
>got loaded.
>
>This doesn't prevent users from experimenting with providing
>their own ROM code, because they can do that with the
>generic loader (passing it either an ELF file set up to
>load to the ROM area or else a binary blob plus the
>start address of 0).
>
>That way we aren't carrying code we aren't using and an
>awkward binary blob in git; we can add those when we need
>them.
Yes, makes sense.
Best regards,
Bernhard
>
>thanks
>-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 17/18] hw/arm/fsl-imx8mp: Add on-chip RAM
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (15 preceding siblings ...)
2025-02-23 11:47 ` [PATCH v2 16/18] hw/arm/fsl-imx8mp: Add boot ROM Bernhard Beschow
@ 2025-02-23 11:47 ` Bernhard Beschow
2025-02-23 11:47 ` [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation Bernhard Beschow
2025-02-25 14:43 ` [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Peter Maydell
18 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:47 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
include/hw/arm/fsl-imx8mp.h | 1 +
hw/arm/fsl-imx8mp.c | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 4dbe30f524..03f057c7db 100644
--- a/include/hw/arm/fsl-imx8mp.h
+++ b/include/hw/arm/fsl-imx8mp.h
@@ -69,6 +69,7 @@ struct FslImx8mpState {
FslImx8mPciePhyState pcie_phy;
OrIRQState gpt5_gpt6_irq;
MemoryRegion boot_rom;
+ MemoryRegion ocram;
uint32_t phy_num;
bool phy_connected;
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index f26cf5984e..4e6c4d0767 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -661,6 +661,16 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
fsl_imx8mp_memmap[FSL_IMX8MP_BOOT_ROM].addr,
&s->boot_rom);
+ /* On-Chip RAM */
+ if (!memory_region_init_ram(&s->ocram, NULL, "imx8mp.ocram",
+ fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].size,
+ errp)) {
+ return;
+ }
+ memory_region_add_subregion(get_system_memory(),
+ fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].addr,
+ &s->ocram);
+
/* Unimplemented devices */
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
switch (i) {
@@ -673,6 +683,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
case FSL_IMX8MP_ENET1:
case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
+ case FSL_IMX8MP_OCRAM:
case FSL_IMX8MP_PCIE1:
case FSL_IMX8MP_PCIE_PHY1:
case FSL_IMX8MP_RAM:
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (16 preceding siblings ...)
2025-02-23 11:47 ` [PATCH v2 17/18] hw/arm/fsl-imx8mp: Add on-chip RAM Bernhard Beschow
@ 2025-02-23 11:47 ` Bernhard Beschow
2025-03-04 18:53 ` Bernhard Beschow
2025-03-11 12:18 ` Fabiano Rosas
2025-02-25 14:43 ` [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Peter Maydell
18 siblings, 2 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-23 11:47 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Fabiano Rosas, Alistair Francis,
Edgar E. Iglesias, Philippe Mathieu-Daudé
The implementation just allows Linux to determine date and time.
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
---
MAINTAINERS | 2 +
hw/rtc/rs5c372.c | 236 +++++++++++++++++++++++++++++++++++++
tests/qtest/rs5c372-test.c | 43 +++++++
hw/rtc/Kconfig | 5 +
hw/rtc/meson.build | 1 +
hw/rtc/trace-events | 4 +
tests/qtest/meson.build | 1 +
7 files changed, 292 insertions(+)
create mode 100644 hw/rtc/rs5c372.c
create mode 100644 tests/qtest/rs5c372-test.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 489e426d85..2552cfd65c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -828,10 +828,12 @@ F: hw/arm/imx8mp-evk.c
F: hw/arm/fsl-imx8mp.c
F: hw/misc/imx8mp_*.c
F: hw/pci-host/fsl_imx8m_phy.c
+F: hw/rtc/rs5c372.c
F: include/hw/arm/fsl-imx8mp.h
F: include/hw/misc/imx8mp_*.h
F: include/hw/pci-host/fsl_imx8m_phy.h
F: pc-bios/imx8mp*
+F: tests/qtest/rs5c372-test.c
F: docs/system/arm/imx8mp-evk.rst
MPS2 / MPS3
diff --git a/hw/rtc/rs5c372.c b/hw/rtc/rs5c372.c
new file mode 100644
index 0000000000..5542f74085
--- /dev/null
+++ b/hw/rtc/rs5c372.c
@@ -0,0 +1,236 @@
+/*
+ * Ricoh RS5C372, R222x I2C RTC
+ *
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * Based on hw/rtc/ds1338.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/i2c/i2c.h"
+#include "hw/qdev-properties.h"
+#include "hw/resettable.h"
+#include "migration/vmstate.h"
+#include "qemu/bcd.h"
+#include "qom/object.h"
+#include "system/rtc.h"
+#include "trace.h"
+
+#define NVRAM_SIZE 0x10
+
+/* Flags definitions */
+#define SECONDS_CH 0x80
+#define HOURS_PM 0x20
+#define CTRL2_24 0x20
+
+#define TYPE_RS5C372 "rs5c372"
+OBJECT_DECLARE_SIMPLE_TYPE(RS5C372State, RS5C372)
+
+struct RS5C372State {
+ I2CSlave parent_obj;
+
+ int64_t offset;
+ uint8_t wday_offset;
+ uint8_t nvram[NVRAM_SIZE];
+ uint8_t ptr;
+ uint8_t tx_format;
+ bool addr_byte;
+};
+
+static void capture_current_time(RS5C372State *s)
+{
+ /*
+ * Capture the current time into the secondary registers which will be
+ * actually read by the data transfer operation.
+ */
+ struct tm now;
+ qemu_get_timedate(&now, s->offset);
+ s->nvram[0] = to_bcd(now.tm_sec);
+ s->nvram[1] = to_bcd(now.tm_min);
+ if (s->nvram[0xf] & CTRL2_24) {
+ s->nvram[2] = to_bcd(now.tm_hour);
+ } else {
+ int tmp = now.tm_hour;
+ if (tmp % 12 == 0) {
+ tmp += 12;
+ }
+ if (tmp <= 12) {
+ s->nvram[2] = to_bcd(tmp);
+ } else {
+ s->nvram[2] = HOURS_PM | to_bcd(tmp - 12);
+ }
+ }
+ s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
+ s->nvram[4] = to_bcd(now.tm_mday);
+ s->nvram[5] = to_bcd(now.tm_mon + 1);
+ s->nvram[6] = to_bcd(now.tm_year - 100);
+}
+
+static void inc_regptr(RS5C372State *s)
+{
+ s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
+}
+
+static int rs5c372_event(I2CSlave *i2c, enum i2c_event event)
+{
+ RS5C372State *s = RS5C372(i2c);
+
+ switch (event) {
+ case I2C_START_RECV:
+ /*
+ * In h/w, capture happens on any START condition, not just a
+ * START_RECV, but there is no need to actually capture on
+ * START_SEND, because the guest can't get at that data
+ * without going through a START_RECV which would overwrite it.
+ */
+ capture_current_time(s);
+ s->ptr = 0xf;
+ break;
+ case I2C_START_SEND:
+ s->addr_byte = true;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static uint8_t rs5c372_recv(I2CSlave *i2c)
+{
+ RS5C372State *s = RS5C372(i2c);
+ uint8_t res;
+
+ res = s->nvram[s->ptr];
+
+ trace_rs5c372_recv(s->ptr, res);
+
+ inc_regptr(s);
+ return res;
+}
+
+static int rs5c372_send(I2CSlave *i2c, uint8_t data)
+{
+ RS5C372State *s = RS5C372(i2c);
+
+ if (s->addr_byte) {
+ s->ptr = data >> 4;
+ s->tx_format = data & 0xf;
+ s->addr_byte = false;
+ return 0;
+ }
+
+ trace_rs5c372_send(s->ptr, data);
+
+ if (s->ptr < 7) {
+ /* Time register. */
+ struct tm now;
+ qemu_get_timedate(&now, s->offset);
+ switch (s->ptr) {
+ case 0:
+ now.tm_sec = from_bcd(data & 0x7f);
+ break;
+ case 1:
+ now.tm_min = from_bcd(data & 0x7f);
+ break;
+ case 2:
+ if (s->nvram[0xf] & CTRL2_24) {
+ now.tm_hour = from_bcd(data & 0x3f);
+ } else {
+ int tmp = from_bcd(data & (HOURS_PM - 1));
+ if (data & HOURS_PM) {
+ tmp += 12;
+ }
+ if (tmp % 12 == 0) {
+ tmp -= 12;
+ }
+ now.tm_hour = tmp;
+ }
+ break;
+ case 3:
+ {
+ /*
+ * The day field is supposed to contain a value in the range
+ * 1-7. Otherwise behavior is undefined.
+ */
+ int user_wday = (data & 7) - 1;
+ s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
+ }
+ break;
+ case 4:
+ now.tm_mday = from_bcd(data & 0x3f);
+ break;
+ case 5:
+ now.tm_mon = from_bcd(data & 0x1f) - 1;
+ break;
+ case 6:
+ now.tm_year = from_bcd(data) + 100;
+ break;
+ }
+ s->offset = qemu_timedate_diff(&now);
+ } else {
+ s->nvram[s->ptr] = data;
+ }
+ inc_regptr(s);
+ return 0;
+}
+
+static void rs5c372_reset_hold(Object *obj, ResetType type)
+{
+ RS5C372State *s = RS5C372(obj);
+
+ /* The clock is running and synchronized with the host */
+ s->offset = 0;
+ s->wday_offset = 0;
+ memset(s->nvram, 0, NVRAM_SIZE);
+ s->ptr = 0;
+ s->addr_byte = false;
+}
+
+static const VMStateDescription rs5c372_vmstate = {
+ .name = "rs5c372",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_I2C_SLAVE(parent_obj, RS5C372State),
+ VMSTATE_INT64(offset, RS5C372State),
+ VMSTATE_UINT8_V(wday_offset, RS5C372State, 2),
+ VMSTATE_UINT8_ARRAY(nvram, RS5C372State, NVRAM_SIZE),
+ VMSTATE_UINT8(ptr, RS5C372State),
+ VMSTATE_UINT8(tx_format, RS5C372State),
+ VMSTATE_BOOL(addr_byte, RS5C372State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void rs5c372_init(Object *obj)
+{
+ qdev_prop_set_uint8(DEVICE(obj), "address", 0x32);
+}
+
+static void rs5c372_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ k->event = rs5c372_event;
+ k->recv = rs5c372_recv;
+ k->send = rs5c372_send;
+ dc->vmsd = &rs5c372_vmstate;
+ rc->phases.hold = rs5c372_reset_hold;
+}
+
+static const TypeInfo rs5c372_types[] = {
+ {
+ .name = TYPE_RS5C372,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(RS5C372State),
+ .instance_init = rs5c372_init,
+ .class_init = rs5c372_class_init,
+ },
+};
+
+DEFINE_TYPES(rs5c372_types)
diff --git a/tests/qtest/rs5c372-test.c b/tests/qtest/rs5c372-test.c
new file mode 100644
index 0000000000..0f6a9b68b9
--- /dev/null
+++ b/tests/qtest/rs5c372-test.c
@@ -0,0 +1,43 @@
+/*
+ * QTest testcase for the RS5C372 RTC
+ *
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * Based on ds1338-test.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bcd.h"
+#include "libqos/i2c.h"
+
+#define RS5C372_ADDR 0x32
+
+static void rs5c372_read_date(void *obj, void *data, QGuestAllocator *alloc)
+{
+ QI2CDevice *i2cdev = obj;
+
+ uint8_t resp[0x10];
+ time_t now = time(NULL);
+ struct tm *utc = gmtime(&now);
+
+ i2c_read_block(i2cdev, 0, resp, sizeof(resp));
+
+ /* check retrieved time against local time */
+ g_assert_cmpuint(from_bcd(resp[5]), == , utc->tm_mday);
+ g_assert_cmpuint(from_bcd(resp[6]), == , 1 + utc->tm_mon);
+ g_assert_cmpuint(2000 + from_bcd(resp[7]), == , 1900 + utc->tm_year);
+}
+
+static void rs5c372_register_nodes(void)
+{
+ QOSGraphEdgeOptions opts = { };
+ add_qi2c_address(&opts, &(QI2CAddress) { RS5C372_ADDR });
+
+ qos_node_create_driver("rs5c372", i2c_device_create);
+ qos_node_consumes("rs5c372", "i2c-bus", &opts);
+ qos_add_test("read_date", "rs5c372", rs5c372_read_date, NULL);
+}
+
+libqos_init(rs5c372_register_nodes);
diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
index 2fe04ec1d0..315b0e4ecc 100644
--- a/hw/rtc/Kconfig
+++ b/hw/rtc/Kconfig
@@ -26,3 +26,8 @@ config GOLDFISH_RTC
config LS7A_RTC
bool
+
+config RS5C372_RTC
+ bool
+ depends on I2C
+ default y if I2C_DEVICES
diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
index 8ecc2d792c..6c87864dc0 100644
--- a/hw/rtc/meson.build
+++ b/hw/rtc/meson.build
@@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
system_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
system_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
+system_ss.add(when: 'CONFIG_RS5C372_RTC', if_true: files('rs5c372.c'))
diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events
index 8012afe102..b9f2852d35 100644
--- a/hw/rtc/trace-events
+++ b/hw/rtc/trace-events
@@ -35,3 +35,7 @@ m48txx_nvram_mem_write(uint32_t addr, uint32_t value) "mem write addr:0x%04x val
# goldfish_rtc.c
goldfish_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
goldfish_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
+
+# rs5c372.c
+rs5c372_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
+rs5c372_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 8a6243382a..9e5380ba7a 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -298,6 +298,7 @@ qos_test_ss.add(
'pca9552-test.c',
'pci-test.c',
'pcnet-test.c',
+ 'rs5c372-test.c',
'sdhci-test.c',
'spapr-phb-test.c',
'tmp105-test.c',
--
2.48.1
^ permalink raw reply related [flat|nested] 45+ messages in thread
* Re: [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation
2025-02-23 11:47 ` [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation Bernhard Beschow
@ 2025-03-04 18:53 ` Bernhard Beschow
2025-03-07 19:18 ` Bernhard Beschow
2025-03-11 12:18 ` Fabiano Rosas
1 sibling, 1 reply; 45+ messages in thread
From: Bernhard Beschow @ 2025-03-04 18:53 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
Am 23. Februar 2025 11:47:08 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>The implementation just allows Linux to determine date and time.
>
>Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>---
> MAINTAINERS | 2 +
> hw/rtc/rs5c372.c | 236 +++++++++++++++++++++++++++++++++++++
> tests/qtest/rs5c372-test.c | 43 +++++++
> hw/rtc/Kconfig | 5 +
> hw/rtc/meson.build | 1 +
> hw/rtc/trace-events | 4 +
> tests/qtest/meson.build | 1 +
> 7 files changed, 292 insertions(+)
> create mode 100644 hw/rtc/rs5c372.c
> create mode 100644 tests/qtest/rs5c372-test.c
Ping for just this patch. I'd like to have it merged for 10.0.
Thanks,
Bernhard
>
>diff --git a/MAINTAINERS b/MAINTAINERS
>index 489e426d85..2552cfd65c 100644
>--- a/MAINTAINERS
>+++ b/MAINTAINERS
>@@ -828,10 +828,12 @@ F: hw/arm/imx8mp-evk.c
> F: hw/arm/fsl-imx8mp.c
> F: hw/misc/imx8mp_*.c
> F: hw/pci-host/fsl_imx8m_phy.c
>+F: hw/rtc/rs5c372.c
> F: include/hw/arm/fsl-imx8mp.h
> F: include/hw/misc/imx8mp_*.h
> F: include/hw/pci-host/fsl_imx8m_phy.h
> F: pc-bios/imx8mp*
>+F: tests/qtest/rs5c372-test.c
> F: docs/system/arm/imx8mp-evk.rst
>
> MPS2 / MPS3
>diff --git a/hw/rtc/rs5c372.c b/hw/rtc/rs5c372.c
>new file mode 100644
>index 0000000000..5542f74085
>--- /dev/null
>+++ b/hw/rtc/rs5c372.c
>@@ -0,0 +1,236 @@
>+/*
>+ * Ricoh RS5C372, R222x I2C RTC
>+ *
>+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
>+ *
>+ * Based on hw/rtc/ds1338.c
>+ *
>+ * SPDX-License-Identifier: GPL-2.0-or-later
>+ */
>+
>+#include "qemu/osdep.h"
>+#include "hw/i2c/i2c.h"
>+#include "hw/qdev-properties.h"
>+#include "hw/resettable.h"
>+#include "migration/vmstate.h"
>+#include "qemu/bcd.h"
>+#include "qom/object.h"
>+#include "system/rtc.h"
>+#include "trace.h"
>+
>+#define NVRAM_SIZE 0x10
>+
>+/* Flags definitions */
>+#define SECONDS_CH 0x80
>+#define HOURS_PM 0x20
>+#define CTRL2_24 0x20
>+
>+#define TYPE_RS5C372 "rs5c372"
>+OBJECT_DECLARE_SIMPLE_TYPE(RS5C372State, RS5C372)
>+
>+struct RS5C372State {
>+ I2CSlave parent_obj;
>+
>+ int64_t offset;
>+ uint8_t wday_offset;
>+ uint8_t nvram[NVRAM_SIZE];
>+ uint8_t ptr;
>+ uint8_t tx_format;
>+ bool addr_byte;
>+};
>+
>+static void capture_current_time(RS5C372State *s)
>+{
>+ /*
>+ * Capture the current time into the secondary registers which will be
>+ * actually read by the data transfer operation.
>+ */
>+ struct tm now;
>+ qemu_get_timedate(&now, s->offset);
>+ s->nvram[0] = to_bcd(now.tm_sec);
>+ s->nvram[1] = to_bcd(now.tm_min);
>+ if (s->nvram[0xf] & CTRL2_24) {
>+ s->nvram[2] = to_bcd(now.tm_hour);
>+ } else {
>+ int tmp = now.tm_hour;
>+ if (tmp % 12 == 0) {
>+ tmp += 12;
>+ }
>+ if (tmp <= 12) {
>+ s->nvram[2] = to_bcd(tmp);
>+ } else {
>+ s->nvram[2] = HOURS_PM | to_bcd(tmp - 12);
>+ }
>+ }
>+ s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
>+ s->nvram[4] = to_bcd(now.tm_mday);
>+ s->nvram[5] = to_bcd(now.tm_mon + 1);
>+ s->nvram[6] = to_bcd(now.tm_year - 100);
>+}
>+
>+static void inc_regptr(RS5C372State *s)
>+{
>+ s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
>+}
>+
>+static int rs5c372_event(I2CSlave *i2c, enum i2c_event event)
>+{
>+ RS5C372State *s = RS5C372(i2c);
>+
>+ switch (event) {
>+ case I2C_START_RECV:
>+ /*
>+ * In h/w, capture happens on any START condition, not just a
>+ * START_RECV, but there is no need to actually capture on
>+ * START_SEND, because the guest can't get at that data
>+ * without going through a START_RECV which would overwrite it.
>+ */
>+ capture_current_time(s);
>+ s->ptr = 0xf;
>+ break;
>+ case I2C_START_SEND:
>+ s->addr_byte = true;
>+ break;
>+ default:
>+ break;
>+ }
>+
>+ return 0;
>+}
>+
>+static uint8_t rs5c372_recv(I2CSlave *i2c)
>+{
>+ RS5C372State *s = RS5C372(i2c);
>+ uint8_t res;
>+
>+ res = s->nvram[s->ptr];
>+
>+ trace_rs5c372_recv(s->ptr, res);
>+
>+ inc_regptr(s);
>+ return res;
>+}
>+
>+static int rs5c372_send(I2CSlave *i2c, uint8_t data)
>+{
>+ RS5C372State *s = RS5C372(i2c);
>+
>+ if (s->addr_byte) {
>+ s->ptr = data >> 4;
>+ s->tx_format = data & 0xf;
>+ s->addr_byte = false;
>+ return 0;
>+ }
>+
>+ trace_rs5c372_send(s->ptr, data);
>+
>+ if (s->ptr < 7) {
>+ /* Time register. */
>+ struct tm now;
>+ qemu_get_timedate(&now, s->offset);
>+ switch (s->ptr) {
>+ case 0:
>+ now.tm_sec = from_bcd(data & 0x7f);
>+ break;
>+ case 1:
>+ now.tm_min = from_bcd(data & 0x7f);
>+ break;
>+ case 2:
>+ if (s->nvram[0xf] & CTRL2_24) {
>+ now.tm_hour = from_bcd(data & 0x3f);
>+ } else {
>+ int tmp = from_bcd(data & (HOURS_PM - 1));
>+ if (data & HOURS_PM) {
>+ tmp += 12;
>+ }
>+ if (tmp % 12 == 0) {
>+ tmp -= 12;
>+ }
>+ now.tm_hour = tmp;
>+ }
>+ break;
>+ case 3:
>+ {
>+ /*
>+ * The day field is supposed to contain a value in the range
>+ * 1-7. Otherwise behavior is undefined.
>+ */
>+ int user_wday = (data & 7) - 1;
>+ s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
>+ }
>+ break;
>+ case 4:
>+ now.tm_mday = from_bcd(data & 0x3f);
>+ break;
>+ case 5:
>+ now.tm_mon = from_bcd(data & 0x1f) - 1;
>+ break;
>+ case 6:
>+ now.tm_year = from_bcd(data) + 100;
>+ break;
>+ }
>+ s->offset = qemu_timedate_diff(&now);
>+ } else {
>+ s->nvram[s->ptr] = data;
>+ }
>+ inc_regptr(s);
>+ return 0;
>+}
>+
>+static void rs5c372_reset_hold(Object *obj, ResetType type)
>+{
>+ RS5C372State *s = RS5C372(obj);
>+
>+ /* The clock is running and synchronized with the host */
>+ s->offset = 0;
>+ s->wday_offset = 0;
>+ memset(s->nvram, 0, NVRAM_SIZE);
>+ s->ptr = 0;
>+ s->addr_byte = false;
>+}
>+
>+static const VMStateDescription rs5c372_vmstate = {
>+ .name = "rs5c372",
>+ .version_id = 1,
>+ .minimum_version_id = 1,
>+ .fields = (const VMStateField[]) {
>+ VMSTATE_I2C_SLAVE(parent_obj, RS5C372State),
>+ VMSTATE_INT64(offset, RS5C372State),
>+ VMSTATE_UINT8_V(wday_offset, RS5C372State, 2),
>+ VMSTATE_UINT8_ARRAY(nvram, RS5C372State, NVRAM_SIZE),
>+ VMSTATE_UINT8(ptr, RS5C372State),
>+ VMSTATE_UINT8(tx_format, RS5C372State),
>+ VMSTATE_BOOL(addr_byte, RS5C372State),
>+ VMSTATE_END_OF_LIST()
>+ }
>+};
>+
>+static void rs5c372_init(Object *obj)
>+{
>+ qdev_prop_set_uint8(DEVICE(obj), "address", 0x32);
>+}
>+
>+static void rs5c372_class_init(ObjectClass *klass, void *data)
>+{
>+ DeviceClass *dc = DEVICE_CLASS(klass);
>+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
>+ ResettableClass *rc = RESETTABLE_CLASS(klass);
>+
>+ k->event = rs5c372_event;
>+ k->recv = rs5c372_recv;
>+ k->send = rs5c372_send;
>+ dc->vmsd = &rs5c372_vmstate;
>+ rc->phases.hold = rs5c372_reset_hold;
>+}
>+
>+static const TypeInfo rs5c372_types[] = {
>+ {
>+ .name = TYPE_RS5C372,
>+ .parent = TYPE_I2C_SLAVE,
>+ .instance_size = sizeof(RS5C372State),
>+ .instance_init = rs5c372_init,
>+ .class_init = rs5c372_class_init,
>+ },
>+};
>+
>+DEFINE_TYPES(rs5c372_types)
>diff --git a/tests/qtest/rs5c372-test.c b/tests/qtest/rs5c372-test.c
>new file mode 100644
>index 0000000000..0f6a9b68b9
>--- /dev/null
>+++ b/tests/qtest/rs5c372-test.c
>@@ -0,0 +1,43 @@
>+/*
>+ * QTest testcase for the RS5C372 RTC
>+ *
>+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
>+ *
>+ * Based on ds1338-test.c
>+ *
>+ * SPDX-License-Identifier: GPL-2.0-or-later
>+ */
>+
>+#include "qemu/osdep.h"
>+#include "qemu/bcd.h"
>+#include "libqos/i2c.h"
>+
>+#define RS5C372_ADDR 0x32
>+
>+static void rs5c372_read_date(void *obj, void *data, QGuestAllocator *alloc)
>+{
>+ QI2CDevice *i2cdev = obj;
>+
>+ uint8_t resp[0x10];
>+ time_t now = time(NULL);
>+ struct tm *utc = gmtime(&now);
>+
>+ i2c_read_block(i2cdev, 0, resp, sizeof(resp));
>+
>+ /* check retrieved time against local time */
>+ g_assert_cmpuint(from_bcd(resp[5]), == , utc->tm_mday);
>+ g_assert_cmpuint(from_bcd(resp[6]), == , 1 + utc->tm_mon);
>+ g_assert_cmpuint(2000 + from_bcd(resp[7]), == , 1900 + utc->tm_year);
>+}
>+
>+static void rs5c372_register_nodes(void)
>+{
>+ QOSGraphEdgeOptions opts = { };
>+ add_qi2c_address(&opts, &(QI2CAddress) { RS5C372_ADDR });
>+
>+ qos_node_create_driver("rs5c372", i2c_device_create);
>+ qos_node_consumes("rs5c372", "i2c-bus", &opts);
>+ qos_add_test("read_date", "rs5c372", rs5c372_read_date, NULL);
>+}
>+
>+libqos_init(rs5c372_register_nodes);
>diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
>index 2fe04ec1d0..315b0e4ecc 100644
>--- a/hw/rtc/Kconfig
>+++ b/hw/rtc/Kconfig
>@@ -26,3 +26,8 @@ config GOLDFISH_RTC
>
> config LS7A_RTC
> bool
>+
>+config RS5C372_RTC
>+ bool
>+ depends on I2C
>+ default y if I2C_DEVICES
>diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
>index 8ecc2d792c..6c87864dc0 100644
>--- a/hw/rtc/meson.build
>+++ b/hw/rtc/meson.build
>@@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
> system_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
> system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
> system_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
>+system_ss.add(when: 'CONFIG_RS5C372_RTC', if_true: files('rs5c372.c'))
>diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events
>index 8012afe102..b9f2852d35 100644
>--- a/hw/rtc/trace-events
>+++ b/hw/rtc/trace-events
>@@ -35,3 +35,7 @@ m48txx_nvram_mem_write(uint32_t addr, uint32_t value) "mem write addr:0x%04x val
> # goldfish_rtc.c
> goldfish_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
> goldfish_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
>+
>+# rs5c372.c
>+rs5c372_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
>+rs5c372_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
>diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
>index 8a6243382a..9e5380ba7a 100644
>--- a/tests/qtest/meson.build
>+++ b/tests/qtest/meson.build
>@@ -298,6 +298,7 @@ qos_test_ss.add(
> 'pca9552-test.c',
> 'pci-test.c',
> 'pcnet-test.c',
>+ 'rs5c372-test.c',
> 'sdhci-test.c',
> 'spapr-phb-test.c',
> 'tmp105-test.c',
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation
2025-03-04 18:53 ` Bernhard Beschow
@ 2025-03-07 19:18 ` Bernhard Beschow
2025-03-11 7:34 ` Bernhard Beschow
0 siblings, 1 reply; 45+ messages in thread
From: Bernhard Beschow @ 2025-03-07 19:18 UTC (permalink / raw)
To: qemu-devel, Paolo Bonzini, Philippe Mathieu-Daudé
Cc: Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias
Am 4. März 2025 18:53:10 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>
>
>Am 23. Februar 2025 11:47:08 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>The implementation just allows Linux to determine date and time.
>>
>>Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>>---
>> MAINTAINERS | 2 +
>> hw/rtc/rs5c372.c | 236 +++++++++++++++++++++++++++++++++++++
>> tests/qtest/rs5c372-test.c | 43 +++++++
>> hw/rtc/Kconfig | 5 +
>> hw/rtc/meson.build | 1 +
>> hw/rtc/trace-events | 4 +
>> tests/qtest/meson.build | 1 +
>> 7 files changed, 292 insertions(+)
>> create mode 100644 hw/rtc/rs5c372.c
>> create mode 100644 tests/qtest/rs5c372-test.c
>
>Ping for just this patch. I'd like to have it merged for 10.0.
Ping^2 -- just few days left before soft freeze.
AFAICS no open issues and I'd really like to have this RTC merged for 10.0. What is holding it back?
Best regards,
Bernhard
>
>Thanks,
>Bernhard
>
>>
>>diff --git a/MAINTAINERS b/MAINTAINERS
>>index 489e426d85..2552cfd65c 100644
>>--- a/MAINTAINERS
>>+++ b/MAINTAINERS
>>@@ -828,10 +828,12 @@ F: hw/arm/imx8mp-evk.c
>> F: hw/arm/fsl-imx8mp.c
>> F: hw/misc/imx8mp_*.c
>> F: hw/pci-host/fsl_imx8m_phy.c
>>+F: hw/rtc/rs5c372.c
>> F: include/hw/arm/fsl-imx8mp.h
>> F: include/hw/misc/imx8mp_*.h
>> F: include/hw/pci-host/fsl_imx8m_phy.h
>> F: pc-bios/imx8mp*
>>+F: tests/qtest/rs5c372-test.c
>> F: docs/system/arm/imx8mp-evk.rst
>>
>> MPS2 / MPS3
>>diff --git a/hw/rtc/rs5c372.c b/hw/rtc/rs5c372.c
>>new file mode 100644
>>index 0000000000..5542f74085
>>--- /dev/null
>>+++ b/hw/rtc/rs5c372.c
>>@@ -0,0 +1,236 @@
>>+/*
>>+ * Ricoh RS5C372, R222x I2C RTC
>>+ *
>>+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
>>+ *
>>+ * Based on hw/rtc/ds1338.c
>>+ *
>>+ * SPDX-License-Identifier: GPL-2.0-or-later
>>+ */
>>+
>>+#include "qemu/osdep.h"
>>+#include "hw/i2c/i2c.h"
>>+#include "hw/qdev-properties.h"
>>+#include "hw/resettable.h"
>>+#include "migration/vmstate.h"
>>+#include "qemu/bcd.h"
>>+#include "qom/object.h"
>>+#include "system/rtc.h"
>>+#include "trace.h"
>>+
>>+#define NVRAM_SIZE 0x10
>>+
>>+/* Flags definitions */
>>+#define SECONDS_CH 0x80
>>+#define HOURS_PM 0x20
>>+#define CTRL2_24 0x20
>>+
>>+#define TYPE_RS5C372 "rs5c372"
>>+OBJECT_DECLARE_SIMPLE_TYPE(RS5C372State, RS5C372)
>>+
>>+struct RS5C372State {
>>+ I2CSlave parent_obj;
>>+
>>+ int64_t offset;
>>+ uint8_t wday_offset;
>>+ uint8_t nvram[NVRAM_SIZE];
>>+ uint8_t ptr;
>>+ uint8_t tx_format;
>>+ bool addr_byte;
>>+};
>>+
>>+static void capture_current_time(RS5C372State *s)
>>+{
>>+ /*
>>+ * Capture the current time into the secondary registers which will be
>>+ * actually read by the data transfer operation.
>>+ */
>>+ struct tm now;
>>+ qemu_get_timedate(&now, s->offset);
>>+ s->nvram[0] = to_bcd(now.tm_sec);
>>+ s->nvram[1] = to_bcd(now.tm_min);
>>+ if (s->nvram[0xf] & CTRL2_24) {
>>+ s->nvram[2] = to_bcd(now.tm_hour);
>>+ } else {
>>+ int tmp = now.tm_hour;
>>+ if (tmp % 12 == 0) {
>>+ tmp += 12;
>>+ }
>>+ if (tmp <= 12) {
>>+ s->nvram[2] = to_bcd(tmp);
>>+ } else {
>>+ s->nvram[2] = HOURS_PM | to_bcd(tmp - 12);
>>+ }
>>+ }
>>+ s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
>>+ s->nvram[4] = to_bcd(now.tm_mday);
>>+ s->nvram[5] = to_bcd(now.tm_mon + 1);
>>+ s->nvram[6] = to_bcd(now.tm_year - 100);
>>+}
>>+
>>+static void inc_regptr(RS5C372State *s)
>>+{
>>+ s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
>>+}
>>+
>>+static int rs5c372_event(I2CSlave *i2c, enum i2c_event event)
>>+{
>>+ RS5C372State *s = RS5C372(i2c);
>>+
>>+ switch (event) {
>>+ case I2C_START_RECV:
>>+ /*
>>+ * In h/w, capture happens on any START condition, not just a
>>+ * START_RECV, but there is no need to actually capture on
>>+ * START_SEND, because the guest can't get at that data
>>+ * without going through a START_RECV which would overwrite it.
>>+ */
>>+ capture_current_time(s);
>>+ s->ptr = 0xf;
>>+ break;
>>+ case I2C_START_SEND:
>>+ s->addr_byte = true;
>>+ break;
>>+ default:
>>+ break;
>>+ }
>>+
>>+ return 0;
>>+}
>>+
>>+static uint8_t rs5c372_recv(I2CSlave *i2c)
>>+{
>>+ RS5C372State *s = RS5C372(i2c);
>>+ uint8_t res;
>>+
>>+ res = s->nvram[s->ptr];
>>+
>>+ trace_rs5c372_recv(s->ptr, res);
>>+
>>+ inc_regptr(s);
>>+ return res;
>>+}
>>+
>>+static int rs5c372_send(I2CSlave *i2c, uint8_t data)
>>+{
>>+ RS5C372State *s = RS5C372(i2c);
>>+
>>+ if (s->addr_byte) {
>>+ s->ptr = data >> 4;
>>+ s->tx_format = data & 0xf;
>>+ s->addr_byte = false;
>>+ return 0;
>>+ }
>>+
>>+ trace_rs5c372_send(s->ptr, data);
>>+
>>+ if (s->ptr < 7) {
>>+ /* Time register. */
>>+ struct tm now;
>>+ qemu_get_timedate(&now, s->offset);
>>+ switch (s->ptr) {
>>+ case 0:
>>+ now.tm_sec = from_bcd(data & 0x7f);
>>+ break;
>>+ case 1:
>>+ now.tm_min = from_bcd(data & 0x7f);
>>+ break;
>>+ case 2:
>>+ if (s->nvram[0xf] & CTRL2_24) {
>>+ now.tm_hour = from_bcd(data & 0x3f);
>>+ } else {
>>+ int tmp = from_bcd(data & (HOURS_PM - 1));
>>+ if (data & HOURS_PM) {
>>+ tmp += 12;
>>+ }
>>+ if (tmp % 12 == 0) {
>>+ tmp -= 12;
>>+ }
>>+ now.tm_hour = tmp;
>>+ }
>>+ break;
>>+ case 3:
>>+ {
>>+ /*
>>+ * The day field is supposed to contain a value in the range
>>+ * 1-7. Otherwise behavior is undefined.
>>+ */
>>+ int user_wday = (data & 7) - 1;
>>+ s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
>>+ }
>>+ break;
>>+ case 4:
>>+ now.tm_mday = from_bcd(data & 0x3f);
>>+ break;
>>+ case 5:
>>+ now.tm_mon = from_bcd(data & 0x1f) - 1;
>>+ break;
>>+ case 6:
>>+ now.tm_year = from_bcd(data) + 100;
>>+ break;
>>+ }
>>+ s->offset = qemu_timedate_diff(&now);
>>+ } else {
>>+ s->nvram[s->ptr] = data;
>>+ }
>>+ inc_regptr(s);
>>+ return 0;
>>+}
>>+
>>+static void rs5c372_reset_hold(Object *obj, ResetType type)
>>+{
>>+ RS5C372State *s = RS5C372(obj);
>>+
>>+ /* The clock is running and synchronized with the host */
>>+ s->offset = 0;
>>+ s->wday_offset = 0;
>>+ memset(s->nvram, 0, NVRAM_SIZE);
>>+ s->ptr = 0;
>>+ s->addr_byte = false;
>>+}
>>+
>>+static const VMStateDescription rs5c372_vmstate = {
>>+ .name = "rs5c372",
>>+ .version_id = 1,
>>+ .minimum_version_id = 1,
>>+ .fields = (const VMStateField[]) {
>>+ VMSTATE_I2C_SLAVE(parent_obj, RS5C372State),
>>+ VMSTATE_INT64(offset, RS5C372State),
>>+ VMSTATE_UINT8_V(wday_offset, RS5C372State, 2),
>>+ VMSTATE_UINT8_ARRAY(nvram, RS5C372State, NVRAM_SIZE),
>>+ VMSTATE_UINT8(ptr, RS5C372State),
>>+ VMSTATE_UINT8(tx_format, RS5C372State),
>>+ VMSTATE_BOOL(addr_byte, RS5C372State),
>>+ VMSTATE_END_OF_LIST()
>>+ }
>>+};
>>+
>>+static void rs5c372_init(Object *obj)
>>+{
>>+ qdev_prop_set_uint8(DEVICE(obj), "address", 0x32);
>>+}
>>+
>>+static void rs5c372_class_init(ObjectClass *klass, void *data)
>>+{
>>+ DeviceClass *dc = DEVICE_CLASS(klass);
>>+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
>>+ ResettableClass *rc = RESETTABLE_CLASS(klass);
>>+
>>+ k->event = rs5c372_event;
>>+ k->recv = rs5c372_recv;
>>+ k->send = rs5c372_send;
>>+ dc->vmsd = &rs5c372_vmstate;
>>+ rc->phases.hold = rs5c372_reset_hold;
>>+}
>>+
>>+static const TypeInfo rs5c372_types[] = {
>>+ {
>>+ .name = TYPE_RS5C372,
>>+ .parent = TYPE_I2C_SLAVE,
>>+ .instance_size = sizeof(RS5C372State),
>>+ .instance_init = rs5c372_init,
>>+ .class_init = rs5c372_class_init,
>>+ },
>>+};
>>+
>>+DEFINE_TYPES(rs5c372_types)
>>diff --git a/tests/qtest/rs5c372-test.c b/tests/qtest/rs5c372-test.c
>>new file mode 100644
>>index 0000000000..0f6a9b68b9
>>--- /dev/null
>>+++ b/tests/qtest/rs5c372-test.c
>>@@ -0,0 +1,43 @@
>>+/*
>>+ * QTest testcase for the RS5C372 RTC
>>+ *
>>+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
>>+ *
>>+ * Based on ds1338-test.c
>>+ *
>>+ * SPDX-License-Identifier: GPL-2.0-or-later
>>+ */
>>+
>>+#include "qemu/osdep.h"
>>+#include "qemu/bcd.h"
>>+#include "libqos/i2c.h"
>>+
>>+#define RS5C372_ADDR 0x32
>>+
>>+static void rs5c372_read_date(void *obj, void *data, QGuestAllocator *alloc)
>>+{
>>+ QI2CDevice *i2cdev = obj;
>>+
>>+ uint8_t resp[0x10];
>>+ time_t now = time(NULL);
>>+ struct tm *utc = gmtime(&now);
>>+
>>+ i2c_read_block(i2cdev, 0, resp, sizeof(resp));
>>+
>>+ /* check retrieved time against local time */
>>+ g_assert_cmpuint(from_bcd(resp[5]), == , utc->tm_mday);
>>+ g_assert_cmpuint(from_bcd(resp[6]), == , 1 + utc->tm_mon);
>>+ g_assert_cmpuint(2000 + from_bcd(resp[7]), == , 1900 + utc->tm_year);
>>+}
>>+
>>+static void rs5c372_register_nodes(void)
>>+{
>>+ QOSGraphEdgeOptions opts = { };
>>+ add_qi2c_address(&opts, &(QI2CAddress) { RS5C372_ADDR });
>>+
>>+ qos_node_create_driver("rs5c372", i2c_device_create);
>>+ qos_node_consumes("rs5c372", "i2c-bus", &opts);
>>+ qos_add_test("read_date", "rs5c372", rs5c372_read_date, NULL);
>>+}
>>+
>>+libqos_init(rs5c372_register_nodes);
>>diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
>>index 2fe04ec1d0..315b0e4ecc 100644
>>--- a/hw/rtc/Kconfig
>>+++ b/hw/rtc/Kconfig
>>@@ -26,3 +26,8 @@ config GOLDFISH_RTC
>>
>> config LS7A_RTC
>> bool
>>+
>>+config RS5C372_RTC
>>+ bool
>>+ depends on I2C
>>+ default y if I2C_DEVICES
>>diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
>>index 8ecc2d792c..6c87864dc0 100644
>>--- a/hw/rtc/meson.build
>>+++ b/hw/rtc/meson.build
>>@@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
>> system_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
>> system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
>> system_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
>>+system_ss.add(when: 'CONFIG_RS5C372_RTC', if_true: files('rs5c372.c'))
>>diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events
>>index 8012afe102..b9f2852d35 100644
>>--- a/hw/rtc/trace-events
>>+++ b/hw/rtc/trace-events
>>@@ -35,3 +35,7 @@ m48txx_nvram_mem_write(uint32_t addr, uint32_t value) "mem write addr:0x%04x val
>> # goldfish_rtc.c
>> goldfish_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
>> goldfish_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
>>+
>>+# rs5c372.c
>>+rs5c372_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
>>+rs5c372_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
>>diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
>>index 8a6243382a..9e5380ba7a 100644
>>--- a/tests/qtest/meson.build
>>+++ b/tests/qtest/meson.build
>>@@ -298,6 +298,7 @@ qos_test_ss.add(
>> 'pca9552-test.c',
>> 'pci-test.c',
>> 'pcnet-test.c',
>>+ 'rs5c372-test.c',
>> 'sdhci-test.c',
>> 'spapr-phb-test.c',
>> 'tmp105-test.c',
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation
2025-03-07 19:18 ` Bernhard Beschow
@ 2025-03-11 7:34 ` Bernhard Beschow
2025-03-11 9:20 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 45+ messages in thread
From: Bernhard Beschow @ 2025-03-11 7:34 UTC (permalink / raw)
To: qemu-devel, Paolo Bonzini, Philippe Mathieu-Daudé
Cc: Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias
Am 7. März 2025 19:18:34 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>
>
>Am 4. März 2025 18:53:10 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>
>>
>>Am 23. Februar 2025 11:47:08 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>>The implementation just allows Linux to determine date and time.
>>>
>>>Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>>>---
>>> MAINTAINERS | 2 +
>>> hw/rtc/rs5c372.c | 236 +++++++++++++++++++++++++++++++++++++
>>> tests/qtest/rs5c372-test.c | 43 +++++++
>>> hw/rtc/Kconfig | 5 +
>>> hw/rtc/meson.build | 1 +
>>> hw/rtc/trace-events | 4 +
>>> tests/qtest/meson.build | 1 +
>>> 7 files changed, 292 insertions(+)
>>> create mode 100644 hw/rtc/rs5c372.c
>>> create mode 100644 tests/qtest/rs5c372-test.c
>>
>>Ping for just this patch. I'd like to have it merged for 10.0.
>
>Ping^2 -- just few days left before soft freeze.
Last ping before the freeze
It would really be nice to have this device model in 10.0 since this would allow me to use upstream QEMU.
Thanks,
Bernhard
>
>AFAICS no open issues and I'd really like to have this RTC merged for 10.0. What is holding it back?
>
>Best regards,
>Bernhard
>
>>
>>Thanks,
>>Bernhard
>>
>>>
>>>diff --git a/MAINTAINERS b/MAINTAINERS
>>>index 489e426d85..2552cfd65c 100644
>>>--- a/MAINTAINERS
>>>+++ b/MAINTAINERS
>>>@@ -828,10 +828,12 @@ F: hw/arm/imx8mp-evk.c
>>> F: hw/arm/fsl-imx8mp.c
>>> F: hw/misc/imx8mp_*.c
>>> F: hw/pci-host/fsl_imx8m_phy.c
>>>+F: hw/rtc/rs5c372.c
>>> F: include/hw/arm/fsl-imx8mp.h
>>> F: include/hw/misc/imx8mp_*.h
>>> F: include/hw/pci-host/fsl_imx8m_phy.h
>>> F: pc-bios/imx8mp*
>>>+F: tests/qtest/rs5c372-test.c
>>> F: docs/system/arm/imx8mp-evk.rst
>>>
>>> MPS2 / MPS3
>>>diff --git a/hw/rtc/rs5c372.c b/hw/rtc/rs5c372.c
>>>new file mode 100644
>>>index 0000000000..5542f74085
>>>--- /dev/null
>>>+++ b/hw/rtc/rs5c372.c
>>>@@ -0,0 +1,236 @@
>>>+/*
>>>+ * Ricoh RS5C372, R222x I2C RTC
>>>+ *
>>>+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
>>>+ *
>>>+ * Based on hw/rtc/ds1338.c
>>>+ *
>>>+ * SPDX-License-Identifier: GPL-2.0-or-later
>>>+ */
>>>+
>>>+#include "qemu/osdep.h"
>>>+#include "hw/i2c/i2c.h"
>>>+#include "hw/qdev-properties.h"
>>>+#include "hw/resettable.h"
>>>+#include "migration/vmstate.h"
>>>+#include "qemu/bcd.h"
>>>+#include "qom/object.h"
>>>+#include "system/rtc.h"
>>>+#include "trace.h"
>>>+
>>>+#define NVRAM_SIZE 0x10
>>>+
>>>+/* Flags definitions */
>>>+#define SECONDS_CH 0x80
>>>+#define HOURS_PM 0x20
>>>+#define CTRL2_24 0x20
>>>+
>>>+#define TYPE_RS5C372 "rs5c372"
>>>+OBJECT_DECLARE_SIMPLE_TYPE(RS5C372State, RS5C372)
>>>+
>>>+struct RS5C372State {
>>>+ I2CSlave parent_obj;
>>>+
>>>+ int64_t offset;
>>>+ uint8_t wday_offset;
>>>+ uint8_t nvram[NVRAM_SIZE];
>>>+ uint8_t ptr;
>>>+ uint8_t tx_format;
>>>+ bool addr_byte;
>>>+};
>>>+
>>>+static void capture_current_time(RS5C372State *s)
>>>+{
>>>+ /*
>>>+ * Capture the current time into the secondary registers which will be
>>>+ * actually read by the data transfer operation.
>>>+ */
>>>+ struct tm now;
>>>+ qemu_get_timedate(&now, s->offset);
>>>+ s->nvram[0] = to_bcd(now.tm_sec);
>>>+ s->nvram[1] = to_bcd(now.tm_min);
>>>+ if (s->nvram[0xf] & CTRL2_24) {
>>>+ s->nvram[2] = to_bcd(now.tm_hour);
>>>+ } else {
>>>+ int tmp = now.tm_hour;
>>>+ if (tmp % 12 == 0) {
>>>+ tmp += 12;
>>>+ }
>>>+ if (tmp <= 12) {
>>>+ s->nvram[2] = to_bcd(tmp);
>>>+ } else {
>>>+ s->nvram[2] = HOURS_PM | to_bcd(tmp - 12);
>>>+ }
>>>+ }
>>>+ s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
>>>+ s->nvram[4] = to_bcd(now.tm_mday);
>>>+ s->nvram[5] = to_bcd(now.tm_mon + 1);
>>>+ s->nvram[6] = to_bcd(now.tm_year - 100);
>>>+}
>>>+
>>>+static void inc_regptr(RS5C372State *s)
>>>+{
>>>+ s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
>>>+}
>>>+
>>>+static int rs5c372_event(I2CSlave *i2c, enum i2c_event event)
>>>+{
>>>+ RS5C372State *s = RS5C372(i2c);
>>>+
>>>+ switch (event) {
>>>+ case I2C_START_RECV:
>>>+ /*
>>>+ * In h/w, capture happens on any START condition, not just a
>>>+ * START_RECV, but there is no need to actually capture on
>>>+ * START_SEND, because the guest can't get at that data
>>>+ * without going through a START_RECV which would overwrite it.
>>>+ */
>>>+ capture_current_time(s);
>>>+ s->ptr = 0xf;
>>>+ break;
>>>+ case I2C_START_SEND:
>>>+ s->addr_byte = true;
>>>+ break;
>>>+ default:
>>>+ break;
>>>+ }
>>>+
>>>+ return 0;
>>>+}
>>>+
>>>+static uint8_t rs5c372_recv(I2CSlave *i2c)
>>>+{
>>>+ RS5C372State *s = RS5C372(i2c);
>>>+ uint8_t res;
>>>+
>>>+ res = s->nvram[s->ptr];
>>>+
>>>+ trace_rs5c372_recv(s->ptr, res);
>>>+
>>>+ inc_regptr(s);
>>>+ return res;
>>>+}
>>>+
>>>+static int rs5c372_send(I2CSlave *i2c, uint8_t data)
>>>+{
>>>+ RS5C372State *s = RS5C372(i2c);
>>>+
>>>+ if (s->addr_byte) {
>>>+ s->ptr = data >> 4;
>>>+ s->tx_format = data & 0xf;
>>>+ s->addr_byte = false;
>>>+ return 0;
>>>+ }
>>>+
>>>+ trace_rs5c372_send(s->ptr, data);
>>>+
>>>+ if (s->ptr < 7) {
>>>+ /* Time register. */
>>>+ struct tm now;
>>>+ qemu_get_timedate(&now, s->offset);
>>>+ switch (s->ptr) {
>>>+ case 0:
>>>+ now.tm_sec = from_bcd(data & 0x7f);
>>>+ break;
>>>+ case 1:
>>>+ now.tm_min = from_bcd(data & 0x7f);
>>>+ break;
>>>+ case 2:
>>>+ if (s->nvram[0xf] & CTRL2_24) {
>>>+ now.tm_hour = from_bcd(data & 0x3f);
>>>+ } else {
>>>+ int tmp = from_bcd(data & (HOURS_PM - 1));
>>>+ if (data & HOURS_PM) {
>>>+ tmp += 12;
>>>+ }
>>>+ if (tmp % 12 == 0) {
>>>+ tmp -= 12;
>>>+ }
>>>+ now.tm_hour = tmp;
>>>+ }
>>>+ break;
>>>+ case 3:
>>>+ {
>>>+ /*
>>>+ * The day field is supposed to contain a value in the range
>>>+ * 1-7. Otherwise behavior is undefined.
>>>+ */
>>>+ int user_wday = (data & 7) - 1;
>>>+ s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
>>>+ }
>>>+ break;
>>>+ case 4:
>>>+ now.tm_mday = from_bcd(data & 0x3f);
>>>+ break;
>>>+ case 5:
>>>+ now.tm_mon = from_bcd(data & 0x1f) - 1;
>>>+ break;
>>>+ case 6:
>>>+ now.tm_year = from_bcd(data) + 100;
>>>+ break;
>>>+ }
>>>+ s->offset = qemu_timedate_diff(&now);
>>>+ } else {
>>>+ s->nvram[s->ptr] = data;
>>>+ }
>>>+ inc_regptr(s);
>>>+ return 0;
>>>+}
>>>+
>>>+static void rs5c372_reset_hold(Object *obj, ResetType type)
>>>+{
>>>+ RS5C372State *s = RS5C372(obj);
>>>+
>>>+ /* The clock is running and synchronized with the host */
>>>+ s->offset = 0;
>>>+ s->wday_offset = 0;
>>>+ memset(s->nvram, 0, NVRAM_SIZE);
>>>+ s->ptr = 0;
>>>+ s->addr_byte = false;
>>>+}
>>>+
>>>+static const VMStateDescription rs5c372_vmstate = {
>>>+ .name = "rs5c372",
>>>+ .version_id = 1,
>>>+ .minimum_version_id = 1,
>>>+ .fields = (const VMStateField[]) {
>>>+ VMSTATE_I2C_SLAVE(parent_obj, RS5C372State),
>>>+ VMSTATE_INT64(offset, RS5C372State),
>>>+ VMSTATE_UINT8_V(wday_offset, RS5C372State, 2),
>>>+ VMSTATE_UINT8_ARRAY(nvram, RS5C372State, NVRAM_SIZE),
>>>+ VMSTATE_UINT8(ptr, RS5C372State),
>>>+ VMSTATE_UINT8(tx_format, RS5C372State),
>>>+ VMSTATE_BOOL(addr_byte, RS5C372State),
>>>+ VMSTATE_END_OF_LIST()
>>>+ }
>>>+};
>>>+
>>>+static void rs5c372_init(Object *obj)
>>>+{
>>>+ qdev_prop_set_uint8(DEVICE(obj), "address", 0x32);
>>>+}
>>>+
>>>+static void rs5c372_class_init(ObjectClass *klass, void *data)
>>>+{
>>>+ DeviceClass *dc = DEVICE_CLASS(klass);
>>>+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
>>>+ ResettableClass *rc = RESETTABLE_CLASS(klass);
>>>+
>>>+ k->event = rs5c372_event;
>>>+ k->recv = rs5c372_recv;
>>>+ k->send = rs5c372_send;
>>>+ dc->vmsd = &rs5c372_vmstate;
>>>+ rc->phases.hold = rs5c372_reset_hold;
>>>+}
>>>+
>>>+static const TypeInfo rs5c372_types[] = {
>>>+ {
>>>+ .name = TYPE_RS5C372,
>>>+ .parent = TYPE_I2C_SLAVE,
>>>+ .instance_size = sizeof(RS5C372State),
>>>+ .instance_init = rs5c372_init,
>>>+ .class_init = rs5c372_class_init,
>>>+ },
>>>+};
>>>+
>>>+DEFINE_TYPES(rs5c372_types)
>>>diff --git a/tests/qtest/rs5c372-test.c b/tests/qtest/rs5c372-test.c
>>>new file mode 100644
>>>index 0000000000..0f6a9b68b9
>>>--- /dev/null
>>>+++ b/tests/qtest/rs5c372-test.c
>>>@@ -0,0 +1,43 @@
>>>+/*
>>>+ * QTest testcase for the RS5C372 RTC
>>>+ *
>>>+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
>>>+ *
>>>+ * Based on ds1338-test.c
>>>+ *
>>>+ * SPDX-License-Identifier: GPL-2.0-or-later
>>>+ */
>>>+
>>>+#include "qemu/osdep.h"
>>>+#include "qemu/bcd.h"
>>>+#include "libqos/i2c.h"
>>>+
>>>+#define RS5C372_ADDR 0x32
>>>+
>>>+static void rs5c372_read_date(void *obj, void *data, QGuestAllocator *alloc)
>>>+{
>>>+ QI2CDevice *i2cdev = obj;
>>>+
>>>+ uint8_t resp[0x10];
>>>+ time_t now = time(NULL);
>>>+ struct tm *utc = gmtime(&now);
>>>+
>>>+ i2c_read_block(i2cdev, 0, resp, sizeof(resp));
>>>+
>>>+ /* check retrieved time against local time */
>>>+ g_assert_cmpuint(from_bcd(resp[5]), == , utc->tm_mday);
>>>+ g_assert_cmpuint(from_bcd(resp[6]), == , 1 + utc->tm_mon);
>>>+ g_assert_cmpuint(2000 + from_bcd(resp[7]), == , 1900 + utc->tm_year);
>>>+}
>>>+
>>>+static void rs5c372_register_nodes(void)
>>>+{
>>>+ QOSGraphEdgeOptions opts = { };
>>>+ add_qi2c_address(&opts, &(QI2CAddress) { RS5C372_ADDR });
>>>+
>>>+ qos_node_create_driver("rs5c372", i2c_device_create);
>>>+ qos_node_consumes("rs5c372", "i2c-bus", &opts);
>>>+ qos_add_test("read_date", "rs5c372", rs5c372_read_date, NULL);
>>>+}
>>>+
>>>+libqos_init(rs5c372_register_nodes);
>>>diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
>>>index 2fe04ec1d0..315b0e4ecc 100644
>>>--- a/hw/rtc/Kconfig
>>>+++ b/hw/rtc/Kconfig
>>>@@ -26,3 +26,8 @@ config GOLDFISH_RTC
>>>
>>> config LS7A_RTC
>>> bool
>>>+
>>>+config RS5C372_RTC
>>>+ bool
>>>+ depends on I2C
>>>+ default y if I2C_DEVICES
>>>diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
>>>index 8ecc2d792c..6c87864dc0 100644
>>>--- a/hw/rtc/meson.build
>>>+++ b/hw/rtc/meson.build
>>>@@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
>>> system_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
>>> system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
>>> system_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
>>>+system_ss.add(when: 'CONFIG_RS5C372_RTC', if_true: files('rs5c372.c'))
>>>diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events
>>>index 8012afe102..b9f2852d35 100644
>>>--- a/hw/rtc/trace-events
>>>+++ b/hw/rtc/trace-events
>>>@@ -35,3 +35,7 @@ m48txx_nvram_mem_write(uint32_t addr, uint32_t value) "mem write addr:0x%04x val
>>> # goldfish_rtc.c
>>> goldfish_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
>>> goldfish_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
>>>+
>>>+# rs5c372.c
>>>+rs5c372_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
>>>+rs5c372_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
>>>diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
>>>index 8a6243382a..9e5380ba7a 100644
>>>--- a/tests/qtest/meson.build
>>>+++ b/tests/qtest/meson.build
>>>@@ -298,6 +298,7 @@ qos_test_ss.add(
>>> 'pca9552-test.c',
>>> 'pci-test.c',
>>> 'pcnet-test.c',
>>>+ 'rs5c372-test.c',
>>> 'sdhci-test.c',
>>> 'spapr-phb-test.c',
>>> 'tmp105-test.c',
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation
2025-03-11 7:34 ` Bernhard Beschow
@ 2025-03-11 9:20 ` Philippe Mathieu-Daudé
2025-03-11 15:49 ` Corey Minyard
0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-03-11 9:20 UTC (permalink / raw)
To: Bernhard Beschow, qemu-devel, Paolo Bonzini, Corey Minyard
Cc: Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias
On 11/3/25 08:34, Bernhard Beschow wrote:
>
>
> Am 7. März 2025 19:18:34 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>
>>
>> Am 4. März 2025 18:53:10 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>>
>>>
>>> Am 23. Februar 2025 11:47:08 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>>> The implementation just allows Linux to determine date and time.
>>>>
>>>> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>>>> ---
>>>> MAINTAINERS | 2 +
>>>> hw/rtc/rs5c372.c | 236 +++++++++++++++++++++++++++++++++++++
>>>> tests/qtest/rs5c372-test.c | 43 +++++++
>>>> hw/rtc/Kconfig | 5 +
>>>> hw/rtc/meson.build | 1 +
>>>> hw/rtc/trace-events | 4 +
>>>> tests/qtest/meson.build | 1 +
>>>> 7 files changed, 292 insertions(+)
>>>> create mode 100644 hw/rtc/rs5c372.c
>>>> create mode 100644 tests/qtest/rs5c372-test.c
>>>
>>> Ping for just this patch. I'd like to have it merged for 10.0.
>>
>> Ping^2 -- just few days left before soft freeze.
>
> Last ping before the freeze
>
> It would really be nice to have this device model in 10.0 since this would allow me to use upstream QEMU.
Apparently I2C maintainer wasn't Cc'ed (now is):
Corey Minyard <cminyard@mvista.com> (maintainer:I2C and SMBus)
At a glance patch LGTM, so:
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>
> Thanks,
> Bernhard
>
>>
>> AFAICS no open issues and I'd really like to have this RTC merged for 10.0. What is holding it back?
>>
>> Best regards,
>> Bernhard
>>
>>>
>>> Thanks,
>>> Bernhard
>>>
>>>>
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index 489e426d85..2552cfd65c 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -828,10 +828,12 @@ F: hw/arm/imx8mp-evk.c
>>>> F: hw/arm/fsl-imx8mp.c
>>>> F: hw/misc/imx8mp_*.c
>>>> F: hw/pci-host/fsl_imx8m_phy.c
>>>> +F: hw/rtc/rs5c372.c
>>>> F: include/hw/arm/fsl-imx8mp.h
>>>> F: include/hw/misc/imx8mp_*.h
>>>> F: include/hw/pci-host/fsl_imx8m_phy.h
>>>> F: pc-bios/imx8mp*
>>>> +F: tests/qtest/rs5c372-test.c
>>>> F: docs/system/arm/imx8mp-evk.rst
>>>>
>>>> MPS2 / MPS3
>>>> diff --git a/hw/rtc/rs5c372.c b/hw/rtc/rs5c372.c
>>>> new file mode 100644
>>>> index 0000000000..5542f74085
>>>> --- /dev/null
>>>> +++ b/hw/rtc/rs5c372.c
>>>> @@ -0,0 +1,236 @@
>>>> +/*
>>>> + * Ricoh RS5C372, R222x I2C RTC
>>>> + *
>>>> + * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
>>>> + *
>>>> + * Based on hw/rtc/ds1338.c
>>>> + *
>>>> + * SPDX-License-Identifier: GPL-2.0-or-later
>>>> + */
>>>> +
>>>> +#include "qemu/osdep.h"
>>>> +#include "hw/i2c/i2c.h"
>>>> +#include "hw/qdev-properties.h"
>>>> +#include "hw/resettable.h"
>>>> +#include "migration/vmstate.h"
>>>> +#include "qemu/bcd.h"
>>>> +#include "qom/object.h"
>>>> +#include "system/rtc.h"
>>>> +#include "trace.h"
>>>> +
>>>> +#define NVRAM_SIZE 0x10
>>>> +
>>>> +/* Flags definitions */
>>>> +#define SECONDS_CH 0x80
>>>> +#define HOURS_PM 0x20
>>>> +#define CTRL2_24 0x20
>>>> +
>>>> +#define TYPE_RS5C372 "rs5c372"
>>>> +OBJECT_DECLARE_SIMPLE_TYPE(RS5C372State, RS5C372)
>>>> +
>>>> +struct RS5C372State {
>>>> + I2CSlave parent_obj;
>>>> +
>>>> + int64_t offset;
>>>> + uint8_t wday_offset;
>>>> + uint8_t nvram[NVRAM_SIZE];
>>>> + uint8_t ptr;
>>>> + uint8_t tx_format;
>>>> + bool addr_byte;
>>>> +};
>>>> +
>>>> +static void capture_current_time(RS5C372State *s)
>>>> +{
>>>> + /*
>>>> + * Capture the current time into the secondary registers which will be
>>>> + * actually read by the data transfer operation.
>>>> + */
>>>> + struct tm now;
>>>> + qemu_get_timedate(&now, s->offset);
>>>> + s->nvram[0] = to_bcd(now.tm_sec);
>>>> + s->nvram[1] = to_bcd(now.tm_min);
>>>> + if (s->nvram[0xf] & CTRL2_24) {
>>>> + s->nvram[2] = to_bcd(now.tm_hour);
>>>> + } else {
>>>> + int tmp = now.tm_hour;
>>>> + if (tmp % 12 == 0) {
>>>> + tmp += 12;
>>>> + }
>>>> + if (tmp <= 12) {
>>>> + s->nvram[2] = to_bcd(tmp);
>>>> + } else {
>>>> + s->nvram[2] = HOURS_PM | to_bcd(tmp - 12);
>>>> + }
>>>> + }
>>>> + s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
>>>> + s->nvram[4] = to_bcd(now.tm_mday);
>>>> + s->nvram[5] = to_bcd(now.tm_mon + 1);
>>>> + s->nvram[6] = to_bcd(now.tm_year - 100);
>>>> +}
>>>> +
>>>> +static void inc_regptr(RS5C372State *s)
>>>> +{
>>>> + s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
>>>> +}
>>>> +
>>>> +static int rs5c372_event(I2CSlave *i2c, enum i2c_event event)
>>>> +{
>>>> + RS5C372State *s = RS5C372(i2c);
>>>> +
>>>> + switch (event) {
>>>> + case I2C_START_RECV:
>>>> + /*
>>>> + * In h/w, capture happens on any START condition, not just a
>>>> + * START_RECV, but there is no need to actually capture on
>>>> + * START_SEND, because the guest can't get at that data
>>>> + * without going through a START_RECV which would overwrite it.
>>>> + */
>>>> + capture_current_time(s);
>>>> + s->ptr = 0xf;
>>>> + break;
>>>> + case I2C_START_SEND:
>>>> + s->addr_byte = true;
>>>> + break;
>>>> + default:
>>>> + break;
>>>> + }
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static uint8_t rs5c372_recv(I2CSlave *i2c)
>>>> +{
>>>> + RS5C372State *s = RS5C372(i2c);
>>>> + uint8_t res;
>>>> +
>>>> + res = s->nvram[s->ptr];
>>>> +
>>>> + trace_rs5c372_recv(s->ptr, res);
>>>> +
>>>> + inc_regptr(s);
>>>> + return res;
>>>> +}
>>>> +
>>>> +static int rs5c372_send(I2CSlave *i2c, uint8_t data)
>>>> +{
>>>> + RS5C372State *s = RS5C372(i2c);
>>>> +
>>>> + if (s->addr_byte) {
>>>> + s->ptr = data >> 4;
>>>> + s->tx_format = data & 0xf;
>>>> + s->addr_byte = false;
>>>> + return 0;
>>>> + }
>>>> +
>>>> + trace_rs5c372_send(s->ptr, data);
>>>> +
>>>> + if (s->ptr < 7) {
>>>> + /* Time register. */
>>>> + struct tm now;
>>>> + qemu_get_timedate(&now, s->offset);
>>>> + switch (s->ptr) {
>>>> + case 0:
>>>> + now.tm_sec = from_bcd(data & 0x7f);
>>>> + break;
>>>> + case 1:
>>>> + now.tm_min = from_bcd(data & 0x7f);
>>>> + break;
>>>> + case 2:
>>>> + if (s->nvram[0xf] & CTRL2_24) {
>>>> + now.tm_hour = from_bcd(data & 0x3f);
>>>> + } else {
>>>> + int tmp = from_bcd(data & (HOURS_PM - 1));
>>>> + if (data & HOURS_PM) {
>>>> + tmp += 12;
>>>> + }
>>>> + if (tmp % 12 == 0) {
>>>> + tmp -= 12;
>>>> + }
>>>> + now.tm_hour = tmp;
>>>> + }
>>>> + break;
>>>> + case 3:
>>>> + {
>>>> + /*
>>>> + * The day field is supposed to contain a value in the range
>>>> + * 1-7. Otherwise behavior is undefined.
>>>> + */
>>>> + int user_wday = (data & 7) - 1;
>>>> + s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
>>>> + }
>>>> + break;
>>>> + case 4:
>>>> + now.tm_mday = from_bcd(data & 0x3f);
>>>> + break;
>>>> + case 5:
>>>> + now.tm_mon = from_bcd(data & 0x1f) - 1;
>>>> + break;
>>>> + case 6:
>>>> + now.tm_year = from_bcd(data) + 100;
>>>> + break;
>>>> + }
>>>> + s->offset = qemu_timedate_diff(&now);
>>>> + } else {
>>>> + s->nvram[s->ptr] = data;
>>>> + }
>>>> + inc_regptr(s);
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static void rs5c372_reset_hold(Object *obj, ResetType type)
>>>> +{
>>>> + RS5C372State *s = RS5C372(obj);
>>>> +
>>>> + /* The clock is running and synchronized with the host */
>>>> + s->offset = 0;
>>>> + s->wday_offset = 0;
>>>> + memset(s->nvram, 0, NVRAM_SIZE);
>>>> + s->ptr = 0;
>>>> + s->addr_byte = false;
>>>> +}
>>>> +
>>>> +static const VMStateDescription rs5c372_vmstate = {
>>>> + .name = "rs5c372",
>>>> + .version_id = 1,
>>>> + .minimum_version_id = 1,
>>>> + .fields = (const VMStateField[]) {
>>>> + VMSTATE_I2C_SLAVE(parent_obj, RS5C372State),
>>>> + VMSTATE_INT64(offset, RS5C372State),
>>>> + VMSTATE_UINT8_V(wday_offset, RS5C372State, 2),
>>>> + VMSTATE_UINT8_ARRAY(nvram, RS5C372State, NVRAM_SIZE),
>>>> + VMSTATE_UINT8(ptr, RS5C372State),
>>>> + VMSTATE_UINT8(tx_format, RS5C372State),
>>>> + VMSTATE_BOOL(addr_byte, RS5C372State),
>>>> + VMSTATE_END_OF_LIST()
>>>> + }
>>>> +};
>>>> +
>>>> +static void rs5c372_init(Object *obj)
>>>> +{
>>>> + qdev_prop_set_uint8(DEVICE(obj), "address", 0x32);
>>>> +}
>>>> +
>>>> +static void rs5c372_class_init(ObjectClass *klass, void *data)
>>>> +{
>>>> + DeviceClass *dc = DEVICE_CLASS(klass);
>>>> + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
>>>> + ResettableClass *rc = RESETTABLE_CLASS(klass);
>>>> +
>>>> + k->event = rs5c372_event;
>>>> + k->recv = rs5c372_recv;
>>>> + k->send = rs5c372_send;
>>>> + dc->vmsd = &rs5c372_vmstate;
>>>> + rc->phases.hold = rs5c372_reset_hold;
>>>> +}
>>>> +
>>>> +static const TypeInfo rs5c372_types[] = {
>>>> + {
>>>> + .name = TYPE_RS5C372,
>>>> + .parent = TYPE_I2C_SLAVE,
>>>> + .instance_size = sizeof(RS5C372State),
>>>> + .instance_init = rs5c372_init,
>>>> + .class_init = rs5c372_class_init,
>>>> + },
>>>> +};
>>>> +
>>>> +DEFINE_TYPES(rs5c372_types)
>>>> diff --git a/tests/qtest/rs5c372-test.c b/tests/qtest/rs5c372-test.c
>>>> new file mode 100644
>>>> index 0000000000..0f6a9b68b9
>>>> --- /dev/null
>>>> +++ b/tests/qtest/rs5c372-test.c
>>>> @@ -0,0 +1,43 @@
>>>> +/*
>>>> + * QTest testcase for the RS5C372 RTC
>>>> + *
>>>> + * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
>>>> + *
>>>> + * Based on ds1338-test.c
>>>> + *
>>>> + * SPDX-License-Identifier: GPL-2.0-or-later
>>>> + */
>>>> +
>>>> +#include "qemu/osdep.h"
>>>> +#include "qemu/bcd.h"
>>>> +#include "libqos/i2c.h"
>>>> +
>>>> +#define RS5C372_ADDR 0x32
>>>> +
>>>> +static void rs5c372_read_date(void *obj, void *data, QGuestAllocator *alloc)
>>>> +{
>>>> + QI2CDevice *i2cdev = obj;
>>>> +
>>>> + uint8_t resp[0x10];
>>>> + time_t now = time(NULL);
>>>> + struct tm *utc = gmtime(&now);
>>>> +
>>>> + i2c_read_block(i2cdev, 0, resp, sizeof(resp));
>>>> +
>>>> + /* check retrieved time against local time */
>>>> + g_assert_cmpuint(from_bcd(resp[5]), == , utc->tm_mday);
>>>> + g_assert_cmpuint(from_bcd(resp[6]), == , 1 + utc->tm_mon);
>>>> + g_assert_cmpuint(2000 + from_bcd(resp[7]), == , 1900 + utc->tm_year);
>>>> +}
>>>> +
>>>> +static void rs5c372_register_nodes(void)
>>>> +{
>>>> + QOSGraphEdgeOptions opts = { };
>>>> + add_qi2c_address(&opts, &(QI2CAddress) { RS5C372_ADDR });
>>>> +
>>>> + qos_node_create_driver("rs5c372", i2c_device_create);
>>>> + qos_node_consumes("rs5c372", "i2c-bus", &opts);
>>>> + qos_add_test("read_date", "rs5c372", rs5c372_read_date, NULL);
>>>> +}
>>>> +
>>>> +libqos_init(rs5c372_register_nodes);
>>>> diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
>>>> index 2fe04ec1d0..315b0e4ecc 100644
>>>> --- a/hw/rtc/Kconfig
>>>> +++ b/hw/rtc/Kconfig
>>>> @@ -26,3 +26,8 @@ config GOLDFISH_RTC
>>>>
>>>> config LS7A_RTC
>>>> bool
>>>> +
>>>> +config RS5C372_RTC
>>>> + bool
>>>> + depends on I2C
>>>> + default y if I2C_DEVICES
>>>> diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
>>>> index 8ecc2d792c..6c87864dc0 100644
>>>> --- a/hw/rtc/meson.build
>>>> +++ b/hw/rtc/meson.build
>>>> @@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
>>>> system_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
>>>> system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
>>>> system_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
>>>> +system_ss.add(when: 'CONFIG_RS5C372_RTC', if_true: files('rs5c372.c'))
>>>> diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events
>>>> index 8012afe102..b9f2852d35 100644
>>>> --- a/hw/rtc/trace-events
>>>> +++ b/hw/rtc/trace-events
>>>> @@ -35,3 +35,7 @@ m48txx_nvram_mem_write(uint32_t addr, uint32_t value) "mem write addr:0x%04x val
>>>> # goldfish_rtc.c
>>>> goldfish_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
>>>> goldfish_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
>>>> +
>>>> +# rs5c372.c
>>>> +rs5c372_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
>>>> +rs5c372_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
>>>> diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
>>>> index 8a6243382a..9e5380ba7a 100644
>>>> --- a/tests/qtest/meson.build
>>>> +++ b/tests/qtest/meson.build
>>>> @@ -298,6 +298,7 @@ qos_test_ss.add(
>>>> 'pca9552-test.c',
>>>> 'pci-test.c',
>>>> 'pcnet-test.c',
>>>> + 'rs5c372-test.c',
>>>> 'sdhci-test.c',
>>>> 'spapr-phb-test.c',
>>>> 'tmp105-test.c',
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation
2025-03-11 9:20 ` Philippe Mathieu-Daudé
@ 2025-03-11 15:49 ` Corey Minyard
2025-03-11 16:01 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 45+ messages in thread
From: Corey Minyard @ 2025-03-11 15:49 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Bernhard Beschow, qemu-devel, Paolo Bonzini,
Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias
[-- Attachment #1: Type: text/plain, Size: 16209 bytes --]
On Tue, Mar 11, 2025 at 10:20:03AM +0100, Philippe Mathieu-Daudé wrote:
> On 11/3/25 08:34, Bernhard Beschow wrote:
> >
> >
> > Am 7. März 2025 19:18:34 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
> > >
> > >
> > > Am 4. März 2025 18:53:10 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
> > > >
> > > >
> > > > Am 23. Februar 2025 11:47:08 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
> > > > > The implementation just allows Linux to determine date and time.
> > > > >
> > > > > Signed-off-by: Bernhard Beschow <shentey@gmail.com>
> > > > > ---
> > > > > MAINTAINERS | 2 +
> > > > > hw/rtc/rs5c372.c | 236 +++++++++++++++++++++++++++++++++++++
> > > > > tests/qtest/rs5c372-test.c | 43 +++++++
> > > > > hw/rtc/Kconfig | 5 +
> > > > > hw/rtc/meson.build | 1 +
> > > > > hw/rtc/trace-events | 4 +
> > > > > tests/qtest/meson.build | 1 +
> > > > > 7 files changed, 292 insertions(+)
> > > > > create mode 100644 hw/rtc/rs5c372.c
> > > > > create mode 100644 tests/qtest/rs5c372-test.c
> > > >
> > > > Ping for just this patch. I'd like to have it merged for 10.0.
> > >
> > > Ping^2 -- just few days left before soft freeze.
> >
> > Last ping before the freeze
> >
> > It would really be nice to have this device model in 10.0 since this would allow me to use upstream QEMU.
>
> Apparently I2C maintainer wasn't Cc'ed (now is):
>
> Corey Minyard <cminyard@mvista.com> (maintainer:I2C and SMBus)
>
> At a glance patch LGTM, so:
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Well, it's fairly hard to read this way :-). But this looks good. My
only comment is on:
>>>> +#define NVRAM_SIZE 0x10
>>>> +
>>>> +/* Flags definitions */
>>>> +#define SECONDS_CH 0x80
>>>> +#define HOURS_PM 0x20
>>>> +#define CTRL2_24 0x20
Those are fairly generic names; when I see things like that I worry
about conflicting with other generic names that might come into an
include later. Not a huge deal, though.
Acked-by: Corey Minyard <cminyard@mvista.com>
>
> >
> > Thanks,
> > Bernhard
> >
> > >
> > > AFAICS no open issues and I'd really like to have this RTC merged for 10.0. What is holding it back?
> > >
> > > Best regards,
> > > Bernhard
> > >
> > > >
> > > > Thanks,
> > > > Bernhard
> > > >
> > > > >
> > > > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > > > index 489e426d85..2552cfd65c 100644
> > > > > --- a/MAINTAINERS
> > > > > +++ b/MAINTAINERS
> > > > > @@ -828,10 +828,12 @@ F: hw/arm/imx8mp-evk.c
> > > > > F: hw/arm/fsl-imx8mp.c
> > > > > F: hw/misc/imx8mp_*.c
> > > > > F: hw/pci-host/fsl_imx8m_phy.c
> > > > > +F: hw/rtc/rs5c372.c
> > > > > F: include/hw/arm/fsl-imx8mp.h
> > > > > F: include/hw/misc/imx8mp_*.h
> > > > > F: include/hw/pci-host/fsl_imx8m_phy.h
> > > > > F: pc-bios/imx8mp*
> > > > > +F: tests/qtest/rs5c372-test.c
> > > > > F: docs/system/arm/imx8mp-evk.rst
> > > > >
> > > > > MPS2 / MPS3
> > > > > diff --git a/hw/rtc/rs5c372.c b/hw/rtc/rs5c372.c
> > > > > new file mode 100644
> > > > > index 0000000000..5542f74085
> > > > > --- /dev/null
> > > > > +++ b/hw/rtc/rs5c372.c
> > > > > @@ -0,0 +1,236 @@
> > > > > +/*
> > > > > + * Ricoh RS5C372, R222x I2C RTC
> > > > > + *
> > > > > + * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
> > > > > + *
> > > > > + * Based on hw/rtc/ds1338.c
> > > > > + *
> > > > > + * SPDX-License-Identifier: GPL-2.0-or-later
> > > > > + */
> > > > > +
> > > > > +#include "qemu/osdep.h"
> > > > > +#include "hw/i2c/i2c.h"
> > > > > +#include "hw/qdev-properties.h"
> > > > > +#include "hw/resettable.h"
> > > > > +#include "migration/vmstate.h"
> > > > > +#include "qemu/bcd.h"
> > > > > +#include "qom/object.h"
> > > > > +#include "system/rtc.h"
> > > > > +#include "trace.h"
> > > > > +
> > > > > +#define NVRAM_SIZE 0x10
> > > > > +
> > > > > +/* Flags definitions */
> > > > > +#define SECONDS_CH 0x80
> > > > > +#define HOURS_PM 0x20
> > > > > +#define CTRL2_24 0x20
> > > > > +
> > > > > +#define TYPE_RS5C372 "rs5c372"
> > > > > +OBJECT_DECLARE_SIMPLE_TYPE(RS5C372State, RS5C372)
> > > > > +
> > > > > +struct RS5C372State {
> > > > > + I2CSlave parent_obj;
> > > > > +
> > > > > + int64_t offset;
> > > > > + uint8_t wday_offset;
> > > > > + uint8_t nvram[NVRAM_SIZE];
> > > > > + uint8_t ptr;
> > > > > + uint8_t tx_format;
> > > > > + bool addr_byte;
> > > > > +};
> > > > > +
> > > > > +static void capture_current_time(RS5C372State *s)
> > > > > +{
> > > > > + /*
> > > > > + * Capture the current time into the secondary registers which will be
> > > > > + * actually read by the data transfer operation.
> > > > > + */
> > > > > + struct tm now;
> > > > > + qemu_get_timedate(&now, s->offset);
> > > > > + s->nvram[0] = to_bcd(now.tm_sec);
> > > > > + s->nvram[1] = to_bcd(now.tm_min);
> > > > > + if (s->nvram[0xf] & CTRL2_24) {
> > > > > + s->nvram[2] = to_bcd(now.tm_hour);
> > > > > + } else {
> > > > > + int tmp = now.tm_hour;
> > > > > + if (tmp % 12 == 0) {
> > > > > + tmp += 12;
> > > > > + }
> > > > > + if (tmp <= 12) {
> > > > > + s->nvram[2] = to_bcd(tmp);
> > > > > + } else {
> > > > > + s->nvram[2] = HOURS_PM | to_bcd(tmp - 12);
> > > > > + }
> > > > > + }
> > > > > + s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
> > > > > + s->nvram[4] = to_bcd(now.tm_mday);
> > > > > + s->nvram[5] = to_bcd(now.tm_mon + 1);
> > > > > + s->nvram[6] = to_bcd(now.tm_year - 100);
> > > > > +}
> > > > > +
> > > > > +static void inc_regptr(RS5C372State *s)
> > > > > +{
> > > > > + s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
> > > > > +}
> > > > > +
> > > > > +static int rs5c372_event(I2CSlave *i2c, enum i2c_event event)
> > > > > +{
> > > > > + RS5C372State *s = RS5C372(i2c);
> > > > > +
> > > > > + switch (event) {
> > > > > + case I2C_START_RECV:
> > > > > + /*
> > > > > + * In h/w, capture happens on any START condition, not just a
> > > > > + * START_RECV, but there is no need to actually capture on
> > > > > + * START_SEND, because the guest can't get at that data
> > > > > + * without going through a START_RECV which would overwrite it.
> > > > > + */
> > > > > + capture_current_time(s);
> > > > > + s->ptr = 0xf;
> > > > > + break;
> > > > > + case I2C_START_SEND:
> > > > > + s->addr_byte = true;
> > > > > + break;
> > > > > + default:
> > > > > + break;
> > > > > + }
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +static uint8_t rs5c372_recv(I2CSlave *i2c)
> > > > > +{
> > > > > + RS5C372State *s = RS5C372(i2c);
> > > > > + uint8_t res;
> > > > > +
> > > > > + res = s->nvram[s->ptr];
> > > > > +
> > > > > + trace_rs5c372_recv(s->ptr, res);
> > > > > +
> > > > > + inc_regptr(s);
> > > > > + return res;
> > > > > +}
> > > > > +
> > > > > +static int rs5c372_send(I2CSlave *i2c, uint8_t data)
> > > > > +{
> > > > > + RS5C372State *s = RS5C372(i2c);
> > > > > +
> > > > > + if (s->addr_byte) {
> > > > > + s->ptr = data >> 4;
> > > > > + s->tx_format = data & 0xf;
> > > > > + s->addr_byte = false;
> > > > > + return 0;
> > > > > + }
> > > > > +
> > > > > + trace_rs5c372_send(s->ptr, data);
> > > > > +
> > > > > + if (s->ptr < 7) {
> > > > > + /* Time register. */
> > > > > + struct tm now;
> > > > > + qemu_get_timedate(&now, s->offset);
> > > > > + switch (s->ptr) {
> > > > > + case 0:
> > > > > + now.tm_sec = from_bcd(data & 0x7f);
> > > > > + break;
> > > > > + case 1:
> > > > > + now.tm_min = from_bcd(data & 0x7f);
> > > > > + break;
> > > > > + case 2:
> > > > > + if (s->nvram[0xf] & CTRL2_24) {
> > > > > + now.tm_hour = from_bcd(data & 0x3f);
> > > > > + } else {
> > > > > + int tmp = from_bcd(data & (HOURS_PM - 1));
> > > > > + if (data & HOURS_PM) {
> > > > > + tmp += 12;
> > > > > + }
> > > > > + if (tmp % 12 == 0) {
> > > > > + tmp -= 12;
> > > > > + }
> > > > > + now.tm_hour = tmp;
> > > > > + }
> > > > > + break;
> > > > > + case 3:
> > > > > + {
> > > > > + /*
> > > > > + * The day field is supposed to contain a value in the range
> > > > > + * 1-7. Otherwise behavior is undefined.
> > > > > + */
> > > > > + int user_wday = (data & 7) - 1;
> > > > > + s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
> > > > > + }
> > > > > + break;
> > > > > + case 4:
> > > > > + now.tm_mday = from_bcd(data & 0x3f);
> > > > > + break;
> > > > > + case 5:
> > > > > + now.tm_mon = from_bcd(data & 0x1f) - 1;
> > > > > + break;
> > > > > + case 6:
> > > > > + now.tm_year = from_bcd(data) + 100;
> > > > > + break;
> > > > > + }
> > > > > + s->offset = qemu_timedate_diff(&now);
> > > > > + } else {
> > > > > + s->nvram[s->ptr] = data;
> > > > > + }
> > > > > + inc_regptr(s);
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +static void rs5c372_reset_hold(Object *obj, ResetType type)
> > > > > +{
> > > > > + RS5C372State *s = RS5C372(obj);
> > > > > +
> > > > > + /* The clock is running and synchronized with the host */
> > > > > + s->offset = 0;
> > > > > + s->wday_offset = 0;
> > > > > + memset(s->nvram, 0, NVRAM_SIZE);
> > > > > + s->ptr = 0;
> > > > > + s->addr_byte = false;
> > > > > +}
> > > > > +
> > > > > +static const VMStateDescription rs5c372_vmstate = {
> > > > > + .name = "rs5c372",
> > > > > + .version_id = 1,
> > > > > + .minimum_version_id = 1,
> > > > > + .fields = (const VMStateField[]) {
> > > > > + VMSTATE_I2C_SLAVE(parent_obj, RS5C372State),
> > > > > + VMSTATE_INT64(offset, RS5C372State),
> > > > > + VMSTATE_UINT8_V(wday_offset, RS5C372State, 2),
> > > > > + VMSTATE_UINT8_ARRAY(nvram, RS5C372State, NVRAM_SIZE),
> > > > > + VMSTATE_UINT8(ptr, RS5C372State),
> > > > > + VMSTATE_UINT8(tx_format, RS5C372State),
> > > > > + VMSTATE_BOOL(addr_byte, RS5C372State),
> > > > > + VMSTATE_END_OF_LIST()
> > > > > + }
> > > > > +};
> > > > > +
> > > > > +static void rs5c372_init(Object *obj)
> > > > > +{
> > > > > + qdev_prop_set_uint8(DEVICE(obj), "address", 0x32);
> > > > > +}
> > > > > +
> > > > > +static void rs5c372_class_init(ObjectClass *klass, void *data)
> > > > > +{
> > > > > + DeviceClass *dc = DEVICE_CLASS(klass);
> > > > > + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
> > > > > + ResettableClass *rc = RESETTABLE_CLASS(klass);
> > > > > +
> > > > > + k->event = rs5c372_event;
> > > > > + k->recv = rs5c372_recv;
> > > > > + k->send = rs5c372_send;
> > > > > + dc->vmsd = &rs5c372_vmstate;
> > > > > + rc->phases.hold = rs5c372_reset_hold;
> > > > > +}
> > > > > +
> > > > > +static const TypeInfo rs5c372_types[] = {
> > > > > + {
> > > > > + .name = TYPE_RS5C372,
> > > > > + .parent = TYPE_I2C_SLAVE,
> > > > > + .instance_size = sizeof(RS5C372State),
> > > > > + .instance_init = rs5c372_init,
> > > > > + .class_init = rs5c372_class_init,
> > > > > + },
> > > > > +};
> > > > > +
> > > > > +DEFINE_TYPES(rs5c372_types)
> > > > > diff --git a/tests/qtest/rs5c372-test.c b/tests/qtest/rs5c372-test.c
> > > > > new file mode 100644
> > > > > index 0000000000..0f6a9b68b9
> > > > > --- /dev/null
> > > > > +++ b/tests/qtest/rs5c372-test.c
> > > > > @@ -0,0 +1,43 @@
> > > > > +/*
> > > > > + * QTest testcase for the RS5C372 RTC
> > > > > + *
> > > > > + * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
> > > > > + *
> > > > > + * Based on ds1338-test.c
> > > > > + *
> > > > > + * SPDX-License-Identifier: GPL-2.0-or-later
> > > > > + */
> > > > > +
> > > > > +#include "qemu/osdep.h"
> > > > > +#include "qemu/bcd.h"
> > > > > +#include "libqos/i2c.h"
> > > > > +
> > > > > +#define RS5C372_ADDR 0x32
> > > > > +
> > > > > +static void rs5c372_read_date(void *obj, void *data, QGuestAllocator *alloc)
> > > > > +{
> > > > > + QI2CDevice *i2cdev = obj;
> > > > > +
> > > > > + uint8_t resp[0x10];
> > > > > + time_t now = time(NULL);
> > > > > + struct tm *utc = gmtime(&now);
> > > > > +
> > > > > + i2c_read_block(i2cdev, 0, resp, sizeof(resp));
> > > > > +
> > > > > + /* check retrieved time against local time */
> > > > > + g_assert_cmpuint(from_bcd(resp[5]), == , utc->tm_mday);
> > > > > + g_assert_cmpuint(from_bcd(resp[6]), == , 1 + utc->tm_mon);
> > > > > + g_assert_cmpuint(2000 + from_bcd(resp[7]), == , 1900 + utc->tm_year);
> > > > > +}
> > > > > +
> > > > > +static void rs5c372_register_nodes(void)
> > > > > +{
> > > > > + QOSGraphEdgeOptions opts = { };
> > > > > + add_qi2c_address(&opts, &(QI2CAddress) { RS5C372_ADDR });
> > > > > +
> > > > > + qos_node_create_driver("rs5c372", i2c_device_create);
> > > > > + qos_node_consumes("rs5c372", "i2c-bus", &opts);
> > > > > + qos_add_test("read_date", "rs5c372", rs5c372_read_date, NULL);
> > > > > +}
> > > > > +
> > > > > +libqos_init(rs5c372_register_nodes);
> > > > > diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
> > > > > index 2fe04ec1d0..315b0e4ecc 100644
> > > > > --- a/hw/rtc/Kconfig
> > > > > +++ b/hw/rtc/Kconfig
> > > > > @@ -26,3 +26,8 @@ config GOLDFISH_RTC
> > > > >
> > > > > config LS7A_RTC
> > > > > bool
> > > > > +
> > > > > +config RS5C372_RTC
> > > > > + bool
> > > > > + depends on I2C
> > > > > + default y if I2C_DEVICES
> > > > > diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
> > > > > index 8ecc2d792c..6c87864dc0 100644
> > > > > --- a/hw/rtc/meson.build
> > > > > +++ b/hw/rtc/meson.build
> > > > > @@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
> > > > > system_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
> > > > > system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
> > > > > system_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
> > > > > +system_ss.add(when: 'CONFIG_RS5C372_RTC', if_true: files('rs5c372.c'))
> > > > > diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events
> > > > > index 8012afe102..b9f2852d35 100644
> > > > > --- a/hw/rtc/trace-events
> > > > > +++ b/hw/rtc/trace-events
> > > > > @@ -35,3 +35,7 @@ m48txx_nvram_mem_write(uint32_t addr, uint32_t value) "mem write addr:0x%04x val
> > > > > # goldfish_rtc.c
> > > > > goldfish_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
> > > > > goldfish_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
> > > > > +
> > > > > +# rs5c372.c
> > > > > +rs5c372_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
> > > > > +rs5c372_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
> > > > > diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
> > > > > index 8a6243382a..9e5380ba7a 100644
> > > > > --- a/tests/qtest/meson.build
> > > > > +++ b/tests/qtest/meson.build
> > > > > @@ -298,6 +298,7 @@ qos_test_ss.add(
> > > > > 'pca9552-test.c',
> > > > > 'pci-test.c',
> > > > > 'pcnet-test.c',
> > > > > + 'rs5c372-test.c',
> > > > > 'sdhci-test.c',
> > > > > 'spapr-phb-test.c',
> > > > > 'tmp105-test.c',
>
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3365 bytes --]
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation
2025-03-11 15:49 ` Corey Minyard
@ 2025-03-11 16:01 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-03-11 16:01 UTC (permalink / raw)
To: cminyard
Cc: Bernhard Beschow, qemu-devel, Paolo Bonzini,
Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias
On 11/3/25 16:49, Corey Minyard wrote:
> On Tue, Mar 11, 2025 at 10:20:03AM +0100, Philippe Mathieu-Daudé wrote:
>> On 11/3/25 08:34, Bernhard Beschow wrote:
>>>
>>>
>>> Am 7. März 2025 19:18:34 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>>>
>>>>
>>>> Am 4. März 2025 18:53:10 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>>>>
>>>>>
>>>>> Am 23. Februar 2025 11:47:08 UTC schrieb Bernhard Beschow <shentey@gmail.com>:
>>>>>> The implementation just allows Linux to determine date and time.
>>>>>>
>>>>>> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
>>>>>> ---
>>>>>> MAINTAINERS | 2 +
>>>>>> hw/rtc/rs5c372.c | 236 +++++++++++++++++++++++++++++++++++++
>>>>>> tests/qtest/rs5c372-test.c | 43 +++++++
>>>>>> hw/rtc/Kconfig | 5 +
>>>>>> hw/rtc/meson.build | 1 +
>>>>>> hw/rtc/trace-events | 4 +
>>>>>> tests/qtest/meson.build | 1 +
>>>>>> 7 files changed, 292 insertions(+)
>>>>>> create mode 100644 hw/rtc/rs5c372.c
>>>>>> create mode 100644 tests/qtest/rs5c372-test.c
>>>>>
>>>>> Ping for just this patch. I'd like to have it merged for 10.0.
>>>>
>>>> Ping^2 -- just few days left before soft freeze.
>>>
>>> Last ping before the freeze
>>>
>>> It would really be nice to have this device model in 10.0 since this would allow me to use upstream QEMU.
>>
>> Apparently I2C maintainer wasn't Cc'ed (now is):
>>
>> Corey Minyard <cminyard@mvista.com> (maintainer:I2C and SMBus)
>>
>> At a glance patch LGTM, so:
>> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>
> Well, it's fairly hard to read this way :-). But this looks good. My
> only comment is on:
>
>>>>> +#define NVRAM_SIZE 0x10
>>>>> +
>>>>> +/* Flags definitions */
>>>>> +#define SECONDS_CH 0x80
>>>>> +#define HOURS_PM 0x20
>>>>> +#define CTRL2_24 0x20
>
> Those are fairly generic names; when I see things like that I worry
> about conflicting with other generic names that might come into an
> include later. Not a huge deal, though.
>
> Acked-by: Corey Minyard <cminyard@mvista.com>
Thank you! Patch queued via my hw-misc tree then.
Regards,
Phil.
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation
2025-02-23 11:47 ` [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation Bernhard Beschow
2025-03-04 18:53 ` Bernhard Beschow
@ 2025-03-11 12:18 ` Fabiano Rosas
1 sibling, 0 replies; 45+ messages in thread
From: Fabiano Rosas @ 2025-03-11 12:18 UTC (permalink / raw)
To: Bernhard Beschow, qemu-devel
Cc: Paolo Bonzini, Jean-Christophe Dubois, qemu-arm, Peter Maydell,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Bernhard Beschow, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
Bernhard Beschow <shentey@gmail.com> writes:
> The implementation just allows Linux to determine date and time.
>
> Signed-off-by: Bernhard Beschow <shentey@gmail.com>
For qtest:
Acked-by: Fabiano Rosas <farosas@suse.de>
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 00/18] Add i.MX 8M Plus EVK machine
2025-02-23 11:46 [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Bernhard Beschow
` (17 preceding siblings ...)
2025-02-23 11:47 ` [PATCH v2 18/18] hw/rtc: Add Ricoh RS5C372 RTC emulation Bernhard Beschow
@ 2025-02-25 14:43 ` Peter Maydell
2025-02-25 19:00 ` Bernhard Beschow
18 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2025-02-25 14:43 UTC (permalink / raw)
To: Bernhard Beschow
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
On Sun, 23 Feb 2025 at 11:47, Bernhard Beschow <shentey@gmail.com> wrote:
>
> This series adds a new aarch64 machine to QEMU: i.MX 8M Plus EVK [1]. It allows
> for running Linux distributions such as Buildroot
> (freescale_imx8mpevk_defconfig) and Arch Linux [2] via direct kernel boot.
> U-Boot does not work yet. I plan to use this machine in CI and I also want to
> make it available to a bigger audience, so I propose to add it to QEMU. My goal
> would be to have it added for 10.0. For this, a Changelog entry could be added
> under https://wiki.qemu.org/ChangeLog/10.0 such as:
> * New board model "imx8mp-evk": i.MX 8M Plus Evaluation Kit
>
> The series is structured as follows: The first three patches fix some issues in
> device models reused by the new machine. Patches 4-17 add the machine step by
> step which includes documentation. The last patch adds an I²C RTC which I'd like
> to use along with the new machine.
>
> I've based some code on existing one (see "Based on" in file headers) and I'm
> unsure how to handle the licensing and attribution correctly -- advice welcome.
Hi; I've applied most of this series to target-arm.next:
patches 1 to 15 and 17. I've left a comment about what
I think we should do about patch 16 (the bootrom).
Patch 18 (the RTC i2c device) I don't have any objection to,
I just didn't have time to review it now and didn't want to delay
getting the new board model in until I did find that time.
Since the board code doesn't instantiate the i2c device,
the RTC is kind of a separate thing from the board series
anyway.
thanks
-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 00/18] Add i.MX 8M Plus EVK machine
2025-02-25 14:43 ` [PATCH v2 00/18] Add i.MX 8M Plus EVK machine Peter Maydell
@ 2025-02-25 19:00 ` Bernhard Beschow
0 siblings, 0 replies; 45+ messages in thread
From: Bernhard Beschow @ 2025-02-25 19:00 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Paolo Bonzini, Jean-Christophe Dubois, qemu-arm,
Marc-André Lureau, Laurent Vivier, Andrey Smirnov,
Fabiano Rosas, Alistair Francis, Edgar E. Iglesias,
Philippe Mathieu-Daudé
Am 25. Februar 2025 14:43:32 UTC schrieb Peter Maydell <peter.maydell@linaro.org>:
>On Sun, 23 Feb 2025 at 11:47, Bernhard Beschow <shentey@gmail.com> wrote:
>>
>> This series adds a new aarch64 machine to QEMU: i.MX 8M Plus EVK [1]. It allows
>> for running Linux distributions such as Buildroot
>> (freescale_imx8mpevk_defconfig) and Arch Linux [2] via direct kernel boot.
>> U-Boot does not work yet. I plan to use this machine in CI and I also want to
>> make it available to a bigger audience, so I propose to add it to QEMU. My goal
>> would be to have it added for 10.0. For this, a Changelog entry could be added
>> under https://wiki.qemu.org/ChangeLog/10.0 such as:
>> * New board model "imx8mp-evk": i.MX 8M Plus Evaluation Kit
>>
>> The series is structured as follows: The first three patches fix some issues in
>> device models reused by the new machine. Patches 4-17 add the machine step by
>> step which includes documentation. The last patch adds an I²C RTC which I'd like
>> to use along with the new machine.
>>
>> I've based some code on existing one (see "Based on" in file headers) and I'm
>> unsure how to handle the licensing and attribution correctly -- advice welcome.
>
>Hi; I've applied most of this series to target-arm.next:
>patches 1 to 15 and 17.
Thanks a lot, Peter!
>I've left a comment about what
>I think we should do about patch 16 (the bootrom).
>Patch 18 (the RTC i2c device) I don't have any objection to,
>I just didn't have time to review it now and didn't want to delay
>getting the new board model in until I did find that time.
>Since the board code doesn't instantiate the i2c device,
>the RTC is kind of a separate thing from the board series
>anyway.
Yes, it's fairly separate. I'm looking forward to any comments.
Best regards,
Bernhard
>
>thanks
>-- PMM
^ permalink raw reply [flat|nested] 45+ messages in thread