1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2022 MediaTek Inc. 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/devfreq.h> 8 #include <linux/minmax.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/of_device.h> 12 #include <linux/platform_device.h> 13 #include <linux/pm_opp.h> 14 #include <linux/regulator/consumer.h> 15 16 struct mtk_ccifreq_platform_data { 17 int min_volt_shift; 18 int max_volt_shift; 19 int proc_max_volt; 20 int sram_min_volt; 21 int sram_max_volt; 22 }; 23 24 struct mtk_ccifreq_drv { 25 struct device *dev; 26 struct devfreq *devfreq; 27 struct regulator *proc_reg; 28 struct regulator *sram_reg; 29 struct clk *cci_clk; 30 struct clk *inter_clk; 31 int inter_voltage; 32 unsigned long pre_freq; 33 /* Avoid race condition for regulators between notify and policy */ 34 struct mutex reg_lock; 35 struct notifier_block opp_nb; 36 const struct mtk_ccifreq_platform_data *soc_data; 37 int vtrack_max; 38 }; 39 40 static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int new_voltage) 41 { 42 const struct mtk_ccifreq_platform_data *soc_data = drv->soc_data; 43 struct device *dev = drv->dev; 44 int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret; 45 int retry_max = drv->vtrack_max; 46 47 if (!drv->sram_reg) { 48 ret = regulator_set_voltage(drv->proc_reg, new_voltage, 49 drv->soc_data->proc_max_volt); 50 return ret; 51 } 52 53 pre_voltage = regulator_get_voltage(drv->proc_reg); 54 if (pre_voltage < 0) { 55 dev_err(dev, "invalid vproc value: %d\n", pre_voltage); 56 return pre_voltage; 57 } 58 59 pre_vsram = regulator_get_voltage(drv->sram_reg); 60 if (pre_vsram < 0) { 61 dev_err(dev, "invalid vsram value: %d\n", pre_vsram); 62 return pre_vsram; 63 } 64 65 new_vsram = clamp(new_voltage + soc_data->min_volt_shift, 66 soc_data->sram_min_volt, soc_data->sram_max_volt); 67 68 do { 69 if (pre_voltage <= new_voltage) { 70 vsram = clamp(pre_voltage + soc_data->max_volt_shift, 71 soc_data->sram_min_volt, new_vsram); 72 ret = regulator_set_voltage(drv->sram_reg, vsram, 73 soc_data->sram_max_volt); 74 if (ret) 75 return ret; 76 77 if (vsram == soc_data->sram_max_volt || 78 new_vsram == soc_data->sram_min_volt) 79 voltage = new_voltage; 80 else 81 voltage = vsram - soc_data->min_volt_shift; 82 83 ret = regulator_set_voltage(drv->proc_reg, voltage, 84 soc_data->proc_max_volt); 85 if (ret) { 86 regulator_set_voltage(drv->sram_reg, pre_vsram, 87 soc_data->sram_max_volt); 88 return ret; 89 } 90 } else if (pre_voltage > new_voltage) { 91 voltage = max(new_voltage, 92 pre_vsram - soc_data->max_volt_shift); 93 ret = regulator_set_voltage(drv->proc_reg, voltage, 94 soc_data->proc_max_volt); 95 if (ret) 96 return ret; 97 98 if (voltage == new_voltage) 99 vsram = new_vsram; 100 else 101 vsram = max(new_vsram, 102 voltage + soc_data->min_volt_shift); 103 104 ret = regulator_set_voltage(drv->sram_reg, vsram, 105 soc_data->sram_max_volt); 106 if (ret) { 107 regulator_set_voltage(drv->proc_reg, pre_voltage, 108 soc_data->proc_max_volt); 109 return ret; 110 } 111 } 112 113 pre_voltage = voltage; 114 pre_vsram = vsram; 115 116 if (--retry_max < 0) { 117 dev_err(dev, 118 "over loop count, failed to set voltage\n"); 119 return -EINVAL; 120 } 121 } while (voltage != new_voltage || vsram != new_vsram); 122 123 return 0; 124 } 125 126 static int mtk_ccifreq_target(struct device *dev, unsigned long *freq, 127 u32 flags) 128 { 129 struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev); 130 struct clk *cci_pll; 131 struct dev_pm_opp *opp; 132 unsigned long opp_rate; 133 int voltage, pre_voltage, inter_voltage, target_voltage, ret; 134 135 if (!drv) 136 return -EINVAL; 137 138 if (drv->pre_freq == *freq) 139 return 0; 140 141 inter_voltage = drv->inter_voltage; 142 cci_pll = clk_get_parent(drv->cci_clk); 143 144 opp_rate = *freq; 145 opp = devfreq_recommended_opp(dev, &opp_rate, 1); 146 if (IS_ERR(opp)) { 147 dev_err(dev, "failed to find opp for freq: %ld\n", opp_rate); 148 return PTR_ERR(opp); 149 } 150 151 mutex_lock(&drv->reg_lock); 152 153 voltage = dev_pm_opp_get_voltage(opp); 154 dev_pm_opp_put(opp); 155 156 pre_voltage = regulator_get_voltage(drv->proc_reg); 157 if (pre_voltage < 0) { 158 dev_err(dev, "invalid vproc value: %d\n", pre_voltage); 159 ret = pre_voltage; 160 goto out_unlock; 161 } 162 163 /* scale up: set voltage first then freq. */ 164 target_voltage = max(inter_voltage, voltage); 165 if (pre_voltage <= target_voltage) { 166 ret = mtk_ccifreq_set_voltage(drv, target_voltage); 167 if (ret) { 168 dev_err(dev, "failed to scale up voltage\n"); 169 goto out_restore_voltage; 170 } 171 } 172 173 /* switch the cci clock to intermediate clock source. */ 174 ret = clk_set_parent(drv->cci_clk, drv->inter_clk); 175 if (ret) { 176 dev_err(dev, "failed to re-parent cci clock\n"); 177 goto out_restore_voltage; 178 } 179 180 /* set the original clock to target rate. */ 181 ret = clk_set_rate(cci_pll, *freq); 182 if (ret) { 183 dev_err(dev, "failed to set cci pll rate: %d\n", ret); 184 clk_set_parent(drv->cci_clk, cci_pll); 185 goto out_restore_voltage; 186 } 187 188 /* switch the cci clock back to the original clock source. */ 189 ret = clk_set_parent(drv->cci_clk, cci_pll); 190 if (ret) { 191 dev_err(dev, "failed to re-parent cci clock\n"); 192 mtk_ccifreq_set_voltage(drv, inter_voltage); 193 goto out_unlock; 194 } 195 196 /* 197 * If the new voltage is lower than the intermediate voltage or the 198 * original voltage, scale down to the new voltage. 199 */ 200 if (voltage < inter_voltage || voltage < pre_voltage) { 201 ret = mtk_ccifreq_set_voltage(drv, voltage); 202 if (ret) { 203 dev_err(dev, "failed to scale down voltage\n"); 204 goto out_unlock; 205 } 206 } 207 208 drv->pre_freq = *freq; 209 mutex_unlock(&drv->reg_lock); 210 211 return 0; 212 213 out_restore_voltage: 214 mtk_ccifreq_set_voltage(drv, pre_voltage); 215 216 out_unlock: 217 mutex_unlock(&drv->reg_lock); 218 return ret; 219 } 220 221 static int mtk_ccifreq_opp_notifier(struct notifier_block *nb, 222 unsigned long event, void *data) 223 { 224 struct dev_pm_opp *opp = data; 225 struct mtk_ccifreq_drv *drv; 226 unsigned long freq, volt; 227 228 drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb); 229 230 if (event == OPP_EVENT_ADJUST_VOLTAGE) { 231 freq = dev_pm_opp_get_freq(opp); 232 233 mutex_lock(&drv->reg_lock); 234 /* current opp item is changed */ 235 if (freq == drv->pre_freq) { 236 volt = dev_pm_opp_get_voltage(opp); 237 mtk_ccifreq_set_voltage(drv, volt); 238 } 239 mutex_unlock(&drv->reg_lock); 240 } 241 242 return 0; 243 } 244 245 static struct devfreq_dev_profile mtk_ccifreq_profile = { 246 .target = mtk_ccifreq_target, 247 }; 248 249 static int mtk_ccifreq_probe(struct platform_device *pdev) 250 { 251 struct device *dev = &pdev->dev; 252 struct mtk_ccifreq_drv *drv; 253 struct devfreq_passive_data *passive_data; 254 struct dev_pm_opp *opp; 255 unsigned long rate, opp_volt; 256 int ret; 257 258 drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); 259 if (!drv) 260 return -ENOMEM; 261 262 drv->dev = dev; 263 drv->soc_data = (const struct mtk_ccifreq_platform_data *) 264 of_device_get_match_data(&pdev->dev); 265 mutex_init(&drv->reg_lock); 266 platform_set_drvdata(pdev, drv); 267 268 drv->cci_clk = devm_clk_get(dev, "cci"); 269 if (IS_ERR(drv->cci_clk)) { 270 ret = PTR_ERR(drv->cci_clk); 271 return dev_err_probe(dev, ret, "failed to get cci clk\n"); 272 } 273 274 drv->inter_clk = devm_clk_get(dev, "intermediate"); 275 if (IS_ERR(drv->inter_clk)) { 276 ret = PTR_ERR(drv->inter_clk); 277 return dev_err_probe(dev, ret, 278 "failed to get intermediate clk\n"); 279 } 280 281 drv->proc_reg = devm_regulator_get_optional(dev, "proc"); 282 if (IS_ERR(drv->proc_reg)) { 283 ret = PTR_ERR(drv->proc_reg); 284 return dev_err_probe(dev, ret, 285 "failed to get proc regulator\n"); 286 } 287 288 ret = regulator_enable(drv->proc_reg); 289 if (ret) { 290 dev_err(dev, "failed to enable proc regulator\n"); 291 return ret; 292 } 293 294 drv->sram_reg = devm_regulator_get_optional(dev, "sram"); 295 if (IS_ERR(drv->sram_reg)) { 296 ret = PTR_ERR(drv->sram_reg); 297 if (ret == -EPROBE_DEFER) 298 goto out_free_resources; 299 300 drv->sram_reg = NULL; 301 } else { 302 ret = regulator_enable(drv->sram_reg); 303 if (ret) { 304 dev_err(dev, "failed to enable sram regulator\n"); 305 goto out_free_resources; 306 } 307 } 308 309 /* 310 * We assume min voltage is 0 and tracking target voltage using 311 * min_volt_shift for each iteration. 312 * The retry_max is 3 times of expected iteration count. 313 */ 314 drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt, 315 drv->soc_data->proc_max_volt), 316 drv->soc_data->min_volt_shift); 317 318 ret = clk_prepare_enable(drv->cci_clk); 319 if (ret) 320 goto out_free_resources; 321 322 ret = dev_pm_opp_of_add_table(dev); 323 if (ret) { 324 dev_err(dev, "failed to add opp table: %d\n", ret); 325 goto out_disable_cci_clk; 326 } 327 328 rate = clk_get_rate(drv->inter_clk); 329 opp = dev_pm_opp_find_freq_ceil(dev, &rate); 330 if (IS_ERR(opp)) { 331 ret = PTR_ERR(opp); 332 dev_err(dev, "failed to get intermediate opp: %d\n", ret); 333 goto out_remove_opp_table; 334 } 335 drv->inter_voltage = dev_pm_opp_get_voltage(opp); 336 dev_pm_opp_put(opp); 337 338 rate = U32_MAX; 339 opp = dev_pm_opp_find_freq_floor(drv->dev, &rate); 340 if (IS_ERR(opp)) { 341 dev_err(dev, "failed to get opp\n"); 342 ret = PTR_ERR(opp); 343 goto out_remove_opp_table; 344 } 345 346 opp_volt = dev_pm_opp_get_voltage(opp); 347 dev_pm_opp_put(opp); 348 ret = mtk_ccifreq_set_voltage(drv, opp_volt); 349 if (ret) { 350 dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n", 351 opp_volt); 352 goto out_remove_opp_table; 353 } 354 355 passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL); 356 if (!passive_data) { 357 ret = -ENOMEM; 358 goto out_remove_opp_table; 359 } 360 361 passive_data->parent_type = CPUFREQ_PARENT_DEV; 362 drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile, 363 DEVFREQ_GOV_PASSIVE, 364 passive_data); 365 if (IS_ERR(drv->devfreq)) { 366 ret = -EPROBE_DEFER; 367 dev_err(dev, "failed to add devfreq device: %ld\n", 368 PTR_ERR(drv->devfreq)); 369 goto out_remove_opp_table; 370 } 371 372 drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier; 373 ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb); 374 if (ret) { 375 dev_err(dev, "failed to register opp notifier: %d\n", ret); 376 goto out_remove_opp_table; 377 } 378 return 0; 379 380 out_remove_opp_table: 381 dev_pm_opp_of_remove_table(dev); 382 383 out_disable_cci_clk: 384 clk_disable_unprepare(drv->cci_clk); 385 386 out_free_resources: 387 if (regulator_is_enabled(drv->proc_reg)) 388 regulator_disable(drv->proc_reg); 389 if (drv->sram_reg && regulator_is_enabled(drv->sram_reg)) 390 regulator_disable(drv->sram_reg); 391 392 return ret; 393 } 394 395 static int mtk_ccifreq_remove(struct platform_device *pdev) 396 { 397 struct device *dev = &pdev->dev; 398 struct mtk_ccifreq_drv *drv; 399 400 drv = platform_get_drvdata(pdev); 401 402 dev_pm_opp_unregister_notifier(dev, &drv->opp_nb); 403 dev_pm_opp_of_remove_table(dev); 404 clk_disable_unprepare(drv->cci_clk); 405 regulator_disable(drv->proc_reg); 406 if (drv->sram_reg) 407 regulator_disable(drv->sram_reg); 408 409 return 0; 410 } 411 412 static const struct mtk_ccifreq_platform_data mt8183_platform_data = { 413 .min_volt_shift = 100000, 414 .max_volt_shift = 200000, 415 .proc_max_volt = 1150000, 416 }; 417 418 static const struct mtk_ccifreq_platform_data mt8186_platform_data = { 419 .min_volt_shift = 100000, 420 .max_volt_shift = 250000, 421 .proc_max_volt = 1118750, 422 .sram_min_volt = 850000, 423 .sram_max_volt = 1118750, 424 }; 425 426 static const struct of_device_id mtk_ccifreq_machines[] = { 427 { .compatible = "mediatek,mt8183-cci", .data = &mt8183_platform_data }, 428 { .compatible = "mediatek,mt8186-cci", .data = &mt8186_platform_data }, 429 { }, 430 }; 431 MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines); 432 433 static struct platform_driver mtk_ccifreq_platdrv = { 434 .probe = mtk_ccifreq_probe, 435 .remove = mtk_ccifreq_remove, 436 .driver = { 437 .name = "mtk-ccifreq", 438 .of_match_table = mtk_ccifreq_machines, 439 }, 440 }; 441 module_platform_driver(mtk_ccifreq_platdrv); 442 443 MODULE_DESCRIPTION("MediaTek CCI devfreq driver"); 444 MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>"); 445 MODULE_LICENSE("GPL v2"); 446