xref: /OK3568_Linux_fs/u-boot/drivers/timer/rockchip_timer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <dm.h>
9*4882a593Smuzhiyun #include <dm/ofnode.h>
10*4882a593Smuzhiyun #include <mapmem.h>
11*4882a593Smuzhiyun #include <asm/arch/timer.h>
12*4882a593Smuzhiyun #include <dt-structs.h>
13*4882a593Smuzhiyun #include <timer.h>
14*4882a593Smuzhiyun #include <asm/io.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_PLATDATA)
19*4882a593Smuzhiyun struct rockchip_timer_plat {
20*4882a593Smuzhiyun 	struct dtd_rockchip_rk3368_timer dtd;
21*4882a593Smuzhiyun };
22*4882a593Smuzhiyun #endif
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* Driver private data. Contains timer id. Could be either 0 or 1. */
25*4882a593Smuzhiyun struct rockchip_timer_priv {
26*4882a593Smuzhiyun 	struct rk_timer *timer;
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun 
rockchip_timer_get_curr_value(struct rk_timer * timer)29*4882a593Smuzhiyun static inline int64_t rockchip_timer_get_curr_value(struct rk_timer *timer)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	uint64_t timebase_h, timebase_l;
32*4882a593Smuzhiyun 	uint64_t cntr;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	timebase_l = readl(&timer->timer_curr_value0);
35*4882a593Smuzhiyun 	timebase_h = readl(&timer->timer_curr_value1);
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	cntr = timebase_h << 32 | timebase_l;
38*4882a593Smuzhiyun 	return cntr;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(BOOTSTAGE)
timer_get_boot_us(void)42*4882a593Smuzhiyun ulong timer_get_boot_us(void)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	uint64_t  ticks = 0;
45*4882a593Smuzhiyun 	uint32_t  rate;
46*4882a593Smuzhiyun 	uint64_t  us;
47*4882a593Smuzhiyun 	int ret;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	ret = dm_timer_init();
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	if (!ret) {
52*4882a593Smuzhiyun 		/* The timer is available */
53*4882a593Smuzhiyun 		rate = timer_get_rate(gd->timer);
54*4882a593Smuzhiyun 		timer_get_count(gd->timer, &ticks);
55*4882a593Smuzhiyun #if !CONFIG_IS_ENABLED(OF_PLATDATA)
56*4882a593Smuzhiyun 	} else if (ret == -EAGAIN) {
57*4882a593Smuzhiyun 		/* We have been called so early that the DM is not ready,... */
58*4882a593Smuzhiyun 		ofnode node = offset_to_ofnode(-1);
59*4882a593Smuzhiyun 		struct rk_timer *timer = NULL;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 		/*
62*4882a593Smuzhiyun 		 * ... so we try to access the raw timer, if it is specified
63*4882a593Smuzhiyun 		 * via the tick-timer property in /chosen.
64*4882a593Smuzhiyun 		 */
65*4882a593Smuzhiyun 		node = ofnode_get_chosen_node("tick-timer");
66*4882a593Smuzhiyun 		if (!ofnode_valid(node)) {
67*4882a593Smuzhiyun 			debug("%s: no /chosen/tick-timer\n", __func__);
68*4882a593Smuzhiyun 			return 0;
69*4882a593Smuzhiyun 		}
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 		timer = (struct rk_timer *)ofnode_get_addr(node);
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 		/* This timer is down-counting */
74*4882a593Smuzhiyun 		ticks = ~0uLL - rockchip_timer_get_curr_value(timer);
75*4882a593Smuzhiyun 		if (ofnode_read_u32(node, "clock-frequency", &rate)) {
76*4882a593Smuzhiyun 			debug("%s: could not read clock-frequency\n", __func__);
77*4882a593Smuzhiyun 			return 0;
78*4882a593Smuzhiyun 		}
79*4882a593Smuzhiyun #endif
80*4882a593Smuzhiyun 	} else {
81*4882a593Smuzhiyun 		return 0;
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	us = (ticks * 1000) / rate;
85*4882a593Smuzhiyun 	return us;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun #endif
88*4882a593Smuzhiyun 
rockchip_timer_get_count(struct udevice * dev,u64 * count)89*4882a593Smuzhiyun static int rockchip_timer_get_count(struct udevice *dev, u64 *count)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct rockchip_timer_priv *priv = dev_get_priv(dev);
92*4882a593Smuzhiyun 	uint64_t cntr = rockchip_timer_get_curr_value(priv->timer);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	/* timers are down-counting */
95*4882a593Smuzhiyun 	*count = ~0ull - cntr;
96*4882a593Smuzhiyun 	return 0;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
rockchip_clk_ofdata_to_platdata(struct udevice * dev)99*4882a593Smuzhiyun static int rockchip_clk_ofdata_to_platdata(struct udevice *dev)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun #if !CONFIG_IS_ENABLED(OF_PLATDATA)
102*4882a593Smuzhiyun 	struct rockchip_timer_priv *priv = dev_get_priv(dev);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	priv->timer = dev_read_addr_ptr(dev);
105*4882a593Smuzhiyun 	if (!priv->timer)
106*4882a593Smuzhiyun 		return -ENOENT;
107*4882a593Smuzhiyun #endif
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
rockchip_timer_start(struct udevice * dev)112*4882a593Smuzhiyun static int rockchip_timer_start(struct udevice *dev)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	struct rockchip_timer_priv *priv = dev_get_priv(dev);
115*4882a593Smuzhiyun 	const uint64_t reload_val = ~0uLL;
116*4882a593Smuzhiyun 	const uint32_t reload_val_l = reload_val & 0xffffffff;
117*4882a593Smuzhiyun 	const uint32_t reload_val_h = reload_val >> 32;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	/* don't reinit, if the timer is already running and set up */
120*4882a593Smuzhiyun 	if ((readl(&priv->timer->timer_ctrl_reg) & 1) == 1 &&
121*4882a593Smuzhiyun 	    (readl(&priv->timer->timer_load_count0) == reload_val_l) &&
122*4882a593Smuzhiyun 	    (readl(&priv->timer->timer_load_count1) == reload_val_h))
123*4882a593Smuzhiyun 		return 0;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	/* disable timer and reset all control */
126*4882a593Smuzhiyun 	writel(0, &priv->timer->timer_ctrl_reg);
127*4882a593Smuzhiyun 	/* write reload value */
128*4882a593Smuzhiyun 	writel(reload_val_l, &priv->timer->timer_load_count0);
129*4882a593Smuzhiyun 	writel(reload_val_h, &priv->timer->timer_load_count1);
130*4882a593Smuzhiyun 	/* enable timer */
131*4882a593Smuzhiyun 	writel(1, &priv->timer->timer_ctrl_reg);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	return 0;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
rockchip_timer_probe(struct udevice * dev)136*4882a593Smuzhiyun static int rockchip_timer_probe(struct udevice *dev)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_PLATDATA)
139*4882a593Smuzhiyun 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
140*4882a593Smuzhiyun 	struct rockchip_timer_priv *priv = dev_get_priv(dev);
141*4882a593Smuzhiyun 	struct rockchip_timer_plat *plat = dev_get_platdata(dev);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	priv->timer = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
144*4882a593Smuzhiyun 	uc_priv->clock_rate = plat->dtd.clock_frequency;
145*4882a593Smuzhiyun #endif
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	return rockchip_timer_start(dev);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun static const struct timer_ops rockchip_timer_ops = {
151*4882a593Smuzhiyun 	.get_count = rockchip_timer_get_count,
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun static const struct udevice_id rockchip_timer_ids[] = {
155*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3368-timer" },
156*4882a593Smuzhiyun 	{}
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun U_BOOT_DRIVER(rockchip_rk3368_timer) = {
160*4882a593Smuzhiyun 	.name	= "rockchip_rk3368_timer",
161*4882a593Smuzhiyun 	.id	= UCLASS_TIMER,
162*4882a593Smuzhiyun 	.of_match = rockchip_timer_ids,
163*4882a593Smuzhiyun 	.probe = rockchip_timer_probe,
164*4882a593Smuzhiyun 	.ops	= &rockchip_timer_ops,
165*4882a593Smuzhiyun 	.flags = DM_FLAG_PRE_RELOC,
166*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct rockchip_timer_priv),
167*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_PLATDATA)
168*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct rockchip_timer_plat),
169*4882a593Smuzhiyun #endif
170*4882a593Smuzhiyun 	.ofdata_to_platdata = rockchip_clk_ofdata_to_platdata,
171*4882a593Smuzhiyun };
172