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