xref: /openbmc/u-boot/arch/arm/mach-zynq/timer.c (revision 76b00aca)
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 	struct udevice *dev;
65 	struct clk clk;
66 	int ret;
67 
68 	ret = uclass_get_device_by_driver(UCLASS_CLK,
69 		DM_GET_DRIVER(zynq_clk), &dev);
70 	if (ret)
71 		return ret;
72 
73 	clk.id = cpu_6or4x_clk;
74 	ret = clk_request(dev, &clk);
75 	if (ret < 0)
76 		return ret;
77 
78 	gd->cpu_clk = clk_get_rate(&clk);
79 
80 	clk_free(&clk);
81 
82 	gd->arch.timer_rate_hz = (gd->cpu_clk / 2) / (TIMER_PRESCALE + 1);
83 
84 	/* Load the timer counter register */
85 	writel(0xFFFFFFFF, &timer_base->load);
86 
87 	/*
88 	 * Start the A9Timer device
89 	 * Enable Auto reload mode, Clear prescaler control bits
90 	 * Set prescaler value, Enable the decrementer
91 	 */
92 	clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK,
93 								emask);
94 
95 	/* Reset time */
96 	gd->arch.lastinc = readl(&timer_base->counter) /
97 				(gd->arch.timer_rate_hz / CONFIG_SYS_HZ);
98 	gd->arch.tbl = 0;
99 
100 	return 0;
101 }
102 
103 /*
104  * This function is derived from PowerPC code (timebase clock frequency).
105  * On ARM it returns the number of timer ticks per second.
106  */
107 ulong get_tbclk(void)
108 {
109 	return gd->arch.timer_rate_hz;
110 }
111