Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / acpi / riscv / cppc.c
blob4cdff387deff6cf9da1d80dc0411af3b5406a79f
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Implement CPPC FFH helper routines for RISC-V.
5 * Copyright (C) 2024 Ventana Micro Systems Inc.
6 */
8 #include <acpi/cppc_acpi.h>
9 #include <asm/csr.h>
10 #include <asm/sbi.h>
12 #define SBI_EXT_CPPC 0x43505043
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
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))
25 #define FFH_CPPC_SBI 0x1
26 #define FFH_CPPC_CSR 0x2
28 struct sbi_cppc_data {
29 u64 val;
30 u32 reg;
31 struct sbiret ret;
34 static bool cppc_ext_present;
36 static int __init sbi_cppc_init(void)
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;
47 return 0;
49 device_initcall(sbi_cppc_init);
51 static void sbi_cppc_read(void *read_data)
53 struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
55 data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_READ,
56 data->reg, 0, 0, 0, 0, 0);
59 static void sbi_cppc_write(void *write_data)
61 struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
63 data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_WRITE,
64 data->reg, data->val, 0, 0, 0, 0);
67 static void cppc_ffh_csr_read(void *read_data)
69 struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
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;
83 static void cppc_ffh_csr_write(void *write_data)
85 struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
87 data->ret.error = -EINVAL;
91 * Refer to drivers/acpi/cppc_acpi.c for the description of the functions
92 * below.
94 bool cpc_ffh_supported(void)
96 return true;
99 int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
101 struct sbi_cppc_data data;
103 if (WARN_ON_ONCE(irqs_disabled()))
104 return -EPERM;
106 if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
107 if (!cppc_ext_present)
108 return -EINVAL;
110 data.reg = FFH_CPPC_SBI_REG(reg->address);
112 smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
114 *val = data.ret.value;
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);
120 smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
122 *val = data.ret.value;
124 return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
127 return -EINVAL;
130 int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val)
132 struct sbi_cppc_data data;
134 if (WARN_ON_ONCE(irqs_disabled()))
135 return -EPERM;
137 if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
138 if (!cppc_ext_present)
139 return -EINVAL;
141 data.reg = FFH_CPPC_SBI_REG(reg->address);
142 data.val = val;
144 smp_call_function_single(cpu, sbi_cppc_write, &data, 1);
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;
151 smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1);
153 return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
156 return -EINVAL;