Commit 14449382 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-cpufreq'

Merge cpufreq updates for 6.10:

 - Rework the handling of disabled turbo in the intel_pstate driver and
   make it update the maximum CPU frequency consistently regardless of
   the reason on top of a number of cleanups (Rafael Wysocki).

 - Add missing checks for NULL .exit() cpufreq driver callback to the
   cpufreq core (Viresh Kumar).

 - Prevent pulicy->max from going above the frequency QoS maximum value
   when cpufreq_frequency_table_verify() is used (Xuewen Yan).

 - Prevent a negative CPU number or frequency value from being printed
   if they are really large (Joshua Yeong).

 - Update MAINTAINERS entry for amd-pstate to add two new submaintainers
   and a designated reviewer (Huang Rui).

 - Clean up the amd-pstate driver and update its documentation (Gautham
   Shenoy).

 - Fix the highest frequency issue in the amd-pstate driver which limits
   performance (Perry Yuan).

 - Enable CPPC v2 for certain processors in the family 17H, as requested
   by TR40 processor users who expect improved performance and lower
   system temperature (Perry Yuan).

 - Change latency and delay values to be read from platform firmware
   firstly for more accurate timing (Perry Yuan).

 - A new quirk is introduced for supporting amd-pstate on legacy
   processors which either lack CPPC capability, or only only have CPPC
   v2 capability (Perry Yuan).

 - Sun50i: Add support for opp_supported_hw, H616 platform and general
   cleanups (Andre Przywara, Martin Botka, Brandon Cheo Fusi, Dan
   Carpenter, Viresh Kumar).

 - CPPC: Fix possible null pointer dereference (Aleksandr Mishin).

 - Eliminate uses of of_node_put() (Javier Carrasco, and Shivani Gupta).

 - brcmstb-avs: ISO C90 forbids mixed declarations (Portia Stephens).

 - mediatek: Add support for MT7988A (Sam Shih).

 - cpufreq-qcom-hw: Add SM4450 compatibles in DT bindings (Tengfei Fan).

 - Fix struct cpudata::epp_cached kernel-doc in the intel_pstate cpufreq
   driver (Jeff Johnson).

* pm-cpufreq: (46 commits)
  cpufreq: amd-pstate: fix the highest frequency issue which limits performance
  cpufreq: intel_pstate: fix struct cpudata::epp_cached kernel-doc
  cpufreq: Fix up printing large CPU numbers and frequency values
  MAINTAINERS: cpufreq: amd-pstate: Add co-maintainers and reviewer
  cpufreq: amd-pstate: remove unused variable lowest_nonlinear_freq
  cpufreq: amd-pstate: fix code format problems
  cpufreq: amd-pstate: Add quirk for the pstate CPPC capabilities missing
  cppc_acpi: print error message if CPPC is unsupported
  cpufreq: amd-pstate: get transition delay and latency value from ACPI tables
  cpufreq: amd-pstate: Bail out if min/max/nominal_freq is 0
  cpufreq: amd-pstate: Remove amd_get_{min,max,nominal,lowest_nonlinear}_freq()
  cpufreq: amd-pstate: Unify computation of {max,min,nominal,lowest_nonlinear}_freq
  cpufreq: amd-pstate: Document the units for freq variables in amd_cpudata
  cpufreq: amd-pstate: Document *_limit_* fields in struct amd_cpudata
  dt-bindings: cpufreq: cpufreq-qcom-hw: Add SM4450 compatibles
  cpufreq: sun50i: fix error returns in dt_has_supported_hw()
  cpufreq: brcmstb-avs-cpufreq: ISO C90 forbids mixed declarations
  cpufreq: dt-platdev: eliminate uses of of_node_put()
  cpufreq: dt: eliminate uses of of_node_put()
  cpufreq: ti: Implement scope-based cleanup in ti_cpufreq_match_node()
  ...
parents eefb5dbd bf202e65
......@@ -38,6 +38,7 @@ properties:
- qcom,sc7280-cpufreq-epss
- qcom,sc8280xp-cpufreq-epss
- qcom,sdx75-cpufreq-epss
- qcom,sm4450-cpufreq-epss
- qcom,sm6375-cpufreq-epss
- qcom,sm8250-cpufreq-epss
- qcom,sm8350-cpufreq-epss
......@@ -133,6 +134,7 @@ allOf:
- qcom,sc8280xp-cpufreq-epss
- qcom,sdm670-cpufreq-hw
- qcom,sdm845-cpufreq-hw
- qcom,sm4450-cpufreq-epss
- qcom,sm6115-cpufreq-hw
- qcom,sm6350-cpufreq-hw
- qcom,sm6375-cpufreq-epss
......
......@@ -13,25 +13,25 @@ maintainers:
description: |
For some SoCs, the CPU frequency subset and voltage value of each
OPP varies based on the silicon variant in use. Allwinner Process
Voltage Scaling Tables defines the voltage and frequency value based
on the speedbin blown in the efuse combination. The
sun50i-cpufreq-nvmem driver reads the efuse value from the SoC to
provide the OPP framework with required information.
Voltage Scaling Tables define the voltage and frequency values based
on the speedbin blown in the efuse combination.
allOf:
- $ref: opp-v2-base.yaml#
properties:
compatible:
const: allwinner,sun50i-h6-operating-points
enum:
- allwinner,sun50i-h6-operating-points
- allwinner,sun50i-h616-operating-points
nvmem-cells:
description: |
A phandle pointing to a nvmem-cells node representing the efuse
registers that has information about the speedbin that is used
register that has information about the speedbin that is used
to select the right frequency/voltage value pair. Please refer
the for nvmem-cells bindings
Documentation/devicetree/bindings/nvmem/nvmem.txt and also
to the nvmem-cells bindings in
Documentation/devicetree/bindings/nvmem/nvmem.yaml and also the
examples below.
opp-shared: true
......@@ -47,15 +47,18 @@ patternProperties:
properties:
opp-hz: true
clock-latency-ns: true
opp-microvolt: true
opp-supported-hw:
maxItems: 1
description:
A single 32 bit bitmap value, representing compatible HW, one
bit per speed bin index.
patternProperties:
"^opp-microvolt-speed[0-9]$": true
required:
- opp-hz
- opp-microvolt-speed0
- opp-microvolt-speed1
- opp-microvolt-speed2
unevaluatedProperties: false
......@@ -77,58 +80,54 @@ examples:
opp-microvolt-speed2 = <800000>;
};
opp-720000000 {
opp-1080000000 {
clock-latency-ns = <244144>; /* 8 32k periods */
opp-hz = /bits/ 64 <720000000>;
opp-hz = /bits/ 64 <1080000000>;
opp-microvolt-speed0 = <880000>;
opp-microvolt-speed1 = <820000>;
opp-microvolt-speed2 = <800000>;
opp-microvolt-speed0 = <1060000>;
opp-microvolt-speed1 = <880000>;
opp-microvolt-speed2 = <840000>;
};
opp-816000000 {
opp-1488000000 {
clock-latency-ns = <244144>; /* 8 32k periods */
opp-hz = /bits/ 64 <816000000>;
opp-hz = /bits/ 64 <1488000000>;
opp-microvolt-speed0 = <880000>;
opp-microvolt-speed1 = <820000>;
opp-microvolt-speed2 = <800000>;
opp-microvolt-speed0 = <1160000>;
opp-microvolt-speed1 = <1000000>;
opp-microvolt-speed2 = <960000>;
};
};
opp-888000000 {
clock-latency-ns = <244144>; /* 8 32k periods */
opp-hz = /bits/ 64 <888000000>;
opp-microvolt-speed0 = <940000>;
opp-microvolt-speed1 = <820000>;
opp-microvolt-speed2 = <800000>;
};
- |
opp-table {
compatible = "allwinner,sun50i-h616-operating-points";
nvmem-cells = <&speedbin_efuse>;
opp-shared;
opp-1080000000 {
opp-480000000 {
clock-latency-ns = <244144>; /* 8 32k periods */
opp-hz = /bits/ 64 <1080000000>;
opp-hz = /bits/ 64 <480000000>;
opp-microvolt-speed0 = <1060000>;
opp-microvolt-speed1 = <880000>;
opp-microvolt-speed2 = <840000>;
opp-microvolt = <900000>;
opp-supported-hw = <0x1f>;
};
opp-1320000000 {
opp-792000000 {
clock-latency-ns = <244144>; /* 8 32k periods */
opp-hz = /bits/ 64 <1320000000>;
opp-hz = /bits/ 64 <792000000>;
opp-microvolt-speed0 = <1160000>;
opp-microvolt-speed1 = <940000>;
opp-microvolt-speed2 = <900000>;
opp-microvolt-speed1 = <900000>;
opp-microvolt-speed4 = <940000>;
opp-supported-hw = <0x12>;
};
opp-1488000000 {
opp-1512000000 {
clock-latency-ns = <244144>; /* 8 32k periods */
opp-hz = /bits/ 64 <1488000000>;
opp-hz = /bits/ 64 <1512000000>;
opp-microvolt-speed0 = <1160000>;
opp-microvolt-speed1 = <1000000>;
opp-microvolt-speed2 = <960000>;
opp-microvolt = <1100000>;
opp-supported-hw = <0x0a>;
};
};
......
......@@ -1062,6 +1062,9 @@ F: drivers/gpu/drm/amd/pm/
AMD PSTATE DRIVER
M: Huang Rui <ray.huang@amd.com>
M: Gautham R. Shenoy <gautham.shenoy@amd.com>
M: Mario Limonciello <mario.limonciello@amd.com>
R: Perry Yuan <perry.yuan@amd.com>
L: linux-pm@vger.kernel.org
S: Supported
F: Documentation/admin-guide/pm/amd-pstate.rst
......
......@@ -6,6 +6,7 @@
/dts-v1/;
#include "sun50i-h616.dtsi"
#include "sun50i-h616-cpu-opp.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
......@@ -62,6 +63,10 @@ wifi_pwrseq: wifi-pwrseq {
};
};
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
&mmc0 {
vmmc-supply = <&reg_dldo1>;
/* Card detection pin is not connected */
......
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
// Copyright (C) 2023 Martin Botka <martin@somainline.org>
/ {
cpu_opp_table: opp-table-cpu {
compatible = "allwinner,sun50i-h616-operating-points";
nvmem-cells = <&cpu_speed_grade>;
opp-shared;
opp-480000000 {
opp-hz = /bits/ 64 <480000000>;
opp-microvolt = <900000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x1f>;
};
opp-600000000 {
opp-hz = /bits/ 64 <600000000>;
opp-microvolt = <900000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x12>;
};
opp-720000000 {
opp-hz = /bits/ 64 <720000000>;
opp-microvolt = <900000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x0d>;
};
opp-792000000 {
opp-hz = /bits/ 64 <792000000>;
opp-microvolt-speed1 = <900000>;
opp-microvolt-speed4 = <940000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x12>;
};
opp-936000000 {
opp-hz = /bits/ 64 <936000000>;
opp-microvolt = <900000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x0d>;
};
opp-1008000000 {
opp-hz = /bits/ 64 <1008000000>;
opp-microvolt-speed0 = <950000>;
opp-microvolt-speed1 = <940000>;
opp-microvolt-speed2 = <950000>;
opp-microvolt-speed3 = <950000>;
opp-microvolt-speed4 = <1020000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x1f>;
};
opp-1104000000 {
opp-hz = /bits/ 64 <1104000000>;
opp-microvolt-speed0 = <1000000>;
opp-microvolt-speed2 = <1000000>;
opp-microvolt-speed3 = <1000000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x0d>;
};
opp-1200000000 {
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt-speed0 = <1050000>;
opp-microvolt-speed1 = <1020000>;
opp-microvolt-speed2 = <1050000>;
opp-microvolt-speed3 = <1050000>;
opp-microvolt-speed4 = <1100000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x1f>;
};
opp-1320000000 {
opp-hz = /bits/ 64 <1320000000>;
opp-microvolt = <1100000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x1d>;
};
opp-1416000000 {
opp-hz = /bits/ 64 <1416000000>;
opp-microvolt = <1100000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x0d>;
};
opp-1512000000 {
opp-hz = /bits/ 64 <1512000000>;
opp-microvolt-speed1 = <1100000>;
opp-microvolt-speed3 = <1100000>;
clock-latency-ns = <244144>; /* 8 32k periods */
opp-supported-hw = <0x0a>;
};
};
};
&cpu0 {
operating-points-v2 = <&cpu_opp_table>;
};
&cpu1 {
operating-points-v2 = <&cpu_opp_table>;
};
&cpu2 {
operating-points-v2 = <&cpu_opp_table>;
};
&cpu3 {
operating-points-v2 = <&cpu_opp_table>;
};
......@@ -6,12 +6,17 @@
/dts-v1/;
#include "sun50i-h616-orangepi-zero.dtsi"
#include "sun50i-h616-cpu-opp.dtsi"
/ {
model = "OrangePi Zero2";
compatible = "xunlong,orangepi-zero2", "allwinner,sun50i-h616";
};
&cpu0 {
cpu-supply = <&reg_dcdca>;
};
&emac0 {
allwinner,rx-delay-ps = <3100>;
allwinner,tx-delay-ps = <700>;
......
......@@ -6,6 +6,7 @@
/dts-v1/;
#include "sun50i-h616.dtsi"
#include "sun50i-h616-cpu-opp.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
......@@ -32,6 +33,10 @@ reg_vcc5v: vcc5v {
};
};
&cpu0 {
cpu-supply = <&reg_dcdca>;
};
&ehci0 {
status = "okay";
};
......
......@@ -26,6 +26,7 @@ cpu0: cpu@0 {
reg = <0>;
enable-method = "psci";
clocks = <&ccu CLK_CPUX>;
#cooling-cells = <2>;
};
cpu1: cpu@1 {
......@@ -34,6 +35,7 @@ cpu1: cpu@1 {
reg = <1>;
enable-method = "psci";
clocks = <&ccu CLK_CPUX>;
#cooling-cells = <2>;
};
cpu2: cpu@2 {
......@@ -42,6 +44,7 @@ cpu2: cpu@2 {
reg = <2>;
enable-method = "psci";
clocks = <&ccu CLK_CPUX>;
#cooling-cells = <2>;
};
cpu3: cpu@3 {
......@@ -50,6 +53,7 @@ cpu3: cpu@3 {
reg = <3>;
enable-method = "psci";
clocks = <&ccu CLK_CPUX>;
#cooling-cells = <2>;
};
};
......@@ -156,6 +160,10 @@ sid: efuse@3006000 {
ths_calibration: thermal-sensor-calibration@14 {
reg = <0x14 0x8>;
};
cpu_speed_grade: cpu-speed-grade@0 {
reg = <0x0 2>;
};
};
watchdog: watchdog@30090a0 {
......
......@@ -4,6 +4,11 @@
*/
#include "sun50i-h616.dtsi"
#include "sun50i-h616-cpu-opp.dtsi"
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
&mmc2 {
pinctrl-names = "default";
......
......@@ -6,6 +6,7 @@
/dts-v1/;
#include "sun50i-h616.dtsi"
#include "sun50i-h616-cpu-opp.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
......@@ -53,6 +54,10 @@ reg_vcc3v3: vcc3v3 {
};
};
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
&ehci1 {
status = "okay";
};
......
......@@ -6,12 +6,17 @@
/dts-v1/;
#include "sun50i-h616-orangepi-zero.dtsi"
#include "sun50i-h616-cpu-opp.dtsi"
/ {
model = "OrangePi Zero3";
compatible = "xunlong,orangepi-zero3", "allwinner,sun50i-h618";
};
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
&emac0 {
allwinner,tx-delay-ps = <700>;
phy-mode = "rgmii-rxid";
......
......@@ -6,6 +6,7 @@
/dts-v1/;
#include "sun50i-h616.dtsi"
#include "sun50i-h616-cpu-opp.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
......@@ -51,6 +52,10 @@ wifi_pwrseq: wifi_pwrseq {
};
};
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
&ehci0 {
status = "okay";
};
......
......@@ -686,8 +686,10 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
if (!osc_sb_cppc2_support_acked) {
pr_debug("CPPC v2 _OSC not acked\n");
if (!cpc_supported_by_cpu())
if (!cpc_supported_by_cpu()) {
pr_debug("CPPC is not supported by the CPU\n");
return -ENODEV;
}
}
/* Parse the ACPI _CPC table for this CPU. */
......
This diff is collapsed.
......@@ -481,9 +481,12 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv)
static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
struct private_data *priv;
if (!policy)
return 0;
struct private_data *priv = policy->driver_data;
priv = policy->driver_data;
cpufreq_cpu_put(policy);
......
......@@ -741,10 +741,15 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
{
struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0};
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
struct cppc_cpudata *cpu_data = policy->driver_data;
struct cppc_cpudata *cpu_data;
u64 delivered_perf;
int ret;
if (!policy)
return -ENODEV;
cpu_data = policy->driver_data;
cpufreq_cpu_put(policy);
ret = cppc_get_perf_ctrs(cpu, &fb_ctrs_t0);
......@@ -822,10 +827,15 @@ static struct cpufreq_driver cppc_cpufreq_driver = {
static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
struct cppc_cpudata *cpu_data = policy->driver_data;
struct cppc_cpudata *cpu_data;
u64 desired_perf;
int ret;
if (!policy)
return -ENODEV;
cpu_data = policy->driver_data;
cpufreq_cpu_put(policy);
ret = cppc_get_desired_perf(cpu, &desired_perf);
......
......@@ -104,6 +104,9 @@ static const struct of_device_id allowlist[] __initconst = {
*/
static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "allwinner,sun50i-h6", },
{ .compatible = "allwinner,sun50i-h616", },
{ .compatible = "allwinner,sun50i-h618", },
{ .compatible = "allwinner,sun50i-h700", },
{ .compatible = "apple,arm-platform", },
......@@ -195,19 +198,18 @@ static const struct of_device_id blocklist[] __initconst = {
static bool __init cpu0_node_has_opp_v2_prop(void)
{
struct device_node *np = of_cpu_device_node_get(0);
struct device_node *np __free(device_node) = of_cpu_device_node_get(0);
bool ret = false;
if (of_property_present(np, "operating-points-v2"))
ret = true;
of_node_put(np);
return ret;
}
static int __init cpufreq_dt_platdev_init(void)
{
struct device_node *np = of_find_node_by_path("/");
struct device_node *np __free(device_node) = of_find_node_by_path("/");
const struct of_device_id *match;
const void *data = NULL;
......@@ -223,11 +225,9 @@ static int __init cpufreq_dt_platdev_init(void)
if (cpu0_node_has_opp_v2_prop() && !of_match_node(blocklist, np))
goto create_pdev;
of_node_put(np);
return -ENODEV;
create_pdev:
of_node_put(np);
return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq-dt",
-1, data,
sizeof(struct cpufreq_dt_platform_data)));
......
......@@ -68,12 +68,9 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index)
*/
static const char *find_supply_name(struct device *dev)
{
struct device_node *np;
struct device_node *np __free(device_node) = of_node_get(dev->of_node);
struct property *pp;
int cpu = dev->id;
const char *name = NULL;
np = of_node_get(dev->of_node);
/* This must be valid for sure */
if (WARN_ON(!np))
......@@ -82,22 +79,16 @@ static const char *find_supply_name(struct device *dev)
/* Try "cpu0" for older DTs */
if (!cpu) {
pp = of_find_property(np, "cpu0-supply", NULL);
if (pp) {
name = "cpu0";
goto node_put;
}
if (pp)
return "cpu0";
}
pp = of_find_property(np, "cpu-supply", NULL);
if (pp) {
name = "cpu";
goto node_put;
}
if (pp)
return "cpu";
dev_dbg(dev, "no regulator for cpu%d\n", cpu);
node_put:
of_node_put(np);
return name;
return NULL;
}
static int cpufreq_init(struct cpufreq_policy *policy)
......
......@@ -1679,10 +1679,13 @@ static void __cpufreq_offline(unsigned int cpu, struct cpufreq_policy *policy)
*/
if (cpufreq_driver->offline) {
cpufreq_driver->offline(policy);
} else if (cpufreq_driver->exit) {
cpufreq_driver->exit(policy);
policy->freq_table = NULL;
return;
}
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
policy->freq_table = NULL;
}
static int cpufreq_offline(unsigned int cpu)
......@@ -1740,7 +1743,7 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
}
/* We did light-weight exit earlier, do full tear down now */
if (cpufreq_driver->offline)
if (cpufreq_driver->offline && cpufreq_driver->exit)
cpufreq_driver->exit(policy);
up_write(&policy->rwsem);
......
......@@ -70,7 +70,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy,
struct cpufreq_frequency_table *table)
{
struct cpufreq_frequency_table *pos;
unsigned int freq, next_larger = ~0;
unsigned int freq, prev_smaller = 0;
bool found = false;
pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
......@@ -86,12 +86,12 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy,
break;
}
if ((next_larger > freq) && (freq > policy->max))
next_larger = freq;
if ((prev_smaller < freq) && (freq <= policy->max))
prev_smaller = freq;
}
if (!found) {
policy->max = next_larger;
policy->max = prev_smaller;
cpufreq_verify_within_cpu_limits(policy);
}
......@@ -194,7 +194,7 @@ int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
}
if (optimal.driver_data > i) {
if (suboptimal.driver_data > i) {
WARN(1, "Invalid frequency table: %d\n", policy->cpu);
WARN(1, "Invalid frequency table: %u\n", policy->cpu);
return 0;
}
......@@ -254,7 +254,7 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
continue;
count += sprintf(&buf[count], "%d ", pos->frequency);
count += sprintf(&buf[count], "%u ", pos->frequency);
}
count += sprintf(&buf[count], "\n");
......
This diff is collapsed.
......@@ -707,6 +707,15 @@ static const struct mtk_cpufreq_platform_data mt7623_platform_data = {
.ccifreq_supported = false,
};
static const struct mtk_cpufreq_platform_data mt7988_platform_data = {
.min_volt_shift = 100000,
.max_volt_shift = 200000,
.proc_max_volt = 900000,
.sram_min_volt = 0,
.sram_max_volt = 1150000,
.ccifreq_supported = true,
};
static const struct mtk_cpufreq_platform_data mt8183_platform_data = {
.min_volt_shift = 100000,
.max_volt_shift = 200000,
......@@ -740,6 +749,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
{ .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt7622", .data = &mt7622_platform_data },
{ .compatible = "mediatek,mt7623", .data = &mt7623_platform_data },
{ .compatible = "mediatek,mt7988a", .data = &mt7988_platform_data },
{ .compatible = "mediatek,mt8167", .data = &mt8516_platform_data },
{ .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
......
......@@ -10,6 +10,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/arm-smccc.h>
#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
......@@ -18,26 +19,155 @@
#include <linux/pm_opp.h>
#include <linux/slab.h>
#define MAX_NAME_LEN 7
#define NVMEM_MASK 0x7
#define NVMEM_SHIFT 5
static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev;
struct sunxi_cpufreq_data {
u32 (*efuse_xlate)(u32 speedbin);
};
static u32 sun50i_h6_efuse_xlate(u32 speedbin)
{
u32 efuse_value;
efuse_value = (speedbin >> NVMEM_SHIFT) & NVMEM_MASK;
/*
* We treat unexpected efuse values as if the SoC was from
* the slowest bin. Expected efuse values are 1-3, slowest
* to fastest.
*/
if (efuse_value >= 1 && efuse_value <= 3)
return efuse_value - 1;
else
return 0;
}
static int get_soc_id_revision(void)
{
#ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY
return arm_smccc_get_soc_id_revision();
#else
return SMCCC_RET_NOT_SUPPORTED;
#endif
}
/*
* Judging by the OPP tables in the vendor BSP, the quality order of the
* returned speedbin index is 4 -> 0/2 -> 3 -> 1, from worst to best.
* 0 and 2 seem identical from the OPP tables' point of view.
*/
static u32 sun50i_h616_efuse_xlate(u32 speedbin)
{
int ver_bits = get_soc_id_revision();
u32 value = 0;
switch (speedbin & 0xffff) {
case 0x2000:
value = 0;
break;
case 0x2400:
case 0x7400:
case 0x2c00:
case 0x7c00:
if (ver_bits != SMCCC_RET_NOT_SUPPORTED && ver_bits <= 1) {
/* ic version A/B */
value = 1;
} else {
/* ic version C and later version */
value = 2;
}
break;
case 0x5000:
case 0x5400:
case 0x6000:
value = 3;
break;
case 0x5c00:
value = 4;
break;
case 0x5d00:
value = 0;
break;
default:
pr_warn("sun50i-cpufreq-nvmem: unknown speed bin 0x%x, using default bin 0\n",
speedbin & 0xffff);
value = 0;
break;
}
return value;
}
static struct sunxi_cpufreq_data sun50i_h6_cpufreq_data = {
.efuse_xlate = sun50i_h6_efuse_xlate,
};
static struct sunxi_cpufreq_data sun50i_h616_cpufreq_data = {
.efuse_xlate = sun50i_h616_efuse_xlate,
};
static const struct of_device_id cpu_opp_match_list[] = {
{ .compatible = "allwinner,sun50i-h6-operating-points",
.data = &sun50i_h6_cpufreq_data,
},
{ .compatible = "allwinner,sun50i-h616-operating-points",
.data = &sun50i_h616_cpufreq_data,
},
{}
};
/**
* dt_has_supported_hw() - Check if any OPPs use opp-supported-hw
*
* If we ask the cpufreq framework to use the opp-supported-hw feature, it
* will ignore every OPP node without that DT property. If none of the OPPs
* have it, the driver will fail probing, due to the lack of OPPs.
*
* Returns true if we have at least one OPP with the opp-supported-hw property.
*/
static bool dt_has_supported_hw(void)
{
bool has_opp_supported_hw = false;
struct device_node *np, *opp;
struct device *cpu_dev;
cpu_dev = get_cpu_device(0);
if (!cpu_dev)
return false;
np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
if (!np)
return false;
for_each_child_of_node(np, opp) {
if (of_find_property(opp, "opp-supported-hw", NULL)) {
has_opp_supported_hw = true;
break;
}
}
of_node_put(np);
return has_opp_supported_hw;
}
/**
* sun50i_cpufreq_get_efuse() - Determine speed grade from efuse value
* @versions: Set to the value parsed from efuse
*
* Returns 0 if success.
* Returns non-negative speed bin index on success, a negative error
* value otherwise.
*/
static int sun50i_cpufreq_get_efuse(u32 *versions)
static int sun50i_cpufreq_get_efuse(void)
{
const struct sunxi_cpufreq_data *opp_data;
struct nvmem_cell *speedbin_nvmem;
const struct of_device_id *match;
struct device_node *np;
struct device *cpu_dev;
u32 *speedbin, efuse_value;
size_t len;
u32 *speedbin;
int ret;
cpu_dev = get_cpu_device(0);
......@@ -48,12 +178,12 @@ static int sun50i_cpufreq_get_efuse(u32 *versions)
if (!np)
return -ENOENT;
ret = of_device_is_compatible(np,
"allwinner,sun50i-h6-operating-points");
if (!ret) {
match = of_match_node(cpu_opp_match_list, np);
if (!match) {
of_node_put(np);
return -ENOENT;
}
opp_data = match->data;
speedbin_nvmem = of_nvmem_cell_get(np, NULL);
of_node_put(np);
......@@ -61,33 +191,25 @@ static int sun50i_cpufreq_get_efuse(u32 *versions)
return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem),
"Could not get nvmem cell\n");
speedbin = nvmem_cell_read(speedbin_nvmem, &len);
speedbin = nvmem_cell_read(speedbin_nvmem, NULL);
nvmem_cell_put(speedbin_nvmem);
if (IS_ERR(speedbin))
return PTR_ERR(speedbin);
efuse_value = (*speedbin >> NVMEM_SHIFT) & NVMEM_MASK;
/*
* We treat unexpected efuse values as if the SoC was from
* the slowest bin. Expected efuse values are 1-3, slowest
* to fastest.
*/
if (efuse_value >= 1 && efuse_value <= 3)
*versions = efuse_value - 1;
else
*versions = 0;
ret = opp_data->efuse_xlate(*speedbin);
kfree(speedbin);
return 0;
return ret;
};
static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
{
int *opp_tokens;
char name[MAX_NAME_LEN];
unsigned int cpu;
u32 speed = 0;
char name[] = "speedXXXXXXXXXXX"; /* Integers can take 11 chars max */
unsigned int cpu, supported_hw;
struct dev_pm_opp_config config = {};
int speed;
int ret;
opp_tokens = kcalloc(num_possible_cpus(), sizeof(*opp_tokens),
......@@ -95,13 +217,24 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
if (!opp_tokens)
return -ENOMEM;
ret = sun50i_cpufreq_get_efuse(&speed);
if (ret) {
speed = sun50i_cpufreq_get_efuse();
if (speed < 0) {
kfree(opp_tokens);
return ret;
return speed;
}
snprintf(name, MAX_NAME_LEN, "speed%d", speed);
/*
* We need at least one OPP with the "opp-supported-hw" property,
* or else the upper layers will ignore every OPP and will bail out.
*/
if (dt_has_supported_hw()) {
supported_hw = 1U << speed;
config.supported_hw = &supported_hw;
config.supported_hw_count = 1;
}
snprintf(name, sizeof(name), "speed%d", speed);
config.prop_name = name;
for_each_possible_cpu(cpu) {
struct device *cpu_dev = get_cpu_device(cpu);
......@@ -111,12 +244,11 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
goto free_opp;
}
opp_tokens[cpu] = dev_pm_opp_set_prop_name(cpu_dev, name);
if (opp_tokens[cpu] < 0) {
ret = opp_tokens[cpu];
pr_err("Failed to set prop name\n");
ret = dev_pm_opp_set_config(cpu_dev, &config);
if (ret < 0)
goto free_opp;
}
opp_tokens[cpu] = ret;
}
cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1,
......@@ -131,7 +263,7 @@ static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
free_opp:
for_each_possible_cpu(cpu)
dev_pm_opp_put_prop_name(opp_tokens[cpu]);
dev_pm_opp_clear_config(opp_tokens[cpu]);
kfree(opp_tokens);
return ret;
......@@ -145,7 +277,7 @@ static void sun50i_cpufreq_nvmem_remove(struct platform_device *pdev)
platform_device_unregister(cpufreq_dt_pdev);
for_each_possible_cpu(cpu)
dev_pm_opp_put_prop_name(opp_tokens[cpu]);
dev_pm_opp_clear_config(opp_tokens[cpu]);
kfree(opp_tokens);
}
......@@ -160,6 +292,9 @@ static struct platform_driver sun50i_cpufreq_driver = {
static const struct of_device_id sun50i_cpufreq_match_list[] = {
{ .compatible = "allwinner,sun50i-h6" },
{ .compatible = "allwinner,sun50i-h616" },
{ .compatible = "allwinner,sun50i-h618" },
{ .compatible = "allwinner,sun50i-h700" },
{}
};
MODULE_DEVICE_TABLE(of, sun50i_cpufreq_match_list);
......
......@@ -52,12 +52,15 @@ static int tegra124_cpu_switch_to_dfll(struct tegra124_cpufreq_priv *priv)
static int tegra124_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np __free(device_node) = of_cpu_device_node_get(0);
struct tegra124_cpufreq_priv *priv;
struct device_node *np;
struct device *cpu_dev;
struct platform_device_info cpufreq_dt_devinfo = {};
int ret;
if (!np)
return -ENODEV;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
......@@ -66,15 +69,9 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
if (!cpu_dev)
return -ENODEV;
np = of_cpu_device_node_get(0);
if (!np)
return -ENODEV;
priv->cpu_clk = of_clk_get_by_name(np, "cpu_g");
if (IS_ERR(priv->cpu_clk)) {
ret = PTR_ERR(priv->cpu_clk);
goto out_put_np;
}
if (IS_ERR(priv->cpu_clk))
return PTR_ERR(priv->cpu_clk);
priv->dfll_clk = of_clk_get_by_name(np, "dfll");
if (IS_ERR(priv->dfll_clk)) {
......@@ -110,8 +107,6 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
of_node_put(np);
return 0;
out_put_pllp_clk:
......@@ -122,8 +117,6 @@ static int tegra124_cpufreq_probe(struct platform_device *pdev)
clk_put(priv->dfll_clk);
out_put_cpu_clk:
clk_put(priv->cpu_clk);
out_put_np:
of_node_put(np);
return ret;
}
......
......@@ -347,12 +347,10 @@ static const struct of_device_id ti_cpufreq_of_match[] = {
static const struct of_device_id *ti_cpufreq_match_node(void)
{
struct device_node *np;
struct device_node *np __free(device_node) = of_find_node_by_path("/");
const struct of_device_id *match;
np = of_find_node_by_path("/");
match = of_match_node(ti_cpufreq_of_match, np);
of_node_put(np);
return match;
}
......
......@@ -69,6 +69,7 @@ s32 arm_smccc_get_soc_id_revision(void)
{
return smccc_soc_id_revision;
}
EXPORT_SYMBOL_GPL(arm_smccc_get_soc_id_revision);
static int __init smccc_devices_init(void)
{
......
......@@ -49,13 +49,17 @@ struct amd_aperf_mperf {
* @lowest_perf: the absolute lowest performance level of the processor
* @prefcore_ranking: the preferred core ranking, the higher value indicates a higher
* priority.
* @max_freq: the frequency that mapped to highest_perf
* @min_freq: the frequency that mapped to lowest_perf
* @nominal_freq: the frequency that mapped to nominal_perf
* @lowest_nonlinear_freq: the frequency that mapped to lowest_nonlinear_perf
* @min_limit_perf: Cached value of the performance corresponding to policy->min
* @max_limit_perf: Cached value of the performance corresponding to policy->max
* @min_limit_freq: Cached value of policy->min (in khz)
* @max_limit_freq: Cached value of policy->max (in khz)
* @max_freq: the frequency (in khz) that mapped to highest_perf
* @min_freq: the frequency (in khz) that mapped to lowest_perf
* @nominal_freq: the frequency (in khz) that mapped to nominal_perf
* @lowest_nonlinear_freq: the frequency (in khz) that mapped to lowest_nonlinear_perf
* @cur: Difference of Aperf/Mperf/tsc count between last and current sample
* @prev: Last Aperf/Mperf/tsc count value read from register
* @freq: current cpu frequency value
* @freq: current cpu frequency value (in khz)
* @boost_supported: check whether the Processor or SBIOS supports boost mode
* @hw_prefcore: check whether HW supports preferred core featue.
* Only when hw_prefcore and early prefcore param are true,
......@@ -124,4 +128,10 @@ static const char * const amd_pstate_mode_string[] = {
[AMD_PSTATE_GUIDED] = "guided",
NULL,
};
struct quirk_entry {
u32 nominal_freq;
u32 lowest_freq;
};
#endif /* _LINUX_AMD_PSTATE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment