1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2020, The Linux Foundation. All rights reserved. 4 */ 5 6 /* 7 * Each of the CPU clusters (Power and Perf) on msm8996 are 8 * clocked via 2 PLLs, a primary and alternate. There are also 9 * 2 Mux'es, a primary and secondary all connected together 10 * as shown below 11 * 12 * +-------+ 13 * XO | | 14 * +------------------>0 | 15 * | | 16 * PLL/2 | SMUX +----+ 17 * +------->1 | | 18 * | | | | 19 * | +-------+ | +-------+ 20 * | +---->0 | 21 * | | | 22 * +---------------+ | +----------->1 | CPU clk 23 * |Primary PLL +----+ PLL_EARLY | | +------> 24 * | +------+-----------+ +------>2 PMUX | 25 * +---------------+ | | | | 26 * | +------+ | +-->3 | 27 * +--^+ ACD +-----+ | +-------+ 28 * +---------------+ +------+ | 29 * |Alt PLL | | 30 * | +---------------------------+ 31 * +---------------+ PLL_EARLY 32 * 33 * The primary PLL is what drives the CPU clk, except for times 34 * when we are reprogramming the PLL itself (for rate changes) when 35 * we temporarily switch to an alternate PLL. 36 * 37 * The primary PLL operates on a single VCO range, between 600MHz 38 * and 3GHz. However the CPUs do support OPPs with frequencies 39 * between 300MHz and 600MHz. In order to support running the CPUs 40 * at those frequencies we end up having to lock the PLL at twice 41 * the rate and drive the CPU clk via the PLL/2 output and SMUX. 42 * 43 * So for frequencies above 600MHz we follow the following path 44 * Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk 45 * and for frequencies between 300MHz and 600MHz we follow 46 * Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk 47 * 48 * ACD stands for Adaptive Clock Distribution and is used to 49 * detect voltage droops. 50 */ 51 52 #include <linux/clk.h> 53 #include <linux/clk-provider.h> 54 #include <linux/io.h> 55 #include <linux/module.h> 56 #include <linux/platform_device.h> 57 #include <linux/regmap.h> 58 #include <soc/qcom/kryo-l2-accessors.h> 59 60 #include "clk-alpha-pll.h" 61 #include "clk-regmap.h" 62 63 enum _pmux_input { 64 SMUX_INDEX = 0, 65 PLL_INDEX, 66 ACD_INDEX, 67 ALT_INDEX, 68 NUM_OF_PMUX_INPUTS 69 }; 70 71 #define DIV_2_THRESHOLD 600000000 72 #define PWRCL_REG_OFFSET 0x0 73 #define PERFCL_REG_OFFSET 0x80000 74 #define MUX_OFFSET 0x40 75 #define ALT_PLL_OFFSET 0x100 76 #define SSSCTL_OFFSET 0x160 77 78 static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = { 79 [PLL_OFF_L_VAL] = 0x04, 80 [PLL_OFF_ALPHA_VAL] = 0x08, 81 [PLL_OFF_USER_CTL] = 0x10, 82 [PLL_OFF_CONFIG_CTL] = 0x18, 83 [PLL_OFF_CONFIG_CTL_U] = 0x1c, 84 [PLL_OFF_TEST_CTL] = 0x20, 85 [PLL_OFF_TEST_CTL_U] = 0x24, 86 [PLL_OFF_STATUS] = 0x28, 87 }; 88 89 static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = { 90 [PLL_OFF_L_VAL] = 0x04, 91 [PLL_OFF_ALPHA_VAL] = 0x08, 92 [PLL_OFF_ALPHA_VAL_U] = 0x0c, 93 [PLL_OFF_USER_CTL] = 0x10, 94 [PLL_OFF_USER_CTL_U] = 0x14, 95 [PLL_OFF_CONFIG_CTL] = 0x18, 96 [PLL_OFF_TEST_CTL] = 0x20, 97 [PLL_OFF_TEST_CTL_U] = 0x24, 98 [PLL_OFF_STATUS] = 0x28, 99 }; 100 101 /* PLLs */ 102 103 static const struct alpha_pll_config hfpll_config = { 104 .l = 60, 105 .config_ctl_val = 0x200d4aa8, 106 .config_ctl_hi_val = 0x006, 107 .pre_div_mask = BIT(12), 108 .post_div_mask = 0x3 << 8, 109 .post_div_val = 0x1 << 8, 110 .main_output_mask = BIT(0), 111 .early_output_mask = BIT(3), 112 }; 113 114 static struct clk_alpha_pll perfcl_pll = { 115 .offset = PERFCL_REG_OFFSET, 116 .regs = prim_pll_regs, 117 .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE, 118 .clkr.hw.init = &(struct clk_init_data){ 119 .name = "perfcl_pll", 120 .parent_names = (const char *[]){ "xo" }, 121 .num_parents = 1, 122 .ops = &clk_alpha_pll_huayra_ops, 123 }, 124 }; 125 126 static struct clk_alpha_pll pwrcl_pll = { 127 .offset = PWRCL_REG_OFFSET, 128 .regs = prim_pll_regs, 129 .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE, 130 .clkr.hw.init = &(struct clk_init_data){ 131 .name = "pwrcl_pll", 132 .parent_names = (const char *[]){ "xo" }, 133 .num_parents = 1, 134 .ops = &clk_alpha_pll_huayra_ops, 135 }, 136 }; 137 138 static struct clk_fixed_factor pwrcl_pll_postdiv = { 139 .mult = 1, 140 .div = 2, 141 .hw.init = &(struct clk_init_data){ 142 .name = "pwrcl_pll_postdiv", 143 .parent_data = &(const struct clk_parent_data){ 144 .hw = &pwrcl_pll.clkr.hw 145 }, 146 .num_parents = 1, 147 .ops = &clk_fixed_factor_ops, 148 .flags = CLK_SET_RATE_PARENT, 149 }, 150 }; 151 152 static struct clk_fixed_factor perfcl_pll_postdiv = { 153 .mult = 1, 154 .div = 2, 155 .hw.init = &(struct clk_init_data){ 156 .name = "perfcl_pll_postdiv", 157 .parent_data = &(const struct clk_parent_data){ 158 .hw = &perfcl_pll.clkr.hw 159 }, 160 .num_parents = 1, 161 .ops = &clk_fixed_factor_ops, 162 .flags = CLK_SET_RATE_PARENT, 163 }, 164 }; 165 166 static const struct pll_vco alt_pll_vco_modes[] = { 167 VCO(3, 250000000, 500000000), 168 VCO(2, 500000000, 750000000), 169 VCO(1, 750000000, 1000000000), 170 VCO(0, 1000000000, 2150400000), 171 }; 172 173 static const struct alpha_pll_config altpll_config = { 174 .l = 16, 175 .vco_val = 0x3 << 20, 176 .vco_mask = 0x3 << 20, 177 .config_ctl_val = 0x4001051b, 178 .post_div_mask = 0x3 << 8, 179 .post_div_val = 0x1 << 8, 180 .main_output_mask = BIT(0), 181 .early_output_mask = BIT(3), 182 }; 183 184 static struct clk_alpha_pll perfcl_alt_pll = { 185 .offset = PERFCL_REG_OFFSET + ALT_PLL_OFFSET, 186 .regs = alt_pll_regs, 187 .vco_table = alt_pll_vco_modes, 188 .num_vco = ARRAY_SIZE(alt_pll_vco_modes), 189 .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE, 190 .clkr.hw.init = &(struct clk_init_data) { 191 .name = "perfcl_alt_pll", 192 .parent_names = (const char *[]){ "xo" }, 193 .num_parents = 1, 194 .ops = &clk_alpha_pll_hwfsm_ops, 195 }, 196 }; 197 198 static struct clk_alpha_pll pwrcl_alt_pll = { 199 .offset = PWRCL_REG_OFFSET + ALT_PLL_OFFSET, 200 .regs = alt_pll_regs, 201 .vco_table = alt_pll_vco_modes, 202 .num_vco = ARRAY_SIZE(alt_pll_vco_modes), 203 .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE, 204 .clkr.hw.init = &(struct clk_init_data) { 205 .name = "pwrcl_alt_pll", 206 .parent_names = (const char *[]){ "xo" }, 207 .num_parents = 1, 208 .ops = &clk_alpha_pll_hwfsm_ops, 209 }, 210 }; 211 212 struct clk_cpu_8996_mux { 213 u32 reg; 214 u8 shift; 215 u8 width; 216 struct notifier_block nb; 217 struct clk_hw *pll; 218 struct clk_hw *pll_div_2; 219 struct clk_regmap clkr; 220 }; 221 222 static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event, 223 void *data); 224 225 #define to_clk_cpu_8996_mux_nb(_nb) \ 226 container_of(_nb, struct clk_cpu_8996_mux, nb) 227 228 static inline struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw) 229 { 230 return container_of(to_clk_regmap(hw), struct clk_cpu_8996_mux, clkr); 231 } 232 233 static u8 clk_cpu_8996_mux_get_parent(struct clk_hw *hw) 234 { 235 struct clk_regmap *clkr = to_clk_regmap(hw); 236 struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw); 237 u32 mask = GENMASK(cpuclk->width - 1, 0); 238 u32 val; 239 240 regmap_read(clkr->regmap, cpuclk->reg, &val); 241 val >>= cpuclk->shift; 242 243 return val & mask; 244 } 245 246 static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index) 247 { 248 struct clk_regmap *clkr = to_clk_regmap(hw); 249 struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw); 250 u32 mask = GENMASK(cpuclk->width + cpuclk->shift - 1, cpuclk->shift); 251 u32 val; 252 253 val = index; 254 val <<= cpuclk->shift; 255 256 return regmap_update_bits(clkr->regmap, cpuclk->reg, mask, val); 257 } 258 259 static int clk_cpu_8996_mux_determine_rate(struct clk_hw *hw, 260 struct clk_rate_request *req) 261 { 262 struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw); 263 struct clk_hw *parent = cpuclk->pll; 264 265 if (cpuclk->pll_div_2 && req->rate < DIV_2_THRESHOLD) { 266 if (req->rate < (DIV_2_THRESHOLD / 2)) 267 return -EINVAL; 268 269 parent = cpuclk->pll_div_2; 270 } 271 272 req->best_parent_rate = clk_hw_round_rate(parent, req->rate); 273 req->best_parent_hw = parent; 274 275 return 0; 276 } 277 278 static const struct clk_ops clk_cpu_8996_mux_ops = { 279 .set_parent = clk_cpu_8996_mux_set_parent, 280 .get_parent = clk_cpu_8996_mux_get_parent, 281 .determine_rate = clk_cpu_8996_mux_determine_rate, 282 }; 283 284 static struct clk_cpu_8996_mux pwrcl_smux = { 285 .reg = PWRCL_REG_OFFSET + MUX_OFFSET, 286 .shift = 2, 287 .width = 2, 288 .clkr.hw.init = &(struct clk_init_data) { 289 .name = "pwrcl_smux", 290 .parent_names = (const char *[]){ 291 "xo", 292 "pwrcl_pll_postdiv", 293 }, 294 .num_parents = 2, 295 .ops = &clk_cpu_8996_mux_ops, 296 .flags = CLK_SET_RATE_PARENT, 297 }, 298 }; 299 300 static struct clk_cpu_8996_mux perfcl_smux = { 301 .reg = PERFCL_REG_OFFSET + MUX_OFFSET, 302 .shift = 2, 303 .width = 2, 304 .clkr.hw.init = &(struct clk_init_data) { 305 .name = "perfcl_smux", 306 .parent_names = (const char *[]){ 307 "xo", 308 "perfcl_pll_postdiv", 309 }, 310 .num_parents = 2, 311 .ops = &clk_cpu_8996_mux_ops, 312 .flags = CLK_SET_RATE_PARENT, 313 }, 314 }; 315 316 static struct clk_cpu_8996_mux pwrcl_pmux = { 317 .reg = PWRCL_REG_OFFSET + MUX_OFFSET, 318 .shift = 0, 319 .width = 2, 320 .pll = &pwrcl_pll.clkr.hw, 321 .pll_div_2 = &pwrcl_smux.clkr.hw, 322 .nb.notifier_call = cpu_clk_notifier_cb, 323 .clkr.hw.init = &(struct clk_init_data) { 324 .name = "pwrcl_pmux", 325 .parent_names = (const char *[]){ 326 "pwrcl_smux", 327 "pwrcl_pll", 328 "pwrcl_pll_acd", 329 "pwrcl_alt_pll", 330 }, 331 .num_parents = 4, 332 .ops = &clk_cpu_8996_mux_ops, 333 /* CPU clock is critical and should never be gated */ 334 .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 335 }, 336 }; 337 338 static struct clk_cpu_8996_mux perfcl_pmux = { 339 .reg = PERFCL_REG_OFFSET + MUX_OFFSET, 340 .shift = 0, 341 .width = 2, 342 .pll = &perfcl_pll.clkr.hw, 343 .pll_div_2 = &perfcl_smux.clkr.hw, 344 .nb.notifier_call = cpu_clk_notifier_cb, 345 .clkr.hw.init = &(struct clk_init_data) { 346 .name = "perfcl_pmux", 347 .parent_names = (const char *[]){ 348 "perfcl_smux", 349 "perfcl_pll", 350 "perfcl_pll_acd", 351 "perfcl_alt_pll", 352 }, 353 .num_parents = 4, 354 .ops = &clk_cpu_8996_mux_ops, 355 /* CPU clock is critical and should never be gated */ 356 .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 357 }, 358 }; 359 360 static const struct regmap_config cpu_msm8996_regmap_config = { 361 .reg_bits = 32, 362 .reg_stride = 4, 363 .val_bits = 32, 364 .max_register = 0x80210, 365 .fast_io = true, 366 .val_format_endian = REGMAP_ENDIAN_LITTLE, 367 }; 368 369 static struct clk_regmap *cpu_msm8996_clks[] = { 370 &perfcl_pll.clkr, 371 &pwrcl_pll.clkr, 372 &perfcl_alt_pll.clkr, 373 &pwrcl_alt_pll.clkr, 374 &perfcl_smux.clkr, 375 &pwrcl_smux.clkr, 376 &perfcl_pmux.clkr, 377 &pwrcl_pmux.clkr, 378 }; 379 380 static int qcom_cpu_clk_msm8996_register_clks(struct device *dev, 381 struct regmap *regmap) 382 { 383 int i, ret; 384 385 ret = devm_clk_hw_register(dev, &pwrcl_pll_postdiv.hw); 386 if (ret) { 387 dev_err(dev, "Failed to register pwrcl_pll_postdiv: %d", ret); 388 return ret; 389 } 390 391 ret = devm_clk_hw_register(dev, &perfcl_pll_postdiv.hw); 392 if (ret) { 393 dev_err(dev, "Failed to register perfcl_pll_postdiv: %d", ret); 394 return ret; 395 } 396 397 pwrcl_smux.pll = &pwrcl_pll_postdiv.hw; 398 perfcl_smux.pll = &perfcl_pll_postdiv.hw; 399 400 for (i = 0; i < ARRAY_SIZE(cpu_msm8996_clks); i++) { 401 ret = devm_clk_register_regmap(dev, cpu_msm8996_clks[i]); 402 if (ret) 403 return ret; 404 } 405 406 clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config); 407 clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config); 408 clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config); 409 clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config); 410 411 /* Enable alt PLLs */ 412 clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk); 413 clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk); 414 415 clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb); 416 clk_notifier_register(perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb); 417 418 return ret; 419 } 420 421 static int qcom_cpu_clk_msm8996_unregister_clks(void) 422 { 423 int ret = 0; 424 425 ret = clk_notifier_unregister(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb); 426 if (ret) 427 return ret; 428 429 ret = clk_notifier_unregister(perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb); 430 if (ret) 431 return ret; 432 433 return 0; 434 } 435 436 #define CPU_AFINITY_MASK 0xFFF 437 #define PWRCL_CPU_REG_MASK 0x3 438 #define PERFCL_CPU_REG_MASK 0x103 439 440 #define L2ACDCR_REG 0x580ULL 441 #define L2ACDTD_REG 0x581ULL 442 #define L2ACDDVMRC_REG 0x584ULL 443 #define L2ACDSSCR_REG 0x589ULL 444 445 static DEFINE_SPINLOCK(qcom_clk_acd_lock); 446 static void __iomem *base; 447 448 static void qcom_cpu_clk_msm8996_acd_init(void __iomem *base) 449 { 450 u64 hwid; 451 unsigned long flags; 452 453 spin_lock_irqsave(&qcom_clk_acd_lock, flags); 454 455 hwid = read_cpuid_mpidr() & CPU_AFINITY_MASK; 456 457 kryo_l2_set_indirect_reg(L2ACDTD_REG, 0x00006a11); 458 kryo_l2_set_indirect_reg(L2ACDDVMRC_REG, 0x000e0f0f); 459 kryo_l2_set_indirect_reg(L2ACDSSCR_REG, 0x00000601); 460 461 if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) { 462 writel(0xf, base + PWRCL_REG_OFFSET + SSSCTL_OFFSET); 463 kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002c5ffd); 464 } 465 466 if (PERFCL_CPU_REG_MASK == (hwid | PERFCL_CPU_REG_MASK)) { 467 kryo_l2_set_indirect_reg(L2ACDCR_REG, 0x002c5ffd); 468 writel(0xf, base + PERFCL_REG_OFFSET + SSSCTL_OFFSET); 469 } 470 471 spin_unlock_irqrestore(&qcom_clk_acd_lock, flags); 472 } 473 474 static int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event, 475 void *data) 476 { 477 struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb); 478 struct clk_notifier_data *cnd = data; 479 int ret; 480 481 switch (event) { 482 case PRE_RATE_CHANGE: 483 ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX); 484 qcom_cpu_clk_msm8996_acd_init(base); 485 break; 486 case POST_RATE_CHANGE: 487 if (cnd->new_rate < DIV_2_THRESHOLD) 488 ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, 489 SMUX_INDEX); 490 else 491 ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, 492 ACD_INDEX); 493 break; 494 default: 495 ret = 0; 496 break; 497 } 498 499 return notifier_from_errno(ret); 500 }; 501 502 static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev) 503 { 504 struct regmap *regmap; 505 struct clk_hw_onecell_data *data; 506 struct device *dev = &pdev->dev; 507 int ret; 508 509 data = devm_kzalloc(dev, struct_size(data, hws, 2), GFP_KERNEL); 510 if (!data) 511 return -ENOMEM; 512 513 base = devm_platform_ioremap_resource(pdev, 0); 514 if (IS_ERR(base)) 515 return PTR_ERR(base); 516 517 regmap = devm_regmap_init_mmio(dev, base, &cpu_msm8996_regmap_config); 518 if (IS_ERR(regmap)) 519 return PTR_ERR(regmap); 520 521 ret = qcom_cpu_clk_msm8996_register_clks(dev, regmap); 522 if (ret) 523 return ret; 524 525 qcom_cpu_clk_msm8996_acd_init(base); 526 527 data->hws[0] = &pwrcl_pmux.clkr.hw; 528 data->hws[1] = &perfcl_pmux.clkr.hw; 529 data->num = 2; 530 531 return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, data); 532 } 533 534 static int qcom_cpu_clk_msm8996_driver_remove(struct platform_device *pdev) 535 { 536 return qcom_cpu_clk_msm8996_unregister_clks(); 537 } 538 539 static const struct of_device_id qcom_cpu_clk_msm8996_match_table[] = { 540 { .compatible = "qcom,msm8996-apcc" }, 541 {} 542 }; 543 MODULE_DEVICE_TABLE(of, qcom_cpu_clk_msm8996_match_table); 544 545 static struct platform_driver qcom_cpu_clk_msm8996_driver = { 546 .probe = qcom_cpu_clk_msm8996_driver_probe, 547 .remove = qcom_cpu_clk_msm8996_driver_remove, 548 .driver = { 549 .name = "qcom-msm8996-apcc", 550 .of_match_table = qcom_cpu_clk_msm8996_match_table, 551 }, 552 }; 553 module_platform_driver(qcom_cpu_clk_msm8996_driver); 554 555 MODULE_DESCRIPTION("QCOM MSM8996 CPU Clock Driver"); 556 MODULE_LICENSE("GPL v2"); 557