Hi Matyáš, Pavel,

Some small remarks regarding the use of hard-coded constants such as FSL_IMX6_NUM_WDTS in loops, IMHO, it would be better to use |ARRAY_SIZE()|instead:

-    for (i = 0; i < FSL_IMX6_NUM_CANS; i++) {
+    for (i = 0; i < ARRAY_SIZE(s->can); i++) {

BTW, it would be also more logical to combine |CanBusState|and |FlexcanState|into a single structure (possibly anonymous), for example:struct FslIMX6State { ...

 struct {
    CanBusState       *state;
    FlexcanState       flexcan;
 } can[FSL_IMX6_NUM_CANS];

...
};

As a matter of personal preference, I would also rename "|can"|to "|flexcan"/"fcan"|, since these objects represent FlexCAN controllers rather than CAN2.0 ones.

Regards,
Andrey VOLKOV

Le 28/05/2026 à 19:17, Matyáš Bobek a écrit :
FlexcanState is added to the FslIMX6State struct like other peripherals.

Add two new machine properties to Sabrelite machine for linking
the embedded FlexCAN instances to QEMU CAN buses by name.
No other machine uses FslIMX6State.

Signed-off-by: Matyáš Bobek <[email protected]>
Signed-off-by: Pavel Pisa <[email protected]>
Tested-by: Pavel Pisa <[email protected]>
Reviewed-by: Bernhard Beschow <[email protected]>
Reviewed-by: Pavel Pisa <[email protected]>
---
  hw/arm/Kconfig            |  1 +
  hw/arm/fsl-imx6.c         | 29 +++++++++++++++++++++++++++++
  hw/arm/sabrelite.c        | 24 ++++++++++++++++++++++++
  include/hw/arm/fsl-imx6.h |  6 ++++++
  4 files changed, 60 insertions(+)

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 5b198402d5..c44fc562e1 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -519,6 +519,7 @@ config FSL_IMX6
      select IMX_FEC
      select IMX_I2C
      select IMX_USBPHY
+    select CAN_FLEXCAN
      select WDT_IMX2
      select PL310  # cache controller
      select PCI_EXPRESS_DESIGNWARE
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index f663ddbf0a..337921d17d 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -90,6 +90,10 @@ static void fsl_imx6_init(Object *obj)
          snprintf(name, NAME_SIZE, "spi%d", i + 1);
          object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
      }
+    for (i = 0; i < FSL_IMX6_NUM_CANS; i++) {
+        snprintf(name, NAME_SIZE, "flexcan%d", i + 1);
+        object_initialize_child(obj, name, &s->can[i], TYPE_CAN_FLEXCAN);
+    }
      for (i = 0; i < FSL_IMX6_NUM_WDTS; i++) {
          snprintf(name, NAME_SIZE, "wdt%d", i);
          object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
@@ -377,6 +381,27 @@ static void fsl_imx6_realize(DeviceState *dev, Error 
**errp)
                             qdev_get_gpio_in(gic, spi_table[i].irq));
      }
+ /* Initialize all FLEXCANs */
+    for (i = 0; i < FSL_IMX6_NUM_CANS; i++) {
+        static const struct {
+            hwaddr addr;
+            unsigned int irq;
+        } flexcan_table[FSL_IMX6_NUM_CANS] = {
+            { FSL_IMX6_CAN1_ADDR, FSL_IMX6_FLEXCAN1_IRQ },
+            { FSL_IMX6_CAN2_ADDR, FSL_IMX6_FLEXCAN2_IRQ },
+        };
+
+        s->can[i].ccm = IMX_CCM(&s->ccm);
+        object_property_set_link(OBJECT(&s->can[i]), "canbus",
+                                 OBJECT(s->canbus[i]), &error_abort);
+
+        sysbus_realize(SYS_BUS_DEVICE(&s->can[i]), &error_abort);
+
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->can[i]), 0, flexcan_table[i].addr);
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->can[i]), 0,
+                           qdev_get_gpio_in(gic, flexcan_table[i].irq));
+    }
+
      object_property_set_uint(OBJECT(&s->eth), "phy-num", s->phy_num,
                               &error_abort);
      qemu_configure_nic_device(DEVICE(&s->eth), true, NULL);
@@ -480,6 +505,10 @@ static void fsl_imx6_realize(DeviceState *dev, Error 
**errp)
static const Property fsl_imx6_properties[] = {
      DEFINE_PROP_UINT32("fec-phy-num", FslIMX6State, phy_num, 0),
+    DEFINE_PROP_LINK("canbus0", FslIMX6State, canbus[0], TYPE_CAN_BUS,
+                     CanBusState *),
+    DEFINE_PROP_LINK("canbus1", FslIMX6State, canbus[1], TYPE_CAN_BUS,
+                     CanBusState *),
  };
static void fsl_imx6_class_init(ObjectClass *oc, const void *data)
diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
index 7e036e6388..84bbc2f979 100644
--- a/hw/arm/sabrelite.c
+++ b/hw/arm/sabrelite.c
@@ -24,6 +24,7 @@ struct SabreliteMachineState {
      MachineState parent_obj;
FslIMX6State soc;
+    CanBusState *canbus[FSL_IMX6_NUM_CANS];
  };
#define TYPE_SABRELITE_MACHINE MACHINE_TYPE_NAME("sabrelite")
@@ -64,6 +65,13 @@ static void sabrelite_init(MachineState *machine)
      /* Ethernet PHY address is 6 */
      object_property_set_int(OBJECT(&s->soc), "fec-phy-num", 6, &error_fatal);
+ for (int i = 0; i < FSL_IMX6_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);
+    }
+
      qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR,
@@ -112,6 +120,21 @@ static void sabrelite_init(MachineState *machine)
      }
  }
+static void sabrelite_machine_instance_init(Object *obj)
+{
+    SabreliteMachineState *s = SABRELITE_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 sabrelite_machine_class_init(ObjectClass *oc, const void *data)
  {
      MachineClass *mc = MACHINE_CLASS(oc);
@@ -128,6 +151,7 @@ static const TypeInfo sabrelite_machine_init_typeinfo = {
      .name          = TYPE_SABRELITE_MACHINE,
      .parent        = TYPE_MACHINE,
      .class_init    = sabrelite_machine_class_init,
+    .instance_init = sabrelite_machine_instance_init,
      .instance_size = sizeof(SabreliteMachineState),
      .abstract      = false,
      .interfaces    = arm_machine_interfaces,
diff --git a/include/hw/arm/fsl-imx6.h b/include/hw/arm/fsl-imx6.h
index cddd100dd6..8ea1677e86 100644
--- a/include/hw/arm/fsl-imx6.h
+++ b/include/hw/arm/fsl-imx6.h
@@ -30,12 +30,14 @@
  #include "hw/sd/sdhci.h"
  #include "hw/ssi/imx_spi.h"
  #include "hw/net/imx_fec.h"
+#include "hw/net/flexcan.h"
  #include "hw/usb/chipidea.h"
  #include "hw/usb/imx-usb-phy.h"
  #include "hw/pci-host/designware.h"
  #include "hw/core/or-irq.h"
  #include "system/memory.h"
  #include "target/arm/cpu.h"
+#include "net/can_emu.h"
  #include "qom/object.h"
#define TYPE_FSL_IMX6 "fsl-imx6"
@@ -51,6 +53,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(FslIMX6State, FSL_IMX6)
  #define FSL_IMX6_NUM_WDTS 2
  #define FSL_IMX6_NUM_USB_PHYS 2
  #define FSL_IMX6_NUM_USBS 4
+#define FSL_IMX6_NUM_CANS 2
struct FslIMX6State {
      /*< private >*/
@@ -73,6 +76,7 @@ struct FslIMX6State {
      IMXUSBPHYState     usbphy[FSL_IMX6_NUM_USB_PHYS];
      ChipideaState      usb[FSL_IMX6_NUM_USBS];
      IMXFECState        eth;
+    FlexcanState       can[FSL_IMX6_NUM_CANS];
      DesignwarePCIEHost pcie;
      OrIRQState         pcie4_msi_irq;
      MemoryRegion       rom;
@@ -80,6 +84,8 @@ struct FslIMX6State {
      MemoryRegion       ocram;
      MemoryRegion       ocram_alias;
      uint32_t           phy_num;
+
+    CanBusState       *canbus[FSL_IMX6_NUM_CANS];
  };

Reply via email to