^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * RCPM(Run Control/Power Management) support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2012-2015 Freescale Semiconductor Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Chenhui Zhao <chenhui.zhao@freescale.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #define pr_fmt(fmt) "%s: " fmt, __func__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/fsl/guts.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/cputhreads.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/fsl_pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static struct ccsr_rcpm_v1 __iomem *rcpm_v1_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static struct ccsr_rcpm_v2 __iomem *rcpm_v2_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static unsigned int fsl_supported_pm_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static void rcpm_v1_irq_mask(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int hw_cpu = get_hard_smp_processor_id(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) unsigned int mask = 1 << hw_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) setbits32(&rcpm_v1_regs->cpmimr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) setbits32(&rcpm_v1_regs->cpmcimr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) setbits32(&rcpm_v1_regs->cpmmcmr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) setbits32(&rcpm_v1_regs->cpmnmimr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static void rcpm_v2_irq_mask(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int hw_cpu = get_hard_smp_processor_id(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned int mask = 1 << hw_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) setbits32(&rcpm_v2_regs->tpmimr0, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) setbits32(&rcpm_v2_regs->tpmcimr0, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) setbits32(&rcpm_v2_regs->tpmmcmr0, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) setbits32(&rcpm_v2_regs->tpmnmimr0, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static void rcpm_v1_irq_unmask(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int hw_cpu = get_hard_smp_processor_id(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned int mask = 1 << hw_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) clrbits32(&rcpm_v1_regs->cpmimr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) clrbits32(&rcpm_v1_regs->cpmcimr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) clrbits32(&rcpm_v1_regs->cpmmcmr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) clrbits32(&rcpm_v1_regs->cpmnmimr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static void rcpm_v2_irq_unmask(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) int hw_cpu = get_hard_smp_processor_id(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned int mask = 1 << hw_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) clrbits32(&rcpm_v2_regs->tpmimr0, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) clrbits32(&rcpm_v2_regs->tpmcimr0, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) clrbits32(&rcpm_v2_regs->tpmmcmr0, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) clrbits32(&rcpm_v2_regs->tpmnmimr0, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static void rcpm_v1_set_ip_power(bool enable, u32 mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) setbits32(&rcpm_v1_regs->ippdexpcr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) clrbits32(&rcpm_v1_regs->ippdexpcr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static void rcpm_v2_set_ip_power(bool enable, u32 mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) setbits32(&rcpm_v2_regs->ippdexpcr[0], mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) clrbits32(&rcpm_v2_regs->ippdexpcr[0], mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static void rcpm_v1_cpu_enter_state(int cpu, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int hw_cpu = get_hard_smp_processor_id(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) unsigned int mask = 1 << hw_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) switch (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) case E500_PM_PH10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) setbits32(&rcpm_v1_regs->cdozcr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case E500_PM_PH15:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) setbits32(&rcpm_v1_regs->cnapcr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) pr_warn("Unknown cpu PM state (%d)\n", state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static void rcpm_v2_cpu_enter_state(int cpu, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) int hw_cpu = get_hard_smp_processor_id(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) u32 mask = 1 << cpu_core_index_of_thread(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) switch (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) case E500_PM_PH10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /* one bit corresponds to one thread for PH10 of 6500 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) setbits32(&rcpm_v2_regs->tph10setr0, 1 << hw_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) case E500_PM_PH15:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) setbits32(&rcpm_v2_regs->pcph15setr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) case E500_PM_PH20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) setbits32(&rcpm_v2_regs->pcph20setr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) case E500_PM_PH30:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) setbits32(&rcpm_v2_regs->pcph30setr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) pr_warn("Unknown cpu PM state (%d)\n", state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static void rcpm_v1_cpu_die(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) rcpm_v1_cpu_enter_state(cpu, E500_PM_PH15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static void qoriq_disable_thread(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) int thread = cpu_thread_in_core(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) book3e_stop_thread(thread);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static void rcpm_v2_cpu_die(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int primary;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (threads_per_core == 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) primary = cpu_first_thread_sibling(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (cpu_is_offline(primary) && cpu_is_offline(primary + 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* if both threads are offline, put the cpu in PH20 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) rcpm_v2_cpu_enter_state(cpu, E500_PM_PH20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* if only one thread is offline, disable the thread */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) qoriq_disable_thread(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (threads_per_core == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) rcpm_v2_cpu_enter_state(cpu, E500_PM_PH20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static void rcpm_v1_cpu_exit_state(int cpu, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) int hw_cpu = get_hard_smp_processor_id(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) unsigned int mask = 1 << hw_cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) switch (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) case E500_PM_PH10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) clrbits32(&rcpm_v1_regs->cdozcr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) case E500_PM_PH15:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) clrbits32(&rcpm_v1_regs->cnapcr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) pr_warn("Unknown cpu PM state (%d)\n", state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static void rcpm_v1_cpu_up_prepare(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) rcpm_v1_cpu_exit_state(cpu, E500_PM_PH15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) rcpm_v1_irq_unmask(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static void rcpm_v2_cpu_exit_state(int cpu, int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) int hw_cpu = get_hard_smp_processor_id(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) u32 mask = 1 << cpu_core_index_of_thread(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) switch (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) case E500_PM_PH10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) setbits32(&rcpm_v2_regs->tph10clrr0, 1 << hw_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) case E500_PM_PH15:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) setbits32(&rcpm_v2_regs->pcph15clrr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) case E500_PM_PH20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) setbits32(&rcpm_v2_regs->pcph20clrr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case E500_PM_PH30:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) setbits32(&rcpm_v2_regs->pcph30clrr, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) pr_warn("Unknown cpu PM state (%d)\n", state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static void rcpm_v2_cpu_up_prepare(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) rcpm_v2_cpu_exit_state(cpu, E500_PM_PH20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) rcpm_v2_irq_unmask(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static int rcpm_v1_plat_enter_state(int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) u32 *pmcsr_reg = &rcpm_v1_regs->powmgtcsr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) switch (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) case PLAT_PM_SLEEP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) setbits32(pmcsr_reg, RCPM_POWMGTCSR_SLP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /* Upon resume, wait for RCPM_POWMGTCSR_SLP bit to be clear. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) result = spin_event_timeout(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_SLP), 10000, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (!result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) pr_err("timeout waiting for SLP bit to be cleared\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) ret = -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) pr_warn("Unknown platform PM state (%d)", state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) static int rcpm_v2_plat_enter_state(int state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) u32 *pmcsr_reg = &rcpm_v2_regs->powmgtcsr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) switch (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) case PLAT_PM_LPM20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /* clear previous LPM20 status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) setbits32(pmcsr_reg, RCPM_POWMGTCSR_P_LPM20_ST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* enter LPM20 status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) setbits32(pmcsr_reg, RCPM_POWMGTCSR_LPM20_RQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /* At this point, the device is in LPM20 status. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* resume ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) result = spin_event_timeout(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_LPM20_ST), 10000, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (!result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) pr_err("timeout waiting for LPM20 bit to be cleared\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) ret = -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) pr_warn("Unknown platform PM state (%d)\n", state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) static int rcpm_v1_plat_enter_sleep(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return rcpm_v1_plat_enter_state(PLAT_PM_SLEEP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static int rcpm_v2_plat_enter_sleep(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return rcpm_v2_plat_enter_state(PLAT_PM_LPM20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static void rcpm_common_freeze_time_base(u32 *tben_reg, int freeze)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) static u32 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (freeze) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) mask = in_be32(tben_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) clrbits32(tben_reg, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) setbits32(tben_reg, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) /* read back to push the previous write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) in_be32(tben_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static void rcpm_v1_freeze_time_base(bool freeze)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) rcpm_common_freeze_time_base(&rcpm_v1_regs->ctbenr, freeze);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static void rcpm_v2_freeze_time_base(bool freeze)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) rcpm_common_freeze_time_base(&rcpm_v2_regs->pctbenr, freeze);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static unsigned int rcpm_get_pm_modes(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return fsl_supported_pm_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static const struct fsl_pm_ops qoriq_rcpm_v1_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) .irq_mask = rcpm_v1_irq_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .irq_unmask = rcpm_v1_irq_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .cpu_enter_state = rcpm_v1_cpu_enter_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .cpu_exit_state = rcpm_v1_cpu_exit_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .cpu_up_prepare = rcpm_v1_cpu_up_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .cpu_die = rcpm_v1_cpu_die,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .plat_enter_sleep = rcpm_v1_plat_enter_sleep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .set_ip_power = rcpm_v1_set_ip_power,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .freeze_time_base = rcpm_v1_freeze_time_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .get_pm_modes = rcpm_get_pm_modes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static const struct fsl_pm_ops qoriq_rcpm_v2_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .irq_mask = rcpm_v2_irq_mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) .irq_unmask = rcpm_v2_irq_unmask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) .cpu_enter_state = rcpm_v2_cpu_enter_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) .cpu_exit_state = rcpm_v2_cpu_exit_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .cpu_up_prepare = rcpm_v2_cpu_up_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) .cpu_die = rcpm_v2_cpu_die,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .plat_enter_sleep = rcpm_v2_plat_enter_sleep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) .set_ip_power = rcpm_v2_set_ip_power,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) .freeze_time_base = rcpm_v2_freeze_time_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) .get_pm_modes = rcpm_get_pm_modes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static const struct of_device_id rcpm_matches[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) .compatible = "fsl,qoriq-rcpm-1.0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) .data = &qoriq_rcpm_v1_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) .compatible = "fsl,qoriq-rcpm-2.0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) .data = &qoriq_rcpm_v2_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) .compatible = "fsl,qoriq-rcpm-2.1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) .data = &qoriq_rcpm_v2_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) int __init fsl_rcpm_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) const struct of_device_id *match;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) np = of_find_matching_node_and_match(NULL, rcpm_matches, &match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) base = of_iomap(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (!base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) pr_err("of_iomap() error.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) rcpm_v1_regs = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) rcpm_v2_regs = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) /* support sleep by default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) fsl_supported_pm_modes = FSL_PM_SLEEP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) qoriq_pm_ops = match->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }