Commit 7a4775d07f for qemu.org
commit 7a4775d07f08307ad392f6651ed088816a8eb900
Author: Bernhard Beschow <shentey@gmail.com>
Date: Thu Jul 2 20:40:38 2026 +0200
hw/arm: Add basic FlexCAN3 support to TYPE_FSL_IMX8MP and imx8mp-evk
Real hardware supports CAN FD which is missing in the emulation and is
considered future work. Still, CAN communication already works under Linux.
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Pavel Pisa <pisa@fel.cvut.cz>
Tested-by: Pavel Pisa <pisa@fel.cvut.cz>
Message-ID: <20260702184038.178196-6-shentey@gmail.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
diff --git a/docs/system/arm/imx8m.rst b/docs/system/arm/imx8m.rst
index afbc33b2f4..1bcb8255be 100644
--- a/docs/system/arm/imx8m.rst
+++ b/docs/system/arm/imx8m.rst
@@ -18,6 +18,7 @@ following devices:
* 1 Designware PCI Express Controller
* 1 Ethernet Controller
* 2 Designware USB 3 Controllers
+ * 2 FlexCAN 3 CAN Controllers (``imx8mp-evk`` only)
* 5 GPIO Controllers
* 6 I2C Controllers
* 3 SPI Controllers
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index f9a225c19b..82e0bc2e70 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -601,6 +601,7 @@ config FSL_IMX8MP
imply I2C_DEVICES
imply PCI_DEVICES
select ARM_GIC
+ select CAN_FLEXCAN
select FSL_IMX8MP_ANALOG
select FSL_IMX8MP_CCM
select IMX
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
index 7c03ed3c34..bcd91739d9 100644
--- a/hw/arm/fsl-imx8mp.c
+++ b/hw/arm/fsl-imx8mp.c
@@ -246,6 +246,11 @@ static void fsl_imx8mp_init(Object *obj)
object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
}
+ for (i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
+ g_autofree char *name = g_strdup_printf("flexcan%d", i);
+ object_initialize_child(obj, name, &s->flexcan[i], TYPE_CAN_FLEXCAN3);
+ }
+
object_initialize_child(obj, "eth0", &s->enet, TYPE_IMX_ENET);
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
@@ -669,6 +674,34 @@ 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);
+ /* FlexCANs */
+ for (i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
+ static const struct {
+ hwaddr addr;
+ unsigned int irq;
+ } flexcan_table[FSL_IMX8MP_NUM_CANS] = {
+ {
+ fsl_imx8mp_memmap[FSL_IMX8MP_FLEXCAN1].addr,
+ FSL_IMX8MP_FLEXCAN1_IRQ
+ }, {
+ fsl_imx8mp_memmap[FSL_IMX8MP_FLEXCAN2].addr,
+ FSL_IMX8MP_FLEXCAN2_IRQ
+ },
+ };
+
+ object_property_set_link(OBJECT(&s->flexcan[i]), "clock-control-module",
+ OBJECT(&s->ccm), &error_abort);
+ object_property_set_link(OBJECT(&s->flexcan[i]), "canbus",
+ OBJECT(s->canbus[i]), &error_abort);
+
+ sysbus_realize(SYS_BUS_DEVICE(&s->flexcan[i]), &error_abort);
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->flexcan[i]), 0,
+ flexcan_table[i].addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->flexcan[i]), 0,
+ qdev_get_gpio_in(gicdev, flexcan_table[i].irq));
+ }
+
/* On-Chip RAM */
if (!memory_region_init_ram(&s->ocram, OBJECT(dev), "imx8mp.ocram",
fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].size,
@@ -684,6 +717,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
switch (i) {
case FSL_IMX8MP_ANA_PLL:
case FSL_IMX8MP_CCM:
+ case FSL_IMX8MP_FLEXCAN1 ... FSL_IMX8MP_FLEXCAN2:
case FSL_IMX8MP_GIC_DIST:
case FSL_IMX8MP_GIC_REDIST:
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
@@ -715,6 +749,10 @@ 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),
+ DEFINE_PROP_LINK("canbus0", FslImx8mpState, canbus[0], TYPE_CAN_BUS,
+ CanBusState *),
+ DEFINE_PROP_LINK("canbus1", FslImx8mpState, canbus[1], TYPE_CAN_BUS,
+ CanBusState *),
};
static void fsl_imx8mp_class_init(ObjectClass *oc, const void *data)
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
index ca0ee2d3f2..16e9722d14 100644
--- a/hw/arm/imx8mp-evk.c
+++ b/hw/arm/imx8mp-evk.c
@@ -26,6 +26,7 @@ struct FslImx8mpEvkState {
MachineState parent_obj;
FslImx8mpState soc;
+ CanBusState *canbus[FSL_IMX8MP_NUM_CANS];
struct arm_boot_info boot_info;
};
@@ -86,6 +87,12 @@ static void imx8mp_evk_init(MachineState *machine)
object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX8MP);
object_property_set_uint(OBJECT(&s->soc), "fec1-phy-num", 1, &error_fatal);
+ for (int i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
+ g_autofree char *bus_name = g_strdup_printf("canbus%d", i);
+
+ object_property_set_link(OBJECT(&s->soc), bus_name,
+ OBJECT(s->canbus[i]), &error_fatal);
+ }
sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->soc), &error_fatal);
memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
@@ -122,6 +129,19 @@ static const char *imx8mp_evk_get_default_cpu_type(const MachineState *ms)
return ARM_CPU_TYPE_NAME("cortex-a53");
}
+static void imx8mp_evk_machine_init(Object *obj)
+{
+ FslImx8mpEvkState *s = IMX8MPEVK_MACHINE(obj);
+
+ object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
+ (Object **)&s->canbus[0],
+ object_property_allow_set_link, 0);
+
+ object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
+ (Object **)&s->canbus[1],
+ object_property_allow_set_link, 0);
+}
+
static void imx8mp_evk_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -140,6 +160,7 @@ static const TypeInfo imx8mp_evk_machine_types[] = {
.name = TYPE_IMX8MPEVK_MACHINE,
.parent = TYPE_MACHINE,
.class_init = imx8mp_evk_machine_class_init,
+ .instance_init = imx8mp_evk_machine_init,
.instance_size = sizeof(FslImx8mpEvkState),
.interfaces = aarch64_machine_interfaces,
},
diff --git a/hw/misc/imx8mp_ccm.c b/hw/misc/imx8mp_ccm.c
index 911911ed86..97d363e79d 100644
--- a/hw/misc/imx8mp_ccm.c
+++ b/hw/misc/imx8mp_ccm.c
@@ -129,6 +129,9 @@ static uint32_t imx8mp_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
case CLK_HIGH:
freq = CKIH_FREQ;
break;
+ case CLK_CAN:
+ freq = 40000000; /* 40Mhz, taken from device tree */
+ break;
case CLK_IPG:
case CLK_IPG_HIGH:
/*
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
index 3b6183ed1d..2be3c51af5 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/flexcan.h"
#include "hw/net/imx_fec.h"
#include "hw/core/or-irq.h"
#include "hw/pci-host/designware.h"
@@ -37,6 +38,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
#define FSL_IMX8MP_RAM_SIZE_MAX (8 * GiB)
enum FslImx8mpConfiguration {
+ FSL_IMX8MP_NUM_CANS = 2,
FSL_IMX8MP_NUM_CPUS = 4,
FSL_IMX8MP_NUM_ECSPIS = 3,
FSL_IMX8MP_NUM_GPIOS = 5,
@@ -68,11 +70,14 @@ struct FslImx8mpState {
USBDWC3 usb[FSL_IMX8MP_NUM_USBS];
DesignwarePCIEHost pcie;
FslImx8mPciePhyState pcie_phy;
+ FlexcanState flexcan[FSL_IMX8MP_NUM_CANS];
OrIRQState gpt5_gpt6_irq;
MemoryRegion ocram;
uint32_t phy_num;
bool phy_connected;
+
+ CanBusState *canbus[FSL_IMX8MP_NUM_CANS];
};
enum FslImx8mpMemoryRegions {
@@ -279,6 +284,9 @@ enum FslImx8mpIrqs {
FSL_IMX8MP_PCI_INTC_IRQ = 124,
FSL_IMX8MP_PCI_INTD_IRQ = 123,
FSL_IMX8MP_PCI_MSI_IRQ = 140,
+
+ FSL_IMX8MP_FLEXCAN1_IRQ = 142,
+ FSL_IMX8MP_FLEXCAN2_IRQ = 144,
};
#endif /* FSL_IMX8MP_H */