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