diff --git a/arch/riscv/boot/dts/spacemit/k1-x.dtsi b/arch/riscv/boot/dts/spacemit/k1-x.dtsi index 8ba531cdf2efaa..946644a88f36e4 100644 --- a/arch/riscv/boot/dts/spacemit/k1-x.dtsi +++ b/arch/riscv/boot/dts/spacemit/k1-x.dtsi @@ -417,7 +417,7 @@ opp-hz = /bits/ 64 <1600000000>; tcm-hz = /bits/ 64 <800000000>; ace-hz = /bits/ 64 <800000000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; @@ -425,7 +425,7 @@ opp-hz = /bits/ 64 <1228800000>; tcm-hz = /bits/ 64 <614400000>; ace-hz = /bits/ 64 <614400000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; @@ -433,15 +433,15 @@ opp-hz = /bits/ 64 <1000000000>; tcm-hz = /bits/ 64 <500000000>; ace-hz = /bits/ 64 <500000000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; opp819000000 { opp-hz = /bits/ 64 <819000000>; - opp-microvolt = <950000>; tcm-hz = /bits/ 64 <409500000>; ace-hz = /bits/ 64 <409500000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; @@ -449,7 +449,7 @@ opp-hz = /bits/ 64 <614400000>; tcm-hz = /bits/ 64 <307200000>; ace-hz = /bits/ 64 <307200000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; }; @@ -465,35 +465,35 @@ opp1600000000 { opp-hz = /bits/ 64 <1600000000>; ace-hz = /bits/ 64 <800000000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; opp1228800000 { opp-hz = /bits/ 64 <1228800000>; ace-hz = /bits/ 64 <614400000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; opp1000000000 { opp-hz = /bits/ 64 <1000000000>; ace-hz = /bits/ 64 <500000000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; opp819000000 { opp-hz = /bits/ 64 <819000000>; ace-hz = /bits/ 64 <409500000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; opp614400000 { opp-hz = /bits/ 64 <614400000>; ace-hz = /bits/ 64 <307200000>; - opp-microvolt = <950000>; + opp-microvolt = <950000 950000 1050000>; clock-latency-ns = <200000>; }; }; diff --git a/arch/riscv/boot/dts/spacemit/k1-x_deb1.dts b/arch/riscv/boot/dts/spacemit/k1-x_deb1.dts index a33b41620fe524..219cd2e3f998f3 100644 --- a/arch/riscv/boot/dts/spacemit/k1-x_deb1.dts +++ b/arch/riscv/boot/dts/spacemit/k1-x_deb1.dts @@ -900,19 +900,46 @@ }; &cpu_0 { - clst0-supply = <&dcdc_1>; - vin-supply-names = "clst0"; + cpu-supply = <&dcdc_1>; +}; + +&cpu_1 { + cpu-supply = <&dcdc_1>; +}; + +&cpu_2 { + cpu-supply = <&dcdc_1>; +}; + +&cpu_3 { + cpu-supply = <&dcdc_1>; +}; + +&cpu_4 { + cpu-supply = <&dcdc_1>; +}; + +&cpu_5 { + cpu-supply = <&dcdc_1>; +}; + +&cpu_6 { + cpu-supply = <&dcdc_1>; +}; + +&cpu_7 { + cpu-supply = <&dcdc_1>; }; &clst0_core_opp_table { opp1600000000 { - opp-microvolt = <1050000>; + opp-microvolt = <1050000 950000 1050000>; }; }; &clst1_core_opp_table { opp1600000000 { - opp-microvolt = <1050000>; + opp-microvolt = <1050000 950000 1050000>; }; }; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 2561b215432a82..cf72c899435eca 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -272,6 +272,16 @@ config LOONGSON3_CPUFREQ If in doubt, say N. endif +if RISCV +config SPACEMIT_CPUFREQ + tristate "SpacemiT CPUFreq Driver" + depends on OF && COMMON_CLK && CPUFREQ_DT + help + This option adds a CPUFreq driver for SpacemiT SoCs. + + if in doubt, say N. +endif + if SPARC64 config SPARC_US3_CPUFREQ tristate "UltraSPARC-III CPU Frequency driver" diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 0f184031dd123c..4aed57514a76c1 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -104,6 +104,7 @@ obj-$(CONFIG_POWERNV_CPUFREQ) += powernv-cpufreq.o obj-$(CONFIG_BMIPS_CPUFREQ) += bmips-cpufreq.o obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o obj-$(CONFIG_LOONGSON3_CPUFREQ) += loongson3_cpufreq.o +obj-$(CONFIG_SPACEMIT_CPUFREQ) += spacemit-cpufreq.o obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o diff --git a/drivers/cpufreq/spacemit-cpufreq.c b/drivers/cpufreq/spacemit-cpufreq.c new file mode 100644 index 00000000000000..c6c8962f0edbbb --- /dev/null +++ b/drivers/cpufreq/spacemit-cpufreq.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../opp/opp.h" +#include "cpufreq-dt.h" + +#define TURBO_FREQUENCY (1600000000) +#define STABLE_FREQUENCY (1200000000) + +#define PRODUCT_ID_M1 (0x36070000) + +static int spacemit_policy_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + int cpu; + u64 rates; + static int cci_init; + struct clk *cci_clk; + struct device *cpu_dev; + struct cpufreq_policy *policy = data; + struct opp_table *opp_table; + + cpu = cpumask_first(policy->related_cpus); + cpu_dev = get_cpu_device(cpu); + opp_table = _find_opp_table(cpu_dev); + + if (cci_init == 0) { + cci_clk = of_clk_get_by_name(opp_table->np, "cci"); + if (IS_ERR(cci_clk)) + return 0; + + of_property_read_u64_array(opp_table->np, "cci-hz", &rates, 1); + clk_set_rate(cci_clk, rates); + clk_put(cci_clk); + cci_init = 1; + } + + return 0; +} + +static int spacemit_processor_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + int cpu; + struct device *cpu_dev; + struct cpufreq_freqs *freqs = (struct cpufreq_freqs *)data; + struct cpufreq_policy *policy = ( struct cpufreq_policy *)freqs->policy; + struct opp_table *opp_table; + struct device_node *np; + struct clk *tcm_clk, *ace0_clk, *ace1_clk; + u64 rates; + + cpu = cpumask_first(policy->related_cpus); + cpu_dev = get_cpu_device(cpu); + opp_table = _find_opp_table(cpu_dev); + + /* get the tcm/ace clk handler */ + tcm_clk = of_clk_get_by_name(opp_table->np, "tcm"); + ace0_clk = of_clk_get_by_name(opp_table->np, "ace0"); + ace1_clk = of_clk_get_by_name(opp_table->np, "ace1"); + + if (event == CPUFREQ_PRECHANGE) { + /** + * change the tcm/ace's frequency first. + * binary division is safe + */ + if (!IS_ERR(ace0_clk)) { + clk_set_rate(ace0_clk, clk_get_rate(clk_get_parent(ace0_clk)) / 2); + clk_put(ace0_clk); + } + + if (!IS_ERR(ace1_clk)) { + clk_set_rate(ace1_clk, clk_get_rate(clk_get_parent(ace1_clk)) / 2); + clk_put(ace1_clk); + } + + if (!IS_ERR(tcm_clk)) { + clk_set_rate(tcm_clk, clk_get_rate(clk_get_parent(tcm_clk)) / 2); + clk_put(tcm_clk); + } + + if (freqs->new * 1000 >= TURBO_FREQUENCY) { + if (freqs->old * 1000 >= TURBO_FREQUENCY) + clk_set_rate(opp_table->clk, STABLE_FREQUENCY); + } + + } + + if (event == CPUFREQ_POSTCHANGE) { + if (!IS_ERR(tcm_clk)) { + clk_get_rate(clk_get_parent(tcm_clk)); + /* get the tcm-hz */ + of_property_read_u64_array(np, "tcm-hz", &rates, 1); + /* then set rate */ + clk_set_rate(tcm_clk, rates); + clk_put(tcm_clk); + } + + if (!IS_ERR(ace0_clk)) { + clk_get_rate(clk_get_parent(ace0_clk)); + /* get the ace-hz */ + of_property_read_u64_array(np, "ace0-hz", &rates, 1); + /* then set rate */ + clk_set_rate(ace0_clk, rates); + clk_put(ace0_clk); + } + + if (!IS_ERR(ace1_clk)) { + clk_get_rate(clk_get_parent(ace1_clk)); + /* get the ace-hz */ + of_property_read_u64_array(np, "ace1-hz", &rates, 1); + /* then set rate */ + clk_set_rate(ace1_clk, rates); + clk_put(ace1_clk); + } + } + + dev_pm_opp_put_opp_table(opp_table); + + return 0; +} + +static struct notifier_block spacemit_processor_notifier_block = { + .notifier_call = spacemit_processor_notifier, +}; + +static struct notifier_block spacemit_policy_notifier_block = { + .notifier_call = spacemit_policy_notifier, +}; + +static int __init spacemit_processor_driver_init(void) +{ + int ret; + + ret = cpufreq_register_notifier(&spacemit_processor_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); + if (ret) { + pr_err("register cpufreq notifier failed\n"); + return -EINVAL; + } + + ret = cpufreq_register_notifier(&spacemit_policy_notifier_block, CPUFREQ_POLICY_NOTIFIER); + if (ret) { + pr_err("register cpufreq notifier failed\n"); + return -EINVAL; + } + + return 0; +} + +arch_initcall(spacemit_processor_driver_init);