static int a6xx_gmu_build_freq_table(struct device *dev, unsigned long *freqs, u32 size) { int count = dev_pm_opp_get_opp_count(dev); struct dev_pm_opp *opp; int i, index = 0; unsigned long freq = 1; /* * The OPP table doesn't contain the "off" frequency level so we need to * add 1 to the table size to account for it */ if (WARN(count + 1 > size, "The GMU frequency table is being truncated\n")) count = size - 1; /* Set the "off" frequency */ freqs[index++] = 0; for (i = 0; i < count; i++) { opp = dev_pm_opp_find_freq_ceil(dev, &freq); if (IS_ERR(opp)) break; dev_pm_opp_put(opp); freqs[index++] = freq++; } return index; }
/** * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device * @dev: device for which we do this operation * @table: Cpufreq table returned back to caller * * Generate a cpufreq table for a provided device- this assumes that the * opp list is already initialized and ready for usage. * * This function allocates required memory for the cpufreq table. It is * expected that the caller does the required maintenance such as freeing * the table as required. * * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM * if no memory available for the operation (table is not populated), returns 0 * if successful and table is populated. * * WARNING: It is important for the callers to ensure refreshing their copy of * the table if any of the mentioned functions have been invoked in the interim. * * Locking: The internal device_opp and opp structures are RCU protected. * Since we just use the regular accessor functions to access the internal data * structures, we use RCU read lock inside this function. As a result, users of * this function DONOT need to use explicit locks for invoking. */ int dev_pm_opp_init_cpufreq_table(struct device *dev, struct cpufreq_frequency_table **table) { struct dev_pm_opp *opp; struct cpufreq_frequency_table *freq_table = NULL; int i, max_opps, ret = 0; unsigned long rate; rcu_read_lock(); max_opps = dev_pm_opp_get_opp_count(dev); if (max_opps <= 0) { ret = max_opps ? max_opps : -ENODATA; goto out; } freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC); if (!freq_table) { ret = -ENOMEM; goto out; } for (i = 0, rate = 0; i < max_opps; i++, rate++) { /* find next rate */ opp = dev_pm_opp_find_freq_ceil(dev, &rate); if (IS_ERR(opp)) { ret = PTR_ERR(opp); goto out; } freq_table[i].driver_data = i; freq_table[i].frequency = rate / 1000; /* Is Boost/turbo opp ? */ if (dev_pm_opp_is_turbo(opp)) freq_table[i].flags = CPUFREQ_BOOST_FREQ; } freq_table[i].driver_data = i; freq_table[i].frequency = CPUFREQ_TABLE_END; *table = &freq_table[0]; out: rcu_read_unlock(); if (ret) kfree(freq_table); return ret; }
static int kbase_devfreq_init_freq_table(struct kbase_device *kbdev, struct devfreq_dev_profile *dp) { int count; int i = 0; unsigned long freq = 0; struct dev_pm_opp *opp; rcu_read_lock(); count = dev_pm_opp_get_opp_count(kbdev->dev); if (count < 0) { rcu_read_unlock(); return count; } rcu_read_unlock(); dp->freq_table = kmalloc_array(count, sizeof(dp->freq_table[0]), GFP_KERNEL); if (!dp->freq_table) return -ENOMEM; rcu_read_lock(); for (i = 0; i < count; i++, freq++) { opp = dev_pm_opp_find_freq_ceil(kbdev->dev, &freq); if (IS_ERR(opp)) break; dp->freq_table[i] = freq; } rcu_read_unlock(); if (count != i) dev_warn(kbdev->dev, "Unable to enumerate all OPPs (%d!=%d\n", count, i); dp->max_state = i; return 0; }
static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) { struct device *cpu_dev; struct regulator *proc_reg = ERR_PTR(-ENODEV); struct regulator *sram_reg = ERR_PTR(-ENODEV); struct clk *cpu_clk = ERR_PTR(-ENODEV); struct clk *inter_clk = ERR_PTR(-ENODEV); struct dev_pm_opp *opp; unsigned long rate; int ret; cpu_dev = get_cpu_device(cpu); if (!cpu_dev) { pr_err("failed to get cpu%d device\n", cpu); return -ENODEV; } cpu_clk = clk_get(cpu_dev, "cpu"); if (IS_ERR(cpu_clk)) { if (PTR_ERR(cpu_clk) == -EPROBE_DEFER) pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu); else pr_err("failed to get cpu clk for cpu%d\n", cpu); ret = PTR_ERR(cpu_clk); return ret; } inter_clk = clk_get(cpu_dev, "intermediate"); if (IS_ERR(inter_clk)) { if (PTR_ERR(inter_clk) == -EPROBE_DEFER) pr_warn("intermediate clk for cpu%d not ready, retry.\n", cpu); else pr_err("failed to get intermediate clk for cpu%d\n", cpu); ret = PTR_ERR(inter_clk); goto out_free_resources; } proc_reg = regulator_get_exclusive(cpu_dev, "proc"); if (IS_ERR(proc_reg)) { if (PTR_ERR(proc_reg) == -EPROBE_DEFER) pr_warn("proc regulator for cpu%d not ready, retry.\n", cpu); else pr_err("failed to get proc regulator for cpu%d\n", cpu); ret = PTR_ERR(proc_reg); goto out_free_resources; } /* Both presence and absence of sram regulator are valid cases. */ sram_reg = regulator_get_exclusive(cpu_dev, "sram"); ret = dev_pm_opp_of_add_table(cpu_dev); if (ret) { pr_warn("no OPP table for cpu%d\n", cpu); goto out_free_resources; } /* Search a safe voltage for intermediate frequency. */ rate = clk_get_rate(inter_clk); rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate); if (IS_ERR(opp)) { rcu_read_unlock(); pr_err("failed to get intermediate opp for cpu%d\n", cpu); ret = PTR_ERR(opp); goto out_free_opp_table; } info->intermediate_voltage = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); info->cpu_dev = cpu_dev; info->proc_reg = proc_reg; info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg; info->cpu_clk = cpu_clk; info->inter_clk = inter_clk; /* * If SRAM regulator is present, software "voltage tracking" is needed * for this CPU power domain. */ info->need_voltage_tracking = !IS_ERR(sram_reg); return 0; out_free_opp_table: dev_pm_opp_of_remove_table(cpu_dev); out_free_resources: if (!IS_ERR(proc_reg)) regulator_put(proc_reg); if (!IS_ERR(sram_reg)) regulator_put(sram_reg); if (!IS_ERR(cpu_clk)) clk_put(cpu_clk); if (!IS_ERR(inter_clk)) clk_put(inter_clk); return ret; }
static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) { struct cpufreq_frequency_table *freq_table = policy->freq_table; struct clk *cpu_clk = policy->clk; struct clk *armpll = clk_get_parent(cpu_clk); struct mtk_cpu_dvfs_info *info = policy->driver_data; struct device *cpu_dev = info->cpu_dev; struct dev_pm_opp *opp; long freq_hz, old_freq_hz; int vproc, old_vproc, inter_vproc, target_vproc, ret; inter_vproc = info->intermediate_voltage; old_freq_hz = clk_get_rate(cpu_clk); old_vproc = regulator_get_voltage(info->proc_reg); freq_hz = freq_table[index].frequency * 1000; rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { rcu_read_unlock(); pr_err("cpu%d: failed to find OPP for %ld\n", policy->cpu, freq_hz); return PTR_ERR(opp); } vproc = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); /* * If the new voltage or the intermediate voltage is higher than the * current voltage, scale up voltage first. */ target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc; if (old_vproc < target_vproc) { ret = mtk_cpufreq_set_voltage(info, target_vproc); if (ret) { pr_err("cpu%d: failed to scale up voltage!\n", policy->cpu); mtk_cpufreq_set_voltage(info, old_vproc); return ret; } } /* Reparent the CPU clock to intermediate clock. */ ret = clk_set_parent(cpu_clk, info->inter_clk); if (ret) { pr_err("cpu%d: failed to re-parent cpu clock!\n", policy->cpu); mtk_cpufreq_set_voltage(info, old_vproc); WARN_ON(1); return ret; } /* Set the original PLL to target rate. */ ret = clk_set_rate(armpll, freq_hz); if (ret) { pr_err("cpu%d: failed to scale cpu clock rate!\n", policy->cpu); clk_set_parent(cpu_clk, armpll); mtk_cpufreq_set_voltage(info, old_vproc); return ret; } /* Set parent of CPU clock back to the original PLL. */ ret = clk_set_parent(cpu_clk, armpll); if (ret) { pr_err("cpu%d: failed to re-parent cpu clock!\n", policy->cpu); mtk_cpufreq_set_voltage(info, inter_vproc); WARN_ON(1); return ret; } /* * If the new voltage is lower than the intermediate voltage or the * original voltage, scale down to the new voltage. */ if (vproc < inter_vproc || vproc < old_vproc) { ret = mtk_cpufreq_set_voltage(info, vproc); if (ret) { pr_err("cpu%d: failed to scale down voltage!\n", policy->cpu); clk_set_parent(cpu_clk, info->inter_clk); clk_set_rate(armpll, old_freq_hz); clk_set_parent(cpu_clk, armpll); return ret; } } return 0; }
static int imx7d_set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; unsigned long freq_hz, volt, volt_old; unsigned int old_freq, new_freq; int ret; mutex_lock(&set_cpufreq_lock); new_freq = freq_table[index].frequency; freq_hz = new_freq * 1000; old_freq = clk_get_rate(arm_clk) / 1000; rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); mutex_unlock(&set_cpufreq_lock); return PTR_ERR(opp); } volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); volt_old = regulator_get_voltage(arm_reg); dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", old_freq / 1000, volt_old / 1000, new_freq / 1000, volt / 1000); /* Scaling up? scale voltage before frequency */ if (new_freq > old_freq) { ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret); mutex_unlock(&set_cpufreq_lock); return ret; } } /* before changing pll_arm rate, change the arm_src's soure * to pll_sys_main clk first. */ clk_set_parent(arm_src, pll_sys_main); clk_set_rate(pll_arm, new_freq * 1000); clk_set_parent(arm_src, pll_arm); /* change the cpu frequency */ ret = clk_set_rate(arm_clk, new_freq * 1000); if (ret) { dev_err(cpu_dev, " failed to set clock rate: %d\n", ret); regulator_set_voltage_tol(arm_reg, volt_old, 0); mutex_unlock(&set_cpufreq_lock); return ret; } /* scaling down? scaling voltage after frequency */ if (new_freq < old_freq) { ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_warn(cpu_dev, "failed to scale vddarm down: %d\n", ret); ret = 0; } } mutex_unlock(&set_cpufreq_lock); return 0; }
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; unsigned long freq_hz, volt, volt_old; unsigned int old_freq, new_freq; bool pll1_sys_temp_enabled = false; int ret; new_freq = freq_table[index].frequency; freq_hz = new_freq * 1000; old_freq = clk_get_rate(arm_clk) / 1000; opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); return PTR_ERR(opp); } volt = dev_pm_opp_get_voltage(opp); dev_pm_opp_put(opp); volt_old = regulator_get_voltage(arm_reg); dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", old_freq / 1000, volt_old / 1000, new_freq / 1000, volt / 1000); /* scaling up? scale voltage before frequency */ if (new_freq > old_freq) { if (!IS_ERR(pu_reg)) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret); return ret; } } ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); return ret; } ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret); return ret; } } /* * The setpoints are selected per PLL/PDF frequencies, so we need to * reprogram PLL for frequency scaling. The procedure of reprogramming * PLL1 is as below. * For i.MX6UL, it has a secondary clk mux, the cpu frequency change * flow is slightly different from other i.MX6 OSC. * The cpu frequeny change flow for i.MX6(except i.MX6UL) is as below: * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it * - Disable pll2_pfd2_396m_clk */ if (of_machine_is_compatible("fsl,imx6ul") || of_machine_is_compatible("fsl,imx6ull")) { /* * When changing pll1_sw_clk's parent to pll1_sys_clk, * CPU may run at higher than 528MHz, this will lead to * the system unstable if the voltage is lower than the * voltage of 528MHz, so lower the CPU frequency to one * half before changing CPU frequency. */ clk_set_rate(arm_clk, (old_freq >> 1) * 1000); clk_set_parent(pll1_sw_clk, pll1_sys_clk); if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) clk_set_parent(secondary_sel_clk, pll2_bus_clk); else clk_set_parent(secondary_sel_clk, pll2_pfd2_396m_clk); clk_set_parent(step_clk, secondary_sel_clk); clk_set_parent(pll1_sw_clk, step_clk); } else {
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; unsigned long freq_hz, volt, volt_old; unsigned int old_freq, new_freq; int ret; mutex_lock(&set_cpufreq_lock); new_freq = freq_table[index].frequency; freq_hz = new_freq * 1000; old_freq = clk_get_rate(arm_clk) / 1000; rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); mutex_unlock(&set_cpufreq_lock); return PTR_ERR(opp); } volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); volt_old = regulator_get_voltage(arm_reg); dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", old_freq / 1000, volt_old / 1000, new_freq / 1000, volt / 1000); /* * CPU freq is increasing, so need to ensure * that bus frequency is increased too. */ if (old_freq <= FREQ_396_MHZ && new_freq > FREQ_396_MHZ) request_bus_freq(BUS_FREQ_HIGH); /* scaling up? scale voltage before frequency */ if (new_freq > old_freq) { if (!IS_ERR(pu_reg)) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret); mutex_unlock(&set_cpufreq_lock); return ret; } } ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); mutex_unlock(&set_cpufreq_lock); return ret; } ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret); mutex_unlock(&set_cpufreq_lock); return ret; } } /* * The setpoints are selected per PLL/PDF frequencies, so we need to * reprogram PLL for frequency scaling. The procedure of reprogramming * PLL1 is as below. * For i.MX6UL, it has a secondary clk mux, the cpu frequency change * flow is slightly different from other I.MX6 SOC. * * The cpu frequency change flow for i.MX6(except i.MX6UL) is as below: * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it * - Disable pll2_pfd2_396m_clk */ if (!IS_ERR(secondary_sel)) { /* When changing pll1_sw source to pll1_sys, cpu may run at higher * than 528MHz, this will lead to the system unstable if the voltage * is lower than the voltage of 528MHz. So lower the cpu frequency to * one half before changing cpu frequency. */ clk_set_rate(arm_clk, (old_freq >> 1) * 1000); clk_set_parent(pll1_sw_clk, pll1_sys_clk); clk_set_parent(step_clk, osc); if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) clk_set_parent(secondary_sel, pll2_bus); else clk_set_parent(secondary_sel, pll2_pfd2_396m_clk); clk_set_parent(step_clk, secondary_sel); clk_set_parent(pll1_sw_clk, step_clk); if (freq_hz > clk_get_rate(pll2_bus)) { clk_set_rate(pll1, new_freq * 1000); clk_set_parent(pll1_sw_clk, pll1_sys_clk); } } else {
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; unsigned long freq_hz, volt, volt_old; unsigned int old_freq, new_freq; int ret; new_freq = freq_table[index].frequency; freq_hz = new_freq * 1000; old_freq = clk_get_rate(arm_clk) / 1000; rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); return PTR_ERR(opp); } volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); volt_old = regulator_get_voltage(arm_reg); dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", old_freq / 1000, volt_old / 1000, new_freq / 1000, volt / 1000); /* scaling up? scale voltage before frequency */ if (new_freq > old_freq) { if (!IS_ERR(pu_reg)) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret); return ret; } } ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); return ret; } ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret); return ret; } } /* * The setpoints are selected per PLL/PDF frequencies, so we need to * reprogram PLL for frequency scaling. The procedure of reprogramming * PLL1 is as below. * * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it * - Disable pll2_pfd2_396m_clk */ clk_set_parent(step_clk, pll2_pfd2_396m_clk); clk_set_parent(pll1_sw_clk, step_clk); if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { clk_set_rate(pll1_sys_clk, new_freq * 1000); clk_set_parent(pll1_sw_clk, pll1_sys_clk); } /* Ensure the arm clock divider is what we expect */ ret = clk_set_rate(arm_clk, new_freq * 1000); if (ret) { dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); regulator_set_voltage_tol(arm_reg, volt_old, 0); return ret; } /* scaling down? scale voltage after frequency */ if (new_freq < old_freq) { ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_warn(cpu_dev, "failed to scale vddarm down: %d\n", ret); ret = 0; } ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); if (ret) { dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret); ret = 0; } if (!IS_ERR(pu_reg)) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (ret) { dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret); ret = 0; } } } return 0; }
static int set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; struct cpufreq_frequency_table *freq_table = policy->freq_table; struct clk *cpu_clk = policy->clk; struct private_data *priv = policy->driver_data; struct device *cpu_dev = priv->cpu_dev; struct regulator *cpu_reg = priv->cpu_reg; unsigned long volt = 0, volt_old = 0, tol = 0; unsigned int old_freq, new_freq; long freq_Hz, freq_exact; int ret; freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); if (freq_Hz <= 0) freq_Hz = freq_table[index].frequency * 1000; freq_exact = freq_Hz; new_freq = freq_Hz / 1000; old_freq = clk_get_rate(cpu_clk) / 1000; if (!IS_ERR(cpu_reg)) { rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_Hz); return PTR_ERR(opp); } volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); tol = volt * priv->voltage_tolerance / 100; volt_old = regulator_get_voltage(cpu_reg); } dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", old_freq / 1000, volt_old ? volt_old / 1000 : -1, new_freq / 1000, volt ? volt / 1000 : -1); /* scaling up? scale voltage before frequency */ if (!IS_ERR(cpu_reg) && new_freq > old_freq) { ret = regulator_set_voltage_tol(cpu_reg, volt, tol); if (ret) { dev_err(cpu_dev, "failed to scale voltage up: %d\n", ret); return ret; } } ret = clk_set_rate(cpu_clk, freq_exact); if (ret) { dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); if (!IS_ERR(cpu_reg)) regulator_set_voltage_tol(cpu_reg, volt_old, tol); return ret; } /* scaling down? scale voltage after frequency */ if (!IS_ERR(cpu_reg) && new_freq < old_freq) { ret = regulator_set_voltage_tol(cpu_reg, volt, tol); if (ret) { dev_err(cpu_dev, "failed to scale voltage down: %d\n", ret); clk_set_rate(cpu_clk, old_freq * 1000); } } return ret; }
static int cpufreq_init(struct cpufreq_policy *policy) { struct cpufreq_dt_platform_data *pd; struct cpufreq_frequency_table *freq_table; struct thermal_cooling_device *cdev; struct device_node *np; struct private_data *priv; struct device *cpu_dev; struct regulator *cpu_reg; struct clk *cpu_clk; unsigned long min_uV = ~0, max_uV = 0; unsigned int transition_latency; int ret; ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk); if (ret) { pr_err("%s: Failed to allocate resources\n: %d", __func__, ret); return ret; } np = of_node_get(cpu_dev->of_node); if (!np) { dev_err(cpu_dev, "failed to find cpu%d node\n", policy->cpu); ret = -ENOENT; goto out_put_reg_clk; } /* OPPs might be populated at runtime, don't check for error here */ of_init_opp_table(cpu_dev); priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; goto out_put_node; } of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance); if (of_property_read_u32(np, "clock-latency", &transition_latency)) transition_latency = CPUFREQ_ETERNAL; if (!IS_ERR(cpu_reg)) { unsigned long opp_freq = 0; /* * Disable any OPPs where the connected regulator isn't able to * provide the specified voltage and record minimum and maximum * voltage levels. */ while (1) { struct dev_pm_opp *opp; unsigned long opp_uV, tol_uV; rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &opp_freq); if (IS_ERR(opp)) { rcu_read_unlock(); break; } opp_uV = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); tol_uV = opp_uV * priv->voltage_tolerance / 100; if (regulator_is_supported_voltage(cpu_reg, opp_uV, opp_uV + tol_uV)) { if (opp_uV < min_uV) min_uV = opp_uV; if (opp_uV > max_uV) max_uV = opp_uV; } else { dev_pm_opp_disable(cpu_dev, opp_freq); } opp_freq++; } ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV); if (ret > 0) transition_latency += ret * 1000; } ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); if (ret) { pr_err("failed to init cpufreq table: %d\n", ret); goto out_free_priv; } /* * For now, just loading the cooling device; * thermal DT code takes care of matching them. */ if (of_find_property(np, "#cooling-cells", NULL)) { cdev = of_cpufreq_cooling_register(np, cpu_present_mask); if (IS_ERR(cdev)) dev_err(cpu_dev, "running cpufreq without cooling device: %ld\n", PTR_ERR(cdev)); else priv->cdev = cdev; } priv->cpu_dev = cpu_dev; priv->cpu_reg = cpu_reg; policy->driver_data = priv; policy->clk = cpu_clk; ret = cpufreq_table_validate_and_show(policy, freq_table); if (ret) { dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, ret); goto out_cooling_unregister; } policy->cpuinfo.transition_latency = transition_latency; pd = cpufreq_get_driver_data(); if (!pd || !pd->independent_clocks) cpumask_setall(policy->cpus); of_node_put(np); return 0; out_cooling_unregister: cpufreq_cooling_unregister(priv->cdev); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); out_free_priv: kfree(priv); out_put_node: of_node_put(np); out_put_reg_clk: clk_put(cpu_clk); if (!IS_ERR(cpu_reg)) regulator_put(cpu_reg); return ret; }
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; unsigned long freq_hz, volt, volt_old; unsigned int old_freq, new_freq; int ret; mutex_lock(&set_cpufreq_lock); new_freq = freq_table[index].frequency; freq_hz = new_freq * 1000; old_freq = clk_get_rate(arm_clk) / 1000; rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); mutex_unlock(&set_cpufreq_lock); return PTR_ERR(opp); } volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); volt_old = regulator_get_voltage(arm_reg); dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", old_freq / 1000, volt_old / 1000, new_freq / 1000, volt / 1000); /* * CPU freq is increasing, so need to ensure * that bus frequency is increased too. */ if (old_freq <= FREQ_396_MHZ && new_freq > FREQ_396_MHZ) request_bus_freq(BUS_FREQ_HIGH); /* scaling up? scale voltage before frequency */ if (new_freq > old_freq) { if (!IS_ERR(pu_reg) && regulator_is_enabled(pu_reg)) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret); mutex_unlock(&set_cpufreq_lock); return ret; } } ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); if (ret) { dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); mutex_unlock(&set_cpufreq_lock); return ret; } ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret); mutex_unlock(&set_cpufreq_lock); return ret; } } /* * The setpoints are selected per PLL/PDF frequencies, so we need to * reprogram PLL for frequency scaling. The procedure of reprogramming * PLL1 is as below. * * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it * - Disable pll2_pfd2_396m_clk */ clk_set_parent(step_clk, pll2_pfd2_396m_clk); clk_set_parent(pll1_sw_clk, step_clk); if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { clk_set_rate(pll1, new_freq * 1000); /* * Ensure pll1_bypass is set back to pll1. */ clk_set_parent(pll1_bypass, pll1); clk_set_parent(pll1_sw_clk, pll1_sys_clk); } else /* * Need to ensure that PLL1 is bypassed and enabled * before ARM-PODF is set. */ clk_set_parent(pll1_bypass, pll1_bypass_src); /* Ensure the arm clock divider is what we expect */ ret = clk_set_rate(arm_clk, new_freq * 1000); if (ret) { dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); regulator_set_voltage_tol(arm_reg, volt_old, 0); mutex_unlock(&set_cpufreq_lock); return ret; } /* scaling down? scale voltage after frequency */ if (new_freq < old_freq) { ret = regulator_set_voltage_tol(arm_reg, volt, 0); if (ret) { dev_warn(cpu_dev, "failed to scale vddarm down: %d\n", ret); ret = 0; } ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); if (ret) { dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret); ret = 0; } if (!IS_ERR(pu_reg) && regulator_is_enabled(pu_reg)) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (ret) { dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret); ret = 0; } } } /* * If CPU is dropped to the lowest level, release the need * for a high bus frequency. */ if (old_freq > FREQ_396_MHZ && new_freq <= FREQ_396_MHZ) release_bus_freq(BUS_FREQ_HIGH); mutex_unlock(&set_cpufreq_lock); return 0; }
static int omap_target(struct cpufreq_policy *policy, unsigned int index) { int r, ret; struct dev_pm_opp *opp; unsigned long freq, volt = 0, volt_old = 0, tol = 0; unsigned int old_freq, new_freq; old_freq = policy->cur; new_freq = freq_table[index].frequency; freq = new_freq * 1000; ret = clk_round_rate(policy->clk, freq); if (IS_ERR_VALUE(ret)) { dev_warn(mpu_dev, "CPUfreq: Cannot find matching frequency for %lu\n", freq); return ret; } freq = ret; if (mpu_reg) { rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq); if (IS_ERR(opp)) { rcu_read_unlock(); dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", __func__, new_freq); return -EINVAL; } volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); tol = volt * OPP_TOLERANCE / 100; volt_old = regulator_get_voltage(mpu_reg); } dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", old_freq / 1000, volt_old ? volt_old / 1000 : -1, new_freq / 1000, volt ? volt / 1000 : -1); /* scaling up? scale voltage before frequency */ if (mpu_reg && (new_freq > old_freq)) { r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); if (r < 0) { dev_warn(mpu_dev, "%s: unable to scale voltage up.\n", __func__); return r; } } ret = clk_set_rate(policy->clk, new_freq * 1000); /* scaling down? scale voltage after frequency */ if (mpu_reg && (new_freq < old_freq)) { r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); if (r < 0) { dev_warn(mpu_dev, "%s: unable to scale voltage down.\n", __func__); clk_set_rate(policy->clk, old_freq * 1000); return r; } } return ret; }