diff --git a/anolis/configs/L0-MANDATORY/riscv/CONFIG_ACPI_PROCESSOR b/anolis/configs/L0-MANDATORY/riscv/CONFIG_ACPI_PROCESSOR deleted file mode 100644 index 71d30f116a41dc50368493ae2309b0ff91e4c635..0000000000000000000000000000000000000000 --- a/anolis/configs/L0-MANDATORY/riscv/CONFIG_ACPI_PROCESSOR +++ /dev/null @@ -1 +0,0 @@ -# CONFIG_ACPI_PROCESSOR is not set diff --git a/anolis/configs/L1-RECOMMEND/riscv/CONFIG_ACPI_CPPC_CPUFREQ b/anolis/configs/L1-RECOMMEND/riscv/CONFIG_ACPI_CPPC_CPUFREQ new file mode 100644 index 0000000000000000000000000000000000000000..5cc88132a9210ef8428ece2a235d652506fd2f7b --- /dev/null +++ b/anolis/configs/L1-RECOMMEND/riscv/CONFIG_ACPI_CPPC_CPUFREQ @@ -0,0 +1 @@ +CONFIG_ACPI_CPPC_CPUFREQ=m diff --git a/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_CPPC_CPUFREQ_FIE b/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_CPPC_CPUFREQ_FIE new file mode 100644 index 0000000000000000000000000000000000000000..da007c591e66b1658b75148befab92c058f2a574 --- /dev/null +++ b/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_CPPC_CPUFREQ_FIE @@ -0,0 +1 @@ +CONFIG_ACPI_CPPC_CPUFREQ_FIE=y diff --git a/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_CPPC_LIB b/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_CPPC_LIB deleted file mode 100644 index 6c1fd1674d772f573881acc815a4c81f7ea5a289..0000000000000000000000000000000000000000 --- a/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_CPPC_LIB +++ /dev/null @@ -1 +0,0 @@ -# CONFIG_ACPI_CPPC_LIB is not set diff --git a/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_HOTPLUG_CPU b/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_HOTPLUG_CPU deleted file mode 100644 index 401c35bd564c470314bed9aff80e940cf1f1c0e2..0000000000000000000000000000000000000000 --- a/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_HOTPLUG_CPU +++ /dev/null @@ -1 +0,0 @@ -# CONFIG_ACPI_HOTPLUG_CPU is not set diff --git a/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_PROCESSOR_IDLE b/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_PROCESSOR_IDLE deleted file mode 100644 index 6931b739fb89c18a64cd2675cd235838a44dbbe9..0000000000000000000000000000000000000000 --- a/anolis/configs/L2-OPTIONAL/riscv/CONFIG_ACPI_PROCESSOR_IDLE +++ /dev/null @@ -1 +0,0 @@ -# CONFIG_ACPI_PROCESSOR_IDLE is not set diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index 184e0df48ecd0823c45a9b12866b581bb8dd1130..6aadb657157821f0940d7ad5f7b18d82fd0cecda 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -37,6 +37,7 @@ CONFIG_SMP=y CONFIG_HOTPLUG_CPU=y CONFIG_PM=y CONFIG_CPU_IDLE=y +CONFIG_ACPI_CPPC_CPUFREQ=m CONFIG_VIRTUALIZATION=y CONFIG_KVM=m CONFIG_ACPI=y diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index cee82b473dc50921c31e6dcfc0b573cdcf0962e9..c7e4ea25d2a0e405673a1373fd045132e3db2b8a 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -281,7 +281,7 @@ config ACPI_CPPC_LIB config ACPI_PROCESSOR tristate "Processor" - depends on X86 || IA64 || ARM64 || LOONGARCH + depends on X86 || IA64 || ARM64 || LOONGARCH || RISCV select ACPI_PROCESSOR_IDLE select ACPI_CPU_FREQ_PSS if X86 || IA64 || LOONGARCH select THERMAL diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile index 05d593d4bbb03391dd2a1747404477896a9cebce..6b5940b806ecdf6e73887301dd63c4130a74dcf3 100644 --- a/drivers/acpi/riscv/Makefile +++ b/drivers/acpi/riscv/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += rhct.o init.o irq.o +obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o diff --git a/drivers/acpi/riscv/cppc.c b/drivers/acpi/riscv/cppc.c new file mode 100644 index 0000000000000000000000000000000000000000..4cdff387deff6cf9da1d80dc0411af3b5406a79f --- /dev/null +++ b/drivers/acpi/riscv/cppc.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implement CPPC FFH helper routines for RISC-V. + * + * Copyright (C) 2024 Ventana Micro Systems Inc. + */ + +#include +#include +#include + +#define SBI_EXT_CPPC 0x43505043 + +/* CPPC interfaces defined in SBI spec */ +#define SBI_CPPC_PROBE 0x0 +#define SBI_CPPC_READ 0x1 +#define SBI_CPPC_READ_HI 0x2 +#define SBI_CPPC_WRITE 0x3 + +/* RISC-V FFH definitions from RISC-V FFH spec */ +#define FFH_CPPC_TYPE(r) (((r) & GENMASK_ULL(63, 60)) >> 60) +#define FFH_CPPC_SBI_REG(r) ((r) & GENMASK(31, 0)) +#define FFH_CPPC_CSR_NUM(r) ((r) & GENMASK(11, 0)) + +#define FFH_CPPC_SBI 0x1 +#define FFH_CPPC_CSR 0x2 + +struct sbi_cppc_data { + u64 val; + u32 reg; + struct sbiret ret; +}; + +static bool cppc_ext_present; + +static int __init sbi_cppc_init(void) +{ + if (sbi_spec_version >= sbi_mk_version(2, 0) && + sbi_probe_extension(SBI_EXT_CPPC) > 0) { + pr_info("SBI CPPC extension detected\n"); + cppc_ext_present = true; + } else { + pr_info("SBI CPPC extension NOT detected!!\n"); + cppc_ext_present = false; + } + + return 0; +} +device_initcall(sbi_cppc_init); + +static void sbi_cppc_read(void *read_data) +{ + struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data; + + data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_READ, + data->reg, 0, 0, 0, 0, 0); +} + +static void sbi_cppc_write(void *write_data) +{ + struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data; + + data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_WRITE, + data->reg, data->val, 0, 0, 0, 0); +} + +static void cppc_ffh_csr_read(void *read_data) +{ + struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data; + + switch (data->reg) { + /* Support only TIME CSR for now */ + case CSR_TIME: + data->ret.value = csr_read(CSR_TIME); + data->ret.error = 0; + break; + default: + data->ret.error = -EINVAL; + break; + } +} + +static void cppc_ffh_csr_write(void *write_data) +{ + struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data; + + data->ret.error = -EINVAL; +} + +/* + * Refer to drivers/acpi/cppc_acpi.c for the description of the functions + * below. + */ +bool cpc_ffh_supported(void) +{ + return true; +} + +int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val) +{ + struct sbi_cppc_data data; + + if (WARN_ON_ONCE(irqs_disabled())) + return -EPERM; + + if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) { + if (!cppc_ext_present) + return -EINVAL; + + data.reg = FFH_CPPC_SBI_REG(reg->address); + + smp_call_function_single(cpu, sbi_cppc_read, &data, 1); + + *val = data.ret.value; + + return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0; + } else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) { + data.reg = FFH_CPPC_CSR_NUM(reg->address); + + smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1); + + *val = data.ret.value; + + return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0; + } + + return -EINVAL; +} + +int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val) +{ + struct sbi_cppc_data data; + + if (WARN_ON_ONCE(irqs_disabled())) + return -EPERM; + + if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) { + if (!cppc_ext_present) + return -EINVAL; + + data.reg = FFH_CPPC_SBI_REG(reg->address); + data.val = val; + + smp_call_function_single(cpu, sbi_cppc_write, &data, 1); + + return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0; + } else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) { + data.reg = FFH_CPPC_CSR_NUM(reg->address); + data.val = val; + + smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1); + + return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0; + } + + return -EINVAL; +} diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 4c13741a744f9f9e197e6685673718e1c370f04b..d03d2df7bc156eea00c592574533bf8fbed16397 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -337,4 +337,33 @@ config QORIQ_CPUFREQ which are capable of changing the CPU's frequency dynamically. endif + +config ACPI_CPPC_CPUFREQ + tristate "CPUFreq driver based on the ACPI CPPC spec" + depends on ACPI_PROCESSOR + depends on ARM || ARM64 || RISCV + select ACPI_CPPC_LIB + help + This adds a CPUFreq driver which uses CPPC methods + as described in the ACPIv5.1 spec. CPPC stands for + Collaborative Processor Performance Controls. It + is based on an abstract continuous scale of CPU + performance values which allows the remote power + processor to flexibly optimize for power and + performance. CPPC relies on power management firmware + support for its operation. + + If in doubt, say N. + +config ACPI_CPPC_CPUFREQ_FIE + bool "Frequency Invariance support for CPPC cpufreq driver" + depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY + depends on ARM || ARM64 || RISCV + default y + help + This extends frequency invariance support in the CPPC cpufreq driver, + by using CPPC delivered and reference performance counters. + + If in doubt, say N. + endmenu diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index c5cecbd89ba9cea7ad5361623463f00b98365685..58829582191b665e921d447c465ca6085ecaf467 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -3,32 +3,6 @@ # ARM CPU Frequency scaling drivers # -config ACPI_CPPC_CPUFREQ - tristate "CPUFreq driver based on the ACPI CPPC spec" - depends on ACPI_PROCESSOR - select ACPI_CPPC_LIB - help - This adds a CPUFreq driver which uses CPPC methods - as described in the ACPIv5.1 spec. CPPC stands for - Collaborative Processor Performance Controls. It - is based on an abstract continuous scale of CPU - performance values which allows the remote power - processor to flexibly optimize for power and - performance. CPPC relies on power management firmware - support for its operation. - - If in doubt, say N. - -config ACPI_CPPC_CPUFREQ_FIE - bool "Frequency Invariance support for CPPC cpufreq driver" - depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY - default y - help - This extends frequency invariance support in the CPPC cpufreq driver, - by using CPPC delivered and reference performance counters. - - If in doubt, say N. - config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM tristate "Allwinner nvmem based SUN50I CPUFreq driver" depends on ARCH_SUNXI