1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016-2017 Socionext Inc.
4  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5  */
6 
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <dm/device_compat.h>
11 #include <linux/bitops.h>
12 #include <linux/bug.h>
13 #include <linux/io.h>
14 #include <linux/sizes.h>
15 
16 #include "clk-uniphier.h"
17 
18 /**
19  * struct uniphier_clk_priv - private data for UniPhier clock driver
20  *
21  * @base: base address of the clock provider
22  * @data: SoC specific data
23  */
24 struct uniphier_clk_priv {
25 	struct udevice *dev;
26 	void __iomem *base;
27 	const struct uniphier_clk_data *data;
28 };
29 
uniphier_clk_gate_enable(struct uniphier_clk_priv * priv,const struct uniphier_clk_gate_data * gate)30 static void uniphier_clk_gate_enable(struct uniphier_clk_priv *priv,
31 				     const struct uniphier_clk_gate_data *gate)
32 {
33 	u32 val;
34 
35 	val = readl(priv->base + gate->reg);
36 	val |= BIT(gate->bit);
37 	writel(val, priv->base + gate->reg);
38 }
39 
uniphier_clk_mux_set_parent(struct uniphier_clk_priv * priv,const struct uniphier_clk_mux_data * mux,u8 id)40 static void uniphier_clk_mux_set_parent(struct uniphier_clk_priv *priv,
41 					const struct uniphier_clk_mux_data *mux,
42 					u8 id)
43 {
44 	u32 val;
45 	int i;
46 
47 	for (i = 0; i < mux->num_parents; i++) {
48 		if (mux->parent_ids[i] != id)
49 			continue;
50 
51 		val = readl(priv->base + mux->reg);
52 		val &= ~mux->masks[i];
53 		val |= mux->vals[i];
54 		writel(val, priv->base + mux->reg);
55 		return;
56 	}
57 
58 	WARN_ON(1);
59 }
60 
uniphier_clk_mux_get_parent(struct uniphier_clk_priv * priv,const struct uniphier_clk_mux_data * mux)61 static u8 uniphier_clk_mux_get_parent(struct uniphier_clk_priv *priv,
62 				      const struct uniphier_clk_mux_data *mux)
63 {
64 	u32 val;
65 	int i;
66 
67 	val = readl(priv->base + mux->reg);
68 
69 	for (i = 0; i < mux->num_parents; i++)
70 		if ((mux->masks[i] & val) == mux->vals[i])
71 			return mux->parent_ids[i];
72 
73 	dev_err(priv->dev, "invalid mux setting\n");
74 
75 	return UNIPHIER_CLK_ID_INVALID;
76 }
77 
uniphier_clk_get_data(struct uniphier_clk_priv * priv,u8 id)78 static const struct uniphier_clk_data *uniphier_clk_get_data(
79 					struct uniphier_clk_priv *priv, u8 id)
80 {
81 	const struct uniphier_clk_data *data;
82 
83 	for (data = priv->data; data->type != UNIPHIER_CLK_TYPE_END; data++)
84 		if (data->id == id)
85 			return data;
86 
87 	dev_err(priv->dev, "id=%u not found\n", id);
88 
89 	return NULL;
90 }
91 
uniphier_clk_get_parent_data(struct uniphier_clk_priv * priv,const struct uniphier_clk_data * data)92 static const struct uniphier_clk_data *uniphier_clk_get_parent_data(
93 					struct uniphier_clk_priv *priv,
94 					const struct uniphier_clk_data *data)
95 {
96 	const struct uniphier_clk_data *parent_data;
97 	u8 parent_id = UNIPHIER_CLK_ID_INVALID;
98 
99 	switch (data->type) {
100 	case UNIPHIER_CLK_TYPE_GATE:
101 		parent_id = data->data.gate.parent_id;
102 		break;
103 	case UNIPHIER_CLK_TYPE_MUX:
104 		parent_id = uniphier_clk_mux_get_parent(priv, &data->data.mux);
105 		break;
106 	default:
107 		break;
108 	}
109 
110 	if (parent_id == UNIPHIER_CLK_ID_INVALID)
111 		return NULL;
112 
113 	parent_data = uniphier_clk_get_data(priv, parent_id);
114 
115 	WARN_ON(!parent_data);
116 
117 	return parent_data;
118 }
119 
__uniphier_clk_enable(struct uniphier_clk_priv * priv,const struct uniphier_clk_data * data)120 static void __uniphier_clk_enable(struct uniphier_clk_priv *priv,
121 				  const struct uniphier_clk_data *data)
122 {
123 	const struct uniphier_clk_data *parent_data;
124 
125 	if (data->type == UNIPHIER_CLK_TYPE_GATE)
126 		uniphier_clk_gate_enable(priv, &data->data.gate);
127 
128 	parent_data = uniphier_clk_get_parent_data(priv, data);
129 	if (!parent_data)
130 		return;
131 
132 	return __uniphier_clk_enable(priv, parent_data);
133 }
134 
uniphier_clk_enable(struct clk * clk)135 static int uniphier_clk_enable(struct clk *clk)
136 {
137 	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
138 	const struct uniphier_clk_data *data;
139 
140 	data = uniphier_clk_get_data(priv, clk->id);
141 	if (!data)
142 		return -ENODEV;
143 
144 	__uniphier_clk_enable(priv, data);
145 
146 	return 0;
147 }
148 
__uniphier_clk_get_rate(struct uniphier_clk_priv * priv,const struct uniphier_clk_data * data)149 static unsigned long __uniphier_clk_get_rate(
150 					struct uniphier_clk_priv *priv,
151 					const struct uniphier_clk_data *data)
152 {
153 	const struct uniphier_clk_data *parent_data;
154 
155 	if (data->type == UNIPHIER_CLK_TYPE_FIXED_RATE)
156 		return data->data.rate.fixed_rate;
157 
158 	parent_data = uniphier_clk_get_parent_data(priv, data);
159 	if (!parent_data)
160 		return 0;
161 
162 	return __uniphier_clk_get_rate(priv, parent_data);
163 }
164 
uniphier_clk_get_rate(struct clk * clk)165 static unsigned long uniphier_clk_get_rate(struct clk *clk)
166 {
167 	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
168 	const struct uniphier_clk_data *data;
169 
170 	data = uniphier_clk_get_data(priv, clk->id);
171 	if (!data)
172 		return -ENODEV;
173 
174 	return __uniphier_clk_get_rate(priv, data);
175 }
176 
__uniphier_clk_set_rate(struct uniphier_clk_priv * priv,const struct uniphier_clk_data * data,unsigned long rate,bool set)177 static unsigned long __uniphier_clk_set_rate(
178 					struct uniphier_clk_priv *priv,
179 					const struct uniphier_clk_data *data,
180 					unsigned long rate, bool set)
181 {
182 	const struct uniphier_clk_data *best_parent_data = NULL;
183 	const struct uniphier_clk_data *parent_data;
184 	unsigned long best_rate = 0;
185 	unsigned long parent_rate;
186 	u8 parent_id;
187 	int i;
188 
189 	if (data->type == UNIPHIER_CLK_TYPE_FIXED_RATE)
190 		return data->data.rate.fixed_rate;
191 
192 	if (data->type == UNIPHIER_CLK_TYPE_GATE) {
193 		parent_data = uniphier_clk_get_parent_data(priv, data);
194 		if (!parent_data)
195 			return 0;
196 
197 		return __uniphier_clk_set_rate(priv, parent_data, rate, set);
198 	}
199 
200 	if (WARN_ON(data->type != UNIPHIER_CLK_TYPE_MUX))
201 		return -EINVAL;
202 
203 	for (i = 0; i < data->data.mux.num_parents; i++) {
204 		parent_id = data->data.mux.parent_ids[i];
205 		parent_data = uniphier_clk_get_data(priv, parent_id);
206 		if (WARN_ON(!parent_data))
207 			return -EINVAL;
208 
209 		parent_rate = __uniphier_clk_set_rate(priv, parent_data, rate,
210 						      false);
211 
212 		if (parent_rate <= rate && best_rate < parent_rate) {
213 			best_rate = parent_rate;
214 			best_parent_data = parent_data;
215 		}
216 	}
217 
218 	dev_dbg(priv->dev, "id=%u, best_rate=%lu\n", data->id, best_rate);
219 
220 	if (!best_parent_data)
221 		return -EINVAL;
222 
223 	if (!set)
224 		return best_rate;
225 
226 	uniphier_clk_mux_set_parent(priv, &data->data.mux,
227 				    best_parent_data->id);
228 
229 	return best_rate = __uniphier_clk_set_rate(priv, best_parent_data,
230 						   rate, true);
231 }
232 
uniphier_clk_set_rate(struct clk * clk,ulong rate)233 static unsigned long uniphier_clk_set_rate(struct clk *clk, ulong rate)
234 {
235 	struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
236 	const struct uniphier_clk_data *data;
237 
238 	data = uniphier_clk_get_data(priv, clk->id);
239 	if (!data)
240 		return -ENODEV;
241 
242 	return __uniphier_clk_set_rate(priv, data, rate, true);
243 }
244 
245 static const struct clk_ops uniphier_clk_ops = {
246 	.enable = uniphier_clk_enable,
247 	.get_rate = uniphier_clk_get_rate,
248 	.set_rate = uniphier_clk_set_rate,
249 };
250 
uniphier_clk_probe(struct udevice * dev)251 static int uniphier_clk_probe(struct udevice *dev)
252 {
253 	struct uniphier_clk_priv *priv = dev_get_priv(dev);
254 	fdt_addr_t addr;
255 
256 	addr = dev_read_addr(dev->parent);
257 	if (addr == FDT_ADDR_T_NONE)
258 		return -EINVAL;
259 
260 	priv->base = devm_ioremap(dev, addr, SZ_4K);
261 	if (!priv->base)
262 		return -ENOMEM;
263 
264 	priv->dev = dev;
265 	priv->data = (void *)dev_get_driver_data(dev);
266 
267 	return 0;
268 }
269 
270 static const struct udevice_id uniphier_clk_match[] = {
271 	/* System clock */
272 	{
273 		.compatible = "socionext,uniphier-ld4-clock",
274 		.data = (ulong)uniphier_pxs2_sys_clk_data,
275 	},
276 	{
277 		.compatible = "socionext,uniphier-pro4-clock",
278 		.data = (ulong)uniphier_pxs2_sys_clk_data,
279 	},
280 	{
281 		.compatible = "socionext,uniphier-sld8-clock",
282 		.data = (ulong)uniphier_pxs2_sys_clk_data,
283 	},
284 	{
285 		.compatible = "socionext,uniphier-pro5-clock",
286 		.data = (ulong)uniphier_pxs2_sys_clk_data,
287 	},
288 	{
289 		.compatible = "socionext,uniphier-pxs2-clock",
290 		.data = (ulong)uniphier_pxs2_sys_clk_data,
291 	},
292 	{
293 		.compatible = "socionext,uniphier-ld11-clock",
294 		.data = (ulong)uniphier_ld20_sys_clk_data,
295 	},
296 	{
297 		.compatible = "socionext,uniphier-ld20-clock",
298 		.data = (ulong)uniphier_ld20_sys_clk_data,
299 	},
300 	{
301 		.compatible = "socionext,uniphier-pxs3-clock",
302 		.data = (ulong)uniphier_pxs3_sys_clk_data,
303 	},
304 	/* Media I/O clock */
305 	{
306 		.compatible = "socionext,uniphier-ld4-mio-clock",
307 		.data = (ulong)uniphier_mio_clk_data,
308 	},
309 	{
310 		.compatible = "socionext,uniphier-pro4-mio-clock",
311 		.data = (ulong)uniphier_mio_clk_data,
312 	},
313 	{
314 		.compatible = "socionext,uniphier-sld8-mio-clock",
315 		.data = (ulong)uniphier_mio_clk_data,
316 	},
317 	{
318 		.compatible = "socionext,uniphier-pro5-sd-clock",
319 		.data = (ulong)uniphier_mio_clk_data,
320 	},
321 	{
322 		.compatible = "socionext,uniphier-pxs2-sd-clock",
323 		.data = (ulong)uniphier_mio_clk_data,
324 	},
325 	{
326 		.compatible = "socionext,uniphier-ld11-mio-clock",
327 		.data = (ulong)uniphier_mio_clk_data,
328 	},
329 	{
330 		.compatible = "socionext,uniphier-ld20-sd-clock",
331 		.data = (ulong)uniphier_mio_clk_data,
332 	},
333 	{
334 		.compatible = "socionext,uniphier-pxs3-sd-clock",
335 		.data = (ulong)uniphier_mio_clk_data,
336 	},
337 	{ /* sentinel */ }
338 };
339 
340 U_BOOT_DRIVER(uniphier_clk) = {
341 	.name = "uniphier-clk",
342 	.id = UCLASS_CLK,
343 	.of_match = uniphier_clk_match,
344 	.probe = uniphier_clk_probe,
345 	.priv_auto	= sizeof(struct uniphier_clk_priv),
346 	.ops = &uniphier_clk_ops,
347 };
348