1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * TI CPUFreq/OPP hw-supported driver 4 * 5 * Copyright (C) 2016-2017 Texas Instruments, Inc. 6 * Dave Gerlach <d-gerlach@ti.com> 7 */ 8 9 #include <linux/cpu.h> 10 #include <linux/io.h> 11 #include <linux/mfd/syscon.h> 12 #include <linux/module.h> 13 #include <linux/init.h> 14 #include <linux/of.h> 15 #include <linux/platform_device.h> 16 #include <linux/pm_opp.h> 17 #include <linux/regmap.h> 18 #include <linux/slab.h> 19 #include <linux/sys_soc.h> 20 21 #define REVISION_MASK 0xF 22 #define REVISION_SHIFT 28 23 24 #define AM33XX_800M_ARM_MPU_MAX_FREQ 0x1E2F 25 #define AM43XX_600M_ARM_MPU_MAX_FREQ 0xFFA 26 27 #define DRA7_EFUSE_HAS_OD_MPU_OPP 11 28 #define DRA7_EFUSE_HAS_HIGH_MPU_OPP 15 29 #define DRA76_EFUSE_HAS_PLUS_MPU_OPP 18 30 #define DRA7_EFUSE_HAS_ALL_MPU_OPP 23 31 #define DRA76_EFUSE_HAS_ALL_MPU_OPP 24 32 33 #define DRA7_EFUSE_NOM_MPU_OPP BIT(0) 34 #define DRA7_EFUSE_OD_MPU_OPP BIT(1) 35 #define DRA7_EFUSE_HIGH_MPU_OPP BIT(2) 36 #define DRA76_EFUSE_PLUS_MPU_OPP BIT(3) 37 38 #define OMAP3_CONTROL_DEVICE_STATUS 0x4800244C 39 #define OMAP3_CONTROL_IDCODE 0x4830A204 40 #define OMAP34xx_ProdID_SKUID 0x4830A20C 41 #define OMAP3_SYSCON_BASE (0x48000000 + 0x2000 + 0x270) 42 43 #define AM625_EFUSE_K_MPU_OPP 11 44 #define AM625_EFUSE_S_MPU_OPP 19 45 #define AM625_EFUSE_T_MPU_OPP 20 46 47 #define AM625_SUPPORT_K_MPU_OPP BIT(0) 48 #define AM625_SUPPORT_S_MPU_OPP BIT(1) 49 #define AM625_SUPPORT_T_MPU_OPP BIT(2) 50 51 enum { 52 AM62A7_EFUSE_M_MPU_OPP = 13, 53 AM62A7_EFUSE_N_MPU_OPP, 54 AM62A7_EFUSE_O_MPU_OPP, 55 AM62A7_EFUSE_P_MPU_OPP, 56 AM62A7_EFUSE_Q_MPU_OPP, 57 AM62A7_EFUSE_R_MPU_OPP, 58 AM62A7_EFUSE_S_MPU_OPP, 59 /* 60 * The V, U, and T speed grade numbering is out of order 61 * to align with the AM625 more uniformly. I promise I know 62 * my ABCs ;) 63 */ 64 AM62A7_EFUSE_V_MPU_OPP, 65 AM62A7_EFUSE_U_MPU_OPP, 66 AM62A7_EFUSE_T_MPU_OPP, 67 }; 68 69 #define AM62A7_SUPPORT_N_MPU_OPP BIT(0) 70 #define AM62A7_SUPPORT_R_MPU_OPP BIT(1) 71 #define AM62A7_SUPPORT_V_MPU_OPP BIT(2) 72 73 #define AM62P5_EFUSE_O_MPU_OPP 15 74 #define AM62P5_EFUSE_S_MPU_OPP 19 75 #define AM62P5_EFUSE_U_MPU_OPP 21 76 77 #define AM62P5_SUPPORT_O_MPU_OPP BIT(0) 78 #define AM62P5_SUPPORT_U_MPU_OPP BIT(2) 79 80 #define VERSION_COUNT 2 81 82 struct ti_cpufreq_data; 83 84 struct ti_cpufreq_soc_data { 85 const char * const *reg_names; 86 unsigned long (*efuse_xlate)(struct ti_cpufreq_data *opp_data, 87 unsigned long efuse); 88 unsigned long efuse_fallback; 89 unsigned long efuse_offset; 90 unsigned long efuse_mask; 91 unsigned long efuse_shift; 92 unsigned long rev_offset; 93 bool multi_regulator; 94 /* Backward compatibility hack: Might have missing syscon */ 95 #define TI_QUIRK_SYSCON_MAY_BE_MISSING 0x1 96 u8 quirks; 97 }; 98 99 struct ti_cpufreq_data { 100 struct device *cpu_dev; 101 struct device_node *opp_node; 102 struct regmap *syscon; 103 const struct ti_cpufreq_soc_data *soc_data; 104 }; 105 106 static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data, 107 unsigned long efuse) 108 { 109 if (!efuse) 110 efuse = opp_data->soc_data->efuse_fallback; 111 /* AM335x and AM437x use "OPP disable" bits, so invert */ 112 return ~efuse; 113 } 114 115 static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data, 116 unsigned long efuse) 117 { 118 unsigned long calculated_efuse = DRA7_EFUSE_NOM_MPU_OPP; 119 120 /* 121 * The efuse on dra7 and am57 parts contains a specific 122 * value indicating the highest available OPP. 123 */ 124 125 switch (efuse) { 126 case DRA76_EFUSE_HAS_PLUS_MPU_OPP: 127 case DRA76_EFUSE_HAS_ALL_MPU_OPP: 128 calculated_efuse |= DRA76_EFUSE_PLUS_MPU_OPP; 129 fallthrough; 130 case DRA7_EFUSE_HAS_ALL_MPU_OPP: 131 case DRA7_EFUSE_HAS_HIGH_MPU_OPP: 132 calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP; 133 fallthrough; 134 case DRA7_EFUSE_HAS_OD_MPU_OPP: 135 calculated_efuse |= DRA7_EFUSE_OD_MPU_OPP; 136 } 137 138 return calculated_efuse; 139 } 140 141 static unsigned long omap3_efuse_xlate(struct ti_cpufreq_data *opp_data, 142 unsigned long efuse) 143 { 144 /* OPP enable bit ("Speed Binned") */ 145 return BIT(efuse); 146 } 147 148 static unsigned long am62p5_efuse_xlate(struct ti_cpufreq_data *opp_data, 149 unsigned long efuse) 150 { 151 unsigned long calculated_efuse = AM62P5_SUPPORT_O_MPU_OPP; 152 153 switch (efuse) { 154 case AM62P5_EFUSE_U_MPU_OPP: 155 case AM62P5_EFUSE_S_MPU_OPP: 156 calculated_efuse |= AM62P5_SUPPORT_U_MPU_OPP; 157 fallthrough; 158 case AM62P5_EFUSE_O_MPU_OPP: 159 calculated_efuse |= AM62P5_SUPPORT_O_MPU_OPP; 160 } 161 162 return calculated_efuse; 163 } 164 165 static unsigned long am62a7_efuse_xlate(struct ti_cpufreq_data *opp_data, 166 unsigned long efuse) 167 { 168 unsigned long calculated_efuse = AM62A7_SUPPORT_N_MPU_OPP; 169 170 switch (efuse) { 171 case AM62A7_EFUSE_V_MPU_OPP: 172 case AM62A7_EFUSE_U_MPU_OPP: 173 case AM62A7_EFUSE_T_MPU_OPP: 174 case AM62A7_EFUSE_S_MPU_OPP: 175 calculated_efuse |= AM62A7_SUPPORT_V_MPU_OPP; 176 fallthrough; 177 case AM62A7_EFUSE_R_MPU_OPP: 178 case AM62A7_EFUSE_Q_MPU_OPP: 179 case AM62A7_EFUSE_P_MPU_OPP: 180 case AM62A7_EFUSE_O_MPU_OPP: 181 calculated_efuse |= AM62A7_SUPPORT_R_MPU_OPP; 182 fallthrough; 183 case AM62A7_EFUSE_N_MPU_OPP: 184 case AM62A7_EFUSE_M_MPU_OPP: 185 calculated_efuse |= AM62A7_SUPPORT_N_MPU_OPP; 186 } 187 188 return calculated_efuse; 189 } 190 191 static unsigned long am625_efuse_xlate(struct ti_cpufreq_data *opp_data, 192 unsigned long efuse) 193 { 194 unsigned long calculated_efuse = AM625_SUPPORT_K_MPU_OPP; 195 196 switch (efuse) { 197 case AM625_EFUSE_T_MPU_OPP: 198 calculated_efuse |= AM625_SUPPORT_T_MPU_OPP; 199 fallthrough; 200 case AM625_EFUSE_S_MPU_OPP: 201 calculated_efuse |= AM625_SUPPORT_S_MPU_OPP; 202 fallthrough; 203 case AM625_EFUSE_K_MPU_OPP: 204 calculated_efuse |= AM625_SUPPORT_K_MPU_OPP; 205 } 206 207 return calculated_efuse; 208 } 209 210 static struct ti_cpufreq_soc_data am3x_soc_data = { 211 .efuse_xlate = amx3_efuse_xlate, 212 .efuse_fallback = AM33XX_800M_ARM_MPU_MAX_FREQ, 213 .efuse_offset = 0x07fc, 214 .efuse_mask = 0x1fff, 215 .rev_offset = 0x600, 216 .multi_regulator = false, 217 }; 218 219 static struct ti_cpufreq_soc_data am4x_soc_data = { 220 .efuse_xlate = amx3_efuse_xlate, 221 .efuse_fallback = AM43XX_600M_ARM_MPU_MAX_FREQ, 222 .efuse_offset = 0x0610, 223 .efuse_mask = 0x3f, 224 .rev_offset = 0x600, 225 .multi_regulator = false, 226 }; 227 228 static struct ti_cpufreq_soc_data dra7_soc_data = { 229 .efuse_xlate = dra7_efuse_xlate, 230 .efuse_offset = 0x020c, 231 .efuse_mask = 0xf80000, 232 .efuse_shift = 19, 233 .rev_offset = 0x204, 234 .multi_regulator = true, 235 }; 236 237 /* 238 * OMAP35x TRM (SPRUF98K): 239 * CONTROL_IDCODE (0x4830 A204) describes Silicon revisions. 240 * Control OMAP Status Register 15:0 (Address 0x4800 244C) 241 * to separate between omap3503, omap3515, omap3525, omap3530 242 * and feature presence. 243 * There are encodings for versions limited to 400/266MHz 244 * but we ignore. 245 * Not clear if this also holds for omap34xx. 246 * some eFuse values e.g. CONTROL_FUSE_OPP1_VDD1 247 * are stored in the SYSCON register range 248 * Register 0x4830A20C [ProdID.SKUID] [0:3] 249 * 0x0 for normal 600/430MHz device. 250 * 0x8 for 720/520MHz device. 251 * Not clear what omap34xx value is. 252 */ 253 254 static struct ti_cpufreq_soc_data omap34xx_soc_data = { 255 .efuse_xlate = omap3_efuse_xlate, 256 .efuse_offset = OMAP34xx_ProdID_SKUID - OMAP3_SYSCON_BASE, 257 .efuse_shift = 3, 258 .efuse_mask = BIT(3), 259 .rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE, 260 .multi_regulator = false, 261 .quirks = TI_QUIRK_SYSCON_MAY_BE_MISSING, 262 }; 263 264 /* 265 * AM/DM37x TRM (SPRUGN4M) 266 * CONTROL_IDCODE (0x4830 A204) describes Silicon revisions. 267 * Control Device Status Register 15:0 (Address 0x4800 244C) 268 * to separate between am3703, am3715, dm3725, dm3730 269 * and feature presence. 270 * Speed Binned = Bit 9 271 * 0 800/600 MHz 272 * 1 1000/800 MHz 273 * some eFuse values e.g. CONTROL_FUSE_OPP 1G_VDD1 274 * are stored in the SYSCON register range. 275 * There is no 0x4830A20C [ProdID.SKUID] register (exists but 276 * seems to always read as 0). 277 */ 278 279 static const char * const omap3_reg_names[] = {"cpu0", "vbb", NULL}; 280 281 static struct ti_cpufreq_soc_data omap36xx_soc_data = { 282 .reg_names = omap3_reg_names, 283 .efuse_xlate = omap3_efuse_xlate, 284 .efuse_offset = OMAP3_CONTROL_DEVICE_STATUS - OMAP3_SYSCON_BASE, 285 .efuse_shift = 9, 286 .efuse_mask = BIT(9), 287 .rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE, 288 .multi_regulator = true, 289 .quirks = TI_QUIRK_SYSCON_MAY_BE_MISSING, 290 }; 291 292 /* 293 * AM3517 is quite similar to AM/DM37x except that it has no 294 * high speed grade eFuse and no abb ldo 295 */ 296 297 static struct ti_cpufreq_soc_data am3517_soc_data = { 298 .efuse_xlate = omap3_efuse_xlate, 299 .efuse_offset = OMAP3_CONTROL_DEVICE_STATUS - OMAP3_SYSCON_BASE, 300 .efuse_shift = 0, 301 .efuse_mask = 0, 302 .rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE, 303 .multi_regulator = false, 304 .quirks = TI_QUIRK_SYSCON_MAY_BE_MISSING, 305 }; 306 307 static const struct soc_device_attribute k3_cpufreq_soc[] = { 308 { .family = "AM62X", .revision = "SR1.0" }, 309 { .family = "AM62AX", .revision = "SR1.0" }, 310 { .family = "AM62PX", .revision = "SR1.0" }, 311 { /* sentinel */ } 312 }; 313 314 static struct ti_cpufreq_soc_data am625_soc_data = { 315 .efuse_xlate = am625_efuse_xlate, 316 .efuse_offset = 0x0018, 317 .efuse_mask = 0x07c0, 318 .efuse_shift = 0x6, 319 .rev_offset = 0x0014, 320 .multi_regulator = false, 321 }; 322 323 static struct ti_cpufreq_soc_data am62a7_soc_data = { 324 .efuse_xlate = am62a7_efuse_xlate, 325 .efuse_offset = 0x0, 326 .efuse_mask = 0x07c0, 327 .efuse_shift = 0x6, 328 .rev_offset = 0x0014, 329 .multi_regulator = false, 330 }; 331 332 static struct ti_cpufreq_soc_data am62p5_soc_data = { 333 .efuse_xlate = am62p5_efuse_xlate, 334 .efuse_offset = 0x0, 335 .efuse_mask = 0x07c0, 336 .efuse_shift = 0x6, 337 .rev_offset = 0x0014, 338 .multi_regulator = false, 339 }; 340 341 /** 342 * ti_cpufreq_get_efuse() - Parse and return efuse value present on SoC 343 * @opp_data: pointer to ti_cpufreq_data context 344 * @efuse_value: Set to the value parsed from efuse 345 * 346 * Returns error code if efuse not read properly. 347 */ 348 static int ti_cpufreq_get_efuse(struct ti_cpufreq_data *opp_data, 349 u32 *efuse_value) 350 { 351 struct device *dev = opp_data->cpu_dev; 352 u32 efuse; 353 int ret; 354 355 ret = regmap_read(opp_data->syscon, opp_data->soc_data->efuse_offset, 356 &efuse); 357 if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) { 358 /* not a syscon register! */ 359 void __iomem *regs = ioremap(OMAP3_SYSCON_BASE + 360 opp_data->soc_data->efuse_offset, 4); 361 362 if (!regs) 363 return -ENOMEM; 364 efuse = readl(regs); 365 iounmap(regs); 366 } 367 else if (ret) { 368 dev_err(dev, 369 "Failed to read the efuse value from syscon: %d\n", 370 ret); 371 return ret; 372 } 373 374 efuse = (efuse & opp_data->soc_data->efuse_mask); 375 efuse >>= opp_data->soc_data->efuse_shift; 376 377 *efuse_value = opp_data->soc_data->efuse_xlate(opp_data, efuse); 378 379 return 0; 380 } 381 382 /** 383 * ti_cpufreq_get_rev() - Parse and return rev value present on SoC 384 * @opp_data: pointer to ti_cpufreq_data context 385 * @revision_value: Set to the value parsed from revision register 386 * 387 * Returns error code if revision not read properly. 388 */ 389 static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data, 390 u32 *revision_value) 391 { 392 struct device *dev = opp_data->cpu_dev; 393 u32 revision; 394 int ret; 395 if (soc_device_match(k3_cpufreq_soc)) { 396 /* 397 * Since the SR is 1.0, hard code the revision_value as 398 * 0x1 here. This way we avoid re using the same register 399 * that is giving us required information inside socinfo 400 * anyway. 401 */ 402 *revision_value = 0x1; 403 goto done; 404 } 405 406 ret = regmap_read(opp_data->syscon, opp_data->soc_data->rev_offset, 407 &revision); 408 if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) { 409 /* not a syscon register! */ 410 void __iomem *regs = ioremap(OMAP3_SYSCON_BASE + 411 opp_data->soc_data->rev_offset, 4); 412 413 if (!regs) 414 return -ENOMEM; 415 revision = readl(regs); 416 iounmap(regs); 417 } 418 else if (ret) { 419 dev_err(dev, 420 "Failed to read the revision number from syscon: %d\n", 421 ret); 422 return ret; 423 } 424 425 *revision_value = BIT((revision >> REVISION_SHIFT) & REVISION_MASK); 426 427 done: 428 return 0; 429 } 430 431 static int ti_cpufreq_setup_syscon_register(struct ti_cpufreq_data *opp_data) 432 { 433 struct device *dev = opp_data->cpu_dev; 434 struct device_node *np = opp_data->opp_node; 435 436 opp_data->syscon = syscon_regmap_lookup_by_phandle(np, 437 "syscon"); 438 if (IS_ERR(opp_data->syscon)) { 439 dev_err(dev, 440 "\"syscon\" is missing, cannot use OPPv2 table.\n"); 441 return PTR_ERR(opp_data->syscon); 442 } 443 444 return 0; 445 } 446 447 static const struct of_device_id ti_cpufreq_of_match[] __maybe_unused = { 448 { .compatible = "ti,am33xx", .data = &am3x_soc_data, }, 449 { .compatible = "ti,am3517", .data = &am3517_soc_data, }, 450 { .compatible = "ti,am43", .data = &am4x_soc_data, }, 451 { .compatible = "ti,dra7", .data = &dra7_soc_data }, 452 { .compatible = "ti,omap34xx", .data = &omap34xx_soc_data, }, 453 { .compatible = "ti,omap36xx", .data = &omap36xx_soc_data, }, 454 { .compatible = "ti,am625", .data = &am625_soc_data, }, 455 { .compatible = "ti,am62a7", .data = &am62a7_soc_data, }, 456 { .compatible = "ti,am62p5", .data = &am62p5_soc_data, }, 457 /* legacy */ 458 { .compatible = "ti,omap3430", .data = &omap34xx_soc_data, }, 459 { .compatible = "ti,omap3630", .data = &omap36xx_soc_data, }, 460 {}, 461 }; 462 463 static const struct of_device_id *ti_cpufreq_match_node(void) 464 { 465 struct device_node *np __free(device_node) = of_find_node_by_path("/"); 466 const struct of_device_id *match; 467 468 match = of_match_node(ti_cpufreq_of_match, np); 469 470 return match; 471 } 472 473 static int ti_cpufreq_probe(struct platform_device *pdev) 474 { 475 u32 version[VERSION_COUNT]; 476 const struct of_device_id *match; 477 struct ti_cpufreq_data *opp_data; 478 const char * const default_reg_names[] = {"vdd", "vbb", NULL}; 479 int ret; 480 struct dev_pm_opp_config config = { 481 .supported_hw = version, 482 .supported_hw_count = ARRAY_SIZE(version), 483 }; 484 485 match = dev_get_platdata(&pdev->dev); 486 if (!match) 487 return -ENODEV; 488 489 opp_data = devm_kzalloc(&pdev->dev, sizeof(*opp_data), GFP_KERNEL); 490 if (!opp_data) 491 return -ENOMEM; 492 493 opp_data->soc_data = match->data; 494 495 opp_data->cpu_dev = get_cpu_device(0); 496 if (!opp_data->cpu_dev) { 497 pr_err("%s: Failed to get device for CPU0\n", __func__); 498 return -ENODEV; 499 } 500 501 opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev); 502 if (!opp_data->opp_node) { 503 dev_info(opp_data->cpu_dev, 504 "OPP-v2 not supported, cpufreq-dt will attempt to use legacy tables.\n"); 505 goto register_cpufreq_dt; 506 } 507 508 ret = ti_cpufreq_setup_syscon_register(opp_data); 509 if (ret) 510 goto fail_put_node; 511 512 /* 513 * OPPs determine whether or not they are supported based on 514 * two metrics: 515 * 0 - SoC Revision 516 * 1 - eFuse value 517 */ 518 ret = ti_cpufreq_get_rev(opp_data, &version[0]); 519 if (ret) 520 goto fail_put_node; 521 522 ret = ti_cpufreq_get_efuse(opp_data, &version[1]); 523 if (ret) 524 goto fail_put_node; 525 526 if (opp_data->soc_data->multi_regulator) { 527 if (opp_data->soc_data->reg_names) 528 config.regulator_names = opp_data->soc_data->reg_names; 529 else 530 config.regulator_names = default_reg_names; 531 } 532 533 ret = dev_pm_opp_set_config(opp_data->cpu_dev, &config); 534 if (ret < 0) { 535 dev_err_probe(opp_data->cpu_dev, ret, "Failed to set OPP config\n"); 536 goto fail_put_node; 537 } 538 539 of_node_put(opp_data->opp_node); 540 541 register_cpufreq_dt: 542 platform_device_register_simple("cpufreq-dt", -1, NULL, 0); 543 544 return 0; 545 546 fail_put_node: 547 of_node_put(opp_data->opp_node); 548 549 return ret; 550 } 551 552 static int __init ti_cpufreq_init(void) 553 { 554 const struct of_device_id *match; 555 556 /* Check to ensure we are on a compatible platform */ 557 match = ti_cpufreq_match_node(); 558 if (match) 559 platform_device_register_data(NULL, "ti-cpufreq", -1, match, 560 sizeof(*match)); 561 562 return 0; 563 } 564 module_init(ti_cpufreq_init); 565 566 static struct platform_driver ti_cpufreq_driver = { 567 .probe = ti_cpufreq_probe, 568 .driver = { 569 .name = "ti-cpufreq", 570 }, 571 }; 572 builtin_platform_driver(ti_cpufreq_driver); 573 574 MODULE_DESCRIPTION("TI CPUFreq/OPP hw-supported driver"); 575 MODULE_AUTHOR("Dave Gerlach <d-gerlach@ti.com>"); 576 MODULE_LICENSE("GPL v2"); 577