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