Skip to content

Commit 30f3ffb

Browse files
vlsunilpalmer-dabbelt
authored andcommitted
ACPI: RISC-V: Add CPPC driver
Add cpufreq driver based on ACPI CPPC for RISC-V. The driver uses either SBI CPPC interfaces or the CSRs to access the CPPC registers as defined by the RISC-V FFH spec. Signed-off-by: Sunil V L <sunilvl@ventanamicro.com> Reviewed-by: Pierre Gondois <pierre.gondois@arm.com> Acked-by: Rafael J. Wysocki <rafael@kernel.org> Acked-by: Sudeep Holla <sudeep.holla@arm.com> Link: https://lore.kernel.org/r/20240208034414.22579-2-sunilvl@ventanamicro.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
1 parent 359df7c commit 30f3ffb

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

drivers/acpi/riscv/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
obj-y += rhct.o
33
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
4+
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o

drivers/acpi/riscv/cppc.c

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Implement CPPC FFH helper routines for RISC-V.
4+
*
5+
* Copyright (C) 2024 Ventana Micro Systems Inc.
6+
*/
7+
8+
#include <acpi/cppc_acpi.h>
9+
#include <asm/csr.h>
10+
#include <asm/sbi.h>
11+
12+
#define SBI_EXT_CPPC 0x43505043
13+
14+
/* CPPC interfaces defined in SBI spec */
15+
#define SBI_CPPC_PROBE 0x0
16+
#define SBI_CPPC_READ 0x1
17+
#define SBI_CPPC_READ_HI 0x2
18+
#define SBI_CPPC_WRITE 0x3
19+
20+
/* RISC-V FFH definitions from RISC-V FFH spec */
21+
#define FFH_CPPC_TYPE(r) (((r) & GENMASK_ULL(63, 60)) >> 60)
22+
#define FFH_CPPC_SBI_REG(r) ((r) & GENMASK(31, 0))
23+
#define FFH_CPPC_CSR_NUM(r) ((r) & GENMASK(11, 0))
24+
25+
#define FFH_CPPC_SBI 0x1
26+
#define FFH_CPPC_CSR 0x2
27+
28+
struct sbi_cppc_data {
29+
u64 val;
30+
u32 reg;
31+
struct sbiret ret;
32+
};
33+
34+
static bool cppc_ext_present;
35+
36+
static int __init sbi_cppc_init(void)
37+
{
38+
if (sbi_spec_version >= sbi_mk_version(2, 0) &&
39+
sbi_probe_extension(SBI_EXT_CPPC) > 0) {
40+
pr_info("SBI CPPC extension detected\n");
41+
cppc_ext_present = true;
42+
} else {
43+
pr_info("SBI CPPC extension NOT detected!!\n");
44+
cppc_ext_present = false;
45+
}
46+
47+
return 0;
48+
}
49+
device_initcall(sbi_cppc_init);
50+
51+
static void sbi_cppc_read(void *read_data)
52+
{
53+
struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
54+
55+
data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_READ,
56+
data->reg, 0, 0, 0, 0, 0);
57+
}
58+
59+
static void sbi_cppc_write(void *write_data)
60+
{
61+
struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
62+
63+
data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_WRITE,
64+
data->reg, data->val, 0, 0, 0, 0);
65+
}
66+
67+
static void cppc_ffh_csr_read(void *read_data)
68+
{
69+
struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
70+
71+
switch (data->reg) {
72+
/* Support only TIME CSR for now */
73+
case CSR_TIME:
74+
data->ret.value = csr_read(CSR_TIME);
75+
data->ret.error = 0;
76+
break;
77+
default:
78+
data->ret.error = -EINVAL;
79+
break;
80+
}
81+
}
82+
83+
static void cppc_ffh_csr_write(void *write_data)
84+
{
85+
struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
86+
87+
data->ret.error = -EINVAL;
88+
}
89+
90+
/*
91+
* Refer to drivers/acpi/cppc_acpi.c for the description of the functions
92+
* below.
93+
*/
94+
bool cpc_ffh_supported(void)
95+
{
96+
return true;
97+
}
98+
99+
int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
100+
{
101+
struct sbi_cppc_data data;
102+
103+
if (WARN_ON_ONCE(irqs_disabled()))
104+
return -EPERM;
105+
106+
if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
107+
if (!cppc_ext_present)
108+
return -EINVAL;
109+
110+
data.reg = FFH_CPPC_SBI_REG(reg->address);
111+
112+
smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
113+
114+
*val = data.ret.value;
115+
116+
return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
117+
} else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
118+
data.reg = FFH_CPPC_CSR_NUM(reg->address);
119+
120+
smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
121+
122+
*val = data.ret.value;
123+
124+
return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
125+
}
126+
127+
return -EINVAL;
128+
}
129+
130+
int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val)
131+
{
132+
struct sbi_cppc_data data;
133+
134+
if (WARN_ON_ONCE(irqs_disabled()))
135+
return -EPERM;
136+
137+
if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
138+
if (!cppc_ext_present)
139+
return -EINVAL;
140+
141+
data.reg = FFH_CPPC_SBI_REG(reg->address);
142+
data.val = val;
143+
144+
smp_call_function_single(cpu, sbi_cppc_write, &data, 1);
145+
146+
return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
147+
} else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
148+
data.reg = FFH_CPPC_CSR_NUM(reg->address);
149+
data.val = val;
150+
151+
smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1);
152+
153+
return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
154+
}
155+
156+
return -EINVAL;
157+
}

0 commit comments

Comments
 (0)