root/arch/powerpc/sysdev/fsl_rcpm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rcpm_v1_irq_mask
  2. rcpm_v2_irq_mask
  3. rcpm_v1_irq_unmask
  4. rcpm_v2_irq_unmask
  5. rcpm_v1_set_ip_power
  6. rcpm_v2_set_ip_power
  7. rcpm_v1_cpu_enter_state
  8. rcpm_v2_cpu_enter_state
  9. rcpm_v1_cpu_die
  10. qoriq_disable_thread
  11. rcpm_v2_cpu_die
  12. rcpm_v1_cpu_exit_state
  13. rcpm_v1_cpu_up_prepare
  14. rcpm_v2_cpu_exit_state
  15. rcpm_v2_cpu_up_prepare
  16. rcpm_v1_plat_enter_state
  17. rcpm_v2_plat_enter_state
  18. rcpm_v1_plat_enter_sleep
  19. rcpm_v2_plat_enter_sleep
  20. rcpm_common_freeze_time_base
  21. rcpm_v1_freeze_time_base
  22. rcpm_v2_freeze_time_base
  23. rcpm_get_pm_modes
  24. fsl_rcpm_init

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

/* [<][>][^][v][top][bottom][index][help] */