[PATCH] zynq: Convert arm twd timer to DM driver
Michal Simek
michal.simek at amd.com
Tue Aug 9 16:15:14 CEST 2022
On 8/5/22 08:16, Stefan Herbrechtsmeier wrote:
> From: Stefan Herbrechtsmeier <stefan.herbrechtsmeier at weidmueller.com>
>
> Move arm twd timer driver from zynq to generic location.
>
> DM timer drivers are designed differently to original driver. Timer is
> counting up and not down.
> Information about clock rates are find out in timer_pre_probe() that's
> why there is no need to get any additional information from DT in the
> driver itself (only register offset).
>
> Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsmeier at weidmueller.com>
>
> ---
>
> arch/arm/Kconfig | 3 +
> arch/arm/dts/zynq-7000.dtsi | 1 +
> arch/arm/mach-zynq/Makefile | 1 -
> arch/arm/mach-zynq/clk.c | 6 +-
> arch/arm/mach-zynq/timer.c | 113 ----------------------------------
> drivers/timer/Kconfig | 6 ++
> drivers/timer/Makefile | 1 +
> drivers/timer/arm_twd_timer.c | 108 ++++++++++++++++++++++++++++++++
> 8 files changed, 123 insertions(+), 116 deletions(-)
> delete mode 100644 arch/arm/mach-zynq/timer.c
> create mode 100644 drivers/timer/arm_twd_timer.c
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 949ebb46ba..bccdc6dfd8 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1249,6 +1249,7 @@ config ARCH_VF610
>
> config ARCH_ZYNQ
> bool "Xilinx Zynq based platform"
> + select ARM_TWD_TIMER
> select CLK
> select CLK_ZYNQ
> select CPU_V7A
> @@ -1268,7 +1269,9 @@ config ARCH_ZYNQ
> select SPL_DM_SPI_FLASH if SPL
> select SPL_OF_CONTROL if SPL
> select SPL_SEPARATE_BSS if SPL
> + select SPL_TIMER if SPL
> select SUPPORT_SPL
> + select TIMER
> imply ARCH_EARLY_INIT_R
> imply BOARD_LATE_INIT
> imply CMD_CLK
> diff --git a/arch/arm/dts/zynq-7000.dtsi b/arch/arm/dts/zynq-7000.dtsi
> index 37155df0fd..a7ca00fb76 100644
> --- a/arch/arm/dts/zynq-7000.dtsi
> +++ b/arch/arm/dts/zynq-7000.dtsi
> @@ -416,6 +416,7 @@
> };
>
> scutimer: timer at f8f00600 {
> + u-boot,dm-pre-reloc;
> interrupt-parent = <&intc>;
> interrupts = <1 13 0x301>;
> compatible = "arm,cortex-a9-twd-timer";
> diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
> index 8737f434d9..d9b2b999e1 100644
> --- a/arch/arm/mach-zynq/Makefile
> +++ b/arch/arm/mach-zynq/Makefile
> @@ -6,7 +6,6 @@
> # (C) Copyright 2008
> # Guennadi Liakhovetki, DENX Software Engineering, <lg at denx.de>
>
> -obj-y := timer.o
> obj-y += cpu.o
> obj-y += ddrc.o
> obj-y += slcr.o
> diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c
> index 27f6bf2183..1945f60e08 100644
> --- a/arch/arm/mach-zynq/clk.c
> +++ b/arch/arm/mach-zynq/clk.c
> @@ -52,10 +52,12 @@ int set_cpu_clk_info(void)
> return ret;
>
> rate = clk_get_rate(&clk) / 1000000;
> - if (i)
> + if (i) {
> gd->bd->bi_ddr_freq = rate;
> - else
> + } else {
> gd->bd->bi_arm_freq = rate;
> + gd->cpu_clk = clk_get_rate(&clk);
> + }
>
> clk_free(&clk);
> }
> diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c
> deleted file mode 100644
> index a51822a530..0000000000
> --- a/arch/arm/mach-zynq/timer.c
> +++ /dev/null
> @@ -1,113 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0+
> -/*
> - * Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
> - * Stefan Herbrechtsmeier <stefan.herbrechtsmeier at weidmueller.com>
> - *
> - * Copyright (C) 2012 Michal Simek <monstr at monstr.eu>
> - * Copyright (C) 2011-2017 Xilinx, Inc. All rights reserved.
> - *
> - * (C) Copyright 2008
> - * Guennadi Liakhovetki, DENX Software Engineering, <lg at denx.de>
> - *
> - * (C) Copyright 2004
> - * Philippe Robin, ARM Ltd. <philippe.robin at arm.com>
> - *
> - * (C) Copyright 2002-2004
> - * Gary Jennejohn, DENX Software Engineering, <gj at denx.de>
> - *
> - * (C) Copyright 2003
> - * Texas Instruments <www.ti.com>
> - *
> - * (C) Copyright 2002
> - * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
> - * Marius Groeger <mgroeger at sysgo.de>
> - *
> - * (C) Copyright 2002
> - * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
> - * Alex Zuepke <azu at sysgo.de>
> - */
> -
> -#include <clk.h>
> -#include <common.h>
> -#include <div64.h>
> -#include <dm.h>
> -#include <init.h>
> -#include <time.h>
> -#include <malloc.h>
> -#include <asm/global_data.h>
> -#include <asm/io.h>
> -#include <asm/arch/hardware.h>
> -#include <asm/arch/clk.h>
> -
> -DECLARE_GLOBAL_DATA_PTR;
> -
> -struct scu_timer {
> - u32 load; /* Timer Load Register */
> - u32 counter; /* Timer Counter Register */
> - u32 control; /* Timer Control Register */
> -};
> -
> -static struct scu_timer *timer_base =
> - (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR;
> -
> -#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */
> -#define SCUTIMER_CONTROL_PRESCALER_SHIFT 8
> -#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */
> -#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */
> -
> -#define TIMER_LOAD_VAL 0xFFFFFFFF
> -#define TIMER_PRESCALE 255
> -
> -int timer_init(void)
> -{
> - const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
> - (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) |
> - SCUTIMER_CONTROL_ENABLE_MASK;
> -
> - struct udevice *dev;
> - struct clk clk;
> - int ret;
> -
> - ret = uclass_get_device_by_driver(UCLASS_CLK,
> - DM_DRIVER_GET(zynq_clk), &dev);
> - if (ret)
> - return ret;
> -
> - clk.id = cpu_6or4x_clk;
> - ret = clk_request(dev, &clk);
> - if (ret < 0)
> - return ret;
> -
> - gd->cpu_clk = clk_get_rate(&clk);
> -
> - clk_free(&clk);
> -
> - gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
> -
> - /* Load the timer counter register */
> - writel(0xFFFFFFFF, &timer_base->load);
> -
> - /*
> - * Start the A9Timer device
> - * Enable Auto reload mode, Clear prescaler control bits
> - * Set prescaler value, Enable the decrementer
> - */
> - clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK,
> - emask);
> -
> - /* Reset time */
> - gd->arch.lastinc = readl(&timer_base->counter) /
> - (gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
> - gd->arch.tbl = 0;
> -
> - return 0;
> -}
> -
> -/*
> - * This function is derived from PowerPC code (timebase clock frequency).
> - * On ARM it returns the number of timer ticks per second.
> - */
> -ulong get_tbclk(void)
> -{
> - return gd->arch.timer_rate_hz;
> -}
> diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
> index 20b5af7e26..1e2b6566c6 100644
> --- a/drivers/timer/Kconfig
> +++ b/drivers/timer/Kconfig
> @@ -73,6 +73,12 @@ config ARC_TIMER
> usually at least one of them exists. Either of them is supported
> in U-Boot.
>
> +config ARM_TWD_TIMER
> + bool "ARM timer watchdog (TWD) timer support"
> + depends on TIMER && CLK
> + help
> + Select this to enable support for the ARM global timer watchdog timer.
> +
> config AST_TIMER
> bool "Aspeed ast2400/ast2500 timer support"
> depends on TIMER
> diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
> index d9822a5370..4db03fe09c 100644
> --- a/drivers/timer/Makefile
> +++ b/drivers/timer/Makefile
> @@ -6,6 +6,7 @@ obj-y += timer-uclass.o
> obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
> obj-$(CONFIG_ANDES_PLMT_TIMER) += andes_plmt_timer.o
> obj-$(CONFIG_ARC_TIMER) += arc_timer.o
> +obj-$(CONFIG_ARM_TWD_TIMER) += arm_twd_timer.o
> obj-$(CONFIG_AST_TIMER) += ast_timer.o
> obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o
> obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o
> diff --git a/drivers/timer/arm_twd_timer.c b/drivers/timer/arm_twd_timer.c
> new file mode 100644
> index 0000000000..40ccd16587
> --- /dev/null
> +++ b/drivers/timer/arm_twd_timer.c
> @@ -0,0 +1,108 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2017-2022 Weidmüller Interface GmbH & Co. KG
> + * Stefan Herbrechtsmeier <stefan.herbrechtsmeier at weidmueller.com>
> + *
> + * Copyright (C) 2012 Michal Simek <monstr at monstr.eu>
> + * Copyright (C) 2011-2017 Xilinx, Inc. All rights reserved.
> + *
> + * (C) Copyright 2008
> + * Guennadi Liakhovetki, DENX Software Engineering, <lg at denx.de>
> + *
> + * (C) Copyright 2004
> + * Philippe Robin, ARM Ltd. <philippe.robin at arm.com>
> + *
> + * (C) Copyright 2002-2004
> + * Gary Jennejohn, DENX Software Engineering, <gj at denx.de>
> + *
> + * (C) Copyright 2003
> + * Texas Instruments <www.ti.com>
> + *
> + * (C) Copyright 2002
> + * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
> + * Marius Groeger <mgroeger at sysgo.de>
> + *
> + * (C) Copyright 2002
> + * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
> + * Alex Zuepke <azu at sysgo.de>
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <fdtdec.h>
> +#include <timer.h>
> +#include <linux/bitops.h>
> +
> +#include <asm/io.h>
> +
> +#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */
> +#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */
> +#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */
> +
> +#define TIMER_LOAD_VAL 0xFFFFFFFF
> +
> +struct arm_twd_timer_regs {
> + u32 load; /* Timer Load Register */
> + u32 counter; /* Timer Counter Register */
> + u32 control; /* Timer Control Register */
> +};
> +
> +struct arm_twd_timer_priv {
> + struct arm_twd_timer_regs *base;
> +};
> +
> +static u64 arm_twd_timer_get_count(struct udevice *dev)
> +{
> + struct arm_twd_timer_priv *priv = dev_get_priv(dev);
> + struct arm_twd_timer_regs *regs = priv->base;
> + u32 count = TIMER_LOAD_VAL - readl(®s->counter);
> +
> + return timer_conv_64(count);
> +}
> +
> +static int arm_twd_timer_probe(struct udevice *dev)
> +{
> + struct arm_twd_timer_priv *priv = dev_get_priv(dev);
> + struct arm_twd_timer_regs *regs;
> + fdt_addr_t addr;
> +
> + addr = dev_read_addr(dev);
> + if (addr == FDT_ADDR_T_NONE)
> + return -EINVAL;
> +
> + priv->base = (struct arm_twd_timer_regs *)addr;
> +
> + regs = priv->base;
> +
> + /* Load the timer counter register */
> + writel(0xFFFFFFFF, ®s->load);
> +
> + /*
> + * Start the A9Timer device
> + * Enable Auto reload mode, Clear prescaler control bits
> + * Set prescaler value, Enable the decrementer
> + */
> + clrsetbits_le32(®s->control, SCUTIMER_CONTROL_PRESCALER_MASK,
> + SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
> + SCUTIMER_CONTROL_ENABLE_MASK);
> +
> + return 0;
> +}
> +
> +static const struct timer_ops arm_twd_timer_ops = {
> + .get_count = arm_twd_timer_get_count,
> +};
> +
> +static const struct udevice_id arm_twd_timer_ids[] = {
> + { .compatible = "arm,cortex-a9-twd-timer" },
> + {}
> +};
> +
> +U_BOOT_DRIVER(arm_twd_timer) = {
> + .name = "arm_twd_timer",
> + .id = UCLASS_TIMER,
> + .of_match = arm_twd_timer_ids,
> + .priv_auto = sizeof(struct arm_twd_timer_priv),
> + .probe = arm_twd_timer_probe,
> + .ops = &arm_twd_timer_ops,
> +};
Looks good to me and also tested on HW.
Aoplied.
M
More information about the U-Boot
mailing list