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