Unverified Commit 028d1aee authored by Palmer Dabbelt's avatar Palmer Dabbelt
Browse files

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: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parents 01261e24 282b9df4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
CONFIG_CPUFREQ_DT=y
CONFIG_ACPI_CPPC_CPUFREQ=m
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=m
CONFIG_ACPI=y
+1 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
obj-y					+= rhct.o
obj-$(CONFIG_ACPI_PROCESSOR_IDLE)	+= cpuidle.o
obj-$(CONFIG_ACPI_CPPC_LIB)		+= cppc.o
+157 −0
Original line number Diff line number Diff line
// 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;
}
+29 −0
Original line number Diff line number Diff line
@@ -302,4 +302,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
+0 −26
Original line number Diff line number Diff line
@@ -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