mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 01:00:58 +07:00
Merge branch 'pm-cpufreq'
* pm-cpufreq: cpufreq: Avoid calling cpufreq_verify_current_freq() from handle_update() cpufreq: Consolidate cpufreq_update_current_freq() and __cpufreq_get() cpufreq: Don't skip frequency validation for has_target() drivers cpufreq: Use has_target() instead of !setpolicy cpufreq: Remove redundant !setpolicy check cpufreq: Move the IS_ENABLED(CPU_THERMAL) macro into a stub cpufreq: s5pv210: Don't flood kernel log after cpufreq change cpufreq: pcc-cpufreq: Fail initialization if driver cannot be registered cpufreq: add driver for Raspberry Pi cpufreq: Switch imx7d to imx-cpufreq-dt for speed grading cpufreq: imx-cpufreq-dt: Remove global platform match list cpufreq: brcmstb-avs-cpufreq: Fix types for voltage/frequency cpufreq: brcmstb-avs-cpufreq: Fix initial command check cpufreq: armada-37xx: Remove set but not used variable 'freq' cpufreq: imx-cpufreq-dt: Fix no OPPs available on unfused parts dt-bindings: imx-cpufreq-dt: Document opp-supported-hw usage cpufreq: Add imx-cpufreq-dt driver
This commit is contained in:
commit
586a07dca8
37
Documentation/devicetree/bindings/cpufreq/imx-cpufreq-dt.txt
Normal file
37
Documentation/devicetree/bindings/cpufreq/imx-cpufreq-dt.txt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
i.MX CPUFreq-DT OPP bindings
|
||||||
|
================================
|
||||||
|
|
||||||
|
Certain i.MX SoCs support different OPPs depending on the "market segment" and
|
||||||
|
"speed grading" value which are written in fuses. These bits are combined with
|
||||||
|
the opp-supported-hw values for each OPP to check if the OPP is allowed.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
For each opp entry in 'operating-points-v2' table:
|
||||||
|
- opp-supported-hw: Two bitmaps indicating:
|
||||||
|
- Supported speed grade mask
|
||||||
|
- Supported market segment mask
|
||||||
|
0: Consumer
|
||||||
|
1: Extended Consumer
|
||||||
|
2: Industrial
|
||||||
|
3: Automotive
|
||||||
|
|
||||||
|
Example:
|
||||||
|
--------
|
||||||
|
|
||||||
|
opp_table {
|
||||||
|
compatible = "operating-points-v2";
|
||||||
|
opp-1000000000 {
|
||||||
|
opp-hz = /bits/ 64 <1000000000>;
|
||||||
|
/* grade >= 0, consumer only */
|
||||||
|
opp-supported-hw = <0xf>, <0x3>;
|
||||||
|
};
|
||||||
|
|
||||||
|
opp-1300000000 {
|
||||||
|
opp-hz = /bits/ 64 <1300000000>;
|
||||||
|
opp-microvolt = <1000000>;
|
||||||
|
/* grade >= 1, all segments */
|
||||||
|
opp-supported-hw = <0xe>, <0x7>;
|
||||||
|
};
|
||||||
|
}
|
@ -93,6 +93,15 @@ config ARM_IMX6Q_CPUFREQ
|
|||||||
|
|
||||||
If in doubt, say N.
|
If in doubt, say N.
|
||||||
|
|
||||||
|
config ARM_IMX_CPUFREQ_DT
|
||||||
|
tristate "Freescale i.MX8M cpufreq support"
|
||||||
|
depends on ARCH_MXC && CPUFREQ_DT
|
||||||
|
help
|
||||||
|
This adds cpufreq driver support for Freescale i.MX8M series SoCs,
|
||||||
|
based on cpufreq-dt.
|
||||||
|
|
||||||
|
If in doubt, say N.
|
||||||
|
|
||||||
config ARM_KIRKWOOD_CPUFREQ
|
config ARM_KIRKWOOD_CPUFREQ
|
||||||
def_bool MACH_KIRKWOOD
|
def_bool MACH_KIRKWOOD
|
||||||
help
|
help
|
||||||
@ -133,6 +142,14 @@ config ARM_QCOM_CPUFREQ_HW
|
|||||||
The driver implements the cpufreq interface for this HW engine.
|
The driver implements the cpufreq interface for this HW engine.
|
||||||
Say Y if you want to support CPUFreq HW.
|
Say Y if you want to support CPUFreq HW.
|
||||||
|
|
||||||
|
config ARM_RASPBERRYPI_CPUFREQ
|
||||||
|
tristate "Raspberry Pi cpufreq support"
|
||||||
|
depends on CLK_RASPBERRYPI || COMPILE_TEST
|
||||||
|
help
|
||||||
|
This adds the CPUFreq driver for Raspberry Pi
|
||||||
|
|
||||||
|
If in doubt, say N.
|
||||||
|
|
||||||
config ARM_S3C_CPUFREQ
|
config ARM_S3C_CPUFREQ
|
||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
|
@ -56,6 +56,7 @@ obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
|
|||||||
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
|
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
|
||||||
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
|
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
|
||||||
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
|
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
|
||||||
|
obj-$(CONFIG_ARM_IMX_CPUFREQ_DT) += imx-cpufreq-dt.o
|
||||||
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
|
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
|
||||||
obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ) += mediatek-cpufreq.o
|
obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ) += mediatek-cpufreq.o
|
||||||
obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
|
obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
|
||||||
@ -64,6 +65,7 @@ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
|
|||||||
obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
|
obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
|
||||||
obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o
|
obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o
|
||||||
obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o
|
obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o
|
||||||
|
obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o
|
||||||
obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
|
obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
|
||||||
obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
|
obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
|
||||||
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
|
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
|
||||||
|
@ -257,7 +257,7 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
|
|||||||
static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
|
static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
|
||||||
struct armada_37xx_dvfs *dvfs)
|
struct armada_37xx_dvfs *dvfs)
|
||||||
{
|
{
|
||||||
unsigned int avs_val = 0, freq;
|
unsigned int avs_val = 0;
|
||||||
int load_level = 0;
|
int load_level = 0;
|
||||||
|
|
||||||
if (base == NULL)
|
if (base == NULL)
|
||||||
@ -275,8 +275,6 @@ static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
|
|||||||
|
|
||||||
|
|
||||||
for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) {
|
for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) {
|
||||||
freq = dvfs->cpu_freq_max / dvfs->divider[load_level];
|
|
||||||
|
|
||||||
avs_val = dvfs->avs[load_level];
|
avs_val = dvfs->avs[load_level];
|
||||||
regmap_update_bits(base, ARMADA_37XX_AVS_VSET(load_level-1),
|
regmap_update_bits(base, ARMADA_37XX_AVS_VSET(load_level-1),
|
||||||
ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_HIGH_VDD_LIMIT |
|
ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_HIGH_VDD_LIMIT |
|
||||||
|
@ -384,12 +384,12 @@ static int brcm_avs_set_pstate(struct private_data *priv, unsigned int pstate)
|
|||||||
return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, true, args);
|
return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, true, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long brcm_avs_get_voltage(void __iomem *base)
|
static u32 brcm_avs_get_voltage(void __iomem *base)
|
||||||
{
|
{
|
||||||
return readl(base + AVS_MBOX_VOLTAGE1);
|
return readl(base + AVS_MBOX_VOLTAGE1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long brcm_avs_get_frequency(void __iomem *base)
|
static u32 brcm_avs_get_frequency(void __iomem *base)
|
||||||
{
|
{
|
||||||
return readl(base + AVS_MBOX_FREQUENCY) * 1000; /* in kHz */
|
return readl(base + AVS_MBOX_FREQUENCY) * 1000; /* in kHz */
|
||||||
}
|
}
|
||||||
@ -446,8 +446,8 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv)
|
|||||||
rc = brcm_avs_get_pmap(priv, NULL);
|
rc = brcm_avs_get_pmap(priv, NULL);
|
||||||
magic = readl(priv->base + AVS_MBOX_MAGIC);
|
magic = readl(priv->base + AVS_MBOX_MAGIC);
|
||||||
|
|
||||||
return (magic == AVS_FIRMWARE_MAGIC) && (rc != -ENOTSUPP) &&
|
return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) ||
|
||||||
(rc != -EINVAL);
|
(rc != -EINVAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
|
static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
|
||||||
@ -653,14 +653,14 @@ static ssize_t show_brcm_avs_voltage(struct cpufreq_policy *policy, char *buf)
|
|||||||
{
|
{
|
||||||
struct private_data *priv = policy->driver_data;
|
struct private_data *priv = policy->driver_data;
|
||||||
|
|
||||||
return sprintf(buf, "0x%08lx\n", brcm_avs_get_voltage(priv->base));
|
return sprintf(buf, "0x%08x\n", brcm_avs_get_voltage(priv->base));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf)
|
static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf)
|
||||||
{
|
{
|
||||||
struct private_data *priv = policy->driver_data;
|
struct private_data *priv = policy->driver_data;
|
||||||
|
|
||||||
return sprintf(buf, "0x%08lx\n", brcm_avs_get_frequency(priv->base));
|
return sprintf(buf, "0x%08x\n", brcm_avs_get_frequency(priv->base));
|
||||||
}
|
}
|
||||||
|
|
||||||
cpufreq_freq_attr_ro(brcm_avs_pstate);
|
cpufreq_freq_attr_ro(brcm_avs_pstate);
|
||||||
|
@ -37,7 +37,6 @@ static const struct of_device_id whitelist[] __initconst = {
|
|||||||
{ .compatible = "fsl,imx27", },
|
{ .compatible = "fsl,imx27", },
|
||||||
{ .compatible = "fsl,imx51", },
|
{ .compatible = "fsl,imx51", },
|
||||||
{ .compatible = "fsl,imx53", },
|
{ .compatible = "fsl,imx53", },
|
||||||
{ .compatible = "fsl,imx7d", },
|
|
||||||
|
|
||||||
{ .compatible = "marvell,berlin", },
|
{ .compatible = "marvell,berlin", },
|
||||||
{ .compatible = "marvell,pxa250", },
|
{ .compatible = "marvell,pxa250", },
|
||||||
@ -105,6 +104,10 @@ static const struct of_device_id blacklist[] __initconst = {
|
|||||||
{ .compatible = "calxeda,highbank", },
|
{ .compatible = "calxeda,highbank", },
|
||||||
{ .compatible = "calxeda,ecx-2000", },
|
{ .compatible = "calxeda,ecx-2000", },
|
||||||
|
|
||||||
|
{ .compatible = "fsl,imx7d", },
|
||||||
|
{ .compatible = "fsl,imx8mq", },
|
||||||
|
{ .compatible = "fsl,imx8mm", },
|
||||||
|
|
||||||
{ .compatible = "marvell,armadaxp", },
|
{ .compatible = "marvell,armadaxp", },
|
||||||
|
|
||||||
{ .compatible = "mediatek,mt2701", },
|
{ .compatible = "mediatek,mt2701", },
|
||||||
|
@ -356,12 +356,10 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
|||||||
* which is not equal to what the cpufreq core thinks is
|
* which is not equal to what the cpufreq core thinks is
|
||||||
* "old frequency".
|
* "old frequency".
|
||||||
*/
|
*/
|
||||||
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
if (policy->cur && policy->cur != freqs->old) {
|
||||||
if (policy->cur && (policy->cur != freqs->old)) {
|
pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
|
||||||
pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
|
freqs->old, policy->cur);
|
||||||
freqs->old, policy->cur);
|
freqs->old = policy->cur;
|
||||||
freqs->old = policy->cur;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
|
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
|
||||||
@ -631,7 +629,7 @@ static int cpufreq_parse_policy(char *str_governor,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cpufreq_parse_governor - parse a governor string only for !setpolicy
|
* cpufreq_parse_governor - parse a governor string only for has_target()
|
||||||
*/
|
*/
|
||||||
static int cpufreq_parse_governor(char *str_governor,
|
static int cpufreq_parse_governor(char *str_governor,
|
||||||
struct cpufreq_policy *policy)
|
struct cpufreq_policy *policy)
|
||||||
@ -1114,13 +1112,25 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void refresh_frequency_limits(struct cpufreq_policy *policy)
|
||||||
|
{
|
||||||
|
struct cpufreq_policy new_policy = *policy;
|
||||||
|
|
||||||
|
pr_debug("updating policy for CPU %u\n", policy->cpu);
|
||||||
|
|
||||||
|
new_policy.min = policy->user_policy.min;
|
||||||
|
new_policy.max = policy->user_policy.max;
|
||||||
|
|
||||||
|
cpufreq_set_policy(policy, &new_policy);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_update(struct work_struct *work)
|
static void handle_update(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct cpufreq_policy *policy =
|
struct cpufreq_policy *policy =
|
||||||
container_of(work, struct cpufreq_policy, update);
|
container_of(work, struct cpufreq_policy, update);
|
||||||
unsigned int cpu = policy->cpu;
|
|
||||||
pr_debug("handle_update for cpu %u called\n", cpu);
|
pr_debug("handle_update for cpu %u called\n", policy->cpu);
|
||||||
cpufreq_update_policy(cpu);
|
refresh_frequency_limits(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
||||||
@ -1300,7 +1310,7 @@ static int cpufreq_online(unsigned int cpu)
|
|||||||
policy->max = policy->user_policy.max;
|
policy->max = policy->user_policy.max;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
|
if (cpufreq_driver->get && has_target()) {
|
||||||
policy->cur = cpufreq_driver->get(policy->cpu);
|
policy->cur = cpufreq_driver->get(policy->cpu);
|
||||||
if (!policy->cur) {
|
if (!policy->cur) {
|
||||||
pr_err("%s: ->get() failed\n", __func__);
|
pr_err("%s: ->get() failed\n", __func__);
|
||||||
@ -1375,8 +1385,7 @@ static int cpufreq_online(unsigned int cpu)
|
|||||||
if (cpufreq_driver->ready)
|
if (cpufreq_driver->ready)
|
||||||
cpufreq_driver->ready(policy);
|
cpufreq_driver->ready(policy);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_CPU_THERMAL) &&
|
if (cpufreq_thermal_control_enabled(cpufreq_driver))
|
||||||
cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV)
|
|
||||||
policy->cdev = of_cpufreq_cooling_register(policy);
|
policy->cdev = of_cpufreq_cooling_register(policy);
|
||||||
|
|
||||||
pr_debug("initialization complete\n");
|
pr_debug("initialization complete\n");
|
||||||
@ -1466,8 +1475,7 @@ static int cpufreq_offline(unsigned int cpu)
|
|||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_CPU_THERMAL) &&
|
if (cpufreq_thermal_control_enabled(cpufreq_driver)) {
|
||||||
cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) {
|
|
||||||
cpufreq_cooling_unregister(policy->cdev);
|
cpufreq_cooling_unregister(policy->cdev);
|
||||||
policy->cdev = NULL;
|
policy->cdev = NULL;
|
||||||
}
|
}
|
||||||
@ -1546,6 +1554,30 @@ static void cpufreq_out_of_sync(struct cpufreq_policy *policy,
|
|||||||
cpufreq_freq_transition_end(policy, &freqs, 0);
|
cpufreq_freq_transition_end(policy, &freqs, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int cpufreq_verify_current_freq(struct cpufreq_policy *policy, bool update)
|
||||||
|
{
|
||||||
|
unsigned int new_freq;
|
||||||
|
|
||||||
|
new_freq = cpufreq_driver->get(policy->cpu);
|
||||||
|
if (!new_freq)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If fast frequency switching is used with the given policy, the check
|
||||||
|
* against policy->cur is pointless, so skip it in that case.
|
||||||
|
*/
|
||||||
|
if (policy->fast_switch_enabled || !has_target())
|
||||||
|
return new_freq;
|
||||||
|
|
||||||
|
if (policy->cur != new_freq) {
|
||||||
|
cpufreq_out_of_sync(policy, new_freq);
|
||||||
|
if (update)
|
||||||
|
schedule_work(&policy->update);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_freq;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
|
* cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
|
||||||
* @cpu: CPU number
|
* @cpu: CPU number
|
||||||
@ -1601,31 +1633,10 @@ EXPORT_SYMBOL(cpufreq_quick_get_max);
|
|||||||
|
|
||||||
static unsigned int __cpufreq_get(struct cpufreq_policy *policy)
|
static unsigned int __cpufreq_get(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
unsigned int ret_freq = 0;
|
|
||||||
|
|
||||||
if (unlikely(policy_is_inactive(policy)))
|
if (unlikely(policy_is_inactive(policy)))
|
||||||
return ret_freq;
|
return 0;
|
||||||
|
|
||||||
ret_freq = cpufreq_driver->get(policy->cpu);
|
return cpufreq_verify_current_freq(policy, true);
|
||||||
|
|
||||||
/*
|
|
||||||
* If fast frequency switching is used with the given policy, the check
|
|
||||||
* against policy->cur is pointless, so skip it in that case too.
|
|
||||||
*/
|
|
||||||
if (policy->fast_switch_enabled)
|
|
||||||
return ret_freq;
|
|
||||||
|
|
||||||
if (ret_freq && policy->cur &&
|
|
||||||
!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
|
||||||
/* verify no discrepancy between actual and
|
|
||||||
saved value exists */
|
|
||||||
if (unlikely(ret_freq != policy->cur)) {
|
|
||||||
cpufreq_out_of_sync(policy, ret_freq);
|
|
||||||
schedule_work(&policy->update);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret_freq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1652,24 +1663,6 @@ unsigned int cpufreq_get(unsigned int cpu)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cpufreq_get);
|
EXPORT_SYMBOL(cpufreq_get);
|
||||||
|
|
||||||
static unsigned int cpufreq_update_current_freq(struct cpufreq_policy *policy)
|
|
||||||
{
|
|
||||||
unsigned int new_freq;
|
|
||||||
|
|
||||||
new_freq = cpufreq_driver->get(policy->cpu);
|
|
||||||
if (!new_freq)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!policy->cur) {
|
|
||||||
pr_debug("cpufreq: Driver did not initialize current freq\n");
|
|
||||||
policy->cur = new_freq;
|
|
||||||
} else if (policy->cur != new_freq && has_target()) {
|
|
||||||
cpufreq_out_of_sync(policy, new_freq);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new_freq;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct subsys_interface cpufreq_interface = {
|
static struct subsys_interface cpufreq_interface = {
|
||||||
.name = "cpufreq",
|
.name = "cpufreq",
|
||||||
.subsys = &cpu_subsys,
|
.subsys = &cpu_subsys,
|
||||||
@ -2150,8 +2143,8 @@ static int cpufreq_start_governor(struct cpufreq_policy *policy)
|
|||||||
|
|
||||||
pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
|
pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
|
||||||
|
|
||||||
if (cpufreq_driver->get && !cpufreq_driver->setpolicy)
|
if (cpufreq_driver->get)
|
||||||
cpufreq_update_current_freq(policy);
|
cpufreq_verify_current_freq(policy, false);
|
||||||
|
|
||||||
if (policy->governor->start) {
|
if (policy->governor->start) {
|
||||||
ret = policy->governor->start(policy);
|
ret = policy->governor->start(policy);
|
||||||
@ -2392,7 +2385,6 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
|
|||||||
void cpufreq_update_policy(unsigned int cpu)
|
void cpufreq_update_policy(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
|
struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
|
||||||
struct cpufreq_policy new_policy;
|
|
||||||
|
|
||||||
if (!policy)
|
if (!policy)
|
||||||
return;
|
return;
|
||||||
@ -2401,16 +2393,11 @@ void cpufreq_update_policy(unsigned int cpu)
|
|||||||
* BIOS might change freq behind our back
|
* BIOS might change freq behind our back
|
||||||
* -> ask driver for current freq and notify governors about a change
|
* -> ask driver for current freq and notify governors about a change
|
||||||
*/
|
*/
|
||||||
if (cpufreq_driver->get && !cpufreq_driver->setpolicy &&
|
if (cpufreq_driver->get && has_target() &&
|
||||||
(cpufreq_suspended || WARN_ON(!cpufreq_update_current_freq(policy))))
|
(cpufreq_suspended || WARN_ON(!cpufreq_verify_current_freq(policy, false))))
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
pr_debug("updating policy for CPU %u\n", cpu);
|
refresh_frequency_limits(policy);
|
||||||
memcpy(&new_policy, policy, sizeof(*policy));
|
|
||||||
new_policy.min = policy->user_policy.min;
|
|
||||||
new_policy.max = policy->user_policy.max;
|
|
||||||
|
|
||||||
cpufreq_set_policy(policy, &new_policy);
|
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
cpufreq_cpu_release(policy);
|
cpufreq_cpu_release(policy);
|
||||||
|
97
drivers/cpufreq/imx-cpufreq-dt.c
Normal file
97
drivers/cpufreq/imx-cpufreq-dt.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright 2019 NXP
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/nvmem-consumer.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_opp.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#define OCOTP_CFG3_SPEED_GRADE_SHIFT 8
|
||||||
|
#define OCOTP_CFG3_SPEED_GRADE_MASK (0x3 << 8)
|
||||||
|
#define OCOTP_CFG3_MKT_SEGMENT_SHIFT 6
|
||||||
|
#define OCOTP_CFG3_MKT_SEGMENT_MASK (0x3 << 6)
|
||||||
|
|
||||||
|
/* cpufreq-dt device registered by imx-cpufreq-dt */
|
||||||
|
static struct platform_device *cpufreq_dt_pdev;
|
||||||
|
static struct opp_table *cpufreq_opp_table;
|
||||||
|
|
||||||
|
static int imx_cpufreq_dt_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *cpu_dev = get_cpu_device(0);
|
||||||
|
u32 cell_value, supported_hw[2];
|
||||||
|
int speed_grade, mkt_segment;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nvmem_cell_read_u32(cpu_dev, "speed_grade", &cell_value);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK) >> OCOTP_CFG3_SPEED_GRADE_SHIFT;
|
||||||
|
mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Early samples without fuses written report "0 0" which means
|
||||||
|
* consumer segment and minimum speed grading.
|
||||||
|
*
|
||||||
|
* According to datasheet minimum speed grading is not supported for
|
||||||
|
* consumer parts so clamp to 1 to avoid warning for "no OPPs"
|
||||||
|
*
|
||||||
|
* Applies to 8mq and 8mm.
|
||||||
|
*/
|
||||||
|
if (mkt_segment == 0 && speed_grade == 0 && (
|
||||||
|
of_machine_is_compatible("fsl,imx8mm") ||
|
||||||
|
of_machine_is_compatible("fsl,imx8mq")))
|
||||||
|
speed_grade = 1;
|
||||||
|
|
||||||
|
supported_hw[0] = BIT(speed_grade);
|
||||||
|
supported_hw[1] = BIT(mkt_segment);
|
||||||
|
dev_info(&pdev->dev, "cpu speed grade %d mkt segment %d supported-hw %#x %#x\n",
|
||||||
|
speed_grade, mkt_segment, supported_hw[0], supported_hw[1]);
|
||||||
|
|
||||||
|
cpufreq_opp_table = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2);
|
||||||
|
if (IS_ERR(cpufreq_opp_table)) {
|
||||||
|
ret = PTR_ERR(cpufreq_opp_table);
|
||||||
|
dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpufreq_dt_pdev = platform_device_register_data(
|
||||||
|
&pdev->dev, "cpufreq-dt", -1, NULL, 0);
|
||||||
|
if (IS_ERR(cpufreq_dt_pdev)) {
|
||||||
|
dev_pm_opp_put_supported_hw(cpufreq_opp_table);
|
||||||
|
ret = PTR_ERR(cpufreq_dt_pdev);
|
||||||
|
dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx_cpufreq_dt_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
platform_device_unregister(cpufreq_dt_pdev);
|
||||||
|
dev_pm_opp_put_supported_hw(cpufreq_opp_table);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver imx_cpufreq_dt_driver = {
|
||||||
|
.probe = imx_cpufreq_dt_probe,
|
||||||
|
.remove = imx_cpufreq_dt_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "imx-cpufreq-dt",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(imx_cpufreq_dt_driver);
|
||||||
|
|
||||||
|
MODULE_ALIAS("platform:imx-cpufreq-dt");
|
||||||
|
MODULE_DESCRIPTION("Freescale i.MX cpufreq speed grading driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -582,10 +582,10 @@ static int __init pcc_cpufreq_init(void)
|
|||||||
|
|
||||||
/* Skip initialization if another cpufreq driver is there. */
|
/* Skip initialization if another cpufreq driver is there. */
|
||||||
if (cpufreq_get_current_driver())
|
if (cpufreq_get_current_driver())
|
||||||
return 0;
|
return -EEXIST;
|
||||||
|
|
||||||
if (acpi_disabled)
|
if (acpi_disabled)
|
||||||
return 0;
|
return -ENODEV;
|
||||||
|
|
||||||
ret = pcc_cpufreq_probe();
|
ret = pcc_cpufreq_probe();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
97
drivers/cpufreq/raspberrypi-cpufreq.c
Normal file
97
drivers/cpufreq/raspberrypi-cpufreq.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Raspberry Pi cpufreq driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019, Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/cpufreq.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_opp.h>
|
||||||
|
|
||||||
|
#define RASPBERRYPI_FREQ_INTERVAL 100000000
|
||||||
|
|
||||||
|
static struct platform_device *cpufreq_dt;
|
||||||
|
|
||||||
|
static int raspberrypi_cpufreq_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *cpu_dev;
|
||||||
|
unsigned long min, max;
|
||||||
|
unsigned long rate;
|
||||||
|
struct clk *clk;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cpu_dev = get_cpu_device(0);
|
||||||
|
if (!cpu_dev) {
|
||||||
|
pr_err("Cannot get CPU for cpufreq driver\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
clk = clk_get(cpu_dev, NULL);
|
||||||
|
if (IS_ERR(clk)) {
|
||||||
|
dev_err(cpu_dev, "Cannot get clock for CPU0\n");
|
||||||
|
return PTR_ERR(clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The max and min frequencies are configurable in the Raspberry Pi
|
||||||
|
* firmware, so we query them at runtime.
|
||||||
|
*/
|
||||||
|
min = roundup(clk_round_rate(clk, 0), RASPBERRYPI_FREQ_INTERVAL);
|
||||||
|
max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL);
|
||||||
|
clk_put(clk);
|
||||||
|
|
||||||
|
for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) {
|
||||||
|
ret = dev_pm_opp_add(cpu_dev, rate, 0);
|
||||||
|
if (ret)
|
||||||
|
goto remove_opp;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
|
||||||
|
ret = PTR_ERR_OR_ZERO(cpufreq_dt);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(cpu_dev, "Failed to create platform device, %d\n", ret);
|
||||||
|
goto remove_opp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
remove_opp:
|
||||||
|
dev_pm_opp_remove_all_dynamic(cpu_dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int raspberrypi_cpufreq_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *cpu_dev;
|
||||||
|
|
||||||
|
cpu_dev = get_cpu_device(0);
|
||||||
|
if (cpu_dev)
|
||||||
|
dev_pm_opp_remove_all_dynamic(cpu_dev);
|
||||||
|
|
||||||
|
platform_device_unregister(cpufreq_dt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since the driver depends on clk-raspberrypi, which may return EPROBE_DEFER,
|
||||||
|
* all the activity is performed in the probe, which may be defered as well.
|
||||||
|
*/
|
||||||
|
static struct platform_driver raspberrypi_cpufreq_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "raspberrypi-cpufreq",
|
||||||
|
},
|
||||||
|
.probe = raspberrypi_cpufreq_probe,
|
||||||
|
.remove = raspberrypi_cpufreq_remove,
|
||||||
|
};
|
||||||
|
module_platform_driver(raspberrypi_cpufreq_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de");
|
||||||
|
MODULE_DESCRIPTION("Raspberry Pi cpufreq driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:raspberrypi-cpufreq");
|
@ -478,7 +478,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
|||||||
arm_volt, arm_volt_max);
|
arm_volt, arm_volt_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(KERN_DEBUG "Perf changed[L%d]\n", index);
|
pr_debug("Perf changed[L%d]\n", index);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
mutex_unlock(&set_freq_lock);
|
mutex_unlock(&set_freq_lock);
|
||||||
|
@ -103,6 +103,9 @@ static int __init imx8_soc_init(void)
|
|||||||
if (IS_ERR(soc_dev))
|
if (IS_ERR(soc_dev))
|
||||||
goto free_rev;
|
goto free_rev;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
|
||||||
|
platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_rev:
|
free_rev:
|
||||||
|
@ -406,6 +406,12 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
|
|||||||
const char *cpufreq_get_current_driver(void);
|
const char *cpufreq_get_current_driver(void);
|
||||||
void *cpufreq_get_driver_data(void);
|
void *cpufreq_get_driver_data(void);
|
||||||
|
|
||||||
|
static inline int cpufreq_thermal_control_enabled(struct cpufreq_driver *drv)
|
||||||
|
{
|
||||||
|
return IS_ENABLED(CONFIG_CPU_THERMAL) &&
|
||||||
|
(drv->flags & CPUFREQ_IS_COOLING_DEV);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy,
|
static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy,
|
||||||
unsigned int min, unsigned int max)
|
unsigned int min, unsigned int max)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user