xref: /openbmc/u-boot/drivers/clk/mpc83xx_clk.c (revision da4cfa6b)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2017
4  * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
5  */
6 
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <dm/lists.h>
11 #include <dt-bindings/clk/mpc83xx-clk.h>
12 #include <asm/arch/soc.h>
13 
14 #include "mpc83xx_clk.h"
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 /**
19  * struct mpc83xx_clk_priv - Private data structure for the MPC83xx clock
20  *			     driver
21  * @speed: Array containing the speed values of all system clocks (initialized
22  *	   once, then only read back)
23  */
24 struct mpc83xx_clk_priv {
25 	u32 speed[MPC83XX_CLK_COUNT];
26 };
27 
28 /**
29  * is_clk_valid() - Check if clock ID is valid for given clock device
30  * @clk: The clock device for which to check a clock ID
31  * @id:  The clock ID to check
32  *
33  * Return: true if clock ID is valid for clock device, false if not
34  */
35 static inline bool is_clk_valid(struct udevice *clk, int id)
36 {
37 	ulong type = dev_get_driver_data(clk);
38 
39 	switch (id) {
40 	case MPC83XX_CLK_MEM:
41 		return true;
42 	case MPC83XX_CLK_MEM_SEC:
43 		return type == SOC_MPC8360;
44 	case MPC83XX_CLK_ENC:
45 		return (type == SOC_MPC8308) || (type == SOC_MPC8309);
46 	case MPC83XX_CLK_I2C1:
47 		return true;
48 	case MPC83XX_CLK_TDM:
49 		return type == SOC_MPC8315;
50 	case MPC83XX_CLK_SDHC:
51 		return mpc83xx_has_sdhc(type);
52 	case MPC83XX_CLK_TSEC1:
53 	case MPC83XX_CLK_TSEC2:
54 		return mpc83xx_has_tsec(type);
55 	case MPC83XX_CLK_USBDR:
56 		return type == SOC_MPC8360;
57 	case MPC83XX_CLK_USBMPH:
58 		return type == SOC_MPC8349;
59 	case MPC83XX_CLK_PCIEXP1:
60 		return mpc83xx_has_pcie1(type);
61 	case MPC83XX_CLK_PCIEXP2:
62 		return mpc83xx_has_pcie2(type);
63 	case MPC83XX_CLK_SATA:
64 		return mpc83xx_has_sata(type);
65 	case MPC83XX_CLK_DMAC:
66 		return (type == SOC_MPC8308) || (type == SOC_MPC8309);
67 	case MPC83XX_CLK_PCI:
68 		return mpc83xx_has_pci(type);
69 	case MPC83XX_CLK_CSB:
70 		return true;
71 	case MPC83XX_CLK_I2C2:
72 		return mpc83xx_has_second_i2c(type);
73 	case MPC83XX_CLK_QE:
74 	case MPC83XX_CLK_BRG:
75 		return mpc83xx_has_quicc_engine(type) && (type != SOC_MPC8309);
76 	case MPC83XX_CLK_LCLK:
77 	case MPC83XX_CLK_LBIU:
78 	case MPC83XX_CLK_CORE:
79 		return true;
80 	}
81 
82 	return false;
83 }
84 
85 /**
86  * init_single_clk() - Initialize a clock with a given ID
87  * @dev: The clock device for which to initialize the clock
88  * @clk: The clock ID
89  *
90  * The clock speed is read from the hardware's registers, and stored in the
91  * private data structure of the driver. From there it is only retrieved, and
92  * not set.
93  *
94  * Return: 0 if OK, -ve on error
95  */
96 static int init_single_clk(struct udevice *dev, int clk)
97 {
98 	struct mpc83xx_clk_priv *priv = dev_get_priv(dev);
99 	immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
100 	ulong type = dev_get_driver_data(dev);
101 	struct clk_mode mode;
102 	ulong mask;
103 	u32 csb_clk = get_csb_clk(im);
104 	int ret;
105 
106 	ret = retrieve_mode(clk, type, &mode);
107 	if (ret) {
108 		debug("%s: Could not retrieve mode for clk %d (ret = %d)\n",
109 		      dev->name, clk, ret);
110 		return ret;
111 	}
112 
113 	if (mode.type == TYPE_INVALID) {
114 		debug("%s: clock %d invalid\n", dev->name, clk);
115 		return -EINVAL;
116 	}
117 
118 	if (mode.type == TYPE_SCCR_STANDARD) {
119 		mask = GENMASK(31 - mode.low, 31 - mode.high);
120 
121 		switch (sccr_field(im, mask)) {
122 		case 0:
123 			priv->speed[clk] = 0;
124 			break;
125 		case 1:
126 			priv->speed[clk] = csb_clk;
127 			break;
128 		case 2:
129 			priv->speed[clk] = csb_clk / 2;
130 			break;
131 		case 3:
132 			priv->speed[clk] = csb_clk / 3;
133 			break;
134 		default:
135 			priv->speed[clk] = 0;
136 		}
137 
138 		return 0;
139 	}
140 
141 	if (mode.type == TYPE_SPMR_DIRECT_MULTIPLY) {
142 		mask = GENMASK(31 - mode.low, 31 - mode.high);
143 
144 		priv->speed[clk] = csb_clk * (1 + sccr_field(im, mask));
145 		return 0;
146 	}
147 
148 	if (clk == MPC83XX_CLK_CSB || clk == MPC83XX_CLK_I2C2) {
149 		priv->speed[clk] = csb_clk; /* i2c-2 clk is equal to csb clk */
150 		return 0;
151 	}
152 
153 	if (clk == MPC83XX_CLK_QE || clk == MPC83XX_CLK_BRG) {
154 		u32 pci_sync_in = get_pci_sync_in(im);
155 		u32 qepmf = spmr_field(im, SPMR_CEPMF);
156 		u32 qepdf = spmr_field(im, SPMR_CEPDF);
157 		u32 qe_clk = (pci_sync_in * qepmf) / (1 + qepdf);
158 
159 		if (clk == MPC83XX_CLK_QE)
160 			priv->speed[clk] = qe_clk;
161 		else
162 			priv->speed[clk] = qe_clk / 2;
163 
164 		return 0;
165 	}
166 
167 	if (clk == MPC83XX_CLK_LCLK || clk == MPC83XX_CLK_LBIU) {
168 		u32 lbiu_clk = csb_clk *
169 			(1 + spmr_field(im, SPMR_LBIUCM));
170 		u32 clkdiv = lcrr_field(im, LCRR_CLKDIV);
171 
172 		if (clk == MPC83XX_CLK_LBIU)
173 			priv->speed[clk] = lbiu_clk;
174 
175 		switch (clkdiv) {
176 		case 2:
177 		case 4:
178 		case 8:
179 			priv->speed[clk] = lbiu_clk / clkdiv;
180 			break;
181 		default:
182 			/* unknown lcrr */
183 			priv->speed[clk] = 0;
184 		}
185 
186 		return 0;
187 	}
188 
189 	if (clk == MPC83XX_CLK_CORE) {
190 		u8 corepll = spmr_field(im, SPMR_COREPLL);
191 		u32 corecnf_tab_index = ((corepll & 0x1F) << 2) |
192 					((corepll & 0x60) >> 5);
193 
194 		if (corecnf_tab_index > (ARRAY_SIZE(corecnf_tab))) {
195 			debug("%s: Core configuration index %02x too high; possible wrong value",
196 			      dev->name, corecnf_tab_index);
197 			return -EINVAL;
198 		}
199 
200 		switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) {
201 		case RAT_BYP:
202 		case RAT_1_TO_1:
203 			priv->speed[clk] = csb_clk;
204 			break;
205 		case RAT_1_5_TO_1:
206 			priv->speed[clk] = (3 * csb_clk) / 2;
207 			break;
208 		case RAT_2_TO_1:
209 			priv->speed[clk] = 2 * csb_clk;
210 			break;
211 		case RAT_2_5_TO_1:
212 			priv->speed[clk] = (5 * csb_clk) / 2;
213 			break;
214 		case RAT_3_TO_1:
215 			priv->speed[clk] = 3 * csb_clk;
216 			break;
217 		default:
218 			/* unknown core to csb ratio */
219 			priv->speed[clk] = 0;
220 		}
221 
222 		return 0;
223 	}
224 
225 	/* Unknown clk value -> error */
226 	debug("%s: clock %d invalid\n", dev->name, clk);
227 	return -EINVAL;
228 }
229 
230 /**
231  * init_all_clks() - Initialize all clocks of a clock device
232  * @dev: The clock device whose clocks should be initialized
233  *
234  * Return: 0 if OK, -ve on error
235  */
236 static inline int init_all_clks(struct udevice *dev)
237 {
238 	int i;
239 
240 	for (i = 0; i < MPC83XX_CLK_COUNT; i++) {
241 		int ret;
242 
243 		if (!is_clk_valid(dev, i))
244 			continue;
245 
246 		ret = init_single_clk(dev, i);
247 		if (ret) {
248 			debug("%s: Failed to initialize %s clock\n",
249 			      dev->name, names[i]);
250 			return ret;
251 		}
252 	}
253 
254 	return 0;
255 }
256 
257 static int mpc83xx_clk_request(struct clk *clock)
258 {
259 	/* Reject requests of clocks that are not available */
260 	if (is_clk_valid(clock->dev, clock->id))
261 		return 0;
262 	else
263 		return -ENODEV;
264 }
265 
266 static ulong mpc83xx_clk_get_rate(struct clk *clk)
267 {
268 	struct mpc83xx_clk_priv *priv = dev_get_priv(clk->dev);
269 
270 	if (clk->id >= MPC83XX_CLK_COUNT) {
271 		debug("%s: clock index %lu invalid\n", __func__, clk->id);
272 		return 0;
273 	}
274 
275 	return priv->speed[clk->id];
276 }
277 
278 int get_clocks(void)
279 {
280 	/* Empty implementation to keep the prototype in common.h happy */
281 	return 0;
282 }
283 
284 int get_serial_clock(void)
285 {
286 	struct mpc83xx_clk_priv *priv;
287 	struct udevice *clk;
288 	int ret;
289 
290 	ret = uclass_first_device_err(UCLASS_CLK, &clk);
291 	if (ret) {
292 		debug("%s: Could not get clock device\n", __func__);
293 		return ret;
294 	}
295 
296 	priv = dev_get_priv(clk);
297 
298 	return priv->speed[MPC83XX_CLK_CSB];
299 }
300 
301 const struct clk_ops mpc83xx_clk_ops = {
302 	.request = mpc83xx_clk_request,
303 	.get_rate = mpc83xx_clk_get_rate,
304 };
305 
306 static const struct udevice_id mpc83xx_clk_match[] = {
307 	{ .compatible = "fsl,mpc8308-clk", .data = SOC_MPC8308 },
308 	{ .compatible = "fsl,mpc8309-clk", .data = SOC_MPC8309 },
309 	{ .compatible = "fsl,mpc8313-clk", .data = SOC_MPC8313 },
310 	{ .compatible = "fsl,mpc8315-clk", .data = SOC_MPC8315 },
311 	{ .compatible = "fsl,mpc832x-clk", .data = SOC_MPC832X },
312 	{ .compatible = "fsl,mpc8349-clk", .data = SOC_MPC8349 },
313 	{ .compatible = "fsl,mpc8360-clk", .data = SOC_MPC8360 },
314 	{ .compatible = "fsl,mpc8379-clk", .data = SOC_MPC8379 },
315 	{ /* sentinel */ }
316 };
317 
318 static int mpc83xx_clk_probe(struct udevice *dev)
319 {
320 	struct mpc83xx_clk_priv *priv = dev_get_priv(dev);
321 	ulong type;
322 	int ret;
323 
324 	ret = init_all_clks(dev);
325 	if (ret) {
326 		debug("%s: Could not initialize all clocks (ret = %d)\n",
327 		      dev->name, ret);
328 		return ret;
329 	}
330 
331 	type = dev_get_driver_data(dev);
332 
333 	if (mpc83xx_has_sdhc(type))
334 		gd->arch.sdhc_clk = priv->speed[MPC83XX_CLK_SDHC];
335 
336 	gd->arch.core_clk = priv->speed[MPC83XX_CLK_CORE];
337 	gd->arch.i2c1_clk = priv->speed[MPC83XX_CLK_I2C1];
338 	if (mpc83xx_has_second_i2c(type))
339 		gd->arch.i2c2_clk = priv->speed[MPC83XX_CLK_I2C2];
340 
341 	gd->mem_clk = priv->speed[MPC83XX_CLK_MEM];
342 
343 	if (mpc83xx_has_pci(type))
344 		gd->pci_clk = priv->speed[MPC83XX_CLK_PCI];
345 
346 	gd->cpu_clk = priv->speed[MPC83XX_CLK_CORE];
347 	gd->bus_clk = priv->speed[MPC83XX_CLK_CSB];
348 
349 	return 0;
350 }
351 
352 static int mpc83xx_clk_bind(struct udevice *dev)
353 {
354 	int ret;
355 	struct udevice *sys_child;
356 
357 	/*
358 	 * Since there is no corresponding device tree entry, and since the
359 	 * clock driver has to be present in either case, bind the sysreset
360 	 * driver here.
361 	 */
362 	ret = device_bind_driver(dev, "mpc83xx_sysreset", "sysreset",
363 				 &sys_child);
364 	if (ret)
365 		debug("%s: No sysreset driver: ret=%d\n",
366 		      dev->name, ret);
367 
368 	return 0;
369 }
370 
371 U_BOOT_DRIVER(mpc83xx_clk) = {
372 	.name = "mpc83xx_clk",
373 	.id = UCLASS_CLK,
374 	.of_match = mpc83xx_clk_match,
375 	.ops = &mpc83xx_clk_ops,
376 	.probe = mpc83xx_clk_probe,
377 	.priv_auto_alloc_size	= sizeof(struct mpc83xx_clk_priv),
378 	.bind = mpc83xx_clk_bind,
379 };
380 
381 static int do_clocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
382 {
383 	int i;
384 	char buf[32];
385 	struct udevice *clk;
386 	int ret;
387 	struct mpc83xx_clk_priv *priv;
388 
389 	ret = uclass_first_device_err(UCLASS_CLK, &clk);
390 	if (ret) {
391 		debug("%s: Could not get clock device\n", __func__);
392 		return ret;
393 	}
394 
395 	for (i = 0; i < MPC83XX_CLK_COUNT; i++) {
396 		if (!is_clk_valid(clk, i))
397 			continue;
398 
399 		priv = dev_get_priv(clk);
400 
401 		printf("%s = %s MHz\n", names[i], strmhz(buf, priv->speed[i]));
402 	}
403 
404 	return 0;
405 }
406 
407 U_BOOT_CMD(clocks,	1,	1,	do_clocks,
408 	   "display values of SoC's clocks",
409 	   ""
410 );
411