@samitouri / QOSamiQemu / commits / 7a4775d07f

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>

Bernhard Beschow committed Jul 2, 2026 at 20:40 UTC 7a4775d07f08307ad392f6651ed088816a8eb900
6 files changed +72
docs/system/arm/imx8m.rst
+1
@@ -18,6 +18,7 @@ following devices:
18 * 1 Designware PCI Express Controller
19 * 1 Ethernet Controller
20 * 2 Designware USB 3 Controllers
21 + * 2 FlexCAN 3 CAN Controllers (``imx8mp-evk`` only)
22 * 5 GPIO Controllers
23 * 6 I2C Controllers
24 * 3 SPI Controllers
hw/arm/Kconfig
+1
@@ -601,6 +601,7 @@ config FSL_IMX8MP
601 imply I2C_DEVICES
602 imply PCI_DEVICES
603 select ARM_GIC
604 + select CAN_FLEXCAN
605 select FSL_IMX8MP_ANALOG
606 select FSL_IMX8MP_CCM
607 select IMX
hw/arm/fsl-imx8mp.c
+38
@@ -246,6 +246,11 @@ static void fsl_imx8mp_init(Object *obj)
246 object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
247 }
248
249 + for (i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
250 + g_autofree char *name = g_strdup_printf("flexcan%d", i);
251 + object_initialize_child(obj, name, &s->flexcan[i], TYPE_CAN_FLEXCAN3);
252 + }
253 +
254 object_initialize_child(obj, "eth0", &s->enet, TYPE_IMX_ENET);
255
256 object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
@@ -669,6 +674,34 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
674 sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0,
675 fsl_imx8mp_memmap[FSL_IMX8MP_PCIE_PHY1].addr);
676
677 + /* FlexCANs */
678 + for (i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
679 + static const struct {
680 + hwaddr addr;
681 + unsigned int irq;
682 + } flexcan_table[FSL_IMX8MP_NUM_CANS] = {
683 + {
684 + fsl_imx8mp_memmap[FSL_IMX8MP_FLEXCAN1].addr,
685 + FSL_IMX8MP_FLEXCAN1_IRQ
686 + }, {
687 + fsl_imx8mp_memmap[FSL_IMX8MP_FLEXCAN2].addr,
688 + FSL_IMX8MP_FLEXCAN2_IRQ
689 + },
690 + };
691 +
692 + object_property_set_link(OBJECT(&s->flexcan[i]), "clock-control-module",
693 + OBJECT(&s->ccm), &error_abort);
694 + object_property_set_link(OBJECT(&s->flexcan[i]), "canbus",
695 + OBJECT(s->canbus[i]), &error_abort);
696 +
697 + sysbus_realize(SYS_BUS_DEVICE(&s->flexcan[i]), &error_abort);
698 +
699 + sysbus_mmio_map(SYS_BUS_DEVICE(&s->flexcan[i]), 0,
700 + flexcan_table[i].addr);
701 + sysbus_connect_irq(SYS_BUS_DEVICE(&s->flexcan[i]), 0,
702 + qdev_get_gpio_in(gicdev, flexcan_table[i].irq));
703 + }
704 +
705 /* On-Chip RAM */
706 if (!memory_region_init_ram(&s->ocram, OBJECT(dev), "imx8mp.ocram",
707 fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].size,
@@ -684,6 +717,7 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
717 switch (i) {
718 case FSL_IMX8MP_ANA_PLL:
719 case FSL_IMX8MP_CCM:
720 + case FSL_IMX8MP_FLEXCAN1 ... FSL_IMX8MP_FLEXCAN2:
721 case FSL_IMX8MP_GIC_DIST:
722 case FSL_IMX8MP_GIC_REDIST:
723 case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
@@ -715,6 +749,10 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
749 static const Property fsl_imx8mp_properties[] = {
750 DEFINE_PROP_UINT32("fec1-phy-num", FslImx8mpState, phy_num, 0),
751 DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mpState, phy_connected, true),
752 + DEFINE_PROP_LINK("canbus0", FslImx8mpState, canbus[0], TYPE_CAN_BUS,
753 + CanBusState *),
754 + DEFINE_PROP_LINK("canbus1", FslImx8mpState, canbus[1], TYPE_CAN_BUS,
755 + CanBusState *),
756 };
757
758 static void fsl_imx8mp_class_init(ObjectClass *oc, const void *data)
hw/arm/imx8mp-evk.c
+21
@@ -26,6 +26,7 @@ struct FslImx8mpEvkState {
26 MachineState parent_obj;
27
28 FslImx8mpState soc;
29 + CanBusState *canbus[FSL_IMX8MP_NUM_CANS];
30
31 struct arm_boot_info boot_info;
32 };
@@ -86,6 +87,12 @@ static void imx8mp_evk_init(MachineState *machine)
87
88 object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX8MP);
89 object_property_set_uint(OBJECT(&s->soc), "fec1-phy-num", 1, &error_fatal);
90 + for (int i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
91 + g_autofree char *bus_name = g_strdup_printf("canbus%d", i);
92 +
93 + object_property_set_link(OBJECT(&s->soc), bus_name,
94 + OBJECT(s->canbus[i]), &error_fatal);
95 + }
96 sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->soc), &error_fatal);
97
98 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)
129 return ARM_CPU_TYPE_NAME("cortex-a53");
130 }
131
132 +static void imx8mp_evk_machine_init(Object *obj)
133 +{
134 + FslImx8mpEvkState *s = IMX8MPEVK_MACHINE(obj);
135 +
136 + object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
137 + (Object **)&s->canbus[0],
138 + object_property_allow_set_link, 0);
139 +
140 + object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
141 + (Object **)&s->canbus[1],
142 + object_property_allow_set_link, 0);
143 +}
144 +
145 static void imx8mp_evk_machine_class_init(ObjectClass *oc, const void *data)
146 {
147 MachineClass *mc = MACHINE_CLASS(oc);
@@ -140,6 +160,7 @@ static const TypeInfo imx8mp_evk_machine_types[] = {
160 .name = TYPE_IMX8MPEVK_MACHINE,
161 .parent = TYPE_MACHINE,
162 .class_init = imx8mp_evk_machine_class_init,
163 + .instance_init = imx8mp_evk_machine_init,
164 .instance_size = sizeof(FslImx8mpEvkState),
165 .interfaces = aarch64_machine_interfaces,
166 },
hw/misc/imx8mp_ccm.c
+3
@@ -129,6 +129,9 @@ static uint32_t imx8mp_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
129 case CLK_HIGH:
130 freq = CKIH_FREQ;
131 break;
132 + case CLK_CAN:
133 + freq = 40000000; /* 40Mhz, taken from device tree */
134 + break;
135 case CLK_IPG:
136 case CLK_IPG_HIGH:
137 /*
include/hw/arm/fsl-imx8mp.h
+8
@@ -17,6 +17,7 @@
17 #include "hw/misc/imx7_snvs.h"
18 #include "hw/misc/imx8mp_analog.h"
19 #include "hw/misc/imx8mp_ccm.h"
20 +#include "hw/net/flexcan.h"
21 #include "hw/net/imx_fec.h"
22 #include "hw/core/or-irq.h"
23 #include "hw/pci-host/designware.h"
@@ -37,6 +38,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
38 #define FSL_IMX8MP_RAM_SIZE_MAX (8 * GiB)
39
40 enum FslImx8mpConfiguration {
41 + FSL_IMX8MP_NUM_CANS = 2,
42 FSL_IMX8MP_NUM_CPUS = 4,
43 FSL_IMX8MP_NUM_ECSPIS = 3,
44 FSL_IMX8MP_NUM_GPIOS = 5,
@@ -68,11 +70,14 @@ struct FslImx8mpState {
70 USBDWC3 usb[FSL_IMX8MP_NUM_USBS];
71 DesignwarePCIEHost pcie;
72 FslImx8mPciePhyState pcie_phy;
73 + FlexcanState flexcan[FSL_IMX8MP_NUM_CANS];
74 OrIRQState gpt5_gpt6_irq;
75 MemoryRegion ocram;
76
77 uint32_t phy_num;
78 bool phy_connected;
79 +
80 + CanBusState *canbus[FSL_IMX8MP_NUM_CANS];
81 };
82
83 enum FslImx8mpMemoryRegions {
@@ -279,6 +284,9 @@ enum FslImx8mpIrqs {
284 FSL_IMX8MP_PCI_INTC_IRQ = 124,
285 FSL_IMX8MP_PCI_INTD_IRQ = 123,
286 FSL_IMX8MP_PCI_MSI_IRQ = 140,
287 +
288 + FSL_IMX8MP_FLEXCAN1_IRQ = 142,
289 + FSL_IMX8MP_FLEXCAN2_IRQ = 144,
290 };
291
292 #endif /* FSL_IMX8MP_H */