[PATCH 00/16] Fix i.MXRT1020/50

This patchset adds imx-gpt-timer driver that is supported by i.MXRT and also a lot of other i.MX* SoCs. This driver is needed for i.MXRT SoC family that is lacking at the moment the timer at all and that makes u-boot to fail running on i.MXRT. There are also some fixes in imxrt10*0-evk.dts and other minor fixed and improvements.
Giulio Benetti (16): arm: imxrt: soc: make mpu regions generic timer: imx-gpt: Add timer support for i.MX SoCs family ARM: dts: imxrt1020: add alias to osc ARM: dts: imxrt1020: add gpt1 node ARM: dts: imxrt1020-evk: enable gpt1 timer ARM: dts: imxrt1020-evk: set gpt1 as tick-timer for u-boot ARM: dts: imxrt1020-evk-u-boot: make gpt1 present for SPL ARM: dts: imxrt1020-evk: add device_type = "memory" to memory node configs: imxrt1020-evk: enable imx gpt timer as tick-timer ARM: dts: imxrt1050: add alias to osc ARM: dts: imxrt1050: add gpt1 node ARM: dts: imxrt1050-evk: enable gpt1 timer ARM: dts: imxrt1050-evk: set gpt1 as tick-timer for u-boot ARM: dts: imxrt1050-evk-u-boot: make gpt1 present for SPL ARM: dts: imxrt1050-evk: add device_type = "memory" to memory node configs: imxrt1050-evk: enable imx gpt timer as tick-timer
arch/arm/dts/imxrt1020-evk-u-boot.dtsi | 4 + arch/arm/dts/imxrt1020-evk.dts | 6 + arch/arm/dts/imxrt1020.dtsi | 10 +- arch/arm/dts/imxrt1050-evk-u-boot.dtsi | 4 + arch/arm/dts/imxrt1050-evk.dts | 6 + arch/arm/dts/imxrt1050.dtsi | 10 +- arch/arm/mach-imx/imxrt/soc.c | 6 +- configs/imxrt1020-evk_defconfig | 1 + configs/imxrt1050-evk_defconfig | 1 + drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/imx-gpt-timer.c | 162 +++++++++++++++++++++++++ 12 files changed, 213 insertions(+), 5 deletions(-) create mode 100644 drivers/timer/imx-gpt-timer.c

This mpu handling works for every i.MXRT SoC that we have, so let's generalize imxrt1050_region_config to imxrt_region_config.
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/mach-imx/imxrt/soc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-imx/imxrt/soc.c b/arch/arm/mach-imx/imxrt/soc.c index 8e7d15160d..c533f3554a 100644 --- a/arch/arm/mach-imx/imxrt/soc.c +++ b/arch/arm/mach-imx/imxrt/soc.c @@ -14,7 +14,7 @@ int arch_cpu_init(void) { int i;
- struct mpu_region_config imxrt1050_region_config[] = { + struct mpu_region_config imxrt_region_config[] = { { 0x00000000, REGION_0, XN_DIS, PRIV_RW_USR_RW, STRONG_ORDER, REGION_4GB }, { PHYS_SDRAM, REGION_1, XN_DIS, PRIV_RW_USR_RW, @@ -29,8 +29,8 @@ int arch_cpu_init(void) * the whole 4GB address space. */ disable_mpu(); - for (i = 0; i < ARRAY_SIZE(imxrt1050_region_config); i++) - mpu_config(&imxrt1050_region_config[i]); + for (i = 0; i < ARRAY_SIZE(imxrt_region_config); i++) + mpu_config(&imxrt_region_config[i]); enable_mpu();
return 0;

This timer driver is using GPT Timer (General Purpose Timer) available on almost all i.MX SoCs family. Since this driver is only meant to provide u-boot's timer and counter, and most of the i.MX* SoCs use a 24Mhz crystal, let's only deal with that specific source.
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com [Giulio: added the driver's stub and handled peripheral clock prescaler setting] Signed-off-by: Jesse Taube mr.bossman075@gmail.com [Jesse: added init, setting prescaler for 24Mhz support and enabling timer] --- drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/imx-gpt-timer.c | 162 ++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 drivers/timer/imx-gpt-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 80743a2551..ee81dfa776 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -227,4 +227,11 @@ config MCHP_PIT64B_TIMER Select this to enable support for Microchip 64-bit periodic interval timer.
+config IMX_GPT_TIMER + bool "NXP i.MX GPT timer support" + depends on TIMER + help + Select this to enable support for the timer found on + NXP i.MX devices. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index eb5c48cc6c..e214ba7268 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_STM32_TIMER) += stm32_timer.o obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_MTK_TIMER) += mtk_timer.o obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o +obj-$(CONFIG_IMX_GPT_TIMER) += imx-gpt-timer.o diff --git a/drivers/timer/imx-gpt-timer.c b/drivers/timer/imx-gpt-timer.c new file mode 100644 index 0000000000..a498f2e21c --- /dev/null +++ b/drivers/timer/imx-gpt-timer.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 + * Author(s): Giulio Benetti giulio.benetti@benettiengineering.com + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <fdtdec.h> +#include <timer.h> +#include <dm/device_compat.h> + +#include <asm/io.h> + +#define GPT_CR_EN BIT(0) +#define GPT_CR_FRR BIT(9) +#define GPT_CR_EN_24M BIT(10) +#define GPT_CR_SWR BIT(15) + +#define GPT_PR_PRESCALER24M_MASK 0x0000F000 +#define GPT_PR_PRESCALER24M_SHIFT 12 +#define GPT_PR_PRESCALER24M_MAX (GPT_PR_PRESCALER24M_MASK >> GPT_PR_PRESCALER24M_SHIFT) +#define GPT_PR_PRESCALER_MASK 0x00000FFF +#define GPT_PR_PRESCALER_SHIFT 0 +#define GPT_PR_PRESCALER_MAX (GPT_PR_PRESCALER_MASK >> GPT_PR_PRESCALER_SHIFT) + +#define GPT_CLKSRC_IPG_CLK (1 << 6) +#define GPT_CLKSRC_IPG_CLK_24M (5 << 6) + +/* If CONFIG_SYS_HZ_CLOCK not specified et's default to 3Mhz */ +#ifndef CONFIG_SYS_HZ_CLOCK +#define CONFIG_SYS_HZ_CLOCK 3000000 +#endif + +struct imx_gpt_timer_regs { + u32 cr; + u32 pr; + u32 sr; + u32 ir; + u32 ocr1; + u32 ocr2; + u32 ocr3; + u32 icr1; + u32 icr2; + u32 cnt; +}; + +struct imx_gpt_timer_priv { + struct imx_gpt_timer_regs *base; +}; + +static u64 imx_gpt_timer_get_count(struct udevice *dev) +{ + struct imx_gpt_timer_priv *priv = dev_get_priv(dev); + struct imx_gpt_timer_regs *regs = priv->base; + + return readl(®s->cnt); +} + +static int imx_gpt_setup(struct imx_gpt_timer_regs *regs, u32 rate) +{ + u32 prescaler = (rate / CONFIG_SYS_HZ_CLOCK) - 1; + + /* Reset the timer */ + setbits_le32(®s->cr, GPT_CR_SWR); + + /* Wait for timer to finish reset */ + while (readl(®s->cr) & GPT_CR_SWR) + ; + + if (rate == 24000000UL) { + /* Set timer frequency if using 24M clock source */ + if (prescaler > GPT_PR_PRESCALER24M_MAX) + return -EINVAL; + + /* Set 24M prescaler */ + writel((prescaler << GPT_PR_PRESCALER24M_SHIFT), ®s->pr); + /* Set Oscillator as clock source, enable 24M input and set gpt + * in free-running mode + */ + writel(GPT_CLKSRC_IPG_CLK_24M | GPT_CR_EN_24M | GPT_CR_FRR, ®s->cr); + } else { + if (prescaler > GPT_PR_PRESCALER_MAX) + return -EINVAL; + + /* Set prescaler */ + writel((prescaler << GPT_PR_PRESCALER_SHIFT), ®s->pr); + /* Set Peripheral as clock source and set gpt in free-running + * mode + */ + writel(GPT_CLKSRC_IPG_CLK | GPT_CR_FRR, ®s->cr); + } + + /* Start timer */ + setbits_le32(®s->cr, GPT_CR_EN); + + return 0; +} + +static int imx_gpt_timer_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct imx_gpt_timer_priv *priv = dev_get_priv(dev); + struct imx_gpt_timer_regs *regs; + struct clk clk; + fdt_addr_t addr; + u32 clk_rate; + int ret; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = (struct imx_gpt_timer_regs *)addr; + regs = priv->base; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + if (ret) { + dev_err(dev, "Failed to enable clock\n"); + return ret; + } + + /* Get timer clock rate */ + clk_rate = clk_get_rate(&clk); + if (clk_rate <= 0) { + dev_err(dev, "Could not get clock rate...\n"); + return -EINVAL; + } + + ret = imx_gpt_setup(regs, clk_rate); + if (ret) { + dev_err(dev, "Could not setup timer\n"); + return ret; + } + + uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK; + + return 0; +} + +static const struct timer_ops imx_gpt_timer_ops = { + .get_count = imx_gpt_timer_get_count, +}; + +static const struct udevice_id imx_gpt_timer_ids[] = { + { .compatible = "fsl,imxrt-gpt" }, + {} +}; + +U_BOOT_DRIVER(imx_gpt_timer) = { + .name = "imx_gpt_timer", + .id = UCLASS_TIMER, + .of_match = imx_gpt_timer_ids, + .priv_auto = sizeof(struct imx_gpt_timer_priv), + .probe = imx_gpt_timer_probe, + .ops = &imx_gpt_timer_ops, +};

On 4/7/21 9:02 PM, Giulio Benetti wrote:
This timer driver is using GPT Timer (General Purpose Timer) available on almost all i.MX SoCs family. Since this driver is only meant to provide u-boot's timer and counter, and most of the i.MX* SoCs use a 24Mhz crystal, let's only deal with that specific source.
Sorry, it's not true we deal 24Mhz only, also peripheral clock is dealt. So commit log should be: ``` This timer driver is using GPT Timer (General Purpose Timer) available on almost all i.MX SoCs family. This driver deals with both 24Mhz oscillator as well as peripheral clock. ```
Let me know if I need to re-send.
Best regards

if (rate == 24000000UL) {
/* Set timer frequency if using 24M clock source */
if (prescaler > GPT_PR_PRESCALER24M_MAX)
return -EINVAL;
In the datasheet for the imxrt1050 the 24Mhz scaler output goes into the normal prescaler.The width of the 24Mhz prescaler is only 4 bits it seems to be meant to divide the 24Mhz to something more reasonable for the other prescaler. I would do something like this...
+ if (rate == 24000000UL) { + /* Set timer frequency if using 24M clock source */ + if (prescaler > (GPT_PR_PRESCALER24M_MAX << 12) | GPT_PR_PRESCALER_MAX) + return -EINVAL; + + /* Set 24M prescaler */ + writel(( (prescaler >> 12) << GPT_PR_PRESCALER24M_SHIFT), ®s->pr); + writel(( (prescaler & GPT_PR_PRESCALER_MASK) << GPT_PR_PRESCALER_SHIFT), ®s->pr);
Ideally we would have the lengths in bits for GPT_PR_PRESCALER_MASK to replace the 12, but we can also do...
+ if (rate == 24000000UL) { + /* Set timer frequency if using 24M clock source */ + if (prescaler > (GPT_PR_PRESCALER24M_MASK | GPT_PR_PRESCALER_MAX)) + return -EINVAL; + + /* Set 24M prescaler */ + writel(prescaler , ®s->pr);
Side note while debugging this i added `KCFLAGS=-DDEBUG` and the boot would hang with it but without it would boot normally. The cause for the hang is this loop will never exit, not this only happens while booting u-boot and not during the spl stage. /drivers/serial/serial_lpuart.c @@ -356,7 +356,9 @@ static void _lpuart32_serial_putc(struct lpuart_serial_plat *plat,
while (true) { lpuart_read32(plat->flags, &base->stat, &stat);
if ((stat & STAT_TDRE)) break;
Sorry if im being dumb im new to this stuff and thanks for every one for walking me through this.
On Wed, Apr 7, 2021 at 3:20 PM Giulio Benetti < giulio.benetti@benettiengineering.com> wrote:
On 4/7/21 9:02 PM, Giulio Benetti wrote:
This timer driver is using GPT Timer (General Purpose Timer) available on almost all i.MX SoCs family. Since this driver is only meant to provide u-boot's timer and counter, and most of the i.MX* SoCs use a 24Mhz crystal, let's only deal with that specific source.
Sorry, it's not true we deal 24Mhz only, also peripheral clock is dealt. So commit log should be:
This timer driver is using GPT Timer (General Purpose Timer) available on almost all i.MX SoCs family. This driver deals with both 24Mhz oscillator as well as peripheral clock.
Let me know if I need to re-send.
Best regards
Giulio Benetti Benetti Engineering sas
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com [Giulio: added the driver's stub and handled peripheral clock prescaler setting] Signed-off-by: Jesse Taube mr.bossman075@gmail.com [Jesse: added init, setting prescaler for 24Mhz support and enabling timer]
drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/imx-gpt-timer.c | 162 ++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 drivers/timer/imx-gpt-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 80743a2551..ee81dfa776 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -227,4 +227,11 @@ config MCHP_PIT64B_TIMER Select this to enable support for Microchip 64-bit periodic interval timer.
+config IMX_GPT_TIMER
bool "NXP i.MX GPT timer support"
depends on TIMER
help
Select this to enable support for the timer found on
NXP i.MX devices.
- endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index eb5c48cc6c..e214ba7268 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_STM32_TIMER) += stm32_timer.o obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_MTK_TIMER) += mtk_timer.o obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o +obj-$(CONFIG_IMX_GPT_TIMER) += imx-gpt-timer.o diff --git a/drivers/timer/imx-gpt-timer.c
b/drivers/timer/imx-gpt-timer.c
new file mode 100644 index 0000000000..a498f2e21c --- /dev/null +++ b/drivers/timer/imx-gpt-timer.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2021
- Author(s): Giulio Benetti giulio.benetti@benettiengineering.com
- */
+#include <common.h> +#include <clk.h> +#include <dm.h> +#include <fdtdec.h> +#include <timer.h> +#include <dm/device_compat.h>
+#include <asm/io.h>
+#define GPT_CR_EN BIT(0) +#define GPT_CR_FRR BIT(9) +#define GPT_CR_EN_24M BIT(10) +#define GPT_CR_SWR BIT(15)
+#define GPT_PR_PRESCALER24M_MASK 0x0000F000 +#define GPT_PR_PRESCALER24M_SHIFT 12 +#define GPT_PR_PRESCALER24M_MAX (GPT_PR_PRESCALER24M_MASK >>
GPT_PR_PRESCALER24M_SHIFT)
+#define GPT_PR_PRESCALER_MASK 0x00000FFF +#define GPT_PR_PRESCALER_SHIFT 0 +#define GPT_PR_PRESCALER_MAX (GPT_PR_PRESCALER_MASK >>
GPT_PR_PRESCALER_SHIFT)
+#define GPT_CLKSRC_IPG_CLK (1 << 6) +#define GPT_CLKSRC_IPG_CLK_24M (5 << 6)
+/* If CONFIG_SYS_HZ_CLOCK not specified et's default to 3Mhz */ +#ifndef CONFIG_SYS_HZ_CLOCK +#define CONFIG_SYS_HZ_CLOCK 3000000 +#endif
+struct imx_gpt_timer_regs {
u32 cr;
u32 pr;
u32 sr;
u32 ir;
u32 ocr1;
u32 ocr2;
u32 ocr3;
u32 icr1;
u32 icr2;
u32 cnt;
+};
+struct imx_gpt_timer_priv {
struct imx_gpt_timer_regs *base;
+};
+static u64 imx_gpt_timer_get_count(struct udevice *dev) +{
struct imx_gpt_timer_priv *priv = dev_get_priv(dev);
struct imx_gpt_timer_regs *regs = priv->base;
return readl(®s->cnt);
+}
+static int imx_gpt_setup(struct imx_gpt_timer_regs *regs, u32 rate) +{
u32 prescaler = (rate / CONFIG_SYS_HZ_CLOCK) - 1;
/* Reset the timer */
setbits_le32(®s->cr, GPT_CR_SWR);
/* Wait for timer to finish reset */
while (readl(®s->cr) & GPT_CR_SWR)
;
if (rate == 24000000UL) {
/* Set timer frequency if using 24M clock source */
if (prescaler > GPT_PR_PRESCALER24M_MAX)
return -EINVAL;
/* Set 24M prescaler */
writel((prescaler << GPT_PR_PRESCALER24M_SHIFT),
®s->pr);
/* Set Oscillator as clock source, enable 24M input and
set gpt
* in free-running mode
*/
writel(GPT_CLKSRC_IPG_CLK_24M | GPT_CR_EN_24M |
GPT_CR_FRR, ®s->cr);
} else {
if (prescaler > GPT_PR_PRESCALER_MAX)
return -EINVAL;
/* Set prescaler */
writel((prescaler << GPT_PR_PRESCALER_SHIFT), ®s->pr);
/* Set Peripheral as clock source and set gpt in
free-running
* mode
*/
writel(GPT_CLKSRC_IPG_CLK | GPT_CR_FRR, ®s->cr);
}
/* Start timer */
setbits_le32(®s->cr, GPT_CR_EN);
return 0;
+}
+static int imx_gpt_timer_probe(struct udevice *dev) +{
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct imx_gpt_timer_priv *priv = dev_get_priv(dev);
struct imx_gpt_timer_regs *regs;
struct clk clk;
fdt_addr_t addr;
u32 clk_rate;
int ret;
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->base = (struct imx_gpt_timer_regs *)addr;
regs = priv->base;
ret = clk_get_by_index(dev, 0, &clk);
if (ret < 0)
return ret;
ret = clk_enable(&clk);
if (ret) {
dev_err(dev, "Failed to enable clock\n");
return ret;
}
/* Get timer clock rate */
clk_rate = clk_get_rate(&clk);
if (clk_rate <= 0) {
dev_err(dev, "Could not get clock rate...\n");
return -EINVAL;
}
ret = imx_gpt_setup(regs, clk_rate);
if (ret) {
dev_err(dev, "Could not setup timer\n");
return ret;
}
uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
return 0;
+}
+static const struct timer_ops imx_gpt_timer_ops = {
.get_count = imx_gpt_timer_get_count,
+};
+static const struct udevice_id imx_gpt_timer_ids[] = {
{ .compatible = "fsl,imxrt-gpt" },
{}
+};
+U_BOOT_DRIVER(imx_gpt_timer) = {
.name = "imx_gpt_timer",
.id = UCLASS_TIMER,
.of_match = imx_gpt_timer_ids,
.priv_auto = sizeof(struct imx_gpt_timer_priv),
.probe = imx_gpt_timer_probe,
.ops = &imx_gpt_timer_ops,
+};

Hi Jesse,
please use plain-text e-mail instead of html,
On 4/8/21 3:06 AM, Jesse T wrote:
> + if (rate == 24000000UL) { > + /* Set timer frequency if using 24M clock source */ > + if (prescaler > GPT_PR_PRESCALER24M_MAX) > + return -EINVAL; > +
In the datasheet for the imxrt1050 the 24Mhz scaler output goes into the normal prescaler.The width of the 24Mhz prescaler is only 4 bits it seems to be meant to divide the 24Mhz to something more reasonable for the other prescaler.
You're right, I've missed RM Figure 51-2 against 51-1, I was sure that Prescaler 24M was directly feeding the Timer Counter. Anyway I was trying to follow what they do in Linux kernel: https://elixir.bootlin.com/linux/latest/source/drivers/clocksource/timer-imx...
What they try to do as I understand is to avoid using PLL if 3Mhz is the wished rate and the same I'm trying to do here. Then yes, you're right that main prescaler can divide again.
I would do something like this...
+ if (rate == 24000000UL) { + /* Set timer frequency if using 24M clock source */ + if (prescaler > (GPT_PR_PRESCALER24M_MAX << 12) | GPT_PR_PRESCALER_MAX)
I can't understand this check ^^^
+ return -EINVAL;
+ /* Set 24M prescaler */ + writel(( (prescaler >> 12) << GPT_PR_PRESCALER24M_SHIFT), ®s->pr); + writel(( (prescaler & GPT_PR_PRESCALER_MASK) << GPT_PR_PRESCALER_SHIFT), ®s->pr);
This way ^^^ you set the 2 in-series prescalers with the same value if it's what you mean.
Ideally we would have the lengths in bits for GPT_PR_PRESCALER_MASK to replace the 12, but we can also do...
+ if (rate == 24000000UL) { + /* Set timer frequency if using 24M clock source */ + if (prescaler > (GPT_PR_PRESCALER24M_MASK | GPT_PR_PRESCALER_MAX))
Still don't understand this ^^^ with the 2 or'ed macros.
That gets expanded like: ``` if (prescaler > (GPT_PR_PRESCALER24M_MASK | ((GPT_PR_PRESCALER24M_MASK
GPT_PR_PRESCALER24M_SHIFT)))
``` and to: ``` if (prescaler > (0x0000F000 | (0x0000F000 >> 12))) ``` that results in: ``` if (prescaler > (0x0000F000 | 0xF)) ```
so it doesn't make sense to me, maybe did you mean something different or I'm wrong while expanding?
+ return -EINVAL;
+ /* Set 24M prescaler */ + writel(prescaler , ®s->pr);
Side note while debugging this i added `KCFLAGS=-DDEBUG` and the boot would hang with it but without it would boot normally. The cause for the hang is this loop will never exit, not this only happens while booting u-boot and not during the spl stage. /drivers/serial/serial_lpuart.c @@ -356,7 +356,9 @@ static void _lpuart32_serial_putc(struct lpuart_serial_plat *plat,
while (true) { lpuart_read32(plat->flags, &base->stat, &stat);
if ((stat & STAT_TDRE)) break;
Thanks for recalling me this, I still didn't check it, so I'm going through this and fix it.
Sorry if im being dumb
You're not being dumb
im new to this stuff and thanks for every one for
walking me through this.
You're welcome :-) and thank you for helping me with this driver and reviewing! Reviewing is a very important part of the process of upstreaming patches.
Kind regards

On 4/7/21 3:02 PM, Giulio Benetti wrote:
This timer driver is using GPT Timer (General Purpose Timer) available on almost all i.MX SoCs family. Since this driver is only meant to provide u-boot's timer and counter, and most of the i.MX* SoCs use a 24Mhz crystal, let's only deal with that specific source.
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com [Giulio: added the driver's stub and handled peripheral clock prescaler setting] Signed-off-by: Jesse Taube mr.bossman075@gmail.com [Jesse: added init, setting prescaler for 24Mhz support and enabling timer]
drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/imx-gpt-timer.c | 162 ++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 drivers/timer/imx-gpt-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 80743a2551..ee81dfa776 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -227,4 +227,11 @@ config MCHP_PIT64B_TIMER Select this to enable support for Microchip 64-bit periodic interval timer.
+config IMX_GPT_TIMER
- bool "NXP i.MX GPT timer support"
- depends on TIMER
- help
Select this to enable support for the timer found on
NXP i.MX devices.
- endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index eb5c48cc6c..e214ba7268 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_STM32_TIMER) += stm32_timer.o obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_MTK_TIMER) += mtk_timer.o obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o +obj-$(CONFIG_IMX_GPT_TIMER) += imx-gpt-timer.o diff --git a/drivers/timer/imx-gpt-timer.c b/drivers/timer/imx-gpt-timer.c new file mode 100644 index 0000000000..a498f2e21c --- /dev/null +++ b/drivers/timer/imx-gpt-timer.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2021
- Author(s): Giulio Benetti giulio.benetti@benettiengineering.com
- */
+#include <common.h> +#include <clk.h> +#include <dm.h> +#include <fdtdec.h> +#include <timer.h> +#include <dm/device_compat.h>
+#include <asm/io.h>
+#define GPT_CR_EN BIT(0) +#define GPT_CR_FRR BIT(9) +#define GPT_CR_EN_24M BIT(10) +#define GPT_CR_SWR BIT(15)
+#define GPT_PR_PRESCALER24M_MASK 0x0000F000 +#define GPT_PR_PRESCALER24M_SHIFT 12 +#define GPT_PR_PRESCALER24M_MAX (GPT_PR_PRESCALER24M_MASK >> GPT_PR_PRESCALER24M_SHIFT) +#define GPT_PR_PRESCALER_MASK 0x00000FFF +#define GPT_PR_PRESCALER_SHIFT 0 +#define GPT_PR_PRESCALER_MAX (GPT_PR_PRESCALER_MASK >> GPT_PR_PRESCALER_SHIFT)
+#define GPT_CLKSRC_IPG_CLK (1 << 6) +#define GPT_CLKSRC_IPG_CLK_24M (5 << 6)
+/* If CONFIG_SYS_HZ_CLOCK not specified et's default to 3Mhz */ +#ifndef CONFIG_SYS_HZ_CLOCK +#define CONFIG_SYS_HZ_CLOCK 3000000 +#endif
+struct imx_gpt_timer_regs {
- u32 cr;
- u32 pr;
- u32 sr;
- u32 ir;
- u32 ocr1;
- u32 ocr2;
- u32 ocr3;
- u32 icr1;
- u32 icr2;
- u32 cnt;
+};
+struct imx_gpt_timer_priv {
- struct imx_gpt_timer_regs *base;
+};
+static u64 imx_gpt_timer_get_count(struct udevice *dev) +{
- struct imx_gpt_timer_priv *priv = dev_get_priv(dev);
- struct imx_gpt_timer_regs *regs = priv->base;
- return readl(®s->cnt);
This should use timer_conv_64 since it is a 32-bit timer.
--Sean
+}
+static int imx_gpt_setup(struct imx_gpt_timer_regs *regs, u32 rate) +{
- u32 prescaler = (rate / CONFIG_SYS_HZ_CLOCK) - 1;
- /* Reset the timer */
- setbits_le32(®s->cr, GPT_CR_SWR);
- /* Wait for timer to finish reset */
- while (readl(®s->cr) & GPT_CR_SWR)
;
- if (rate == 24000000UL) {
/* Set timer frequency if using 24M clock source */
if (prescaler > GPT_PR_PRESCALER24M_MAX)
return -EINVAL;
/* Set 24M prescaler */
writel((prescaler << GPT_PR_PRESCALER24M_SHIFT), ®s->pr);
/* Set Oscillator as clock source, enable 24M input and set gpt
* in free-running mode
*/
writel(GPT_CLKSRC_IPG_CLK_24M | GPT_CR_EN_24M | GPT_CR_FRR, ®s->cr);
- } else {
if (prescaler > GPT_PR_PRESCALER_MAX)
return -EINVAL;
/* Set prescaler */
writel((prescaler << GPT_PR_PRESCALER_SHIFT), ®s->pr);
/* Set Peripheral as clock source and set gpt in free-running
* mode
*/
writel(GPT_CLKSRC_IPG_CLK | GPT_CR_FRR, ®s->cr);
- }
- /* Start timer */
- setbits_le32(®s->cr, GPT_CR_EN);
- return 0;
+}
+static int imx_gpt_timer_probe(struct udevice *dev) +{
- struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
- struct imx_gpt_timer_priv *priv = dev_get_priv(dev);
- struct imx_gpt_timer_regs *regs;
- struct clk clk;
- fdt_addr_t addr;
- u32 clk_rate;
- int ret;
- addr = dev_read_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- priv->base = (struct imx_gpt_timer_regs *)addr;
- regs = priv->base;
- ret = clk_get_by_index(dev, 0, &clk);
- if (ret < 0)
return ret;
- ret = clk_enable(&clk);
- if (ret) {
dev_err(dev, "Failed to enable clock\n");
return ret;
- }
- /* Get timer clock rate */
- clk_rate = clk_get_rate(&clk);
- if (clk_rate <= 0) {
dev_err(dev, "Could not get clock rate...\n");
return -EINVAL;
- }
- ret = imx_gpt_setup(regs, clk_rate);
- if (ret) {
dev_err(dev, "Could not setup timer\n");
return ret;
- }
- uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
- return 0;
+}
+static const struct timer_ops imx_gpt_timer_ops = {
- .get_count = imx_gpt_timer_get_count,
+};
+static const struct udevice_id imx_gpt_timer_ids[] = {
- { .compatible = "fsl,imxrt-gpt" },
- {}
+};
+U_BOOT_DRIVER(imx_gpt_timer) = {
- .name = "imx_gpt_timer",
- .id = UCLASS_TIMER,
- .of_match = imx_gpt_timer_ids,
- .priv_auto = sizeof(struct imx_gpt_timer_priv),
- .probe = imx_gpt_timer_probe,
- .ops = &imx_gpt_timer_ops,
+};

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/dts/imxrt1020.dtsi b/arch/arm/dts/imxrt1020.dtsi index 97f3cec9f3..0a3a3b451a 100644 --- a/arch/arm/dts/imxrt1020.dtsi +++ b/arch/arm/dts/imxrt1020.dtsi @@ -36,7 +36,7 @@ clock-frequency = <0>; };
- osc { + osc: osc { u-boot,dm-spl; compatible = "fsl,imx-osc", "fixed-clock"; #clock-cells = <0>;

Hi Giulio,
On Wed, Apr 7, 2021 at 4:03 PM Giulio Benetti giulio.benetti@benettiengineering.com wrote:
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com
arch/arm/dts/imxrt1020.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/dts/imxrt1020.dtsi b/arch/arm/dts/imxrt1020.dtsi index 97f3cec9f3..0a3a3b451a 100644 --- a/arch/arm/dts/imxrt1020.dtsi +++ b/arch/arm/dts/imxrt1020.dtsi @@ -36,7 +36,7 @@ clock-frequency = <0>; };
osc {
osc: osc {
Nit: what you are adding here is a "node label", not an "alias".
It would be nice to always add a commit log, even if it is a short one.

Hi Gabio,
Il giorno 3 mag 2021, alle ore 16:01, Fabio Estevam festevam@gmail.com ha scritto:
Hi Giulio,
On Wed, Apr 7, 2021 at 4:03 PM Giulio Benetti giulio.benetti@benettiengineering.com wrote:
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com
arch/arm/dts/imxrt1020.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/dts/imxrt1020.dtsi b/arch/arm/dts/imxrt1020.dtsi index 97f3cec9f3..0a3a3b451a 100644 --- a/arch/arm/dts/imxrt1020.dtsi +++ b/arch/arm/dts/imxrt1020.dtsi @@ -36,7 +36,7 @@ clock-frequency = <0>; };
osc {
osc: osc {
Nit: what you are adding here is a "node label", not an "alias".
Thank you, you’re right.
It would be nice to always add a commit log, even if it is a short one.
Ok, is it ok if it even repeats the first line? Because I don’t know what write more than that.
Best regards Giulio Benetti

On Mon, May 3, 2021 at 2:52 PM Giulio Benetti giulio.benetti@benettiengineering.com wrote:
Ok, is it ok if it even repeats the first line? Because I don’t know what write more than that.
Yes, that would be fine.

Il giorno 3 mag 2021, alle ore 20:21, Fabio Estevam festevam@gmail.com ha scritto:
On Mon, May 3, 2021 at 2:52 PM Giulio Benetti giulio.benetti@benettiengineering.com wrote:
Ok, is it ok if it even repeats the first line? Because I don’t know what write more than that.
Yes, that would be fine.
Ok thank you. This was a doubt I always had.
Giulio

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/dts/imxrt1020.dtsi b/arch/arm/dts/imxrt1020.dtsi index 0a3a3b451a..cab608c644 100644 --- a/arch/arm/dts/imxrt1020.dtsi +++ b/arch/arm/dts/imxrt1020.dtsi @@ -129,5 +129,13 @@ interrupt-controller; #interrupt-cells = <2>; }; + + gpt1: gpt1@401ec000 { + compatible = "fsl,imxrt-gpt"; + reg = <0x401ec000 0x4000>; + interrupts = <100>; + clocks = <&osc>; + status = "disabled"; + }; }; };

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020-evk.dts | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/dts/imxrt1020-evk.dts b/arch/arm/dts/imxrt1020-evk.dts index ece13601bd..a471ff3838 100644 --- a/arch/arm/dts/imxrt1020-evk.dts +++ b/arch/arm/dts/imxrt1020-evk.dts @@ -186,6 +186,10 @@ }; };
+&gpt1 { + status = "okay"; +}; + &usdhc1 { pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; pinctrl-0 = <&pinctrl_usdhc0>;

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020-evk.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/imxrt1020-evk.dts b/arch/arm/dts/imxrt1020-evk.dts index a471ff3838..b527206fcf 100644 --- a/arch/arm/dts/imxrt1020-evk.dts +++ b/arch/arm/dts/imxrt1020-evk.dts @@ -16,6 +16,7 @@ chosen { bootargs = "root=/dev/ram"; stdout-path = "serial0:115200n8"; + tick-timer = &gpt1; };
memory {

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020-evk-u-boot.dtsi | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/dts/imxrt1020-evk-u-boot.dtsi b/arch/arm/dts/imxrt1020-evk-u-boot.dtsi index d32c98de9c..34d19e06c5 100644 --- a/arch/arm/dts/imxrt1020-evk-u-boot.dtsi +++ b/arch/arm/dts/imxrt1020-evk-u-boot.dtsi @@ -10,6 +10,10 @@ }; };
+&gpt1 { + u-boot,dm-spl; +}; + &lpuart1 { /* console */ u-boot,dm-spl; };

Now device_type = "memory" is mandatory to allow u-boot to read memory node, so let's add it to memory node.
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020-evk.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/imxrt1020-evk.dts b/arch/arm/dts/imxrt1020-evk.dts index b527206fcf..2da79e5c20 100644 --- a/arch/arm/dts/imxrt1020-evk.dts +++ b/arch/arm/dts/imxrt1020-evk.dts @@ -20,6 +20,7 @@ };
memory { + device_type = "memory"; reg = <0x80000000 0x2000000>; }; };

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- configs/imxrt1020-evk_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/imxrt1020-evk_defconfig b/configs/imxrt1020-evk_defconfig index 9bddb69cd4..51ff702bc6 100644 --- a/configs/imxrt1020-evk_defconfig +++ b/configs/imxrt1020-evk_defconfig @@ -62,6 +62,7 @@ CONFIG_IMXRT_SDRAM=y CONFIG_FSL_LPUART=y CONFIG_TIMER=y CONFIG_SPL_TIMER=y +CONFIG_IMX_GPT_TIMER=y CONFIG_SHA1=y CONFIG_SHA256=y CONFIG_HEXDUMP=y

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1050.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/dts/imxrt1050.dtsi b/arch/arm/dts/imxrt1050.dtsi index a9281001e5..b7cc3fbc2a 100644 --- a/arch/arm/dts/imxrt1050.dtsi +++ b/arch/arm/dts/imxrt1050.dtsi @@ -28,7 +28,7 @@ clocks { u-boot,dm-spl;
- osc { + osc: osc { u-boot,dm-spl; compatible = "fsl,imx-osc", "fixed-clock"; #clock-cells = <0>;

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1050.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/dts/imxrt1050.dtsi b/arch/arm/dts/imxrt1050.dtsi index b7cc3fbc2a..6f9da3fe8a 100644 --- a/arch/arm/dts/imxrt1050.dtsi +++ b/arch/arm/dts/imxrt1050.dtsi @@ -154,5 +154,13 @@ clock-names = "per"; status = "disabled"; }; + + gpt1: gpt1@401ec000 { + compatible = "fsl,imxrt-gpt"; + reg = <0x401ec000 0x4000>; + interrupts = <100>; + clocks = <&osc>; + status = "disabled"; + }; }; };

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1050-evk.dts | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/dts/imxrt1050-evk.dts b/arch/arm/dts/imxrt1050-evk.dts index b5e781275e..e592330332 100644 --- a/arch/arm/dts/imxrt1050-evk.dts +++ b/arch/arm/dts/imxrt1050-evk.dts @@ -215,6 +215,10 @@ }; };
+&gpt1 { + status = "okay"; +}; + &usdhc1 { pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; pinctrl-0 = <&pinctrl_usdhc0>;

This patchset adds imx-gpt-timer driver that is supported by i.MXRT and also a lot of other i.MX* SoCs. This driver is needed for i.MXRT SoC family that is lacking at the moment the timer at all and that makes u-boot to fail running on i.MXRT. There are also some fixes in imxrt10*0-evk.dts and other minor fixed and improvements.
--- V1->V2: * fixed 32 to 64 bit conversion on timer as suggested by Sean Anderson ---
Giulio Benetti (16): arm: imxrt: soc: make mpu regions generic timer: imx-gpt: Add timer support for i.MX SoCs family ARM: dts: imxrt1020: add alias to osc ARM: dts: imxrt1020: add gpt1 node ARM: dts: imxrt1020-evk: enable gpt1 timer ARM: dts: imxrt1020-evk: set gpt1 as tick-timer for u-boot ARM: dts: imxrt1020-evk-u-boot: make gpt1 present for SPL ARM: dts: imxrt1020-evk: add device_type = "memory" to memory node configs: imxrt1020-evk: enable imx gpt timer as tick-timer ARM: dts: imxrt1050: add alias to osc ARM: dts: imxrt1050: add gpt1 node ARM: dts: imxrt1050-evk: enable gpt1 timer ARM: dts: imxrt1050-evk: set gpt1 as tick-timer for u-boot ARM: dts: imxrt1050-evk-u-boot: make gpt1 present for SPL ARM: dts: imxrt1050-evk: add device_type = "memory" to memory node configs: imxrt1050-evk: enable imx gpt timer as tick-timer
arch/arm/dts/imxrt1020-evk-u-boot.dtsi | 4 + arch/arm/dts/imxrt1020-evk.dts | 6 + arch/arm/dts/imxrt1020.dtsi | 10 +- arch/arm/dts/imxrt1050-evk-u-boot.dtsi | 4 + arch/arm/dts/imxrt1050-evk.dts | 6 + arch/arm/dts/imxrt1050.dtsi | 10 +- arch/arm/mach-imx/imxrt/soc.c | 6 +- configs/imxrt1020-evk_defconfig | 1 + configs/imxrt1050-evk_defconfig | 1 + drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/imx-gpt-timer.c | 162 +++++++++++++++++++++++++ 12 files changed, 213 insertions(+), 5 deletions(-) create mode 100644 drivers/timer/imx-gpt-timer.c

This mpu handling works for every i.MXRT SoC that we have, so let's generalize imxrt1050_region_config to imxrt_region_config.
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/mach-imx/imxrt/soc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-imx/imxrt/soc.c b/arch/arm/mach-imx/imxrt/soc.c index 8e7d15160d..c533f3554a 100644 --- a/arch/arm/mach-imx/imxrt/soc.c +++ b/arch/arm/mach-imx/imxrt/soc.c @@ -14,7 +14,7 @@ int arch_cpu_init(void) { int i;
- struct mpu_region_config imxrt1050_region_config[] = { + struct mpu_region_config imxrt_region_config[] = { { 0x00000000, REGION_0, XN_DIS, PRIV_RW_USR_RW, STRONG_ORDER, REGION_4GB }, { PHYS_SDRAM, REGION_1, XN_DIS, PRIV_RW_USR_RW, @@ -29,8 +29,8 @@ int arch_cpu_init(void) * the whole 4GB address space. */ disable_mpu(); - for (i = 0; i < ARRAY_SIZE(imxrt1050_region_config); i++) - mpu_config(&imxrt1050_region_config[i]); + for (i = 0; i < ARRAY_SIZE(imxrt_region_config); i++) + mpu_config(&imxrt_region_config[i]); enable_mpu();
return 0;

This timer driver uses GPT Timer (General Purpose Timer) available on a lot of i.MX SoCs family. This driver deals with both 24Mhz oscillator as well as peripheral clock.
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com [Giulio: added the driver's stub and handled peripheral clock prescaler setting] Signed-off-by: Jesse Taube mr.bossman075@gmail.com [Jesse: added init, setting prescaler for 24Mhz support and enabling timer] --- V1->V2: * fixed 32 to 64 bit conversion on timer as suggested by Sean Anderson by using timer_conv_64() in imx_gpt_timer_get_count() --- drivers/timer/Kconfig | 7 ++ drivers/timer/Makefile | 1 + drivers/timer/imx-gpt-timer.c | 162 ++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 drivers/timer/imx-gpt-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 80743a2551..ee81dfa776 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -227,4 +227,11 @@ config MCHP_PIT64B_TIMER Select this to enable support for Microchip 64-bit periodic interval timer.
+config IMX_GPT_TIMER + bool "NXP i.MX GPT timer support" + depends on TIMER + help + Select this to enable support for the timer found on + NXP i.MX devices. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index eb5c48cc6c..e214ba7268 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_STM32_TIMER) += stm32_timer.o obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_MTK_TIMER) += mtk_timer.o obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o +obj-$(CONFIG_IMX_GPT_TIMER) += imx-gpt-timer.o diff --git a/drivers/timer/imx-gpt-timer.c b/drivers/timer/imx-gpt-timer.c new file mode 100644 index 0000000000..72be297754 --- /dev/null +++ b/drivers/timer/imx-gpt-timer.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 + * Author(s): Giulio Benetti giulio.benetti@benettiengineering.com + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <fdtdec.h> +#include <timer.h> +#include <dm/device_compat.h> + +#include <asm/io.h> + +#define GPT_CR_EN BIT(0) +#define GPT_CR_FRR BIT(9) +#define GPT_CR_EN_24M BIT(10) +#define GPT_CR_SWR BIT(15) + +#define GPT_PR_PRESCALER24M_MASK 0x0000F000 +#define GPT_PR_PRESCALER24M_SHIFT 12 +#define GPT_PR_PRESCALER24M_MAX (GPT_PR_PRESCALER24M_MASK >> GPT_PR_PRESCALER24M_SHIFT) +#define GPT_PR_PRESCALER_MASK 0x00000FFF +#define GPT_PR_PRESCALER_SHIFT 0 +#define GPT_PR_PRESCALER_MAX (GPT_PR_PRESCALER_MASK >> GPT_PR_PRESCALER_SHIFT) + +#define GPT_CLKSRC_IPG_CLK (1 << 6) +#define GPT_CLKSRC_IPG_CLK_24M (5 << 6) + +/* If CONFIG_SYS_HZ_CLOCK not specified et's default to 3Mhz */ +#ifndef CONFIG_SYS_HZ_CLOCK +#define CONFIG_SYS_HZ_CLOCK 3000000 +#endif + +struct imx_gpt_timer_regs { + u32 cr; + u32 pr; + u32 sr; + u32 ir; + u32 ocr1; + u32 ocr2; + u32 ocr3; + u32 icr1; + u32 icr2; + u32 cnt; +}; + +struct imx_gpt_timer_priv { + struct imx_gpt_timer_regs *base; +}; + +static u64 imx_gpt_timer_get_count(struct udevice *dev) +{ + struct imx_gpt_timer_priv *priv = dev_get_priv(dev); + struct imx_gpt_timer_regs *regs = priv->base; + + return timer_conv_64(readl(®s->cnt)); +} + +static int imx_gpt_setup(struct imx_gpt_timer_regs *regs, u32 rate) +{ + u32 prescaler = (rate / CONFIG_SYS_HZ_CLOCK) - 1; + + /* Reset the timer */ + setbits_le32(®s->cr, GPT_CR_SWR); + + /* Wait for timer to finish reset */ + while (readl(®s->cr) & GPT_CR_SWR) + ; + + if (rate == 24000000UL) { + /* Set timer frequency if using 24M clock source */ + if (prescaler > GPT_PR_PRESCALER24M_MAX) + return -EINVAL; + + /* Set 24M prescaler */ + writel((prescaler << GPT_PR_PRESCALER24M_SHIFT), ®s->pr); + /* Set Oscillator as clock source, enable 24M input and set gpt + * in free-running mode + */ + writel(GPT_CLKSRC_IPG_CLK_24M | GPT_CR_EN_24M | GPT_CR_FRR, ®s->cr); + } else { + if (prescaler > GPT_PR_PRESCALER_MAX) + return -EINVAL; + + /* Set prescaler */ + writel((prescaler << GPT_PR_PRESCALER_SHIFT), ®s->pr); + /* Set Peripheral as clock source and set gpt in free-running + * mode + */ + writel(GPT_CLKSRC_IPG_CLK | GPT_CR_FRR, ®s->cr); + } + + /* Start timer */ + setbits_le32(®s->cr, GPT_CR_EN); + + return 0; +} + +static int imx_gpt_timer_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct imx_gpt_timer_priv *priv = dev_get_priv(dev); + struct imx_gpt_timer_regs *regs; + struct clk clk; + fdt_addr_t addr; + u32 clk_rate; + int ret; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = (struct imx_gpt_timer_regs *)addr; + regs = priv->base; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + if (ret) { + dev_err(dev, "Failed to enable clock\n"); + return ret; + } + + /* Get timer clock rate */ + clk_rate = clk_get_rate(&clk); + if (clk_rate <= 0) { + dev_err(dev, "Could not get clock rate...\n"); + return -EINVAL; + } + + ret = imx_gpt_setup(regs, clk_rate); + if (ret) { + dev_err(dev, "Could not setup timer\n"); + return ret; + } + + uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK; + + return 0; +} + +static const struct timer_ops imx_gpt_timer_ops = { + .get_count = imx_gpt_timer_get_count, +}; + +static const struct udevice_id imx_gpt_timer_ids[] = { + { .compatible = "fsl,imxrt-gpt" }, + {} +}; + +U_BOOT_DRIVER(imx_gpt_timer) = { + .name = "imx_gpt_timer", + .id = UCLASS_TIMER, + .of_match = imx_gpt_timer_ids, + .priv_auto = sizeof(struct imx_gpt_timer_priv), + .probe = imx_gpt_timer_probe, + .ops = &imx_gpt_timer_ops, +};

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/dts/imxrt1020.dtsi b/arch/arm/dts/imxrt1020.dtsi index 97f3cec9f3..0a3a3b451a 100644 --- a/arch/arm/dts/imxrt1020.dtsi +++ b/arch/arm/dts/imxrt1020.dtsi @@ -36,7 +36,7 @@ clock-frequency = <0>; };
- osc { + osc: osc { u-boot,dm-spl; compatible = "fsl,imx-osc", "fixed-clock"; #clock-cells = <0>;

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/dts/imxrt1020.dtsi b/arch/arm/dts/imxrt1020.dtsi index 0a3a3b451a..cab608c644 100644 --- a/arch/arm/dts/imxrt1020.dtsi +++ b/arch/arm/dts/imxrt1020.dtsi @@ -129,5 +129,13 @@ interrupt-controller; #interrupt-cells = <2>; }; + + gpt1: gpt1@401ec000 { + compatible = "fsl,imxrt-gpt"; + reg = <0x401ec000 0x4000>; + interrupts = <100>; + clocks = <&osc>; + status = "disabled"; + }; }; };

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020-evk.dts | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/dts/imxrt1020-evk.dts b/arch/arm/dts/imxrt1020-evk.dts index ece13601bd..a471ff3838 100644 --- a/arch/arm/dts/imxrt1020-evk.dts +++ b/arch/arm/dts/imxrt1020-evk.dts @@ -186,6 +186,10 @@ }; };
+&gpt1 { + status = "okay"; +}; + &usdhc1 { pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; pinctrl-0 = <&pinctrl_usdhc0>;

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020-evk.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/imxrt1020-evk.dts b/arch/arm/dts/imxrt1020-evk.dts index a471ff3838..b527206fcf 100644 --- a/arch/arm/dts/imxrt1020-evk.dts +++ b/arch/arm/dts/imxrt1020-evk.dts @@ -16,6 +16,7 @@ chosen { bootargs = "root=/dev/ram"; stdout-path = "serial0:115200n8"; + tick-timer = &gpt1; };
memory {

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020-evk-u-boot.dtsi | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/dts/imxrt1020-evk-u-boot.dtsi b/arch/arm/dts/imxrt1020-evk-u-boot.dtsi index d32c98de9c..34d19e06c5 100644 --- a/arch/arm/dts/imxrt1020-evk-u-boot.dtsi +++ b/arch/arm/dts/imxrt1020-evk-u-boot.dtsi @@ -10,6 +10,10 @@ }; };
+&gpt1 { + u-boot,dm-spl; +}; + &lpuart1 { /* console */ u-boot,dm-spl; };

Now device_type = "memory" is mandatory to allow u-boot to read memory node, so let's add it to memory node.
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1020-evk.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/imxrt1020-evk.dts b/arch/arm/dts/imxrt1020-evk.dts index b527206fcf..2da79e5c20 100644 --- a/arch/arm/dts/imxrt1020-evk.dts +++ b/arch/arm/dts/imxrt1020-evk.dts @@ -20,6 +20,7 @@ };
memory { + device_type = "memory"; reg = <0x80000000 0x2000000>; }; };

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- configs/imxrt1020-evk_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/imxrt1020-evk_defconfig b/configs/imxrt1020-evk_defconfig index 9bddb69cd4..51ff702bc6 100644 --- a/configs/imxrt1020-evk_defconfig +++ b/configs/imxrt1020-evk_defconfig @@ -62,6 +62,7 @@ CONFIG_IMXRT_SDRAM=y CONFIG_FSL_LPUART=y CONFIG_TIMER=y CONFIG_SPL_TIMER=y +CONFIG_IMX_GPT_TIMER=y CONFIG_SHA1=y CONFIG_SHA256=y CONFIG_HEXDUMP=y

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1050.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/dts/imxrt1050.dtsi b/arch/arm/dts/imxrt1050.dtsi index a9281001e5..b7cc3fbc2a 100644 --- a/arch/arm/dts/imxrt1050.dtsi +++ b/arch/arm/dts/imxrt1050.dtsi @@ -28,7 +28,7 @@ clocks { u-boot,dm-spl;
- osc { + osc: osc { u-boot,dm-spl; compatible = "fsl,imx-osc", "fixed-clock"; #clock-cells = <0>;

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1050.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/arch/arm/dts/imxrt1050.dtsi b/arch/arm/dts/imxrt1050.dtsi index b7cc3fbc2a..6f9da3fe8a 100644 --- a/arch/arm/dts/imxrt1050.dtsi +++ b/arch/arm/dts/imxrt1050.dtsi @@ -154,5 +154,13 @@ clock-names = "per"; status = "disabled"; }; + + gpt1: gpt1@401ec000 { + compatible = "fsl,imxrt-gpt"; + reg = <0x401ec000 0x4000>; + interrupts = <100>; + clocks = <&osc>; + status = "disabled"; + }; }; };

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1050-evk.dts | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/dts/imxrt1050-evk.dts b/arch/arm/dts/imxrt1050-evk.dts index b5e781275e..e592330332 100644 --- a/arch/arm/dts/imxrt1050-evk.dts +++ b/arch/arm/dts/imxrt1050-evk.dts @@ -215,6 +215,10 @@ }; };
+&gpt1 { + status = "okay"; +}; + &usdhc1 { pinctrl-names = "default", "state_100mhz", "state_200mhz", "sleep"; pinctrl-0 = <&pinctrl_usdhc0>;

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1050-evk.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/imxrt1050-evk.dts b/arch/arm/dts/imxrt1050-evk.dts index e592330332..6d21f2b738 100644 --- a/arch/arm/dts/imxrt1050-evk.dts +++ b/arch/arm/dts/imxrt1050-evk.dts @@ -16,6 +16,7 @@ chosen { bootargs = "root=/dev/ram"; stdout-path = "serial0:115200n8"; + tick-timer = &gpt1; };
memory {

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1050-evk-u-boot.dtsi | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/dts/imxrt1050-evk-u-boot.dtsi b/arch/arm/dts/imxrt1050-evk-u-boot.dtsi index fb4f7f6f9d..a4b50f0bb2 100644 --- a/arch/arm/dts/imxrt1050-evk-u-boot.dtsi +++ b/arch/arm/dts/imxrt1050-evk-u-boot.dtsi @@ -10,6 +10,10 @@ }; };
+&gpt1 { + u-boot,dm-spl; +}; + &lpuart1 { /* console */ u-boot,dm-spl; };

Now device_type = "memory" is mandatory to allow u-boot to read memory node, so let's add it to memory node.
Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- arch/arm/dts/imxrt1050-evk.dts | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/dts/imxrt1050-evk.dts b/arch/arm/dts/imxrt1050-evk.dts index 6d21f2b738..2052d4eb4e 100644 --- a/arch/arm/dts/imxrt1050-evk.dts +++ b/arch/arm/dts/imxrt1050-evk.dts @@ -20,6 +20,7 @@ };
memory { + device_type = "memory"; reg = <0x80000000 0x2000000>; }; };

Signed-off-by: Giulio Benetti giulio.benetti@benettiengineering.com --- configs/imxrt1050-evk_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/imxrt1050-evk_defconfig b/configs/imxrt1050-evk_defconfig index f639ea7623..e74473511d 100644 --- a/configs/imxrt1050-evk_defconfig +++ b/configs/imxrt1050-evk_defconfig @@ -65,6 +65,7 @@ CONFIG_IMXRT_SDRAM=y CONFIG_FSL_LPUART=y CONFIG_TIMER=y CONFIG_SPL_TIMER=y +CONFIG_IMX_GPT_TIMER=y CONFIG_DM_VIDEO=y CONFIG_BACKLIGHT_GPIO=y CONFIG_SYS_WHITE_ON_BLACK=y
participants (4)
-
Fabio Estevam
-
Giulio Benetti
-
Jesse T
-
Sean Anderson