mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 06:34:12 +08:00
Merge patch series "RISC-V: ACPI: Enable CPPC based cpufreq support"
Sunil V L <sunilvl@ventanamicro.com> says: This series enables the support for "Collaborative Processor Performance Control (CPPC) on ACPI based RISC-V platforms. It depends on the encoding of CPPC registers as defined in RISC-V FFH spec [2]. CPPC is described in the ACPI spec [1]. RISC-V FFH spec required to enable this, is available at [2]. [1] - https://uefi.org/specs/ACPI/6.5/08_Processor_Configuration_and_Control.html#collaborative-processor-performance-control [2] - https://github.com/riscv-non-isa/riscv-acpi-ffh/releases/download/v1.0.0/riscv-ffh.pdf * b4-shazam-merge: RISC-V: defconfig: Enable CONFIG_ACPI_CPPC_CPUFREQ cpufreq: Move CPPC configs to common Kconfig and add RISC-V ACPI: RISC-V: Add CPPC driver Link: https://lore.kernel.org/r/20240208034414.22579-1-sunilvl@ventanamicro.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
This commit is contained in:
commit
028d1aee1f
@ -44,6 +44,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
|||||||
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
||||||
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
|
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
|
||||||
CONFIG_CPUFREQ_DT=y
|
CONFIG_CPUFREQ_DT=y
|
||||||
|
CONFIG_ACPI_CPPC_CPUFREQ=m
|
||||||
CONFIG_VIRTUALIZATION=y
|
CONFIG_VIRTUALIZATION=y
|
||||||
CONFIG_KVM=m
|
CONFIG_KVM=m
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
obj-y += rhct.o
|
obj-y += rhct.o
|
||||||
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
|
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
|
||||||
|
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
|
||||||
|
157
drivers/acpi/riscv/cppc.c
Normal file
157
drivers/acpi/riscv/cppc.c
Normal file
@ -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 <acpi/cppc_acpi.h>
|
||||||
|
#include <asm/csr.h>
|
||||||
|
#include <asm/sbi.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
@ -302,4 +302,33 @@ config QORIQ_CPUFREQ
|
|||||||
which are capable of changing the CPU's frequency dynamically.
|
which are capable of changing the CPU's frequency dynamically.
|
||||||
|
|
||||||
endif
|
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
|
endmenu
|
||||||
|
@ -3,32 +3,6 @@
|
|||||||
# ARM CPU Frequency scaling drivers
|
# 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
|
config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
|
||||||
tristate "Allwinner nvmem based SUN50I CPUFreq driver"
|
tristate "Allwinner nvmem based SUN50I CPUFreq driver"
|
||||||
depends on ARCH_SUNXI
|
depends on ARCH_SUNXI
|
||||||
|
Loading…
Reference in New Issue
Block a user