444 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 15struct 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 23struct 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 39static 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 else80 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 else100 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 125static 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 mutex_lock(&drv->reg_lock);141 142 inter_voltage = drv->inter_voltage;143 cci_pll = clk_get_parent(drv->cci_clk);144 145 opp_rate = *freq;146 opp = devfreq_recommended_opp(dev, &opp_rate, 1);147 if (IS_ERR(opp)) {148 dev_err(dev, "failed to find opp for freq: %ld\n", opp_rate);149 ret = PTR_ERR(opp);150 goto out_unlock;151 }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 the198 * 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 213out_restore_voltage:214 mtk_ccifreq_set_voltage(drv, pre_voltage);215 216out_unlock:217 mutex_unlock(&drv->reg_lock);218 return ret;219}220 221static 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 mutex_lock(&drv->reg_lock);232 freq = dev_pm_opp_get_freq(opp);233 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 245static struct devfreq_dev_profile mtk_ccifreq_profile = {246 .target = mtk_ccifreq_target,247};248 249static 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 using311 * 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 380out_remove_opp_table:381 dev_pm_opp_of_remove_table(dev);382 383out_disable_cci_clk:384 clk_disable_unprepare(drv->cci_clk);385 386out_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 395static void 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 410static const struct mtk_ccifreq_platform_data mt8183_platform_data = {411 .min_volt_shift = 100000,412 .max_volt_shift = 200000,413 .proc_max_volt = 1150000,414};415 416static const struct mtk_ccifreq_platform_data mt8186_platform_data = {417 .min_volt_shift = 100000,418 .max_volt_shift = 250000,419 .proc_max_volt = 1118750,420 .sram_min_volt = 850000,421 .sram_max_volt = 1118750,422};423 424static const struct of_device_id mtk_ccifreq_machines[] = {425 { .compatible = "mediatek,mt8183-cci", .data = &mt8183_platform_data },426 { .compatible = "mediatek,mt8186-cci", .data = &mt8186_platform_data },427 { },428};429MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines);430 431static struct platform_driver mtk_ccifreq_platdrv = {432 .probe = mtk_ccifreq_probe,433 .remove_new = mtk_ccifreq_remove,434 .driver = {435 .name = "mtk-ccifreq",436 .of_match_table = mtk_ccifreq_machines,437 },438};439module_platform_driver(mtk_ccifreq_platdrv);440 441MODULE_DESCRIPTION("MediaTek CCI devfreq driver");442MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>");443MODULE_LICENSE("GPL v2");444