cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mediatek-cpufreq.c (20666B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2015 Linaro Ltd.
      4 * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
      5 */
      6
      7#include <linux/clk.h>
      8#include <linux/cpu.h>
      9#include <linux/cpufreq.h>
     10#include <linux/cpumask.h>
     11#include <linux/minmax.h>
     12#include <linux/module.h>
     13#include <linux/of.h>
     14#include <linux/of_platform.h>
     15#include <linux/platform_device.h>
     16#include <linux/pm_opp.h>
     17#include <linux/regulator/consumer.h>
     18
     19struct mtk_cpufreq_platform_data {
     20	int min_volt_shift;
     21	int max_volt_shift;
     22	int proc_max_volt;
     23	int sram_min_volt;
     24	int sram_max_volt;
     25	bool ccifreq_supported;
     26};
     27
     28/*
     29 * The struct mtk_cpu_dvfs_info holds necessary information for doing CPU DVFS
     30 * on each CPU power/clock domain of Mediatek SoCs. Each CPU cluster in
     31 * Mediatek SoCs has two voltage inputs, Vproc and Vsram. In some cases the two
     32 * voltage inputs need to be controlled under a hardware limitation:
     33 * 100mV < Vsram - Vproc < 200mV
     34 *
     35 * When scaling the clock frequency of a CPU clock domain, the clock source
     36 * needs to be switched to another stable PLL clock temporarily until
     37 * the original PLL becomes stable at target frequency.
     38 */
     39struct mtk_cpu_dvfs_info {
     40	struct cpumask cpus;
     41	struct device *cpu_dev;
     42	struct device *cci_dev;
     43	struct regulator *proc_reg;
     44	struct regulator *sram_reg;
     45	struct clk *cpu_clk;
     46	struct clk *inter_clk;
     47	struct list_head list_head;
     48	int intermediate_voltage;
     49	bool need_voltage_tracking;
     50	int vproc_on_boot;
     51	int pre_vproc;
     52	/* Avoid race condition for regulators between notify and policy */
     53	struct mutex reg_lock;
     54	struct notifier_block opp_nb;
     55	unsigned int opp_cpu;
     56	unsigned long current_freq;
     57	const struct mtk_cpufreq_platform_data *soc_data;
     58	int vtrack_max;
     59	bool ccifreq_bound;
     60};
     61
     62static struct platform_device *cpufreq_pdev;
     63
     64static LIST_HEAD(dvfs_info_list);
     65
     66static struct mtk_cpu_dvfs_info *mtk_cpu_dvfs_info_lookup(int cpu)
     67{
     68	struct mtk_cpu_dvfs_info *info;
     69
     70	list_for_each_entry(info, &dvfs_info_list, list_head) {
     71		if (cpumask_test_cpu(cpu, &info->cpus))
     72			return info;
     73	}
     74
     75	return NULL;
     76}
     77
     78static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
     79					int new_vproc)
     80{
     81	const struct mtk_cpufreq_platform_data *soc_data = info->soc_data;
     82	struct regulator *proc_reg = info->proc_reg;
     83	struct regulator *sram_reg = info->sram_reg;
     84	int pre_vproc, pre_vsram, new_vsram, vsram, vproc, ret;
     85	int retry = info->vtrack_max;
     86
     87	pre_vproc = regulator_get_voltage(proc_reg);
     88	if (pre_vproc < 0) {
     89		dev_err(info->cpu_dev,
     90			"invalid Vproc value: %d\n", pre_vproc);
     91		return pre_vproc;
     92	}
     93
     94	pre_vsram = regulator_get_voltage(sram_reg);
     95	if (pre_vsram < 0) {
     96		dev_err(info->cpu_dev, "invalid Vsram value: %d\n", pre_vsram);
     97		return pre_vsram;
     98	}
     99
    100	new_vsram = clamp(new_vproc + soc_data->min_volt_shift,
    101			  soc_data->sram_min_volt, soc_data->sram_max_volt);
    102
    103	do {
    104		if (pre_vproc <= new_vproc) {
    105			vsram = clamp(pre_vproc + soc_data->max_volt_shift,
    106				      soc_data->sram_min_volt, new_vsram);
    107			ret = regulator_set_voltage(sram_reg, vsram,
    108						    soc_data->sram_max_volt);
    109
    110			if (ret)
    111				return ret;
    112
    113			if (vsram == soc_data->sram_max_volt ||
    114			    new_vsram == soc_data->sram_min_volt)
    115				vproc = new_vproc;
    116			else
    117				vproc = vsram - soc_data->min_volt_shift;
    118
    119			ret = regulator_set_voltage(proc_reg, vproc,
    120						    soc_data->proc_max_volt);
    121			if (ret) {
    122				regulator_set_voltage(sram_reg, pre_vsram,
    123						      soc_data->sram_max_volt);
    124				return ret;
    125			}
    126		} else if (pre_vproc > new_vproc) {
    127			vproc = max(new_vproc,
    128				    pre_vsram - soc_data->max_volt_shift);
    129			ret = regulator_set_voltage(proc_reg, vproc,
    130						    soc_data->proc_max_volt);
    131			if (ret)
    132				return ret;
    133
    134			if (vproc == new_vproc)
    135				vsram = new_vsram;
    136			else
    137				vsram = max(new_vsram,
    138					    vproc + soc_data->min_volt_shift);
    139
    140			ret = regulator_set_voltage(sram_reg, vsram,
    141						    soc_data->sram_max_volt);
    142			if (ret) {
    143				regulator_set_voltage(proc_reg, pre_vproc,
    144						      soc_data->proc_max_volt);
    145				return ret;
    146			}
    147		}
    148
    149		pre_vproc = vproc;
    150		pre_vsram = vsram;
    151
    152		if (--retry < 0) {
    153			dev_err(info->cpu_dev,
    154				"over loop count, failed to set voltage\n");
    155			return -EINVAL;
    156		}
    157	} while (vproc != new_vproc || vsram != new_vsram);
    158
    159	return 0;
    160}
    161
    162static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
    163{
    164	const struct mtk_cpufreq_platform_data *soc_data = info->soc_data;
    165	int ret;
    166
    167	if (info->need_voltage_tracking)
    168		ret = mtk_cpufreq_voltage_tracking(info, vproc);
    169	else
    170		ret = regulator_set_voltage(info->proc_reg, vproc,
    171					    soc_data->proc_max_volt);
    172	if (!ret)
    173		info->pre_vproc = vproc;
    174
    175	return ret;
    176}
    177
    178static bool is_ccifreq_ready(struct mtk_cpu_dvfs_info *info)
    179{
    180	struct device_link *sup_link;
    181
    182	if (info->ccifreq_bound)
    183		return true;
    184
    185	sup_link = device_link_add(info->cpu_dev, info->cci_dev,
    186				   DL_FLAG_AUTOREMOVE_CONSUMER);
    187	if (!sup_link) {
    188		dev_err(info->cpu_dev, "cpu%d: sup_link is NULL\n", info->opp_cpu);
    189		return false;
    190	}
    191
    192	if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND)
    193		return false;
    194
    195	info->ccifreq_bound = true;
    196
    197	return true;
    198}
    199
    200static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
    201				  unsigned int index)
    202{
    203	struct cpufreq_frequency_table *freq_table = policy->freq_table;
    204	struct clk *cpu_clk = policy->clk;
    205	struct clk *armpll = clk_get_parent(cpu_clk);
    206	struct mtk_cpu_dvfs_info *info = policy->driver_data;
    207	struct device *cpu_dev = info->cpu_dev;
    208	struct dev_pm_opp *opp;
    209	long freq_hz, pre_freq_hz;
    210	int vproc, pre_vproc, inter_vproc, target_vproc, ret;
    211
    212	inter_vproc = info->intermediate_voltage;
    213
    214	pre_freq_hz = clk_get_rate(cpu_clk);
    215
    216	mutex_lock(&info->reg_lock);
    217
    218	if (unlikely(info->pre_vproc <= 0))
    219		pre_vproc = regulator_get_voltage(info->proc_reg);
    220	else
    221		pre_vproc = info->pre_vproc;
    222
    223	if (pre_vproc < 0) {
    224		dev_err(cpu_dev, "invalid Vproc value: %d\n", pre_vproc);
    225		ret = pre_vproc;
    226		goto out;
    227	}
    228
    229	freq_hz = freq_table[index].frequency * 1000;
    230
    231	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
    232	if (IS_ERR(opp)) {
    233		dev_err(cpu_dev, "cpu%d: failed to find OPP for %ld\n",
    234			policy->cpu, freq_hz);
    235		ret = PTR_ERR(opp);
    236		goto out;
    237	}
    238	vproc = dev_pm_opp_get_voltage(opp);
    239	dev_pm_opp_put(opp);
    240
    241	/*
    242	 * If MediaTek cci is supported but is not ready, we will use the value
    243	 * of max(target cpu voltage, booting voltage) to prevent high freqeuncy
    244	 * low voltage crash.
    245	 */
    246	if (info->soc_data->ccifreq_supported && !is_ccifreq_ready(info))
    247		vproc = max(vproc, info->vproc_on_boot);
    248
    249	/*
    250	 * If the new voltage or the intermediate voltage is higher than the
    251	 * current voltage, scale up voltage first.
    252	 */
    253	target_vproc = max(inter_vproc, vproc);
    254	if (pre_vproc <= target_vproc) {
    255		ret = mtk_cpufreq_set_voltage(info, target_vproc);
    256		if (ret) {
    257			dev_err(cpu_dev,
    258				"cpu%d: failed to scale up voltage!\n", policy->cpu);
    259			mtk_cpufreq_set_voltage(info, pre_vproc);
    260			goto out;
    261		}
    262	}
    263
    264	/* Reparent the CPU clock to intermediate clock. */
    265	ret = clk_set_parent(cpu_clk, info->inter_clk);
    266	if (ret) {
    267		dev_err(cpu_dev,
    268			"cpu%d: failed to re-parent cpu clock!\n", policy->cpu);
    269		mtk_cpufreq_set_voltage(info, pre_vproc);
    270		goto out;
    271	}
    272
    273	/* Set the original PLL to target rate. */
    274	ret = clk_set_rate(armpll, freq_hz);
    275	if (ret) {
    276		dev_err(cpu_dev,
    277			"cpu%d: failed to scale cpu clock rate!\n", policy->cpu);
    278		clk_set_parent(cpu_clk, armpll);
    279		mtk_cpufreq_set_voltage(info, pre_vproc);
    280		goto out;
    281	}
    282
    283	/* Set parent of CPU clock back to the original PLL. */
    284	ret = clk_set_parent(cpu_clk, armpll);
    285	if (ret) {
    286		dev_err(cpu_dev,
    287			"cpu%d: failed to re-parent cpu clock!\n", policy->cpu);
    288		mtk_cpufreq_set_voltage(info, inter_vproc);
    289		goto out;
    290	}
    291
    292	/*
    293	 * If the new voltage is lower than the intermediate voltage or the
    294	 * original voltage, scale down to the new voltage.
    295	 */
    296	if (vproc < inter_vproc || vproc < pre_vproc) {
    297		ret = mtk_cpufreq_set_voltage(info, vproc);
    298		if (ret) {
    299			dev_err(cpu_dev,
    300				"cpu%d: failed to scale down voltage!\n", policy->cpu);
    301			clk_set_parent(cpu_clk, info->inter_clk);
    302			clk_set_rate(armpll, pre_freq_hz);
    303			clk_set_parent(cpu_clk, armpll);
    304			goto out;
    305		}
    306	}
    307
    308	info->current_freq = freq_hz;
    309
    310out:
    311	mutex_unlock(&info->reg_lock);
    312
    313	return ret;
    314}
    315
    316#define DYNAMIC_POWER "dynamic-power-coefficient"
    317
    318static int mtk_cpufreq_opp_notifier(struct notifier_block *nb,
    319				    unsigned long event, void *data)
    320{
    321	struct dev_pm_opp *opp = data;
    322	struct dev_pm_opp *new_opp;
    323	struct mtk_cpu_dvfs_info *info;
    324	unsigned long freq, volt;
    325	struct cpufreq_policy *policy;
    326	int ret = 0;
    327
    328	info = container_of(nb, struct mtk_cpu_dvfs_info, opp_nb);
    329
    330	if (event == OPP_EVENT_ADJUST_VOLTAGE) {
    331		freq = dev_pm_opp_get_freq(opp);
    332
    333		mutex_lock(&info->reg_lock);
    334		if (info->current_freq == freq) {
    335			volt = dev_pm_opp_get_voltage(opp);
    336			ret = mtk_cpufreq_set_voltage(info, volt);
    337			if (ret)
    338				dev_err(info->cpu_dev,
    339					"failed to scale voltage: %d\n", ret);
    340		}
    341		mutex_unlock(&info->reg_lock);
    342	} else if (event == OPP_EVENT_DISABLE) {
    343		freq = dev_pm_opp_get_freq(opp);
    344
    345		/* case of current opp item is disabled */
    346		if (info->current_freq == freq) {
    347			freq = 1;
    348			new_opp = dev_pm_opp_find_freq_ceil(info->cpu_dev,
    349							    &freq);
    350			if (IS_ERR(new_opp)) {
    351				dev_err(info->cpu_dev,
    352					"all opp items are disabled\n");
    353				ret = PTR_ERR(new_opp);
    354				return notifier_from_errno(ret);
    355			}
    356
    357			dev_pm_opp_put(new_opp);
    358			policy = cpufreq_cpu_get(info->opp_cpu);
    359			if (policy) {
    360				cpufreq_driver_target(policy, freq / 1000,
    361						      CPUFREQ_RELATION_L);
    362				cpufreq_cpu_put(policy);
    363			}
    364		}
    365	}
    366
    367	return notifier_from_errno(ret);
    368}
    369
    370static struct device *of_get_cci(struct device *cpu_dev)
    371{
    372	struct device_node *np;
    373	struct platform_device *pdev;
    374
    375	np = of_parse_phandle(cpu_dev->of_node, "mediatek,cci", 0);
    376	if (IS_ERR_OR_NULL(np))
    377		return NULL;
    378
    379	pdev = of_find_device_by_node(np);
    380	of_node_put(np);
    381	if (IS_ERR_OR_NULL(pdev))
    382		return NULL;
    383
    384	return &pdev->dev;
    385}
    386
    387static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
    388{
    389	struct device *cpu_dev;
    390	struct dev_pm_opp *opp;
    391	unsigned long rate;
    392	int ret;
    393
    394	cpu_dev = get_cpu_device(cpu);
    395	if (!cpu_dev) {
    396		dev_err(cpu_dev, "failed to get cpu%d device\n", cpu);
    397		return -ENODEV;
    398	}
    399	info->cpu_dev = cpu_dev;
    400
    401	info->ccifreq_bound = false;
    402	if (info->soc_data->ccifreq_supported) {
    403		info->cci_dev = of_get_cci(info->cpu_dev);
    404		if (IS_ERR_OR_NULL(info->cci_dev)) {
    405			ret = PTR_ERR(info->cci_dev);
    406			dev_err(cpu_dev, "cpu%d: failed to get cci device\n", cpu);
    407			return -ENODEV;
    408		}
    409	}
    410
    411	info->cpu_clk = clk_get(cpu_dev, "cpu");
    412	if (IS_ERR(info->cpu_clk)) {
    413		ret = PTR_ERR(info->cpu_clk);
    414		return dev_err_probe(cpu_dev, ret,
    415				     "cpu%d: failed to get cpu clk\n", cpu);
    416	}
    417
    418	info->inter_clk = clk_get(cpu_dev, "intermediate");
    419	if (IS_ERR(info->inter_clk)) {
    420		ret = PTR_ERR(info->inter_clk);
    421		dev_err_probe(cpu_dev, ret,
    422			      "cpu%d: failed to get intermediate clk\n", cpu);
    423		goto out_free_resources;
    424	}
    425
    426	info->proc_reg = regulator_get_optional(cpu_dev, "proc");
    427	if (IS_ERR(info->proc_reg)) {
    428		ret = PTR_ERR(info->proc_reg);
    429		dev_err_probe(cpu_dev, ret,
    430			      "cpu%d: failed to get proc regulator\n", cpu);
    431		goto out_free_resources;
    432	}
    433
    434	ret = regulator_enable(info->proc_reg);
    435	if (ret) {
    436		dev_warn(cpu_dev, "cpu%d: failed to enable vproc\n", cpu);
    437		goto out_free_resources;
    438	}
    439
    440	/* Both presence and absence of sram regulator are valid cases. */
    441	info->sram_reg = regulator_get_optional(cpu_dev, "sram");
    442	if (IS_ERR(info->sram_reg))
    443		info->sram_reg = NULL;
    444	else {
    445		ret = regulator_enable(info->sram_reg);
    446		if (ret) {
    447			dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu);
    448			goto out_free_resources;
    449		}
    450	}
    451
    452	/* Get OPP-sharing information from "operating-points-v2" bindings */
    453	ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, &info->cpus);
    454	if (ret) {
    455		dev_err(cpu_dev,
    456			"cpu%d: failed to get OPP-sharing information\n", cpu);
    457		goto out_free_resources;
    458	}
    459
    460	ret = dev_pm_opp_of_cpumask_add_table(&info->cpus);
    461	if (ret) {
    462		dev_warn(cpu_dev, "cpu%d: no OPP table\n", cpu);
    463		goto out_free_resources;
    464	}
    465
    466	ret = clk_prepare_enable(info->cpu_clk);
    467	if (ret)
    468		goto out_free_opp_table;
    469
    470	ret = clk_prepare_enable(info->inter_clk);
    471	if (ret)
    472		goto out_disable_mux_clock;
    473
    474	if (info->soc_data->ccifreq_supported) {
    475		info->vproc_on_boot = regulator_get_voltage(info->proc_reg);
    476		if (info->vproc_on_boot < 0) {
    477			dev_err(info->cpu_dev,
    478				"invalid Vproc value: %d\n", info->vproc_on_boot);
    479			goto out_disable_inter_clock;
    480		}
    481	}
    482
    483	/* Search a safe voltage for intermediate frequency. */
    484	rate = clk_get_rate(info->inter_clk);
    485	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
    486	if (IS_ERR(opp)) {
    487		dev_err(cpu_dev, "cpu%d: failed to get intermediate opp\n", cpu);
    488		ret = PTR_ERR(opp);
    489		goto out_disable_inter_clock;
    490	}
    491	info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
    492	dev_pm_opp_put(opp);
    493
    494	mutex_init(&info->reg_lock);
    495	info->current_freq = clk_get_rate(info->cpu_clk);
    496
    497	info->opp_cpu = cpu;
    498	info->opp_nb.notifier_call = mtk_cpufreq_opp_notifier;
    499	ret = dev_pm_opp_register_notifier(cpu_dev, &info->opp_nb);
    500	if (ret) {
    501		dev_err(cpu_dev, "cpu%d: failed to register opp notifier\n", cpu);
    502		goto out_disable_inter_clock;
    503	}
    504
    505	/*
    506	 * If SRAM regulator is present, software "voltage tracking" is needed
    507	 * for this CPU power domain.
    508	 */
    509	info->need_voltage_tracking = (info->sram_reg != NULL);
    510
    511	/*
    512	 * We assume min voltage is 0 and tracking target voltage using
    513	 * min_volt_shift for each iteration.
    514	 * The vtrack_max is 3 times of expeted iteration count.
    515	 */
    516	info->vtrack_max = 3 * DIV_ROUND_UP(max(info->soc_data->sram_max_volt,
    517						info->soc_data->proc_max_volt),
    518					    info->soc_data->min_volt_shift);
    519
    520	return 0;
    521
    522out_disable_inter_clock:
    523	clk_disable_unprepare(info->inter_clk);
    524
    525out_disable_mux_clock:
    526	clk_disable_unprepare(info->cpu_clk);
    527
    528out_free_opp_table:
    529	dev_pm_opp_of_cpumask_remove_table(&info->cpus);
    530
    531out_free_resources:
    532	if (regulator_is_enabled(info->proc_reg))
    533		regulator_disable(info->proc_reg);
    534	if (info->sram_reg && regulator_is_enabled(info->sram_reg))
    535		regulator_disable(info->sram_reg);
    536
    537	if (!IS_ERR(info->proc_reg))
    538		regulator_put(info->proc_reg);
    539	if (!IS_ERR(info->sram_reg))
    540		regulator_put(info->sram_reg);
    541	if (!IS_ERR(info->cpu_clk))
    542		clk_put(info->cpu_clk);
    543	if (!IS_ERR(info->inter_clk))
    544		clk_put(info->inter_clk);
    545
    546	return ret;
    547}
    548
    549static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
    550{
    551	if (!IS_ERR(info->proc_reg)) {
    552		regulator_disable(info->proc_reg);
    553		regulator_put(info->proc_reg);
    554	}
    555	if (!IS_ERR(info->sram_reg)) {
    556		regulator_disable(info->sram_reg);
    557		regulator_put(info->sram_reg);
    558	}
    559	if (!IS_ERR(info->cpu_clk)) {
    560		clk_disable_unprepare(info->cpu_clk);
    561		clk_put(info->cpu_clk);
    562	}
    563	if (!IS_ERR(info->inter_clk)) {
    564		clk_disable_unprepare(info->inter_clk);
    565		clk_put(info->inter_clk);
    566	}
    567
    568	dev_pm_opp_of_cpumask_remove_table(&info->cpus);
    569	dev_pm_opp_unregister_notifier(info->cpu_dev, &info->opp_nb);
    570}
    571
    572static int mtk_cpufreq_init(struct cpufreq_policy *policy)
    573{
    574	struct mtk_cpu_dvfs_info *info;
    575	struct cpufreq_frequency_table *freq_table;
    576	int ret;
    577
    578	info = mtk_cpu_dvfs_info_lookup(policy->cpu);
    579	if (!info) {
    580		pr_err("dvfs info for cpu%d is not initialized.\n",
    581			policy->cpu);
    582		return -EINVAL;
    583	}
    584
    585	ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
    586	if (ret) {
    587		dev_err(info->cpu_dev,
    588			"failed to init cpufreq table for cpu%d: %d\n",
    589			policy->cpu, ret);
    590		return ret;
    591	}
    592
    593	cpumask_copy(policy->cpus, &info->cpus);
    594	policy->freq_table = freq_table;
    595	policy->driver_data = info;
    596	policy->clk = info->cpu_clk;
    597
    598	return 0;
    599}
    600
    601static int mtk_cpufreq_exit(struct cpufreq_policy *policy)
    602{
    603	struct mtk_cpu_dvfs_info *info = policy->driver_data;
    604
    605	dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table);
    606
    607	return 0;
    608}
    609
    610static struct cpufreq_driver mtk_cpufreq_driver = {
    611	.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK |
    612		 CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
    613		 CPUFREQ_IS_COOLING_DEV,
    614	.verify = cpufreq_generic_frequency_table_verify,
    615	.target_index = mtk_cpufreq_set_target,
    616	.get = cpufreq_generic_get,
    617	.init = mtk_cpufreq_init,
    618	.exit = mtk_cpufreq_exit,
    619	.register_em = cpufreq_register_em_with_opp,
    620	.name = "mtk-cpufreq",
    621	.attr = cpufreq_generic_attr,
    622};
    623
    624static int mtk_cpufreq_probe(struct platform_device *pdev)
    625{
    626	const struct mtk_cpufreq_platform_data *data;
    627	struct mtk_cpu_dvfs_info *info, *tmp;
    628	int cpu, ret;
    629
    630	data = dev_get_platdata(&pdev->dev);
    631	if (!data) {
    632		dev_err(&pdev->dev,
    633			"failed to get mtk cpufreq platform data\n");
    634		return -ENODEV;
    635	}
    636
    637	for_each_possible_cpu(cpu) {
    638		info = mtk_cpu_dvfs_info_lookup(cpu);
    639		if (info)
    640			continue;
    641
    642		info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
    643		if (!info) {
    644			ret = -ENOMEM;
    645			goto release_dvfs_info_list;
    646		}
    647
    648		info->soc_data = data;
    649		ret = mtk_cpu_dvfs_info_init(info, cpu);
    650		if (ret) {
    651			dev_err(&pdev->dev,
    652				"failed to initialize dvfs info for cpu%d\n",
    653				cpu);
    654			goto release_dvfs_info_list;
    655		}
    656
    657		list_add(&info->list_head, &dvfs_info_list);
    658	}
    659
    660	ret = cpufreq_register_driver(&mtk_cpufreq_driver);
    661	if (ret) {
    662		dev_err(&pdev->dev, "failed to register mtk cpufreq driver\n");
    663		goto release_dvfs_info_list;
    664	}
    665
    666	return 0;
    667
    668release_dvfs_info_list:
    669	list_for_each_entry_safe(info, tmp, &dvfs_info_list, list_head) {
    670		mtk_cpu_dvfs_info_release(info);
    671		list_del(&info->list_head);
    672	}
    673
    674	return ret;
    675}
    676
    677static struct platform_driver mtk_cpufreq_platdrv = {
    678	.driver = {
    679		.name	= "mtk-cpufreq",
    680	},
    681	.probe		= mtk_cpufreq_probe,
    682};
    683
    684static const struct mtk_cpufreq_platform_data mt2701_platform_data = {
    685	.min_volt_shift = 100000,
    686	.max_volt_shift = 200000,
    687	.proc_max_volt = 1150000,
    688	.sram_min_volt = 0,
    689	.sram_max_volt = 1150000,
    690	.ccifreq_supported = false,
    691};
    692
    693static const struct mtk_cpufreq_platform_data mt8183_platform_data = {
    694	.min_volt_shift = 100000,
    695	.max_volt_shift = 200000,
    696	.proc_max_volt = 1150000,
    697	.sram_min_volt = 0,
    698	.sram_max_volt = 1150000,
    699	.ccifreq_supported = true,
    700};
    701
    702static const struct mtk_cpufreq_platform_data mt8186_platform_data = {
    703	.min_volt_shift = 100000,
    704	.max_volt_shift = 250000,
    705	.proc_max_volt = 1118750,
    706	.sram_min_volt = 850000,
    707	.sram_max_volt = 1118750,
    708	.ccifreq_supported = true,
    709};
    710
    711/* List of machines supported by this driver */
    712static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
    713	{ .compatible = "mediatek,mt2701", .data = &mt2701_platform_data },
    714	{ .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
    715	{ .compatible = "mediatek,mt7622", .data = &mt2701_platform_data },
    716	{ .compatible = "mediatek,mt7623", .data = &mt2701_platform_data },
    717	{ .compatible = "mediatek,mt8167", .data = &mt2701_platform_data },
    718	{ .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
    719	{ .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
    720	{ .compatible = "mediatek,mt8176", .data = &mt2701_platform_data },
    721	{ .compatible = "mediatek,mt8183", .data = &mt8183_platform_data },
    722	{ .compatible = "mediatek,mt8186", .data = &mt8186_platform_data },
    723	{ .compatible = "mediatek,mt8365", .data = &mt2701_platform_data },
    724	{ .compatible = "mediatek,mt8516", .data = &mt2701_platform_data },
    725	{ }
    726};
    727MODULE_DEVICE_TABLE(of, mtk_cpufreq_machines);
    728
    729static int __init mtk_cpufreq_driver_init(void)
    730{
    731	struct device_node *np;
    732	const struct of_device_id *match;
    733	const struct mtk_cpufreq_platform_data *data;
    734	int err;
    735
    736	np = of_find_node_by_path("/");
    737	if (!np)
    738		return -ENODEV;
    739
    740	match = of_match_node(mtk_cpufreq_machines, np);
    741	of_node_put(np);
    742	if (!match) {
    743		pr_debug("Machine is not compatible with mtk-cpufreq\n");
    744		return -ENODEV;
    745	}
    746	data = match->data;
    747
    748	err = platform_driver_register(&mtk_cpufreq_platdrv);
    749	if (err)
    750		return err;
    751
    752	/*
    753	 * Since there's no place to hold device registration code and no
    754	 * device tree based way to match cpufreq driver yet, both the driver
    755	 * and the device registration codes are put here to handle defer
    756	 * probing.
    757	 */
    758	cpufreq_pdev = platform_device_register_data(NULL, "mtk-cpufreq", -1,
    759						     data, sizeof(*data));
    760	if (IS_ERR(cpufreq_pdev)) {
    761		pr_err("failed to register mtk-cpufreq platform device\n");
    762		platform_driver_unregister(&mtk_cpufreq_platdrv);
    763		return PTR_ERR(cpufreq_pdev);
    764	}
    765
    766	return 0;
    767}
    768module_init(mtk_cpufreq_driver_init)
    769
    770static void __exit mtk_cpufreq_driver_exit(void)
    771{
    772	platform_device_unregister(cpufreq_pdev);
    773	platform_driver_unregister(&mtk_cpufreq_platdrv);
    774}
    775module_exit(mtk_cpufreq_driver_exit)
    776
    777MODULE_DESCRIPTION("MediaTek CPUFreq driver");
    778MODULE_AUTHOR("Pi-Cheng Chen <pi-cheng.chen@linaro.org>");
    779MODULE_LICENSE("GPL v2");