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