Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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) }