0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #define pr_fmt(fmt) "tegra-cpuidle: " fmt
0016
0017 #include <linux/atomic.h>
0018 #include <linux/cpuidle.h>
0019 #include <linux/cpumask.h>
0020 #include <linux/cpu_pm.h>
0021 #include <linux/delay.h>
0022 #include <linux/errno.h>
0023 #include <linux/platform_device.h>
0024 #include <linux/types.h>
0025
0026 #include <linux/clk/tegra.h>
0027 #include <linux/firmware/trusted_foundations.h>
0028
0029 #include <soc/tegra/cpuidle.h>
0030 #include <soc/tegra/flowctrl.h>
0031 #include <soc/tegra/fuse.h>
0032 #include <soc/tegra/irq.h>
0033 #include <soc/tegra/pm.h>
0034 #include <soc/tegra/pmc.h>
0035
0036 #include <asm/cpuidle.h>
0037 #include <asm/firmware.h>
0038 #include <asm/smp_plat.h>
0039 #include <asm/suspend.h>
0040
0041 enum tegra_state {
0042 TEGRA_C1,
0043 TEGRA_C7,
0044 TEGRA_CC6,
0045 TEGRA_STATE_COUNT,
0046 };
0047
0048 static atomic_t tegra_idle_barrier;
0049 static atomic_t tegra_abort_flag;
0050
0051 static void tegra_cpuidle_report_cpus_state(void)
0052 {
0053 unsigned long cpu, lcpu, csr;
0054
0055 for_each_cpu(lcpu, cpu_possible_mask) {
0056 cpu = cpu_logical_map(lcpu);
0057 csr = flowctrl_read_cpu_csr(cpu);
0058
0059 pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n",
0060 cpu, cpu_online(lcpu), csr);
0061 }
0062 }
0063
0064 static int tegra_cpuidle_wait_for_secondary_cpus_parking(void)
0065 {
0066 unsigned int retries = 3;
0067
0068 while (retries--) {
0069 unsigned int delay_us = 10;
0070 unsigned int timeout_us = 500 * 1000 / delay_us;
0071
0072
0073
0074
0075
0076
0077
0078
0079 do {
0080 if (tegra_cpu_rail_off_ready())
0081 return 0;
0082
0083 udelay(delay_us);
0084
0085 } while (timeout_us--);
0086
0087 pr_err("secondary CPU taking too long to park\n");
0088
0089 tegra_cpuidle_report_cpus_state();
0090 }
0091
0092 pr_err("timed out waiting secondaries to park\n");
0093
0094 return -ETIMEDOUT;
0095 }
0096
0097 static void tegra_cpuidle_unpark_secondary_cpus(void)
0098 {
0099 unsigned int cpu, lcpu;
0100
0101 for_each_cpu(lcpu, cpu_online_mask) {
0102 cpu = cpu_logical_map(lcpu);
0103
0104 if (cpu > 0) {
0105 tegra_enable_cpu_clock(cpu);
0106 tegra_cpu_out_of_reset(cpu);
0107 flowctrl_write_cpu_halt(cpu, 0);
0108 }
0109 }
0110 }
0111
0112 static int tegra_cpuidle_cc6_enter(unsigned int cpu)
0113 {
0114 int ret;
0115
0116 if (cpu > 0) {
0117 ret = cpu_suspend(cpu, tegra_pm_park_secondary_cpu);
0118 } else {
0119 ret = tegra_cpuidle_wait_for_secondary_cpus_parking();
0120 if (!ret)
0121 ret = tegra_pm_enter_lp2();
0122
0123 tegra_cpuidle_unpark_secondary_cpus();
0124 }
0125
0126 return ret;
0127 }
0128
0129 static int tegra_cpuidle_c7_enter(void)
0130 {
0131 int err;
0132
0133 err = call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2);
0134 if (err && err != -ENOSYS)
0135 return err;
0136
0137 return cpu_suspend(0, tegra30_pm_secondary_cpu_suspend);
0138 }
0139
0140 static int tegra_cpuidle_coupled_barrier(struct cpuidle_device *dev)
0141 {
0142 if (tegra_pending_sgi()) {
0143
0144
0145
0146
0147
0148
0149 atomic_set(&tegra_abort_flag, 1);
0150 }
0151
0152 cpuidle_coupled_parallel_barrier(dev, &tegra_idle_barrier);
0153
0154 if (atomic_read(&tegra_abort_flag)) {
0155 cpuidle_coupled_parallel_barrier(dev, &tegra_idle_barrier);
0156 atomic_set(&tegra_abort_flag, 0);
0157 return -EINTR;
0158 }
0159
0160 return 0;
0161 }
0162
0163 static int tegra_cpuidle_state_enter(struct cpuidle_device *dev,
0164 int index, unsigned int cpu)
0165 {
0166 int err;
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176 if (index == TEGRA_CC6) {
0177 err = tegra_cpuidle_coupled_barrier(dev);
0178 if (err)
0179 return err;
0180 }
0181
0182 local_fiq_disable();
0183 RCU_NONIDLE(tegra_pm_set_cpu_in_lp2());
0184 cpu_pm_enter();
0185
0186 switch (index) {
0187 case TEGRA_C7:
0188 err = tegra_cpuidle_c7_enter();
0189 break;
0190
0191 case TEGRA_CC6:
0192 err = tegra_cpuidle_cc6_enter(cpu);
0193 break;
0194
0195 default:
0196 err = -EINVAL;
0197 break;
0198 }
0199
0200 cpu_pm_exit();
0201 RCU_NONIDLE(tegra_pm_clear_cpu_in_lp2());
0202 local_fiq_enable();
0203
0204 return err ?: index;
0205 }
0206
0207 static int tegra_cpuidle_adjust_state_index(int index, unsigned int cpu)
0208 {
0209
0210
0211
0212
0213 if (cpu > 0 || index != TEGRA_C7 || tegra_get_chip_id() != TEGRA30)
0214 return index;
0215
0216
0217 if (!IS_ENABLED(CONFIG_PM_SLEEP) || num_online_cpus() > 1)
0218 index = TEGRA_C1;
0219 else
0220 index = TEGRA_CC6;
0221
0222 return index;
0223 }
0224
0225 static int tegra_cpuidle_enter(struct cpuidle_device *dev,
0226 struct cpuidle_driver *drv,
0227 int index)
0228 {
0229 unsigned int cpu = cpu_logical_map(dev->cpu);
0230 int ret;
0231
0232 index = tegra_cpuidle_adjust_state_index(index, cpu);
0233 if (dev->states_usage[index].disable)
0234 return -1;
0235
0236 if (index == TEGRA_C1)
0237 ret = arm_cpuidle_simple_enter(dev, drv, index);
0238 else
0239 ret = tegra_cpuidle_state_enter(dev, index, cpu);
0240
0241 if (ret < 0) {
0242 if (ret != -EINTR || index != TEGRA_CC6)
0243 pr_err_once("failed to enter state %d err: %d\n",
0244 index, ret);
0245 index = -1;
0246 } else {
0247 index = ret;
0248 }
0249
0250 return index;
0251 }
0252
0253 static int tegra114_enter_s2idle(struct cpuidle_device *dev,
0254 struct cpuidle_driver *drv,
0255 int index)
0256 {
0257 tegra_cpuidle_enter(dev, drv, index);
0258
0259 return 0;
0260 }
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279 static struct cpuidle_driver tegra_idle_driver = {
0280 .name = "tegra_idle",
0281 .states = {
0282 [TEGRA_C1] = ARM_CPUIDLE_WFI_STATE_PWR(600),
0283 [TEGRA_C7] = {
0284 .enter = tegra_cpuidle_enter,
0285 .exit_latency = 2000,
0286 .target_residency = 2200,
0287 .power_usage = 100,
0288 .flags = CPUIDLE_FLAG_TIMER_STOP,
0289 .name = "C7",
0290 .desc = "CPU core powered off",
0291 },
0292 [TEGRA_CC6] = {
0293 .enter = tegra_cpuidle_enter,
0294 .exit_latency = 5000,
0295 .target_residency = 10000,
0296 .power_usage = 0,
0297 .flags = CPUIDLE_FLAG_TIMER_STOP |
0298 CPUIDLE_FLAG_COUPLED,
0299 .name = "CC6",
0300 .desc = "CPU cluster powered off",
0301 },
0302 },
0303 .state_count = TEGRA_STATE_COUNT,
0304 .safe_state_index = TEGRA_C1,
0305 };
0306
0307 static inline void tegra_cpuidle_disable_state(enum tegra_state state)
0308 {
0309 cpuidle_driver_state_disabled(&tegra_idle_driver, state, true);
0310 }
0311
0312
0313
0314
0315
0316
0317 void tegra_cpuidle_pcie_irqs_in_use(void)
0318 {
0319 struct cpuidle_state *state_cc6 = &tegra_idle_driver.states[TEGRA_CC6];
0320
0321 if ((state_cc6->flags & CPUIDLE_FLAG_UNUSABLE) ||
0322 tegra_get_chip_id() != TEGRA20)
0323 return;
0324
0325 pr_info("disabling CC6 state, since PCIe IRQs are in use\n");
0326 tegra_cpuidle_disable_state(TEGRA_CC6);
0327 }
0328
0329 static void tegra_cpuidle_setup_tegra114_c7_state(void)
0330 {
0331 struct cpuidle_state *s = &tegra_idle_driver.states[TEGRA_C7];
0332
0333 s->enter_s2idle = tegra114_enter_s2idle;
0334 s->target_residency = 1000;
0335 s->exit_latency = 500;
0336 }
0337
0338 static int tegra_cpuidle_probe(struct platform_device *pdev)
0339 {
0340 if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NOT_READY)
0341 return -EPROBE_DEFER;
0342
0343
0344 if (tegra_pmc_get_suspend_mode() < TEGRA_SUSPEND_LP2)
0345 tegra_cpuidle_disable_state(TEGRA_CC6);
0346
0347
0348
0349
0350
0351
0352 if (!IS_ENABLED(CONFIG_PM_SLEEP)) {
0353 tegra_cpuidle_disable_state(TEGRA_C7);
0354 tegra_cpuidle_disable_state(TEGRA_CC6);
0355 }
0356
0357
0358
0359
0360
0361 switch (tegra_get_chip_id()) {
0362 case TEGRA20:
0363
0364 tegra_cpuidle_disable_state(TEGRA_C7);
0365 break;
0366
0367 case TEGRA30:
0368 break;
0369
0370 case TEGRA114:
0371 case TEGRA124:
0372 tegra_cpuidle_setup_tegra114_c7_state();
0373
0374
0375 tegra_cpuidle_disable_state(TEGRA_CC6);
0376 break;
0377
0378 default:
0379 return -EINVAL;
0380 }
0381
0382 return cpuidle_register(&tegra_idle_driver, cpu_possible_mask);
0383 }
0384
0385 static struct platform_driver tegra_cpuidle_driver = {
0386 .probe = tegra_cpuidle_probe,
0387 .driver = {
0388 .name = "tegra-cpuidle",
0389 },
0390 };
0391 builtin_platform_driver(tegra_cpuidle_driver);