| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- // 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) {
- cppc_ext_present = true;
- } else {
- 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;
- }
- 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;
- }
- return -EINVAL;
- }
|