0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <linux/kernel.h>
0037 #include <linux/io.h>
0038 #include <linux/errno.h>
0039 #include <linux/linkage.h>
0040 #include <linux/smp.h>
0041
0042 #include <asm/cacheflush.h>
0043 #include <asm/tlbflush.h>
0044 #include <asm/smp_scu.h>
0045 #include <asm/suspend.h>
0046 #include <asm/virt.h>
0047 #include <asm/hardware/cache-l2x0.h>
0048
0049 #include "soc.h"
0050 #include "common.h"
0051 #include "omap44xx.h"
0052 #include "omap4-sar-layout.h"
0053 #include "pm.h"
0054 #include "prcm_mpu44xx.h"
0055 #include "prcm_mpu54xx.h"
0056 #include "prminst44xx.h"
0057 #include "prcm44xx.h"
0058 #include "prm44xx.h"
0059 #include "prm-regbits-44xx.h"
0060
0061 static void __iomem *sar_base;
0062 static u32 old_cpu1_ns_pa_addr;
0063
0064 #if defined(CONFIG_PM) && defined(CONFIG_SMP)
0065
0066 struct omap4_cpu_pm_info {
0067 struct powerdomain *pwrdm;
0068 void __iomem *scu_sar_addr;
0069 void __iomem *wkup_sar_addr;
0070 void __iomem *l2x0_sar_addr;
0071 };
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 struct cpu_pm_ops {
0084 int (*finish_suspend)(unsigned long cpu_state);
0085 void (*resume)(void);
0086 void (*scu_prepare)(unsigned int cpu_id, unsigned int cpu_state);
0087 void (*hotplug_restart)(void);
0088 };
0089
0090 static DEFINE_PER_CPU(struct omap4_cpu_pm_info, omap4_pm_info);
0091 static struct powerdomain *mpuss_pd;
0092 static u32 cpu_context_offset;
0093
0094 static int default_finish_suspend(unsigned long cpu_state)
0095 {
0096 omap_do_wfi();
0097 return 0;
0098 }
0099
0100 static void dummy_cpu_resume(void)
0101 {}
0102
0103 static void dummy_scu_prepare(unsigned int cpu_id, unsigned int cpu_state)
0104 {}
0105
0106 static struct cpu_pm_ops omap_pm_ops = {
0107 .finish_suspend = default_finish_suspend,
0108 .resume = dummy_cpu_resume,
0109 .scu_prepare = dummy_scu_prepare,
0110 .hotplug_restart = dummy_cpu_resume,
0111 };
0112
0113
0114
0115
0116
0117 static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 addr)
0118 {
0119 struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
0120
0121 if (pm_info->wkup_sar_addr)
0122 writel_relaxed(addr, pm_info->wkup_sar_addr);
0123 }
0124
0125
0126
0127
0128 static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state)
0129 {
0130 struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
0131 u32 scu_pwr_st;
0132
0133 switch (cpu_state) {
0134 case PWRDM_POWER_RET:
0135 scu_pwr_st = SCU_PM_DORMANT;
0136 break;
0137 case PWRDM_POWER_OFF:
0138 scu_pwr_st = SCU_PM_POWEROFF;
0139 break;
0140 case PWRDM_POWER_ON:
0141 case PWRDM_POWER_INACTIVE:
0142 default:
0143 scu_pwr_st = SCU_PM_NORMAL;
0144 break;
0145 }
0146
0147 if (pm_info->scu_sar_addr)
0148 writel_relaxed(scu_pwr_st, pm_info->scu_sar_addr);
0149 }
0150
0151
0152 static inline void mpuss_clear_prev_logic_pwrst(void)
0153 {
0154 u32 reg;
0155
0156 reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
0157 OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
0158 omap4_prminst_write_inst_reg(reg, OMAP4430_PRM_PARTITION,
0159 OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
0160 }
0161
0162 static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id)
0163 {
0164 u32 reg;
0165
0166 if (cpu_id) {
0167 reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU1_INST,
0168 cpu_context_offset);
0169 omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU1_INST,
0170 cpu_context_offset);
0171 } else {
0172 reg = omap4_prcm_mpu_read_inst_reg(OMAP4430_PRCM_MPU_CPU0_INST,
0173 cpu_context_offset);
0174 omap4_prcm_mpu_write_inst_reg(reg, OMAP4430_PRCM_MPU_CPU0_INST,
0175 cpu_context_offset);
0176 }
0177 }
0178
0179
0180
0181
0182 static void l2x0_pwrst_prepare(unsigned int cpu_id, unsigned int save_state)
0183 {
0184 struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id);
0185
0186 if (pm_info->l2x0_sar_addr)
0187 writel_relaxed(save_state, pm_info->l2x0_sar_addr);
0188 }
0189
0190
0191
0192
0193
0194 #ifdef CONFIG_CACHE_L2X0
0195 static void __init save_l2x0_context(void)
0196 {
0197 void __iomem *l2x0_base = omap4_get_l2cache_base();
0198
0199 if (l2x0_base && sar_base) {
0200 writel_relaxed(l2x0_saved_regs.aux_ctrl,
0201 sar_base + L2X0_AUXCTRL_OFFSET);
0202 writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
0203 sar_base + L2X0_PREFETCH_CTRL_OFFSET);
0204 }
0205 }
0206 #else
0207 static void __init save_l2x0_context(void)
0208 {}
0209 #endif
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225 int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
0226 {
0227 struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
0228 unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET;
0229
0230 if (omap_rev() == OMAP4430_REV_ES1_0)
0231 return -ENXIO;
0232
0233 switch (power_state) {
0234 case PWRDM_POWER_ON:
0235 case PWRDM_POWER_INACTIVE:
0236 save_state = 0;
0237 break;
0238 case PWRDM_POWER_OFF:
0239 cpu_logic_state = PWRDM_POWER_OFF;
0240 save_state = 1;
0241 break;
0242 case PWRDM_POWER_RET:
0243 if (IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE))
0244 save_state = 0;
0245 break;
0246 default:
0247
0248
0249
0250
0251
0252
0253 WARN_ON(1);
0254 return -ENXIO;
0255 }
0256
0257 pwrdm_pre_transition(NULL);
0258
0259
0260
0261
0262
0263 mpuss_clear_prev_logic_pwrst();
0264 if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
0265 (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
0266 save_state = 2;
0267
0268 cpu_clear_prev_logic_pwrst(cpu);
0269 pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
0270 pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state);
0271 set_cpu_wakeup_addr(cpu, __pa_symbol(omap_pm_ops.resume));
0272 omap_pm_ops.scu_prepare(cpu, power_state);
0273 l2x0_pwrst_prepare(cpu, save_state);
0274
0275
0276
0277
0278 if (save_state)
0279 cpu_suspend(save_state, omap_pm_ops.finish_suspend);
0280 else
0281 omap_pm_ops.finish_suspend(save_state);
0282
0283 if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD) && cpu)
0284 gic_dist_enable();
0285
0286
0287
0288
0289
0290
0291
0292
0293 pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
0294
0295 pwrdm_post_transition(NULL);
0296
0297 return 0;
0298 }
0299
0300
0301
0302
0303
0304
0305 int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state)
0306 {
0307 struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
0308 unsigned int cpu_state = 0;
0309
0310 if (omap_rev() == OMAP4430_REV_ES1_0)
0311 return -ENXIO;
0312
0313
0314 power_state = pwrdm_get_valid_lp_state(pm_info->pwrdm,
0315 false, power_state);
0316
0317 if (power_state == PWRDM_POWER_OFF)
0318 cpu_state = 1;
0319
0320 pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
0321 pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
0322 set_cpu_wakeup_addr(cpu, __pa_symbol(omap_pm_ops.hotplug_restart));
0323 omap_pm_ops.scu_prepare(cpu, power_state);
0324
0325
0326
0327
0328
0329
0330 omap_pm_ops.finish_suspend(cpu_state);
0331
0332 pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
0333 return 0;
0334 }
0335
0336
0337
0338
0339
0340 static void enable_mercury_retention_mode(void)
0341 {
0342 u32 reg;
0343
0344 reg = omap4_prcm_mpu_read_inst_reg(OMAP54XX_PRCM_MPU_DEVICE_INST,
0345 OMAP54XX_PRCM_MPU_PRM_PSCON_COUNT_OFFSET);
0346
0347 reg |= BIT(24) | BIT(25);
0348 omap4_prcm_mpu_write_inst_reg(reg, OMAP54XX_PRCM_MPU_DEVICE_INST,
0349 OMAP54XX_PRCM_MPU_PRM_PSCON_COUNT_OFFSET);
0350 }
0351
0352
0353
0354
0355 int __init omap4_mpuss_init(void)
0356 {
0357 struct omap4_cpu_pm_info *pm_info;
0358
0359 if (omap_rev() == OMAP4430_REV_ES1_0) {
0360 WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
0361 return -ENODEV;
0362 }
0363
0364
0365 pm_info = &per_cpu(omap4_pm_info, 0x0);
0366 if (sar_base) {
0367 pm_info->scu_sar_addr = sar_base + SCU_OFFSET0;
0368 if (cpu_is_omap44xx())
0369 pm_info->wkup_sar_addr = sar_base +
0370 CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
0371 else
0372 pm_info->wkup_sar_addr = sar_base +
0373 OMAP5_CPU0_WAKEUP_NS_PA_ADDR_OFFSET;
0374 pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET0;
0375 }
0376 pm_info->pwrdm = pwrdm_lookup("cpu0_pwrdm");
0377 if (!pm_info->pwrdm) {
0378 pr_err("Lookup failed for CPU0 pwrdm\n");
0379 return -ENODEV;
0380 }
0381
0382
0383 pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
0384 cpu_clear_prev_logic_pwrst(0);
0385
0386
0387 pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
0388
0389 pm_info = &per_cpu(omap4_pm_info, 0x1);
0390 if (sar_base) {
0391 pm_info->scu_sar_addr = sar_base + SCU_OFFSET1;
0392 if (cpu_is_omap44xx())
0393 pm_info->wkup_sar_addr = sar_base +
0394 CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
0395 else
0396 pm_info->wkup_sar_addr = sar_base +
0397 OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
0398 pm_info->l2x0_sar_addr = sar_base + L2X0_SAVE_OFFSET1;
0399 }
0400
0401 pm_info->pwrdm = pwrdm_lookup("cpu1_pwrdm");
0402 if (!pm_info->pwrdm) {
0403 pr_err("Lookup failed for CPU1 pwrdm\n");
0404 return -ENODEV;
0405 }
0406
0407
0408 pwrdm_clear_all_prev_pwrst(pm_info->pwrdm);
0409 cpu_clear_prev_logic_pwrst(1);
0410
0411
0412 pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON);
0413
0414 mpuss_pd = pwrdm_lookup("mpu_pwrdm");
0415 if (!mpuss_pd) {
0416 pr_err("Failed to lookup MPUSS power domain\n");
0417 return -ENODEV;
0418 }
0419 pwrdm_clear_all_prev_pwrst(mpuss_pd);
0420 mpuss_clear_prev_logic_pwrst();
0421
0422 if (sar_base) {
0423
0424 writel_relaxed((omap_type() != OMAP2_DEVICE_TYPE_GP) ? 1 : 0,
0425 sar_base + OMAP_TYPE_OFFSET);
0426 save_l2x0_context();
0427 }
0428
0429 if (cpu_is_omap44xx()) {
0430 omap_pm_ops.finish_suspend = omap4_finish_suspend;
0431 omap_pm_ops.resume = omap4_cpu_resume;
0432 omap_pm_ops.scu_prepare = scu_pwrst_prepare;
0433 omap_pm_ops.hotplug_restart = omap4_secondary_startup;
0434 cpu_context_offset = OMAP4_RM_CPU0_CPU0_CONTEXT_OFFSET;
0435 } else if (soc_is_omap54xx() || soc_is_dra7xx()) {
0436 cpu_context_offset = OMAP54XX_RM_CPU0_CPU0_CONTEXT_OFFSET;
0437 enable_mercury_retention_mode();
0438 }
0439
0440 if (cpu_is_omap446x())
0441 omap_pm_ops.hotplug_restart = omap4460_secondary_startup;
0442
0443 return 0;
0444 }
0445
0446 #endif
0447
0448 u32 omap4_get_cpu1_ns_pa_addr(void)
0449 {
0450 return old_cpu1_ns_pa_addr;
0451 }
0452
0453
0454
0455
0456
0457
0458
0459 void __init omap4_mpuss_early_init(void)
0460 {
0461 unsigned long startup_pa;
0462 void __iomem *ns_pa_addr;
0463
0464 if (!(soc_is_omap44xx() || soc_is_omap54xx()))
0465 return;
0466
0467 sar_base = omap4_get_sar_ram_base();
0468
0469
0470 if (soc_is_omap44xx())
0471 ns_pa_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
0472 else
0473 ns_pa_addr = sar_base + OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET;
0474 old_cpu1_ns_pa_addr = readl_relaxed(ns_pa_addr);
0475
0476 if (soc_is_omap443x())
0477 startup_pa = __pa_symbol(omap4_secondary_startup);
0478 else if (soc_is_omap446x())
0479 startup_pa = __pa_symbol(omap4460_secondary_startup);
0480 else if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE)
0481 startup_pa = __pa_symbol(omap5_secondary_hyp_startup);
0482 else
0483 startup_pa = __pa_symbol(omap5_secondary_startup);
0484
0485 if (soc_is_omap44xx())
0486 writel_relaxed(startup_pa, sar_base +
0487 CPU1_WAKEUP_NS_PA_ADDR_OFFSET);
0488 else
0489 writel_relaxed(startup_pa, sar_base +
0490 OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET);
0491 }