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 } 82