[U-Boot] [PATCH 1/3] timer: dw-apb: Add Designware APB timer driver

Add timer driver for the Designware APB Timer IP. This is present for example on the Altera SoCFPGA chips.
Signed-off-by: Marek Vasut marex@denx.de Cc: Chin Liang See chin.liang.see@intel.com Cc: Dinh Nguyen dinguyen@kernel.org Cc: Ley Foon Tan ley.foon.tan@intel.com --- drivers/timer/Kconfig | 7 ++++ drivers/timer/Makefile | 1 + drivers/timer/dw-apb-timer.c | 90 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 drivers/timer/dw-apb-timer.c
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 8a31397553..5ab6749193 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -59,6 +59,13 @@ config CADENCE_TTC_TIMER Enables support for the cadence ttc driver. This driver is present on Xilinx Zynq and ZynqMP SoCs.
+config DESIGNWARE_APB_TIMER + bool "Designware APB Timer" + depends on TIMER + help + Enables support for the Designware APB Timer driver. This timer is + present on Altera SoCFPGA SoCs. + config SANDBOX_TIMER bool "Sandbox timer support" depends on SANDBOX && TIMER diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index ee2fcb1fa7..0c8a62767a 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -5,6 +5,7 @@ obj-y += timer-uclass.o obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o +obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o obj-$(CONFIG_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_OMAP_TIMER) += omap-timer.o diff --git a/drivers/timer/dw-apb-timer.c b/drivers/timer/dw-apb-timer.c new file mode 100644 index 0000000000..031f429acb --- /dev/null +++ b/drivers/timer/dw-apb-timer.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Designware APB Timer driver + * + * Copyright (C) 2018 Marek Vasut marex@denx.de + */ + +#include <common.h> +#include <dm.h> +#include <clk.h> +#include <timer.h> + +#include <asm/io.h> +#include <asm/arch/timer.h> + +#define DW_APB_LOAD_VAL 0x0 +#define DW_APB_CURR_VAL 0x4 +#define DW_APB_CTRL 0x8 + +DECLARE_GLOBAL_DATA_PTR; + +struct dw_apb_timer_priv { + fdt_addr_t regs; +}; + +static int dw_apb_timer_get_count(struct udevice *dev, u64 *count) +{ + struct dw_apb_timer_priv *priv = dev_get_priv(dev); + + /* + * The DW APB counter counts down, but this function + * requires the count to be incrementing. Invert the + * result. + */ + *count = ~readl(priv->regs + DW_APB_CURR_VAL); + + return 0; +} + +static int dw_apb_timer_probe(struct udevice *dev) +{ + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct dw_apb_timer_priv *priv = dev_get_priv(dev); + struct clk clk; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + uc_priv->clock_rate = clk_get_rate(&clk); + + clk_free(&clk); + + /* init timer */ + writel(0xffffffff, priv->regs + DW_APB_LOAD_VAL); + writel(0xffffffff, priv->regs + DW_APB_CURR_VAL); + setbits_le32(priv->regs + DW_APB_CTRL, 0x3); + + return 0; +} + +static int dw_apb_timer_ofdata_to_platdata(struct udevice *dev) +{ + struct dw_apb_timer_priv *priv = dev_get_priv(dev); + + priv->regs = dev_read_addr(dev); + + return 0; +} + +static const struct timer_ops dw_apb_timer_ops = { + .get_count = dw_apb_timer_get_count, +}; + +static const struct udevice_id dw_apb_timer_ids[] = { + { .compatible = "snps,dw-apb-timer" }, + {} +}; + +U_BOOT_DRIVER(dw_apb_timer) = { + .name = "dw_apb_timer", + .id = UCLASS_TIMER, + .ops = &dw_apb_timer_ops, + .probe = dw_apb_timer_probe, + .flags = DM_FLAG_PRE_RELOC, + .of_match = dw_apb_timer_ids, + .ofdata_to_platdata = dw_apb_timer_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct dw_apb_timer_priv), +};

Flag timer clock as DM pre-reloc, so that a timer driver can be used and it can extract information about it's clock rate using the clock framework. This patch also moves some of the pre-reloc flags into the core dtsi file, this is because the timer is not board specific, but rather is used on all boards.
Signed-off-by: Marek Vasut marex@denx.de Cc: Chin Liang See chin.liang.see@intel.com Cc: Dinh Nguyen dinguyen@kernel.org Cc: Ley Foon Tan ley.foon.tan@intel.com --- arch/arm/dts/socfpga_arria10.dtsi | 10 ++++++++++ arch/arm/dts/socfpga_arria10_socdk.dtsi | 12 ------------ 2 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/arch/arm/dts/socfpga_arria10.dtsi b/arch/arm/dts/socfpga_arria10.dtsi index ce000512ef..573974be04 100644 --- a/arch/arm/dts/socfpga_arria10.dtsi +++ b/arch/arm/dts/socfpga_arria10.dtsi @@ -21,6 +21,11 @@ #address-cells = <1>; #size-cells = <1>;
+ chosen { + tick-timer = &timer2; + u-boot,dm-pre-reloc; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -147,6 +152,7 @@ compatible = "altr,socfpga-a10-perip-clk"; clocks = <&main_pll>; div-reg = <0x144 0 11>; + u-boot,dm-pre-reloc; };
main_emaca_clk: main_emaca_clk@68 { @@ -236,6 +242,7 @@ compatible = "altr,socfpga-a10-perip-clk"; clocks = <&periph_pll>; div-reg = <0x144 16 11>; + u-boot,dm-pre-reloc; };
peri_emaca_clk: peri_emaca_clk@e8 { @@ -311,6 +318,7 @@ <&osc1>, <&cb_intosc_hs_div2_clk>, <&f2s_free_clk>; reg = <0x64>; + u-boot,dm-pre-reloc; };
s2f_user1_free_clk: s2f_user1_free_clk@104 { @@ -337,6 +345,7 @@ compatible = "altr,socfpga-a10-perip-clk"; clocks = <&noc_free_clk>; fixed-divider = <4>; + u-boot,dm-pre-reloc; };
l4_main_clk: l4_main_clk { @@ -800,6 +809,7 @@ reg = <0xffd00000 0x100>; clocks = <&l4_sys_free_clk>; clock-names = "timer"; + u-boot,dm-pre-reloc; };
timer3: timer3@ffd00100 { diff --git a/arch/arm/dts/socfpga_arria10_socdk.dtsi b/arch/arm/dts/socfpga_arria10_socdk.dtsi index 9160c20bd0..17e0b75a8f 100644 --- a/arch/arm/dts/socfpga_arria10_socdk.dtsi +++ b/arch/arm/dts/socfpga_arria10_socdk.dtsi @@ -169,22 +169,10 @@ };
/* Clock available early */ -&main_noc_base_clk { - u-boot,dm-pre-reloc; -}; - &main_periph_ref_clk { u-boot,dm-pre-reloc; };
-&peri_noc_base_clk { - u-boot,dm-pre-reloc; -}; - -&noc_free_clk { - u-boot,dm-pre-reloc; -}; - &l4_mp_clk { u-boot,dm-pre-reloc; };

Switch the Arria10 from ad-hoc hardcoded timer to timer framework and the DW APB timer driver. This allows the A10 to extract timer information, like timer rate, from clock framework and thus DT instead of having it hardcoded in U-Boot configuration files.
Signed-off-by: Marek Vasut marex@denx.de Cc: Chin Liang See chin.liang.see@intel.com Cc: Dinh Nguyen dinguyen@kernel.org Cc: Ley Foon Tan ley.foon.tan@intel.com --- arch/arm/mach-socfpga/Makefile | 1 - configs/socfpga_arria10_defconfig | 3 +++ include/configs/socfpga_common.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 654999cdf6..e66720447f 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -26,7 +26,6 @@ obj-y += clock_manager_arria10.o obj-y += misc_arria10.o obj-y += pinmux_arria10.o obj-y += reset_manager_arria10.o -obj-y += timer.o endif
ifdef CONFIG_TARGET_SOCFPGA_STRATIX10 diff --git a/configs/socfpga_arria10_defconfig b/configs/socfpga_arria10_defconfig index 4b0d47489a..a504035547 100644 --- a/configs/socfpga_arria10_defconfig +++ b/configs/socfpga_arria10_defconfig @@ -39,4 +39,7 @@ CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_MII=y CONFIG_SPI=y +CONFIG_TIMER=y +CONFIG_SPL_TIMER=y +CONFIG_DESIGNWARE_APB_TIMER=y CONFIG_USE_TINY_PRINTF=y diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h index 440a918fc7..2330143cf1 100644 --- a/include/configs/socfpga_common.h +++ b/include/configs/socfpga_common.h @@ -86,11 +86,13 @@ /* * L4 OSC1 Timer 0 */ +#ifndef CONFIG_TIMER /* This timer uses eosc1, whose clock frequency is fixed at any condition. */ #define CONFIG_SYS_TIMERBASE SOCFPGA_OSC1TIMER0_ADDRESS #define CONFIG_SYS_TIMER_COUNTS_DOWN #define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMERBASE + 0x4) #define CONFIG_SYS_TIMER_RATE 25000000 +#endif
/* * L4 Watchdog
participants (1)
-
Marek Vasut