Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI: RISC-V: Add LPI driver

Enable Low Power Idle (LPI) based cpuidle driver for RISC-V platforms.
It depends on SBI HSM calls for idle state transitions.

Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://lore.kernel.org/r/20240118062930.245937-3-sunilvl@ventanamicro.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>

authored by

Sunil V L and committed by
Palmer Dabbelt
4877fc92 6649182a

+83 -1
+2 -1
drivers/acpi/riscv/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 - obj-y += rhct.o 2 + obj-y += rhct.o 3 + obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
+81
drivers/acpi/riscv/cpuidle.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2024, Ventana Micro Systems Inc 4 + * Author: Sunil V L <sunilvl@ventanamicro.com> 5 + * 6 + */ 7 + 8 + #include <linux/acpi.h> 9 + #include <acpi/processor.h> 10 + #include <linux/cpu_pm.h> 11 + #include <linux/cpuidle.h> 12 + #include <linux/suspend.h> 13 + #include <asm/cpuidle.h> 14 + #include <asm/sbi.h> 15 + #include <asm/suspend.h> 16 + 17 + #define RISCV_FFH_LPI_TYPE_MASK GENMASK_ULL(63, 60) 18 + #define RISCV_FFH_LPI_RSVD_MASK GENMASK_ULL(59, 32) 19 + 20 + #define RISCV_FFH_LPI_TYPE_SBI BIT_ULL(60) 21 + 22 + static int acpi_cpu_init_idle(unsigned int cpu) 23 + { 24 + int i; 25 + struct acpi_lpi_state *lpi; 26 + struct acpi_processor *pr = per_cpu(processors, cpu); 27 + 28 + if (unlikely(!pr || !pr->flags.has_lpi)) 29 + return -EINVAL; 30 + 31 + if (!riscv_sbi_hsm_is_supported()) 32 + return -ENODEV; 33 + 34 + if (pr->power.count <= 1) 35 + return -ENODEV; 36 + 37 + for (i = 1; i < pr->power.count; i++) { 38 + u32 state; 39 + 40 + lpi = &pr->power.lpi_states[i]; 41 + 42 + /* 43 + * Validate Entry Method as per FFH spec. 44 + * bits[63:60] should be 0x1 45 + * bits[59:32] should be 0x0 46 + * bits[31:0] represent a SBI power_state 47 + */ 48 + if (((lpi->address & RISCV_FFH_LPI_TYPE_MASK) != RISCV_FFH_LPI_TYPE_SBI) || 49 + (lpi->address & RISCV_FFH_LPI_RSVD_MASK)) { 50 + pr_warn("Invalid LPI entry method %#llx\n", lpi->address); 51 + return -EINVAL; 52 + } 53 + 54 + state = lpi->address; 55 + if (!riscv_sbi_suspend_state_is_valid(state)) { 56 + pr_warn("Invalid SBI power state %#x\n", state); 57 + return -EINVAL; 58 + } 59 + } 60 + 61 + return 0; 62 + } 63 + 64 + int acpi_processor_ffh_lpi_probe(unsigned int cpu) 65 + { 66 + return acpi_cpu_init_idle(cpu); 67 + } 68 + 69 + int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi) 70 + { 71 + u32 state = lpi->address; 72 + 73 + if (state & SBI_HSM_SUSP_NON_RET_BIT) 74 + return CPU_PM_CPU_IDLE_ENTER_PARAM(riscv_sbi_hart_suspend, 75 + lpi->index, 76 + state); 77 + else 78 + return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(riscv_sbi_hart_suspend, 79 + lpi->index, 80 + state); 81 + }