zynq: Convert arm twd timer to DM driver

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@weidmueller.com>
Link: https://lore.kernel.org/r/20220805061629.1207-1-stefan.herbrechtsmeier-oss@weidmueller.com
Signed-off-by: Michal Simek <michal.simek@amd.com>
This commit is contained in:
Stefan Herbrechtsmeier 2022-08-05 08:16:28 +02:00 committed by Michal Simek
parent 98b3a998b3
commit b7e0750d88
8 changed files with 123 additions and 116 deletions

View File

@ -1259,6 +1259,7 @@ config ARCH_VF610
config ARCH_ZYNQ config ARCH_ZYNQ
bool "Xilinx Zynq based platform" bool "Xilinx Zynq based platform"
select ARM_TWD_TIMER
select CLK select CLK
select CLK_ZYNQ select CLK_ZYNQ
select CPU_V7A select CPU_V7A
@ -1278,7 +1279,9 @@ config ARCH_ZYNQ
select SPL_DM_SPI_FLASH if SPL select SPL_DM_SPI_FLASH if SPL
select SPL_OF_CONTROL if SPL select SPL_OF_CONTROL if SPL
select SPL_SEPARATE_BSS if SPL select SPL_SEPARATE_BSS if SPL
select SPL_TIMER if SPL
select SUPPORT_SPL select SUPPORT_SPL
select TIMER
imply ARCH_EARLY_INIT_R imply ARCH_EARLY_INIT_R
imply BOARD_LATE_INIT imply BOARD_LATE_INIT
imply CMD_CLK imply CMD_CLK

View File

@ -416,6 +416,7 @@
}; };
scutimer: timer@f8f00600 { scutimer: timer@f8f00600 {
u-boot,dm-pre-reloc;
interrupt-parent = <&intc>; interrupt-parent = <&intc>;
interrupts = <1 13 0x301>; interrupts = <1 13 0x301>;
compatible = "arm,cortex-a9-twd-timer"; compatible = "arm,cortex-a9-twd-timer";

View File

@ -6,7 +6,6 @@
# (C) Copyright 2008 # (C) Copyright 2008
# Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de> # Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
obj-y := timer.o
obj-y += cpu.o obj-y += cpu.o
obj-y += ddrc.o obj-y += ddrc.o
obj-y += slcr.o obj-y += slcr.o

View File

@ -52,10 +52,12 @@ int set_cpu_clk_info(void)
return ret; return ret;
rate = clk_get_rate(&clk) / 1000000; rate = clk_get_rate(&clk) / 1000000;
if (i) if (i) {
gd->bd->bi_ddr_freq = rate; gd->bd->bi_ddr_freq = rate;
else } else {
gd->bd->bi_arm_freq = rate; gd->bd->bi_arm_freq = rate;
gd->cpu_clk = clk_get_rate(&clk);
}
clk_free(&clk); clk_free(&clk);
} }

View File

@ -1,113 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
* Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
*
* Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2011-2017 Xilinx, Inc. All rights reserved.
*
* (C) Copyright 2008
* Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
*
* (C) Copyright 2004
* Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
*
* (C) Copyright 2002-2004
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
*
* (C) Copyright 2003
* Texas Instruments <www.ti.com>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@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;
}

View File

@ -73,6 +73,12 @@ config ARC_TIMER
usually at least one of them exists. Either of them is supported usually at least one of them exists. Either of them is supported
in U-Boot. 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 config AST_TIMER
bool "Aspeed ast2400/ast2500 timer support" bool "Aspeed ast2400/ast2500 timer support"
depends on TIMER depends on TIMER

View File

@ -6,6 +6,7 @@ obj-y += timer-uclass.o
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
obj-$(CONFIG_ANDES_PLMT_TIMER) += andes_plmt_timer.o obj-$(CONFIG_ANDES_PLMT_TIMER) += andes_plmt_timer.o
obj-$(CONFIG_ARC_TIMER) += arc_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_AST_TIMER) += ast_timer.o
obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o
obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o

View File

@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2017-2022 Weidmüller Interface GmbH & Co. KG
* Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
*
* Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2011-2017 Xilinx, Inc. All rights reserved.
*
* (C) Copyright 2008
* Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
*
* (C) Copyright 2004
* Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
*
* (C) Copyright 2002-2004
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
*
* (C) Copyright 2003
* Texas Instruments <www.ti.com>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Alex Zuepke <azu@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,
};