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