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