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