brintos

brintos / linux-shallow public Read only

0
0
Text · 3.5 KiB · 4cdff38 Raw
158 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 0x4350504313 14/* CPPC interfaces defined in SBI spec */15#define SBI_CPPC_PROBE			0x016#define SBI_CPPC_READ			0x117#define SBI_CPPC_READ_HI		0x218#define SBI_CPPC_WRITE			0x319 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			0x126#define FFH_CPPC_CSR			0x227 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		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}49device_initcall(sbi_cppc_init);50 51static 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 59static 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 67static 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 83static 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 functions92 * below.93 */94bool cpc_ffh_supported(void)95{96	return true;97}98 99int 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 130int 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}158