diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-03-30 15:05:01 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-03-30 15:05:01 -0700 |
commit | 49835c15a55225e9b3ff9cc9317135b334ea2d49 (patch) | |
tree | deb20b64d9b5ca9b16f0d8f3a2e23822ec7dcd65 /drivers/cpufreq | |
parent | a231bed2267cf45b0759da1d3ad62483b8bd0925 (diff) | |
parent | 2409000a0cad2242fd4e2578f761f97069625478 (diff) |
Merge tag 'pm-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael Wysocki:
"These clean up and rework the PM QoS API, address a suspend-to-idle
wakeup regression on some ACPI-based platforms, clean up and extend a
few cpuidle drivers, update multiple cpufreq drivers and cpufreq
documentation, and fix a number of issues in devfreq and several other
things all over.
Specifics:
- Clean up and rework the PM QoS API to simplify the code and reduce
the size of it (Rafael Wysocki).
- Fix a suspend-to-idle wakeup regression on Dell XPS13 9370 and
similar platforms where the USB plug/unplug events are handled by
the EC (Rafael Wysocki).
- CLean up the intel_idle and PSCI cpuidle drivers (Rafael Wysocki,
Ulf Hansson).
- Extend the haltpoll cpuidle driver so that it can be forced to run
on some systems where it refused to load (Maciej Szmigiero).
- Convert several cpufreq documents to the .rst format and move the
legacy driver documentation into one common file (Mauro Carvalho
Chehab, Rafael Wysocki).
- Update several cpufreq drivers:
* Extend and fix the imx-cpufreq-dt driver (Anson Huang).
* Improve the -EPROBE_DEFER handling and fix unwanted CPU
overclocking on i.MX6ULL in imx6q-cpufreq (Anson Huang,
Christoph Niedermaier).
* Add support for Krait based SoCs to the qcom driver (Ansuel
Smith).
* Add support for OPP_PLUS to ti-cpufreq (Lokesh Vutla).
* Add platform specific intermediate callbacks support to
cpufreq-dt and update the imx6q driver (Peng Fan).
* Simplify and consolidate some pieces of the intel_pstate
driver and update its documentation (Rafael Wysocki, Alex
Hung).
- Fix several devfreq issues:
* Remove unneeded extern keyword from a devfreq header file and
use the DEVFREQ_GOV_UPDATE_INTERNAL event name instead of
DEVFREQ_GOV_INTERNAL (Chanwoo Choi).
* Fix the handling of dev_pm_qos_remove_request() result
(Leonard Crestez).
* Use constant name for userspace governor (Pierre Kuo).
* Get rid of doc warnings and fix a typo (Christophe JAILLET).
- Use built-in RCU list checking in some places in the PM core to
avoid false-positive RCU usage warnings (Madhuparna Bhowmik).
- Add explicit READ_ONCE()/WRITE_ONCE() annotations to low-level PM
QoS routines (Qian Cai).
- Fix removal of wakeup sources to avoid NULL pointer dereferences in
a corner case (Neeraj Upadhyay).
- Clean up the handling of hibernate compat ioctls and fix the
related documentation (Eric Biggers).
- Update the idle_inject power capping driver to use variable-length
arrays instead of zero-length arrays (Gustavo Silva).
- Fix list format in a PM QoS document (Randy Dunlap).
- Make the cpufreq stats module use scnprintf() to avoid potential
buffer overflows (Takashi Iwai).
- Add pm_runtime_get_if_active() to PM-runtime API (Sakari Ailus).
- Allow no domain-idle-states DT property in generic PM domains (Ulf
Hansson).
- Fix a broken y-axis scale in the intel_pstate_tracer utility (Doug
Smythies)"
* tag 'pm-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (78 commits)
cpufreq: intel_pstate: Simplify intel_pstate_cpu_init()
tools/power/x86/intel_pstate_tracer: fix a broken y-axis scale
ACPI: PM: s2idle: Refine active GPEs check
ACPICA: Allow acpi_any_gpe_status_set() to skip one GPE
PM: sleep: wakeup: Skip wakeup_source_sysfs_remove() if device is not there
PM / devfreq: Get rid of some doc warnings
PM / devfreq: Fix handling dev_pm_qos_remove_request result
PM / devfreq: Fix a typo in a comment
PM / devfreq: Change to DEVFREQ_GOV_UPDATE_INTERVAL event name
PM / devfreq: Remove unneeded extern keyword
PM / devfreq: Use constant name of userspace governor
ACPI: PM: s2idle: Fix comment in acpi_s2idle_prepare_late()
cpufreq: qcom: Add support for krait based socs
cpufreq: imx6q-cpufreq: Improve the logic of -EPROBE_DEFER handling
cpufreq: Use scnprintf() for avoiding potential buffer overflow
cpuidle: psci: Split psci_dt_cpu_init_idle()
PM / Domains: Allow no domain-idle-states DT property in genpd when parsing
PM / hibernate: Remove unnecessary compat ioctl overrides
PM: hibernate: fix docs for ioctls that return loff_t via pointer
Documentation: intel_pstate: update links for references
...
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r-- | drivers/cpufreq/Kconfig.arm | 2 | ||||
-rw-r--r-- | drivers/cpufreq/Kconfig.x86 | 2 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq-dt-platdev.c | 5 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq-dt.c | 4 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq-dt.h | 4 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_stats.c | 14 | ||||
-rw-r--r-- | drivers/cpufreq/imx-cpufreq-dt.c | 13 | ||||
-rw-r--r-- | drivers/cpufreq/imx6q-cpufreq.c | 71 | ||||
-rw-r--r-- | drivers/cpufreq/intel_pstate.c | 26 | ||||
-rw-r--r-- | drivers/cpufreq/qcom-cpufreq-nvmem.c | 191 | ||||
-rw-r--r-- | drivers/cpufreq/ti-cpufreq.c | 7 |
11 files changed, 270 insertions, 69 deletions
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 3858d86cf409..15c1a1231516 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -128,7 +128,7 @@ config ARM_OMAP2PLUS_CPUFREQ config ARM_QCOM_CPUFREQ_NVMEM tristate "Qualcomm nvmem based CPUFreq" - depends on ARM64 + depends on ARCH_QCOM depends on QCOM_QFPROM depends on QCOM_SMEM select PM_OPP diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index a6528388952e..62502d0e4c33 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -25,7 +25,7 @@ config X86_PCC_CPUFREQ This driver adds support for the PCC interface. For details, take a look at: - <file:Documentation/cpu-freq/pcc-cpufreq.txt>. + <file:Documentation/admin-guide/pm/cpufreq_drivers.rst>. To compile this driver as a module, choose M here: the module will be called pcc-cpufreq. diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index f2ae9cd455c1..cb9db16bea61 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -141,6 +141,11 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "ti,dra7", }, { .compatible = "ti,omap3", }, + { .compatible = "qcom,ipq8064", }, + { .compatible = "qcom,apq8064", }, + { .compatible = "qcom,msm8974", }, + { .compatible = "qcom,msm8960", }, + { } }; diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index d2b5f062a07b..26fe8dfb9ce6 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -363,6 +363,10 @@ static int dt_cpufreq_probe(struct platform_device *pdev) dt_cpufreq_driver.resume = data->resume; if (data->suspend) dt_cpufreq_driver.suspend = data->suspend; + if (data->get_intermediate) { + dt_cpufreq_driver.target_intermediate = data->target_intermediate; + dt_cpufreq_driver.get_intermediate = data->get_intermediate; + } } ret = cpufreq_register_driver(&dt_cpufreq_driver); diff --git a/drivers/cpufreq/cpufreq-dt.h b/drivers/cpufreq/cpufreq-dt.h index a5a45b547d0b..28c8af7ec5ef 100644 --- a/drivers/cpufreq/cpufreq-dt.h +++ b/drivers/cpufreq/cpufreq-dt.h @@ -14,6 +14,10 @@ struct cpufreq_policy; struct cpufreq_dt_platform_data { bool have_governor_per_policy; + unsigned int (*get_intermediate)(struct cpufreq_policy *policy, + unsigned int index); + int (*target_intermediate)(struct cpufreq_policy *policy, + unsigned int index); int (*suspend)(struct cpufreq_policy *policy); int (*resume)(struct cpufreq_policy *policy); }; diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index f9bcf0f3ea30..94d959a8e954 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -90,35 +90,35 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) if (policy->fast_switch_enabled) return 0; - len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); - len += snprintf(buf + len, PAGE_SIZE - len, " : "); + len += scnprintf(buf + len, PAGE_SIZE - len, " From : To\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, " : "); for (i = 0; i < stats->state_num; i++) { if (len >= PAGE_SIZE) break; - len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", + len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ", stats->freq_table[i]); } if (len >= PAGE_SIZE) return PAGE_SIZE; - len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); for (i = 0; i < stats->state_num; i++) { if (len >= PAGE_SIZE) break; - len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ", + len += scnprintf(buf + len, PAGE_SIZE - len, "%9u: ", stats->freq_table[i]); for (j = 0; j < stats->state_num; j++) { if (len >= PAGE_SIZE) break; - len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", + len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ", stats->trans_table[i*stats->max_state+j]); } if (len >= PAGE_SIZE) break; - len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); } if (len >= PAGE_SIZE) { diff --git a/drivers/cpufreq/imx-cpufreq-dt.c b/drivers/cpufreq/imx-cpufreq-dt.c index 6cb8193421ea..de206d2745fe 100644 --- a/drivers/cpufreq/imx-cpufreq-dt.c +++ b/drivers/cpufreq/imx-cpufreq-dt.c @@ -19,6 +19,8 @@ #define IMX8MN_OCOTP_CFG3_SPEED_GRADE_MASK (0xf << 8) #define OCOTP_CFG3_MKT_SEGMENT_SHIFT 6 #define OCOTP_CFG3_MKT_SEGMENT_MASK (0x3 << 6) +#define IMX8MP_OCOTP_CFG3_MKT_SEGMENT_SHIFT 5 +#define IMX8MP_OCOTP_CFG3_MKT_SEGMENT_MASK (0x3 << 5) /* cpufreq-dt device registered by imx-cpufreq-dt */ static struct platform_device *cpufreq_dt_pdev; @@ -31,6 +33,9 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev) int speed_grade, mkt_segment; int ret; + if (!of_find_property(cpu_dev->of_node, "cpu-supply", NULL)) + return -ENODEV; + ret = nvmem_cell_read_u32(cpu_dev, "speed_grade", &cell_value); if (ret) return ret; @@ -42,7 +47,13 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev) else 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; + + if (of_machine_is_compatible("fsl,imx8mp")) + mkt_segment = (cell_value & IMX8MP_OCOTP_CFG3_MKT_SEGMENT_MASK) + >> IMX8MP_OCOTP_CFG3_MKT_SEGMENT_SHIFT; + else + mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) + >> OCOTP_CFG3_MKT_SEGMENT_SHIFT; /* * Early samples without fuses written report "0 0" which may NOT diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 648a09a1778a..fdb2ffffbd15 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -216,31 +216,41 @@ static struct cpufreq_driver imx6q_cpufreq_driver = { #define OCOTP_CFG3_SPEED_996MHZ 0x2 #define OCOTP_CFG3_SPEED_852MHZ 0x1 -static void imx6q_opp_check_speed_grading(struct device *dev) +static int imx6q_opp_check_speed_grading(struct device *dev) { struct device_node *np; void __iomem *base; u32 val; + int ret; - np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp"); - if (!np) - return; + if (of_find_property(dev->of_node, "nvmem-cells", NULL)) { + ret = nvmem_cell_read_u32(dev, "speed_grade", &val); + if (ret) + return ret; + } else { + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp"); + if (!np) + return -ENOENT; - base = of_iomap(np, 0); - if (!base) { - dev_err(dev, "failed to map ocotp\n"); - goto put_node; + base = of_iomap(np, 0); + of_node_put(np); + if (!base) { + dev_err(dev, "failed to map ocotp\n"); + return -EFAULT; + } + + /* + * SPEED_GRADING[1:0] defines the max speed of ARM: + * 2b'11: 1200000000Hz; + * 2b'10: 996000000Hz; + * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz. + * 2b'00: 792000000Hz; + * We need to set the max speed of ARM according to fuse map. + */ + val = readl_relaxed(base + OCOTP_CFG3); + iounmap(base); } - /* - * SPEED_GRADING[1:0] defines the max speed of ARM: - * 2b'11: 1200000000Hz; - * 2b'10: 996000000Hz; - * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz. - * 2b'00: 792000000Hz; - * We need to set the max speed of ARM according to fuse map. - */ - val = readl_relaxed(base + OCOTP_CFG3); val >>= OCOTP_CFG3_SPEED_SHIFT; val &= 0x3; @@ -257,9 +267,8 @@ static void imx6q_opp_check_speed_grading(struct device *dev) if (dev_pm_opp_disable(dev, 1200000000)) dev_warn(dev, "failed to disable 1.2GHz OPP\n"); } - iounmap(base); -put_node: - of_node_put(np); + + return 0; } #define OCOTP_CFG3_6UL_SPEED_696MHZ 0x2 @@ -281,6 +290,9 @@ static int imx6ul_opp_check_speed_grading(struct device *dev) np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp"); if (!np) + np = of_find_compatible_node(NULL, NULL, + "fsl,imx6ull-ocotp"); + if (!np) return -ENOENT; base = of_iomap(np, 0); @@ -378,23 +390,22 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) goto put_reg; } + /* Because we have added the OPPs here, we must free them */ + free_opp = true; + if (of_machine_is_compatible("fsl,imx6ul") || of_machine_is_compatible("fsl,imx6ull")) { ret = imx6ul_opp_check_speed_grading(cpu_dev); - if (ret) { - if (ret == -EPROBE_DEFER) - goto put_node; - + } else { + ret = imx6q_opp_check_speed_grading(cpu_dev); + } + if (ret) { + if (ret != -EPROBE_DEFER) dev_err(cpu_dev, "failed to read ocotp: %d\n", ret); - goto put_node; - } - } else { - imx6q_opp_check_speed_grading(cpu_dev); + goto out_free_opp; } - /* Because we have added the OPPs here, we must free them */ - free_opp = true; num = dev_pm_opp_get_opp_count(cpu_dev); if (num < 0) { ret = num; diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index c81e1ff29069..d2297839374d 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -2155,15 +2155,19 @@ static void intel_pstate_adjust_policy_max(struct cpudata *cpu, } } -static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy) +static void intel_pstate_verify_cpu_policy(struct cpudata *cpu, + struct cpufreq_policy_data *policy) { - struct cpudata *cpu = all_cpu_data[policy->cpu]; - update_turbo_state(); cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, intel_pstate_get_max_freq(cpu)); intel_pstate_adjust_policy_max(cpu, policy); +} + +static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy) +{ + intel_pstate_verify_cpu_policy(all_cpu_data[policy->cpu], policy); return 0; } @@ -2243,10 +2247,11 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy) if (ret) return ret; - if (IS_ENABLED(CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE)) - policy->policy = CPUFREQ_POLICY_PERFORMANCE; - else - policy->policy = CPUFREQ_POLICY_POWERSAVE; + /* + * Set the policy to powersave to provide a valid fallback value in case + * the default cpufreq governor is neither powersave nor performance. + */ + policy->policy = CPUFREQ_POLICY_POWERSAVE; return 0; } @@ -2268,12 +2273,7 @@ static int intel_cpufreq_verify_policy(struct cpufreq_policy_data *policy) { struct cpudata *cpu = all_cpu_data[policy->cpu]; - update_turbo_state(); - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - intel_pstate_get_max_freq(cpu)); - - intel_pstate_adjust_policy_max(cpu, policy); - + intel_pstate_verify_cpu_policy(cpu, policy); intel_pstate_update_perf_limits(cpu, policy->min, policy->max); return 0; diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c index f0d2d5035413..a1b8238872a2 100644 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -49,12 +49,14 @@ struct qcom_cpufreq_drv; struct qcom_cpufreq_match_data { int (*get_version)(struct device *cpu_dev, struct nvmem_cell *speedbin_nvmem, + char **pvs_name, struct qcom_cpufreq_drv *drv); const char **genpd_names; }; struct qcom_cpufreq_drv { - struct opp_table **opp_tables; + struct opp_table **names_opp_tables; + struct opp_table **hw_opp_tables; struct opp_table **genpd_opp_tables; u32 versions; const struct qcom_cpufreq_match_data *data; @@ -62,6 +64,84 @@ struct qcom_cpufreq_drv { static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev; +static void get_krait_bin_format_a(struct device *cpu_dev, + int *speed, int *pvs, int *pvs_ver, + struct nvmem_cell *pvs_nvmem, u8 *buf) +{ + u32 pte_efuse; + + pte_efuse = *((u32 *)buf); + + *speed = pte_efuse & 0xf; + if (*speed == 0xf) + *speed = (pte_efuse >> 4) & 0xf; + + if (*speed == 0xf) { + *speed = 0; + dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed); + } else { + dev_dbg(cpu_dev, "Speed bin: %d\n", *speed); + } + + *pvs = (pte_efuse >> 10) & 0x7; + if (*pvs == 0x7) + *pvs = (pte_efuse >> 13) & 0x7; + + if (*pvs == 0x7) { + *pvs = 0; + dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs); + } else { + dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); + } +} + +static void get_krait_bin_format_b(struct device *cpu_dev, + int *speed, int *pvs, int *pvs_ver, + struct nvmem_cell *pvs_nvmem, u8 *buf) +{ + u32 pte_efuse, redundant_sel; + + pte_efuse = *((u32 *)buf); + redundant_sel = (pte_efuse >> 24) & 0x7; + + *pvs_ver = (pte_efuse >> 4) & 0x3; + + switch (redundant_sel) { + case 1: + *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7); + *speed = (pte_efuse >> 27) & 0xf; + break; + case 2: + *pvs = (pte_efuse >> 27) & 0xf; + *speed = pte_efuse & 0x7; + break; + default: + /* 4 bits of PVS are in efuse register bits 31, 8-6. */ + *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7); + *speed = pte_efuse & 0x7; + } + + /* Check SPEED_BIN_BLOW_STATUS */ + if (pte_efuse & BIT(3)) { + dev_dbg(cpu_dev, "Speed bin: %d\n", *speed); + } else { + dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n"); + *speed = 0; + } + + /* Check PVS_BLOW_STATUS */ + pte_efuse = *(((u32 *)buf) + 4); + pte_efuse &= BIT(21); + if (pte_efuse) { + dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs); + } else { + dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n"); + *pvs = 0; + } + + dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver); +} + static enum _msm8996_version qcom_cpufreq_get_msm_id(void) { size_t len; @@ -93,11 +173,13 @@ static enum _msm8996_version qcom_cpufreq_get_msm_id(void) static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, struct nvmem_cell *speedbin_nvmem, + char **pvs_name, struct qcom_cpufreq_drv *drv) { size_t len; u8 *speedbin; enum _msm8996_version msm8996_version; + *pvs_name = NULL; msm8996_version = qcom_cpufreq_get_msm_id(); if (NUM_OF_MSM8996_VERSIONS == msm8996_version) { @@ -125,10 +207,51 @@ static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev, return 0; } +static int qcom_cpufreq_krait_name_version(struct device *cpu_dev, + struct nvmem_cell *speedbin_nvmem, + char **pvs_name, + struct qcom_cpufreq_drv *drv) +{ + int speed = 0, pvs = 0, pvs_ver = 0; + u8 *speedbin; + size_t len; + + speedbin = nvmem_cell_read(speedbin_nvmem, &len); + + if (IS_ERR(speedbin)) + return PTR_ERR(speedbin); + + switch (len) { + case 4: + get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver, + speedbin_nvmem, speedbin); + break; + case 8: + get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver, + speedbin_nvmem, speedbin); + break; + default: + dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n"); + return -ENODEV; + } + + snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d", + speed, pvs, pvs_ver); + + drv->versions = (1 << speed); + + kfree(speedbin); + return 0; +} + static const struct qcom_cpufreq_match_data match_data_kryo = { .get_version = qcom_cpufreq_kryo_name_version, }; +static const struct qcom_cpufreq_match_data match_data_krait = { + .get_version = qcom_cpufreq_krait_name_version, +}; + static const char *qcs404_genpd_names[] = { "cpr", NULL }; static const struct qcom_cpufreq_match_data match_data_qcs404 = { @@ -141,6 +264,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) struct nvmem_cell *speedbin_nvmem; struct device_node *np; struct device *cpu_dev; + char *pvs_name = "speedXX-pvsXX-vXX"; unsigned cpu; const struct of_device_id *match; int ret; @@ -153,7 +277,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) if (!np) return -ENOENT; - ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu"); + ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu"); if (!ret) { of_node_put(np); return -ENOENT; @@ -181,7 +305,8 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) goto free_drv; } - ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv); + ret = drv->data->get_version(cpu_dev, + speedbin_nvmem, &pvs_name, drv); if (ret) { nvmem_cell_put(speedbin_nvmem); goto free_drv; @@ -190,12 +315,20 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) } of_node_put(np); - drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables), + drv->names_opp_tables = kcalloc(num_possible_cpus(), + sizeof(*drv->names_opp_tables), GFP_KERNEL); - if (!drv->opp_tables) { + if (!drv->names_opp_tables) { ret = -ENOMEM; goto free_drv; } + drv->hw_opp_tables = kcalloc(num_possible_cpus(), + sizeof(*drv->hw_opp_tables), + GFP_KERNEL); + if (!drv->hw_opp_tables) { + ret = -ENOMEM; + goto free_opp_names; + } drv->genpd_opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->genpd_opp_tables), @@ -213,11 +346,23 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) } if (drv->data->get_version) { - drv->opp_tables[cpu] = - dev_pm_opp_set_supported_hw(cpu_dev, - &drv->versions, 1); - if (IS_ERR(drv->opp_tables[cpu])) { - ret = PTR_ERR(drv->opp_tables[cpu]); + + if (pvs_name) { + drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name( + cpu_dev, + pvs_name); + if (IS_ERR(drv->names_opp_tables[cpu])) { + ret = PTR_ERR(drv->names_opp_tables[cpu]); + dev_err(cpu_dev, "Failed to add OPP name %s\n", + pvs_name); + goto free_opp; + } + } + + drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw( + cpu_dev, &drv->versions, 1); + if (IS_ERR(drv->hw_opp_tables[cpu])) { + ret = PTR_ERR(drv->hw_opp_tables[cpu]); dev_err(cpu_dev, "Failed to set supported hardware\n"); goto free_genpd_opp; @@ -259,11 +404,18 @@ free_genpd_opp: kfree(drv->genpd_opp_tables); free_opp: for_each_possible_cpu(cpu) { - if (IS_ERR_OR_NULL(drv->opp_tables[cpu])) + if (IS_ERR_OR_NULL(drv->names_opp_tables[cpu])) + break; + dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]); + } + for_each_possible_cpu(cpu) { + if (IS_ERR_OR_NULL(drv->hw_opp_tables[cpu])) break; - dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); + dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]); } - kfree(drv->opp_tables); + kfree(drv->hw_opp_tables); +free_opp_names: + kfree(drv->names_opp_tables); free_drv: kfree(drv); @@ -278,13 +430,16 @@ static int qcom_cpufreq_remove(struct platform_device *pdev) platform_device_unregister(cpufreq_dt_pdev); for_each_possible_cpu(cpu) { - if (drv->opp_tables[cpu]) - dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]); + if (drv->names_opp_tables[cpu]) + dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]); + if (drv->hw_opp_tables[cpu]) + dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]); if (drv->genpd_opp_tables[cpu]) dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]); } - kfree(drv->opp_tables); + kfree(drv->names_opp_tables); + kfree(drv->hw_opp_tables); kfree(drv->genpd_opp_tables); kfree(drv); @@ -303,6 +458,10 @@ static const struct of_device_id qcom_cpufreq_match_list[] __initconst = { { .compatible = "qcom,apq8096", .data = &match_data_kryo }, { .compatible = "qcom,msm8996", .data = &match_data_kryo }, { .compatible = "qcom,qcs404", .data = &match_data_qcs404 }, + { .compatible = "qcom,ipq8064", .data = &match_data_krait }, + { .compatible = "qcom,apq8064", .data = &match_data_krait }, + { .compatible = "qcom,msm8974", .data = &match_data_krait }, + { .compatible = "qcom,msm8960", .data = &match_data_krait }, {}, }; diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index 557cb513bf7f..ab0de27539ad 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -25,11 +25,14 @@ #define DRA7_EFUSE_HAS_OD_MPU_OPP 11 #define DRA7_EFUSE_HAS_HIGH_MPU_OPP 15 +#define DRA76_EFUSE_HAS_PLUS_MPU_OPP 18 #define DRA7_EFUSE_HAS_ALL_MPU_OPP 23 +#define DRA76_EFUSE_HAS_ALL_MPU_OPP 24 #define DRA7_EFUSE_NOM_MPU_OPP BIT(0) #define DRA7_EFUSE_OD_MPU_OPP BIT(1) #define DRA7_EFUSE_HIGH_MPU_OPP BIT(2) +#define DRA76_EFUSE_PLUS_MPU_OPP BIT(3) #define OMAP3_CONTROL_DEVICE_STATUS 0x4800244C #define OMAP3_CONTROL_IDCODE 0x4830A204 @@ -80,6 +83,10 @@ static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data, */ switch (efuse) { + case DRA76_EFUSE_HAS_PLUS_MPU_OPP: + case DRA76_EFUSE_HAS_ALL_MPU_OPP: + calculated_efuse |= DRA76_EFUSE_PLUS_MPU_OPP; + /* Fall through */ case DRA7_EFUSE_HAS_ALL_MPU_OPP: case DRA7_EFUSE_HAS_HIGH_MPU_OPP: calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP; |