@samitouri / QOSamiQemu / commits / 9446f60d99

hw/arm/fsl-imx8mm: Adding support for General Purpose Timers

It enables emulation of GPT in iMX8MM Added GPT IRQ lines Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Signed-off-by: Gaurav Sharma <gaurav.sharma_7@nxp.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Gaurav Sharma committed Apr 21, 2026 at 12:22 UTC 9446f60d99bef25b23a9621cf01065b896ee6a17
5 files changed +94
hw/arm/Kconfig
+1
@@ -626,6 +626,7 @@ config FSL_IMX8MM
626 select FSL_IMX8MP_CCM
627 select IMX
628 select IMX_I2C
629 + select OR_IRQ
630 select SDHCI
631 select PCI_EXPRESS_DESIGNWARE
632 select PCI_EXPRESS_FSL_IMX8M_PHY
hw/arm/fsl-imx8mm.c
+54
@@ -180,6 +180,13 @@ static void fsl_imx8mm_init(Object *obj)
180 object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
181 }
182
183 + for (i = 0; i < FSL_IMX8MM_NUM_GPTS; i++) {
184 + g_autofree char *name = g_strdup_printf("gpt%d", i + 1);
185 + object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX8MM_GPT);
186 + }
187 + object_initialize_child(obj, "gpt5-gpt6-irq", &s->gpt5_gpt6_irq,
188 + TYPE_OR_IRQ);
189 +
190 for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) {
191 g_autofree char *name = g_strdup_printf("i2c%d", i + 1);
192 object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C);
@@ -385,6 +392,52 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
392 fsl_imx8mm_memmap[FSL_IMX8MM_OCRAM].addr,
393 &s->ocram);
394
395 + /* GPTs */
396 + object_property_set_int(OBJECT(&s->gpt5_gpt6_irq), "num-lines", 2,
397 + &error_abort);
398 + if (!qdev_realize(DEVICE(&s->gpt5_gpt6_irq), NULL, errp)) {
399 + return;
400 + }
401 +
402 + qdev_connect_gpio_out(DEVICE(&s->gpt5_gpt6_irq), 0,
403 + qdev_get_gpio_in(gicdev, FSL_IMX8MM_GPT5_GPT6_IRQ));
404 +
405 + for (i = 0; i < FSL_IMX8MM_NUM_GPTS; i++) {
406 + hwaddr gpt_addrs[FSL_IMX8MM_NUM_GPTS] = {
407 + fsl_imx8mm_memmap[FSL_IMX8MM_GPT1].addr,
408 + fsl_imx8mm_memmap[FSL_IMX8MM_GPT2].addr,
409 + fsl_imx8mm_memmap[FSL_IMX8MM_GPT3].addr,
410 + fsl_imx8mm_memmap[FSL_IMX8MM_GPT4].addr,
411 + fsl_imx8mm_memmap[FSL_IMX8MM_GPT5].addr,
412 + fsl_imx8mm_memmap[FSL_IMX8MM_GPT6].addr,
413 + };
414 +
415 + s->gpt[i].ccm = IMX_CCM(&s->ccm);
416 +
417 + if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), errp)) {
418 + return;
419 + }
420 +
421 + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_addrs[i]);
422 +
423 + if (i < FSL_IMX8MM_NUM_GPTS - 2) {
424 + static const unsigned int gpt_irqs[FSL_IMX8MM_NUM_GPTS - 2] = {
425 + FSL_IMX8MM_GPT1_IRQ,
426 + FSL_IMX8MM_GPT2_IRQ,
427 + FSL_IMX8MM_GPT3_IRQ,
428 + FSL_IMX8MM_GPT4_IRQ,
429 + };
430 +
431 + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
432 + qdev_get_gpio_in(gicdev, gpt_irqs[i]));
433 + } else {
434 + int irq = i - FSL_IMX8MM_NUM_GPTS + 2;
435 +
436 + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
437 + qdev_get_gpio_in(DEVICE(&s->gpt5_gpt6_irq), irq));
438 + }
439 + }
440 +
441 /* I2Cs */
442 for (i = 0; i < FSL_IMX8MM_NUM_I2CS; i++) {
443 static const struct {
@@ -555,6 +608,7 @@ static void fsl_imx8mm_realize(DeviceState *dev, Error **errp)
608 case FSL_IMX8MM_GIC_DIST:
609 case FSL_IMX8MM_GIC_REDIST:
610 case FSL_IMX8MM_GPIO1 ... FSL_IMX8MM_GPIO5:
611 + case FSL_IMX8MM_GPT1 ... FSL_IMX8MM_GPT6:
612 case FSL_IMX8MM_ECSPI1 ... FSL_IMX8MM_ECSPI3:
613 case FSL_IMX8MM_I2C1 ... FSL_IMX8MM_I2C4:
614 case FSL_IMX8MM_PCIE1:
hw/timer/imx_gpt.c
+26
@@ -6,6 +6,7 @@
6 * Originally written by Hans Jiang
7 * Updated by Peter Chubb
8 * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
9 + * Updated by Gaurav Sharma <gaurav.sharma_7@nxp.com>
10 *
11 * This code is licensed under GPL version 2 or later. See
12 * the COPYING file in the top-level directory.
@@ -137,6 +138,17 @@ static const IMXClk imx8mp_gpt_clocks[] = {
138 CLK_NONE, /* 111 not defined */
139 };
140
141 +static const IMXClk imx8mm_gpt_clocks[] = {
142 + CLK_NONE, /* 000 No clock source */
143 + CLK_IPG, /* 001 ipg_clk, 532MHz */
144 + CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */
145 + CLK_EXT, /* 011 External clock */
146 + CLK_32k, /* 100 ipg_clk_32k */
147 + CLK_HIGH, /* 101 ipg_clk_16M */
148 + CLK_NONE, /* 110 not defined */
149 + CLK_NONE, /* 111 not defined */
150 +};
151 +
152 /* Must be called from within ptimer_transaction_begin/commit block */
153 static void imx_gpt_set_freq(IMXGPTState *s)
154 {
@@ -570,6 +582,13 @@ static void imx8mp_gpt_init(Object *obj)
582 s->clocks = imx8mp_gpt_clocks;
583 }
584
585 +static void imx8mm_gpt_init(Object *obj)
586 +{
587 + IMXGPTState *s = IMX_GPT(obj);
588 +
589 + s->clocks = imx8mm_gpt_clocks;
590 +}
591 +
592 static const TypeInfo imx25_gpt_info = {
593 .name = TYPE_IMX25_GPT,
594 .parent = TYPE_SYS_BUS_DEVICE,
@@ -608,6 +627,12 @@ static const TypeInfo imx8mp_gpt_info = {
627 .instance_init = imx8mp_gpt_init,
628 };
629
630 +static const TypeInfo imx8mm_gpt_info = {
631 + .name = TYPE_IMX8MM_GPT,
632 + .parent = TYPE_IMX25_GPT,
633 + .instance_init = imx8mm_gpt_init,
634 +};
635 +
636 static void imx_gpt_register_types(void)
637 {
638 type_register_static(&imx25_gpt_info);
@@ -616,6 +641,7 @@ static void imx_gpt_register_types(void)
641 type_register_static(&imx6ul_gpt_info);
642 type_register_static(&imx7_gpt_info);
643 type_register_static(&imx8mp_gpt_info);
644 + type_register_static(&imx8mm_gpt_info);
645 }
646
647 type_init(imx_gpt_register_types)
include/hw/arm/fsl-imx8mm.h
+11
@@ -18,10 +18,12 @@
18 #include "hw/misc/imx7_snvs.h"
19 #include "hw/misc/imx8mp_analog.h"
20 #include "hw/misc/imx8mp_ccm.h"
21 +#include "hw/or-irq.h"
22 #include "hw/pci-host/designware.h"
23 #include "hw/pci-host/fsl_imx8m_phy.h"
24 #include "hw/sd/sdhci.h"
25 #include "hw/ssi/imx_spi.h"
26 +#include "hw/timer/imx_gpt.h"
27 #include "hw/watchdog/wdt_imx2.h"
28 #include "qom/object.h"
29 #include "qemu/units.h"
@@ -36,6 +38,7 @@ enum FslImx8mmConfiguration {
38 FSL_IMX8MM_NUM_CPUS = 4,
39 FSL_IMX8MM_NUM_ECSPIS = 3,
40 FSL_IMX8MM_NUM_GPIOS = 5,
41 + FSL_IMX8MM_NUM_GPTS = 6,
42 FSL_IMX8MM_NUM_I2CS = 4,
43 FSL_IMX8MM_NUM_IRQS = 128,
44 FSL_IMX8MM_NUM_UARTS = 4,
@@ -48,6 +51,7 @@ struct FslImx8mmState {
51
52 ARMCPU cpu[FSL_IMX8MM_NUM_CPUS];
53 GICv3State gic;
54 + IMXGPTState gpt[FSL_IMX8MM_NUM_GPTS];
55 IMXGPIOState gpio[FSL_IMX8MM_NUM_GPIOS];
56 IMX8MPCCMState ccm;
57 IMX8MPAnalogState analog;
@@ -60,6 +64,7 @@ struct FslImx8mmState {
64 IMX2WdtState wdt[FSL_IMX8MM_NUM_WDTS];
65 DesignwarePCIEHost pcie;
66 FslImx8mPciePhyState pcie_phy;
67 + OrIRQState gpt5_gpt6_irq;
68 };
69
70 enum FslImx8mmMemoryRegions {
@@ -192,6 +197,12 @@ enum FslImx8mmIrqs {
197 FSL_IMX8MM_I2C3_IRQ = 37,
198 FSL_IMX8MM_I2C4_IRQ = 38,
199
200 + FSL_IMX8MM_GPT1_IRQ = 55,
201 + FSL_IMX8MM_GPT2_IRQ = 54,
202 + FSL_IMX8MM_GPT3_IRQ = 53,
203 + FSL_IMX8MM_GPT4_IRQ = 52,
204 + FSL_IMX8MM_GPT5_GPT6_IRQ = 51,
205 +
206 FSL_IMX8MM_GPIO1_LOW_IRQ = 64,
207 FSL_IMX8MM_GPIO1_HIGH_IRQ = 65,
208 FSL_IMX8MM_GPIO2_LOW_IRQ = 66,
include/hw/timer/imx_gpt.h
+2
@@ -6,6 +6,7 @@
6 * Originally written by Hans Jiang
7 * Updated by Peter Chubb
8 * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
9 + * Updated by Gaurav Sharma <gaurav.sharma_7@nxp.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
@@ -81,6 +82,7 @@
82 #define TYPE_IMX6UL_GPT "imx6ul.gpt"
83 #define TYPE_IMX7_GPT "imx7.gpt"
84 #define TYPE_IMX8MP_GPT "imx8mp.gpt"
85 +#define TYPE_IMX8MM_GPT "imx8mm.gpt"
86
87 #define TYPE_IMX_GPT TYPE_IMX25_GPT
88