[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(&regs->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, &regs->load);
> +
> +	/*
> +	 * Start the A9Timer device
> +	 * Enable Auto reload mode, Clear prescaler control bits
> +	 * Set prescaler value, Enable the decrementer
> +	 */
> +	clrsetbits_le32(&regs->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