Blame view

drivers/timer/rockchip_timer.c 4.29 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
2
3
  /*
   * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
4
5
6
7
   */
  
  #include <common.h>
  #include <dm.h>
cc7ce94e0   Philipp Tomsich   rockchip: timer: ...
8
  #include <dm/ofnode.h>
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  #include <mapmem.h>
  #include <asm/arch/timer.h>
  #include <dt-structs.h>
  #include <timer.h>
  #include <asm/io.h>
  
  DECLARE_GLOBAL_DATA_PTR;
  
  #if CONFIG_IS_ENABLED(OF_PLATDATA)
  struct rockchip_timer_plat {
  	struct dtd_rockchip_rk3368_timer dtd;
  };
  #endif
  
  /* Driver private data. Contains timer id. Could be either 0 or 1. */
  struct rockchip_timer_priv {
  	struct rk_timer *timer;
  };
cc7ce94e0   Philipp Tomsich   rockchip: timer: ...
27
  static inline int64_t rockchip_timer_get_curr_value(struct rk_timer *timer)
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
28
  {
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
29
30
  	uint64_t timebase_h, timebase_l;
  	uint64_t cntr;
cc7ce94e0   Philipp Tomsich   rockchip: timer: ...
31
32
  	timebase_l = readl(&timer->timer_curr_value0);
  	timebase_h = readl(&timer->timer_curr_value1);
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
33

1168d2dd4   Philipp Tomsich   rockchip: timer: ...
34
  	cntr = timebase_h << 32 | timebase_l;
cc7ce94e0   Philipp Tomsich   rockchip: timer: ...
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  	return cntr;
  }
  
  #if CONFIG_IS_ENABLED(BOOTSTAGE)
  ulong timer_get_boot_us(void)
  {
  	uint64_t  ticks = 0;
  	uint32_t  rate;
  	uint64_t  us;
  	int ret;
  
  	ret = dm_timer_init();
  
  	if (!ret) {
  		/* The timer is available */
  		rate = timer_get_rate(gd->timer);
  		timer_get_count(gd->timer, &ticks);
  #if !CONFIG_IS_ENABLED(OF_PLATDATA)
  	} else if (ret == -EAGAIN) {
  		/* We have been called so early that the DM is not ready,... */
  		ofnode node = offset_to_ofnode(-1);
  		struct rk_timer *timer = NULL;
  
  		/*
  		 * ... so we try to access the raw timer, if it is specified
  		 * via the tick-timer property in /chosen.
  		 */
  		node = ofnode_get_chosen_node("tick-timer");
  		if (!ofnode_valid(node)) {
  			debug("%s: no /chosen/tick-timer
  ", __func__);
  			return 0;
  		}
  
  		timer = (struct rk_timer *)ofnode_get_addr(node);
  
  		/* This timer is down-counting */
  		ticks = ~0uLL - rockchip_timer_get_curr_value(timer);
  		if (ofnode_read_u32(node, "clock-frequency", &rate)) {
  			debug("%s: could not read clock-frequency
  ", __func__);
  			return 0;
  		}
  #endif
  	} else {
  		return 0;
  	}
  
  	us = (ticks * 1000) / rate;
  	return us;
  }
  #endif
  
  static int rockchip_timer_get_count(struct udevice *dev, u64 *count)
  {
  	struct rockchip_timer_priv *priv = dev_get_priv(dev);
  	uint64_t cntr = rockchip_timer_get_curr_value(priv->timer);
  
  	/* timers are down-counting */
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
94
95
96
97
98
99
100
101
  	*count = ~0ull - cntr;
  	return 0;
  }
  
  static int rockchip_clk_ofdata_to_platdata(struct udevice *dev)
  {
  #if !CONFIG_IS_ENABLED(OF_PLATDATA)
  	struct rockchip_timer_priv *priv = dev_get_priv(dev);
6675c952f   Philipp Tomsich   rockchip: timer: ...
102
103
104
  	priv->timer = dev_read_addr_ptr(dev);
  	if (!priv->timer)
  		return -ENOENT;
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
105
106
107
108
109
110
111
112
113
114
115
  #endif
  
  	return 0;
  }
  
  static int rockchip_timer_start(struct udevice *dev)
  {
  	struct rockchip_timer_priv *priv = dev_get_priv(dev);
  	const uint64_t reload_val = ~0uLL;
  	const uint32_t reload_val_l = reload_val & 0xffffffff;
  	const uint32_t reload_val_h = reload_val >> 32;
cc7ce94e0   Philipp Tomsich   rockchip: timer: ...
116
117
118
119
120
  	/* don't reinit, if the timer is already running and set up */
  	if ((readl(&priv->timer->timer_ctrl_reg) & 1) == 1 &&
  	    (readl(&priv->timer->timer_load_count0) == reload_val_l) &&
  	    (readl(&priv->timer->timer_load_count1) == reload_val_h))
  		return 0;
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  	/* disable timer and reset all control */
  	writel(0, &priv->timer->timer_ctrl_reg);
  	/* write reload value */
  	writel(reload_val_l, &priv->timer->timer_load_count0);
  	writel(reload_val_h, &priv->timer->timer_load_count1);
  	/* enable timer */
  	writel(1, &priv->timer->timer_ctrl_reg);
  
  	return 0;
  }
  
  static int rockchip_timer_probe(struct udevice *dev)
  {
  #if CONFIG_IS_ENABLED(OF_PLATDATA)
  	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
  	struct rockchip_timer_priv *priv = dev_get_priv(dev);
  	struct rockchip_timer_plat *plat = dev_get_platdata(dev);
8158a848f   Philipp Tomsich   rockchip: timer: ...
138
  	priv->timer = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
139
140
141
142
143
144
145
146
147
148
149
  	uc_priv->clock_rate = plat->dtd.clock_frequency;
  #endif
  
  	return rockchip_timer_start(dev);
  }
  
  static const struct timer_ops rockchip_timer_ops = {
  	.get_count = rockchip_timer_get_count,
  };
  
  static const struct udevice_id rockchip_timer_ids[] = {
e0e1d3f98   Philipp Tomsich   rockchip: timer: ...
150
151
  	{ .compatible = "rockchip,rk3188-timer" },
  	{ .compatible = "rockchip,rk3288-timer" },
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
152
153
154
  	{ .compatible = "rockchip,rk3368-timer" },
  	{}
  };
5798d503f   Philipp Tomsich   rockchip: timer: ...
155
  U_BOOT_DRIVER(rockchip_rk3368_timer) = {
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
156
157
158
159
160
  	.name	= "rockchip_rk3368_timer",
  	.id	= UCLASS_TIMER,
  	.of_match = rockchip_timer_ids,
  	.probe = rockchip_timer_probe,
  	.ops	= &rockchip_timer_ops,
1168d2dd4   Philipp Tomsich   rockchip: timer: ...
161
162
163
164
165
166
  	.priv_auto_alloc_size = sizeof(struct rockchip_timer_priv),
  #if CONFIG_IS_ENABLED(OF_PLATDATA)
  	.platdata_auto_alloc_size = sizeof(struct rockchip_timer_plat),
  #endif
  	.ofdata_to_platdata = rockchip_clk_ofdata_to_platdata,
  };