1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * RCPM(Run Control/Power Management) support
5 * Copyright 2012-2015 Freescale Semiconductor Inc.
7 * Author: Chenhui Zhao <chenhui.zhao@freescale.com>
10 #define pr_fmt(fmt) "%s: " fmt, __func__
12 #include <linux/types.h>
13 #include <linux/errno.h>
14 #include <linux/of_address.h>
15 #include <linux/export.h>
18 #include <linux/fsl/guts.h>
19 #include <asm/cputhreads.h>
20 #include <asm/fsl_pm.h>
23 static struct ccsr_rcpm_v1 __iomem
*rcpm_v1_regs
;
24 static struct ccsr_rcpm_v2 __iomem
*rcpm_v2_regs
;
25 static unsigned int fsl_supported_pm_modes
;
27 static void rcpm_v1_irq_mask(int cpu
)
29 int hw_cpu
= get_hard_smp_processor_id(cpu
);
30 unsigned int mask
= 1 << hw_cpu
;
32 setbits32(&rcpm_v1_regs
->cpmimr
, mask
);
33 setbits32(&rcpm_v1_regs
->cpmcimr
, mask
);
34 setbits32(&rcpm_v1_regs
->cpmmcmr
, mask
);
35 setbits32(&rcpm_v1_regs
->cpmnmimr
, mask
);
38 static void rcpm_v2_irq_mask(int cpu
)
40 int hw_cpu
= get_hard_smp_processor_id(cpu
);
41 unsigned int mask
= 1 << hw_cpu
;
43 setbits32(&rcpm_v2_regs
->tpmimr0
, mask
);
44 setbits32(&rcpm_v2_regs
->tpmcimr0
, mask
);
45 setbits32(&rcpm_v2_regs
->tpmmcmr0
, mask
);
46 setbits32(&rcpm_v2_regs
->tpmnmimr0
, mask
);
49 static void rcpm_v1_irq_unmask(int cpu
)
51 int hw_cpu
= get_hard_smp_processor_id(cpu
);
52 unsigned int mask
= 1 << hw_cpu
;
54 clrbits32(&rcpm_v1_regs
->cpmimr
, mask
);
55 clrbits32(&rcpm_v1_regs
->cpmcimr
, mask
);
56 clrbits32(&rcpm_v1_regs
->cpmmcmr
, mask
);
57 clrbits32(&rcpm_v1_regs
->cpmnmimr
, mask
);
60 static void rcpm_v2_irq_unmask(int cpu
)
62 int hw_cpu
= get_hard_smp_processor_id(cpu
);
63 unsigned int mask
= 1 << hw_cpu
;
65 clrbits32(&rcpm_v2_regs
->tpmimr0
, mask
);
66 clrbits32(&rcpm_v2_regs
->tpmcimr0
, mask
);
67 clrbits32(&rcpm_v2_regs
->tpmmcmr0
, mask
);
68 clrbits32(&rcpm_v2_regs
->tpmnmimr0
, mask
);
71 static void rcpm_v1_set_ip_power(bool enable
, u32 mask
)
74 setbits32(&rcpm_v1_regs
->ippdexpcr
, mask
);
76 clrbits32(&rcpm_v1_regs
->ippdexpcr
, mask
);
79 static void rcpm_v2_set_ip_power(bool enable
, u32 mask
)
82 setbits32(&rcpm_v2_regs
->ippdexpcr
[0], mask
);
84 clrbits32(&rcpm_v2_regs
->ippdexpcr
[0], mask
);
87 static void rcpm_v1_cpu_enter_state(int cpu
, int state
)
89 int hw_cpu
= get_hard_smp_processor_id(cpu
);
90 unsigned int mask
= 1 << hw_cpu
;
94 setbits32(&rcpm_v1_regs
->cdozcr
, mask
);
97 setbits32(&rcpm_v1_regs
->cnapcr
, mask
);
100 pr_warn("Unknown cpu PM state (%d)\n", state
);
105 static void rcpm_v2_cpu_enter_state(int cpu
, int state
)
107 int hw_cpu
= get_hard_smp_processor_id(cpu
);
108 u32 mask
= 1 << cpu_core_index_of_thread(cpu
);
112 /* one bit corresponds to one thread for PH10 of 6500 */
113 setbits32(&rcpm_v2_regs
->tph10setr0
, 1 << hw_cpu
);
116 setbits32(&rcpm_v2_regs
->pcph15setr
, mask
);
119 setbits32(&rcpm_v2_regs
->pcph20setr
, mask
);
122 setbits32(&rcpm_v2_regs
->pcph30setr
, mask
);
125 pr_warn("Unknown cpu PM state (%d)\n", state
);
129 static void rcpm_v1_cpu_die(int cpu
)
131 rcpm_v1_cpu_enter_state(cpu
, E500_PM_PH15
);
135 static void qoriq_disable_thread(int cpu
)
137 int thread
= cpu_thread_in_core(cpu
);
139 book3e_stop_thread(thread
);
143 static void rcpm_v2_cpu_die(int cpu
)
148 if (threads_per_core
== 2) {
149 primary
= cpu_first_thread_sibling(cpu
);
150 if (cpu_is_offline(primary
) && cpu_is_offline(primary
+ 1)) {
151 /* if both threads are offline, put the cpu in PH20 */
152 rcpm_v2_cpu_enter_state(cpu
, E500_PM_PH20
);
154 /* if only one thread is offline, disable the thread */
155 qoriq_disable_thread(cpu
);
160 if (threads_per_core
== 1)
161 rcpm_v2_cpu_enter_state(cpu
, E500_PM_PH20
);
164 static void rcpm_v1_cpu_exit_state(int cpu
, int state
)
166 int hw_cpu
= get_hard_smp_processor_id(cpu
);
167 unsigned int mask
= 1 << hw_cpu
;
171 clrbits32(&rcpm_v1_regs
->cdozcr
, mask
);
174 clrbits32(&rcpm_v1_regs
->cnapcr
, mask
);
177 pr_warn("Unknown cpu PM state (%d)\n", state
);
182 static void rcpm_v1_cpu_up_prepare(int cpu
)
184 rcpm_v1_cpu_exit_state(cpu
, E500_PM_PH15
);
185 rcpm_v1_irq_unmask(cpu
);
188 static void rcpm_v2_cpu_exit_state(int cpu
, int state
)
190 int hw_cpu
= get_hard_smp_processor_id(cpu
);
191 u32 mask
= 1 << cpu_core_index_of_thread(cpu
);
195 setbits32(&rcpm_v2_regs
->tph10clrr0
, 1 << hw_cpu
);
198 setbits32(&rcpm_v2_regs
->pcph15clrr
, mask
);
201 setbits32(&rcpm_v2_regs
->pcph20clrr
, mask
);
204 setbits32(&rcpm_v2_regs
->pcph30clrr
, mask
);
207 pr_warn("Unknown cpu PM state (%d)\n", state
);
211 static void rcpm_v2_cpu_up_prepare(int cpu
)
213 rcpm_v2_cpu_exit_state(cpu
, E500_PM_PH20
);
214 rcpm_v2_irq_unmask(cpu
);
217 static int rcpm_v1_plat_enter_state(int state
)
219 u32
*pmcsr_reg
= &rcpm_v1_regs
->powmgtcsr
;
225 setbits32(pmcsr_reg
, RCPM_POWMGTCSR_SLP
);
227 /* Upon resume, wait for RCPM_POWMGTCSR_SLP bit to be clear. */
228 result
= spin_event_timeout(
229 !(in_be32(pmcsr_reg
) & RCPM_POWMGTCSR_SLP
), 10000, 10);
231 pr_err("timeout waiting for SLP bit to be cleared\n");
236 pr_warn("Unknown platform PM state (%d)", state
);
243 static int rcpm_v2_plat_enter_state(int state
)
245 u32
*pmcsr_reg
= &rcpm_v2_regs
->powmgtcsr
;
251 /* clear previous LPM20 status */
252 setbits32(pmcsr_reg
, RCPM_POWMGTCSR_P_LPM20_ST
);
253 /* enter LPM20 status */
254 setbits32(pmcsr_reg
, RCPM_POWMGTCSR_LPM20_RQ
);
256 /* At this point, the device is in LPM20 status. */
259 result
= spin_event_timeout(
260 !(in_be32(pmcsr_reg
) & RCPM_POWMGTCSR_LPM20_ST
), 10000, 10);
262 pr_err("timeout waiting for LPM20 bit to be cleared\n");
267 pr_warn("Unknown platform PM state (%d)\n", state
);
274 static int rcpm_v1_plat_enter_sleep(void)
276 return rcpm_v1_plat_enter_state(PLAT_PM_SLEEP
);
279 static int rcpm_v2_plat_enter_sleep(void)
281 return rcpm_v2_plat_enter_state(PLAT_PM_LPM20
);
284 static void rcpm_common_freeze_time_base(u32
*tben_reg
, int freeze
)
289 mask
= in_be32(tben_reg
);
290 clrbits32(tben_reg
, mask
);
292 setbits32(tben_reg
, mask
);
295 /* read back to push the previous write */
299 static void rcpm_v1_freeze_time_base(bool freeze
)
301 rcpm_common_freeze_time_base(&rcpm_v1_regs
->ctbenr
, freeze
);
304 static void rcpm_v2_freeze_time_base(bool freeze
)
306 rcpm_common_freeze_time_base(&rcpm_v2_regs
->pctbenr
, freeze
);
309 static unsigned int rcpm_get_pm_modes(void)
311 return fsl_supported_pm_modes
;
314 static const struct fsl_pm_ops qoriq_rcpm_v1_ops
= {
315 .irq_mask
= rcpm_v1_irq_mask
,
316 .irq_unmask
= rcpm_v1_irq_unmask
,
317 .cpu_enter_state
= rcpm_v1_cpu_enter_state
,
318 .cpu_exit_state
= rcpm_v1_cpu_exit_state
,
319 .cpu_up_prepare
= rcpm_v1_cpu_up_prepare
,
320 .cpu_die
= rcpm_v1_cpu_die
,
321 .plat_enter_sleep
= rcpm_v1_plat_enter_sleep
,
322 .set_ip_power
= rcpm_v1_set_ip_power
,
323 .freeze_time_base
= rcpm_v1_freeze_time_base
,
324 .get_pm_modes
= rcpm_get_pm_modes
,
327 static const struct fsl_pm_ops qoriq_rcpm_v2_ops
= {
328 .irq_mask
= rcpm_v2_irq_mask
,
329 .irq_unmask
= rcpm_v2_irq_unmask
,
330 .cpu_enter_state
= rcpm_v2_cpu_enter_state
,
331 .cpu_exit_state
= rcpm_v2_cpu_exit_state
,
332 .cpu_up_prepare
= rcpm_v2_cpu_up_prepare
,
333 .cpu_die
= rcpm_v2_cpu_die
,
334 .plat_enter_sleep
= rcpm_v2_plat_enter_sleep
,
335 .set_ip_power
= rcpm_v2_set_ip_power
,
336 .freeze_time_base
= rcpm_v2_freeze_time_base
,
337 .get_pm_modes
= rcpm_get_pm_modes
,
340 static const struct of_device_id rcpm_matches
[] = {
342 .compatible
= "fsl,qoriq-rcpm-1.0",
343 .data
= &qoriq_rcpm_v1_ops
,
346 .compatible
= "fsl,qoriq-rcpm-2.0",
347 .data
= &qoriq_rcpm_v2_ops
,
350 .compatible
= "fsl,qoriq-rcpm-2.1",
351 .data
= &qoriq_rcpm_v2_ops
,
356 int __init
fsl_rcpm_init(void)
358 struct device_node
*np
;
359 const struct of_device_id
*match
;
362 np
= of_find_matching_node_and_match(NULL
, rcpm_matches
, &match
);
366 base
= of_iomap(np
, 0);
369 pr_err("of_iomap() error.\n");
376 /* support sleep by default */
377 fsl_supported_pm_modes
= FSL_PM_SLEEP
;
379 qoriq_pm_ops
= match
->data
;