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 */