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