Merge tag 'selinux-pr-20191007' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / arch / arm / mach-omap2 / cpuidle34xx.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * linux/arch/arm/mach-omap2/cpuidle34xx.c
4  *
5  * OMAP3 CPU IDLE Routines
6  *
7  * Copyright (C) 2008 Texas Instruments, Inc.
8  * Rajendra Nayak <rnayak@ti.com>
9  *
10  * Copyright (C) 2007 Texas Instruments, Inc.
11  * Karthik Dasu <karthik-dp@ti.com>
12  *
13  * Copyright (C) 2006 Nokia Corporation
14  * Tony Lindgren <tony@atomide.com>
15  *
16  * Copyright (C) 2005 Texas Instruments, Inc.
17  * Richard Woodruff <r-woodruff2@ti.com>
18  *
19  * Based on pm.c for omap2
20  */
21
22 #include <linux/sched.h>
23 #include <linux/cpuidle.h>
24 #include <linux/export.h>
25 #include <linux/cpu_pm.h>
26 #include <asm/cpuidle.h>
27
28 #include "powerdomain.h"
29 #include "clockdomain.h"
30
31 #include "pm.h"
32 #include "control.h"
33 #include "common.h"
34 #include "soc.h"
35
36 /* Mach specific information to be recorded in the C-state driver_data */
37 struct omap3_idle_statedata {
38         u8 mpu_state;
39         u8 core_state;
40         u8 per_min_state;
41         u8 flags;
42 };
43
44 static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
45
46 /*
47  * Possible flag bits for struct omap3_idle_statedata.flags:
48  *
49  * OMAP_CPUIDLE_CX_NO_CLKDM_IDLE: don't allow the MPU clockdomain to go
50  *    inactive.  This in turn prevents the MPU DPLL from entering autoidle
51  *    mode, so wakeup latency is greatly reduced, at the cost of additional
52  *    energy consumption.  This also prevents the CORE clockdomain from
53  *    entering idle.
54  */
55 #define OMAP_CPUIDLE_CX_NO_CLKDM_IDLE           BIT(0)
56
57 /*
58  * Prevent PER OFF if CORE is not in RETention or OFF as this would
59  * disable PER wakeups completely.
60  */
61 static struct omap3_idle_statedata omap3_idle_data[] = {
62         {
63                 .mpu_state = PWRDM_POWER_ON,
64                 .core_state = PWRDM_POWER_ON,
65                 /* In C1 do not allow PER state lower than CORE state */
66                 .per_min_state = PWRDM_POWER_ON,
67                 .flags = OMAP_CPUIDLE_CX_NO_CLKDM_IDLE,
68         },
69         {
70                 .mpu_state = PWRDM_POWER_ON,
71                 .core_state = PWRDM_POWER_ON,
72                 .per_min_state = PWRDM_POWER_RET,
73         },
74         {
75                 .mpu_state = PWRDM_POWER_RET,
76                 .core_state = PWRDM_POWER_ON,
77                 .per_min_state = PWRDM_POWER_RET,
78         },
79         {
80                 .mpu_state = PWRDM_POWER_OFF,
81                 .core_state = PWRDM_POWER_ON,
82                 .per_min_state = PWRDM_POWER_RET,
83         },
84         {
85                 .mpu_state = PWRDM_POWER_RET,
86                 .core_state = PWRDM_POWER_RET,
87                 .per_min_state = PWRDM_POWER_OFF,
88         },
89         {
90                 .mpu_state = PWRDM_POWER_OFF,
91                 .core_state = PWRDM_POWER_RET,
92                 .per_min_state = PWRDM_POWER_OFF,
93         },
94         {
95                 .mpu_state = PWRDM_POWER_OFF,
96                 .core_state = PWRDM_POWER_OFF,
97                 .per_min_state = PWRDM_POWER_OFF,
98         },
99 };
100
101 /**
102  * omap3_enter_idle - Programs OMAP3 to enter the specified state
103  * @dev: cpuidle device
104  * @drv: cpuidle driver
105  * @index: the index of state to be entered
106  */
107 static int omap3_enter_idle(struct cpuidle_device *dev,
108                             struct cpuidle_driver *drv,
109                             int index)
110 {
111         struct omap3_idle_statedata *cx = &omap3_idle_data[index];
112
113         if (omap_irq_pending() || need_resched())
114                 goto return_sleep_time;
115
116         /* Deny idle for C1 */
117         if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) {
118                 clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]);
119         } else {
120                 pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state);
121                 pwrdm_set_next_pwrst(core_pd, cx->core_state);
122         }
123
124         /*
125          * Call idle CPU PM enter notifier chain so that
126          * VFP context is saved.
127          */
128         if (cx->mpu_state == PWRDM_POWER_OFF)
129                 cpu_pm_enter();
130
131         /* Execute ARM wfi */
132         omap_sram_idle();
133
134         /*
135          * Call idle CPU PM enter notifier chain to restore
136          * VFP context.
137          */
138         if (cx->mpu_state == PWRDM_POWER_OFF &&
139             pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF)
140                 cpu_pm_exit();
141
142         /* Re-allow idle for C1 */
143         if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE)
144                 clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]);
145
146 return_sleep_time:
147
148         return index;
149 }
150
151 /**
152  * next_valid_state - Find next valid C-state
153  * @dev: cpuidle device
154  * @drv: cpuidle driver
155  * @index: Index of currently selected c-state
156  *
157  * If the state corresponding to index is valid, index is returned back
158  * to the caller. Else, this function searches for a lower c-state which is
159  * still valid (as defined in omap3_power_states[]) and returns its index.
160  *
161  * A state is valid if the 'valid' field is enabled and
162  * if it satisfies the enable_off_mode condition.
163  */
164 static int next_valid_state(struct cpuidle_device *dev,
165                             struct cpuidle_driver *drv, int index)
166 {
167         struct omap3_idle_statedata *cx = &omap3_idle_data[index];
168         u32 mpu_deepest_state = PWRDM_POWER_RET;
169         u32 core_deepest_state = PWRDM_POWER_RET;
170         int idx;
171         int next_index = 0; /* C1 is the default value */
172
173         if (enable_off_mode) {
174                 mpu_deepest_state = PWRDM_POWER_OFF;
175                 /*
176                  * Erratum i583: valable for ES rev < Es1.2 on 3630.
177                  * CORE OFF mode is not supported in a stable form, restrict
178                  * instead the CORE state to RET.
179                  */
180                 if (!IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583))
181                         core_deepest_state = PWRDM_POWER_OFF;
182         }
183
184         /* Check if current state is valid */
185         if ((cx->mpu_state >= mpu_deepest_state) &&
186             (cx->core_state >= core_deepest_state))
187                 return index;
188
189         /*
190          * Drop to next valid state.
191          * Start search from the next (lower) state.
192          */
193         for (idx = index - 1; idx >= 0; idx--) {
194                 cx = &omap3_idle_data[idx];
195                 if ((cx->mpu_state >= mpu_deepest_state) &&
196                     (cx->core_state >= core_deepest_state)) {
197                         next_index = idx;
198                         break;
199                 }
200         }
201
202         return next_index;
203 }
204
205 /**
206  * omap3_enter_idle_bm - Checks for any bus activity
207  * @dev: cpuidle device
208  * @drv: cpuidle driver
209  * @index: array index of target state to be programmed
210  *
211  * This function checks for any pending activity and then programs
212  * the device to the specified or a safer state.
213  */
214 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
215                                struct cpuidle_driver *drv,
216                                int index)
217 {
218         int new_state_idx, ret;
219         u8 per_next_state, per_saved_state;
220         struct omap3_idle_statedata *cx;
221
222         /*
223          * Use only C1 if CAM is active.
224          * CAM does not have wakeup capability in OMAP3.
225          */
226         if (pwrdm_read_pwrst(cam_pd) == PWRDM_POWER_ON)
227                 new_state_idx = drv->safe_state_index;
228         else
229                 new_state_idx = next_valid_state(dev, drv, index);
230
231         /*
232          * FIXME: we currently manage device-specific idle states
233          *        for PER and CORE in combination with CPU-specific
234          *        idle states.  This is wrong, and device-specific
235          *        idle management needs to be separated out into
236          *        its own code.
237          */
238
239         /* Program PER state */
240         cx = &omap3_idle_data[new_state_idx];
241
242         per_next_state = pwrdm_read_next_pwrst(per_pd);
243         per_saved_state = per_next_state;
244         if (per_next_state < cx->per_min_state) {
245                 per_next_state = cx->per_min_state;
246                 pwrdm_set_next_pwrst(per_pd, per_next_state);
247         }
248
249         ret = omap3_enter_idle(dev, drv, new_state_idx);
250
251         /* Restore original PER state if it was modified */
252         if (per_next_state != per_saved_state)
253                 pwrdm_set_next_pwrst(per_pd, per_saved_state);
254
255         return ret;
256 }
257
258 static struct cpuidle_driver omap3_idle_driver = {
259         .name             = "omap3_idle",
260         .owner            = THIS_MODULE,
261         .states = {
262                 {
263                         .enter            = omap3_enter_idle_bm,
264                         .exit_latency     = 2 + 2,
265                         .target_residency = 5,
266                         .name             = "C1",
267                         .desc             = "MPU ON + CORE ON",
268                 },
269                 {
270                         .enter            = omap3_enter_idle_bm,
271                         .exit_latency     = 10 + 10,
272                         .target_residency = 30,
273                         .name             = "C2",
274                         .desc             = "MPU ON + CORE ON",
275                 },
276                 {
277                         .enter            = omap3_enter_idle_bm,
278                         .exit_latency     = 50 + 50,
279                         .target_residency = 300,
280                         .name             = "C3",
281                         .desc             = "MPU RET + CORE ON",
282                 },
283                 {
284                         .enter            = omap3_enter_idle_bm,
285                         .exit_latency     = 1500 + 1800,
286                         .target_residency = 4000,
287                         .name             = "C4",
288                         .desc             = "MPU OFF + CORE ON",
289                 },
290                 {
291                         .enter            = omap3_enter_idle_bm,
292                         .exit_latency     = 2500 + 7500,
293                         .target_residency = 12000,
294                         .name             = "C5",
295                         .desc             = "MPU RET + CORE RET",
296                 },
297                 {
298                         .enter            = omap3_enter_idle_bm,
299                         .exit_latency     = 3000 + 8500,
300                         .target_residency = 15000,
301                         .name             = "C6",
302                         .desc             = "MPU OFF + CORE RET",
303                 },
304                 {
305                         .enter            = omap3_enter_idle_bm,
306                         .exit_latency     = 10000 + 30000,
307                         .target_residency = 30000,
308                         .name             = "C7",
309                         .desc             = "MPU OFF + CORE OFF",
310                 },
311         },
312         .state_count = ARRAY_SIZE(omap3_idle_data),
313         .safe_state_index = 0,
314 };
315
316 /*
317  * Numbers based on measurements made in October 2009 for PM optimized kernel
318  * with CPU freq enabled on device Nokia N900. Assumes OPP2 (main idle OPP,
319  * and worst case latencies).
320  */
321 static struct cpuidle_driver omap3430_idle_driver = {
322         .name             = "omap3430_idle",
323         .owner            = THIS_MODULE,
324         .states = {
325                 {
326                         .enter            = omap3_enter_idle_bm,
327                         .exit_latency     = 110 + 162,
328                         .target_residency = 5,
329                         .name             = "C1",
330                         .desc             = "MPU ON + CORE ON",
331                 },
332                 {
333                         .enter            = omap3_enter_idle_bm,
334                         .exit_latency     = 106 + 180,
335                         .target_residency = 309,
336                         .name             = "C2",
337                         .desc             = "MPU ON + CORE ON",
338                 },
339                 {
340                         .enter            = omap3_enter_idle_bm,
341                         .exit_latency     = 107 + 410,
342                         .target_residency = 46057,
343                         .name             = "C3",
344                         .desc             = "MPU RET + CORE ON",
345                 },
346                 {
347                         .enter            = omap3_enter_idle_bm,
348                         .exit_latency     = 121 + 3374,
349                         .target_residency = 46057,
350                         .name             = "C4",
351                         .desc             = "MPU OFF + CORE ON",
352                 },
353                 {
354                         .enter            = omap3_enter_idle_bm,
355                         .exit_latency     = 855 + 1146,
356                         .target_residency = 46057,
357                         .name             = "C5",
358                         .desc             = "MPU RET + CORE RET",
359                 },
360                 {
361                         .enter            = omap3_enter_idle_bm,
362                         .exit_latency     = 7580 + 4134,
363                         .target_residency = 484329,
364                         .name             = "C6",
365                         .desc             = "MPU OFF + CORE RET",
366                 },
367                 {
368                         .enter            = omap3_enter_idle_bm,
369                         .exit_latency     = 7505 + 15274,
370                         .target_residency = 484329,
371                         .name             = "C7",
372                         .desc             = "MPU OFF + CORE OFF",
373                 },
374         },
375         .state_count = ARRAY_SIZE(omap3_idle_data),
376         .safe_state_index = 0,
377 };
378
379 /* Public functions */
380
381 /**
382  * omap3_idle_init - Init routine for OMAP3 idle
383  *
384  * Registers the OMAP3 specific cpuidle driver to the cpuidle
385  * framework with the valid set of states.
386  */
387 int __init omap3_idle_init(void)
388 {
389         mpu_pd = pwrdm_lookup("mpu_pwrdm");
390         core_pd = pwrdm_lookup("core_pwrdm");
391         per_pd = pwrdm_lookup("per_pwrdm");
392         cam_pd = pwrdm_lookup("cam_pwrdm");
393
394         if (!mpu_pd || !core_pd || !per_pd || !cam_pd)
395                 return -ENODEV;
396
397         if (cpu_is_omap3430())
398                 return cpuidle_register(&omap3430_idle_driver, NULL);
399         else
400                 return cpuidle_register(&omap3_idle_driver, NULL);
401 }