xref: /rk3399_rockchip-uboot/arch/arm/mach-zynq/timer.c (revision f96fccba7152dac3e83bfe3366932b9d78a98293)
1 /*
2  * Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG
3  * Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
4  *
5  * Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
6  * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
7  *
8  * (C) Copyright 2008
9  * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
10  *
11  * (C) Copyright 2004
12  * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
13  *
14  * (C) Copyright 2002-2004
15  * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
16  *
17  * (C) Copyright 2003
18  * Texas Instruments <www.ti.com>
19  *
20  * (C) Copyright 2002
21  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
22  * Marius Groeger <mgroeger@sysgo.de>
23  *
24  * (C) Copyright 2002
25  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
26  * Alex Zuepke <azu@sysgo.de>
27  *
28  * SPDX-License-Identifier:	GPL-2.0+
29  */
30 
31 #include <clk.h>
32 #include <common.h>
33 #include <div64.h>
34 #include <dm.h>
35 #include <asm/io.h>
36 #include <asm/arch/hardware.h>
37 #include <asm/arch/clk.h>
38 
39 DECLARE_GLOBAL_DATA_PTR;
40 
41 struct scu_timer {
42 	u32 load; /* Timer Load Register */
43 	u32 counter; /* Timer Counter Register */
44 	u32 control; /* Timer Control Register */
45 };
46 
47 static struct scu_timer *timer_base =
48 			      (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR;
49 
50 #define SCUTIMER_CONTROL_PRESCALER_MASK	0x0000FF00 /* Prescaler */
51 #define SCUTIMER_CONTROL_PRESCALER_SHIFT	8
52 #define SCUTIMER_CONTROL_AUTO_RELOAD_MASK	0x00000002 /* Auto-reload */
53 #define SCUTIMER_CONTROL_ENABLE_MASK		0x00000001 /* Timer enable */
54 
55 #define TIMER_LOAD_VAL 0xFFFFFFFF
56 #define TIMER_PRESCALE 255
57 
58 int timer_init(void)
59 {
60 	const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK |
61 			(TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) |
62 			SCUTIMER_CONTROL_ENABLE_MASK;
63 
64 #if defined(CONFIG_CLK) || defined(CONFIG_SPL_CLK)
65 	struct udevice *dev;
66 	struct clk clk;
67 	int ret;
68 
69 	ret = uclass_get_device_by_driver(UCLASS_CLK,
70 		DM_GET_DRIVER(zynq_clk), &dev);
71 	if (ret)
72 		return ret;
73 
74 	clk.id = cpu_6or4x_clk;
75 	ret = clk_request(dev, &clk);
76 	if (ret < 0)
77 		return ret;
78 
79 	gd->cpu_clk = clk_get_rate(&clk);
80 
81 	clk_free(&clk);
82 #endif
83 
84 	gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
85 
86 	/* Load the timer counter register */
87 	writel(0xFFFFFFFF, &timer_base->load);
88 
89 	/*
90 	 * Start the A9Timer device
91 	 * Enable Auto reload mode, Clear prescaler control bits
92 	 * Set prescaler value, Enable the decrementer
93 	 */
94 	clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK,
95 								emask);
96 
97 	/* Reset time */
98 	gd->arch.lastinc = readl(&timer_base->counter) /
99 				(gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
100 	gd->arch.tbl = 0;
101 
102 	return 0;
103 }
104 
105 /*
106  * This function is derived from PowerPC code (timebase clock frequency).
107  * On ARM it returns the number of timer ticks per second.
108  */
109 ulong get_tbclk(void)
110 {
111 	return gd->arch.timer_rate_hz;
112 }
113