File Index
Files and directories
Sign in
FILE

cppc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/acpi/riscv/cppc.c C
  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
 28struct sbi_cppc_data {
 29	u64 val;
 30	u32 reg;
 31	struct sbiret ret;
 32};
 33
 34static bool cppc_ext_present;
 35
 36static 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		cppc_ext_present = true;
 41	} else {
 42		cppc_ext_present = false;
 43	}
 44
 45	return 0;
 46}
 47device_initcall(sbi_cppc_init);
 48
 49static void sbi_cppc_read(void *read_data)
 50{
 51	struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
 52
 53	data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_READ,
 54			      data->reg, 0, 0, 0, 0, 0);
 55}
 56
 57static void sbi_cppc_write(void *write_data)
 58{
 59	struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
 60
 61	data->ret = sbi_ecall(SBI_EXT_CPPC, SBI_CPPC_WRITE,
 62			      data->reg, data->val, 0, 0, 0, 0);
 63}
 64
 65static void cppc_ffh_csr_read(void *read_data)
 66{
 67	struct sbi_cppc_data *data = (struct sbi_cppc_data *)read_data;
 68
 69	switch (data->reg) {
 70	/* Support only TIME CSR for now */
 71	case CSR_TIME:
 72		data->ret.value = csr_read(CSR_TIME);
 73		data->ret.error = 0;
 74		break;
 75	default:
 76		data->ret.error = -EINVAL;
 77		break;
 78	}
 79}
 80
 81static void cppc_ffh_csr_write(void *write_data)
 82{
 83	struct sbi_cppc_data *data = (struct sbi_cppc_data *)write_data;
 84
 85	data->ret.error = -EINVAL;
 86}
 87
 88/*
 89 * Refer to drivers/acpi/cppc_acpi.c for the description of the functions
 90 * below.
 91 */
 92bool cpc_ffh_supported(void)
 93{
 94	return true;
 95}
 96
 97int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
 98{
 99	struct sbi_cppc_data data;
100
101	if (WARN_ON_ONCE(irqs_disabled()))
102		return -EPERM;
103
104	if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
105		if (!cppc_ext_present)
106			return -EINVAL;
107
108		data.reg = FFH_CPPC_SBI_REG(reg->address);
109
110		smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
111
112		*val = data.ret.value;
113
114		return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
115	} else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
116		data.reg = FFH_CPPC_CSR_NUM(reg->address);
117
118		smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
119
120		*val = data.ret.value;
121
122		return data.ret.error;
123	}
124
125	return -EINVAL;
126}
127
128int cpc_write_ffh(int cpu, struct cpc_reg *reg, u64 val)
129{
130	struct sbi_cppc_data data;
131
132	if (WARN_ON_ONCE(irqs_disabled()))
133		return -EPERM;
134
135	if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
136		if (!cppc_ext_present)
137			return -EINVAL;
138
139		data.reg = FFH_CPPC_SBI_REG(reg->address);
140		data.val = val;
141
142		smp_call_function_single(cpu, sbi_cppc_write, &data, 1);
143
144		return (data.ret.error) ? sbi_err_map_linux_errno(data.ret.error) : 0;
145	} else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
146		data.reg = FFH_CPPC_CSR_NUM(reg->address);
147		data.val = val;
148
149		smp_call_function_single(cpu, cppc_ffh_csr_write, &data, 1);
150
151		return data.ret.error;
152	}
153
154	return -EINVAL;
155}
~/ Read-only file preview.