GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / tidspbridge / core / tiomap3430_pwr.c
blobb789f8fdd89bcec76713f3bc8be98c38c4610d7e
1 /*
2 * tiomap_pwr.c
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * Implementation of DSP wake/sleep routines.
8 * Copyright (C) 2007-2008 Texas Instruments, Inc.
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 /* ----------------------------------- DSP/BIOS Bridge */
20 #include <dspbridge/dbdefs.h>
21 #include <dspbridge/cfg.h>
22 #include <dspbridge/drv.h>
23 #include <dspbridge/io_sm.h>
25 /* ----------------------------------- Platform Manager */
26 #include <dspbridge/brddefs.h>
27 #include <dspbridge/dev.h>
28 #include <dspbridge/iodefs.h>
30 /* ------------------------------------ Hardware Abstraction Layer */
31 #include <hw_defs.h>
32 #include <hw_mmu.h>
34 #include <dspbridge/pwr_sh.h>
36 /* ----------------------------------- Bridge Driver */
37 #include <dspbridge/dspdeh.h>
38 #include <dspbridge/wdt.h>
40 /* ----------------------------------- specific to this file */
41 #include "_tiomap.h"
42 #include "_tiomap_pwr.h"
43 #include <mach-omap2/prm-regbits-34xx.h>
44 #include <mach-omap2/cm-regbits-34xx.h>
46 #define PWRSTST_TIMEOUT 200
49 * ======== handle_constraints_set ========
50 * Sets new DSP constraint
52 int handle_constraints_set(struct bridge_dev_context *dev_context,
53 void *pargs)
55 #ifdef CONFIG_TIDSPBRIDGE_DVFS
56 u32 *constraint_val;
57 struct dspbridge_platform_data *pdata =
58 omap_dspbridge_dev->dev.platform_data;
60 constraint_val = (u32 *) (pargs);
61 /* Read the target value requested by DSP */
62 dev_dbg(bridge, "OPP: %s opp requested = 0x%x\n", __func__,
63 (u32) *(constraint_val + 1));
65 /* Set the new opp value */
66 if (pdata->dsp_set_min_opp)
67 (*pdata->dsp_set_min_opp) ((u32) *(constraint_val + 1));
68 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
69 return 0;
73 * ======== handle_hibernation_from_dsp ========
74 * Handle Hibernation requested from DSP
76 int handle_hibernation_from_dsp(struct bridge_dev_context *dev_context)
78 int status = 0;
79 #ifdef CONFIG_PM
80 u16 timeout = PWRSTST_TIMEOUT / 10;
81 u32 pwr_state;
82 #ifdef CONFIG_TIDSPBRIDGE_DVFS
83 u32 opplevel;
84 struct io_mgr *hio_mgr;
85 #endif
86 struct dspbridge_platform_data *pdata =
87 omap_dspbridge_dev->dev.platform_data;
89 pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
90 OMAP_POWERSTATEST_MASK;
91 /* Wait for DSP to move into OFF state */
92 while ((pwr_state != PWRDM_POWER_OFF) && --timeout) {
93 if (msleep_interruptible(10)) {
94 pr_err("Waiting for DSP OFF mode interrupted\n");
95 return -EPERM;
97 pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
98 OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
100 if (timeout == 0) {
101 pr_err("%s: Timed out waiting for DSP off mode\n", __func__);
102 status = -ETIMEDOUT;
103 return status;
104 } else {
106 /* Save mailbox settings */
107 omap_mbox_save_ctx(dev_context->mbox);
109 /* Turn off DSP Peripheral clocks and DSP Load monitor timer */
110 status = dsp_clock_disable_all(dev_context->dsp_per_clks);
112 /* Disable wdt on hibernation. */
113 dsp_wdt_enable(false);
115 if (!status) {
116 /* Update the Bridger Driver state */
117 dev_context->dw_brd_state = BRD_DSP_HIBERNATION;
118 #ifdef CONFIG_TIDSPBRIDGE_DVFS
119 status =
120 dev_get_io_mgr(dev_context->hdev_obj, &hio_mgr);
121 if (!hio_mgr) {
122 status = DSP_EHANDLE;
123 return status;
125 io_sh_msetting(hio_mgr, SHM_GETOPP, &opplevel);
128 * Set the OPP to low level before moving to OFF
129 * mode
131 if (pdata->dsp_set_min_opp)
132 (*pdata->dsp_set_min_opp) (VDD1_OPP1);
133 status = 0;
134 #endif /* CONFIG_TIDSPBRIDGE_DVFS */
137 #endif
138 return status;
142 * ======== sleep_dsp ========
143 * Put DSP in low power consuming state.
145 int sleep_dsp(struct bridge_dev_context *dev_context, u32 dw_cmd,
146 void *pargs)
148 int status = 0;
149 #ifdef CONFIG_PM
150 #ifdef CONFIG_TIDSPBRIDGE_NTFY_PWRERR
151 struct deh_mgr *hdeh_mgr;
152 #endif /* CONFIG_TIDSPBRIDGE_NTFY_PWRERR */
153 u16 timeout = PWRSTST_TIMEOUT / 10;
154 u32 pwr_state, target_pwr_state;
155 struct dspbridge_platform_data *pdata =
156 omap_dspbridge_dev->dev.platform_data;
158 /* Check if sleep code is valid */
159 if ((dw_cmd != PWR_DEEPSLEEP) && (dw_cmd != PWR_EMERGENCYDEEPSLEEP))
160 return -EINVAL;
162 switch (dev_context->dw_brd_state) {
163 case BRD_RUNNING:
164 omap_mbox_save_ctx(dev_context->mbox);
165 if (dsp_test_sleepstate == PWRDM_POWER_OFF) {
166 sm_interrupt_dsp(dev_context, MBX_PM_DSPHIBERNATE);
167 dev_dbg(bridge, "PM: %s - sent hibernate cmd to DSP\n",
168 __func__);
169 target_pwr_state = PWRDM_POWER_OFF;
170 } else {
171 sm_interrupt_dsp(dev_context, MBX_PM_DSPRETENTION);
172 target_pwr_state = PWRDM_POWER_RET;
174 break;
175 case BRD_RETENTION:
176 omap_mbox_save_ctx(dev_context->mbox);
177 if (dsp_test_sleepstate == PWRDM_POWER_OFF) {
178 sm_interrupt_dsp(dev_context, MBX_PM_DSPHIBERNATE);
179 target_pwr_state = PWRDM_POWER_OFF;
180 } else
181 return 0;
182 break;
183 case BRD_HIBERNATION:
184 case BRD_DSP_HIBERNATION:
185 /* Already in Hibernation, so just return */
186 dev_dbg(bridge, "PM: %s - DSP already in hibernation\n",
187 __func__);
188 return 0;
189 case BRD_STOPPED:
190 dev_dbg(bridge, "PM: %s - Board in STOP state\n", __func__);
191 return 0;
192 default:
193 dev_dbg(bridge, "PM: %s - Bridge in Illegal state\n", __func__);
194 return -EPERM;
197 /* Get the PRCM DSP power domain status */
198 pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
199 OMAP_POWERSTATEST_MASK;
201 /* Wait for DSP to move into target power state */
202 while ((pwr_state != target_pwr_state) && --timeout) {
203 if (msleep_interruptible(10)) {
204 pr_err("Waiting for DSP to Suspend interrupted\n");
205 return -EPERM;
207 pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
208 OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
211 if (!timeout) {
212 pr_err("%s: Timed out waiting for DSP off mode, state %x\n",
213 __func__, pwr_state);
214 #ifdef CONFIG_TIDSPBRIDGE_NTFY_PWRERR
215 dev_get_deh_mgr(dev_context->hdev_obj, &hdeh_mgr);
216 bridge_deh_notify(hdeh_mgr, DSP_PWRERROR, 0);
217 #endif /* CONFIG_TIDSPBRIDGE_NTFY_PWRERR */
218 return -ETIMEDOUT;
219 } else {
220 /* Update the Bridger Driver state */
221 if (dsp_test_sleepstate == PWRDM_POWER_OFF)
222 dev_context->dw_brd_state = BRD_HIBERNATION;
223 else
224 dev_context->dw_brd_state = BRD_RETENTION;
226 /* Disable wdt on hibernation. */
227 dsp_wdt_enable(false);
229 /* Turn off DSP Peripheral clocks */
230 status = dsp_clock_disable_all(dev_context->dsp_per_clks);
231 if (status)
232 return status;
233 #ifdef CONFIG_TIDSPBRIDGE_DVFS
234 else if (target_pwr_state == PWRDM_POWER_OFF) {
236 * Set the OPP to low level before moving to OFF mode
238 if (pdata->dsp_set_min_opp)
239 (*pdata->dsp_set_min_opp) (VDD1_OPP1);
241 #endif /* CONFIG_TIDSPBRIDGE_DVFS */
243 #endif /* CONFIG_PM */
244 return status;
248 * ======== wake_dsp ========
249 * Wake up DSP from sleep.
251 int wake_dsp(struct bridge_dev_context *dev_context, void *pargs)
253 int status = 0;
254 #ifdef CONFIG_PM
256 /* Check the board state, if it is not 'SLEEP' then return */
257 if (dev_context->dw_brd_state == BRD_RUNNING ||
258 dev_context->dw_brd_state == BRD_STOPPED) {
259 /* The Device is in 'RET' or 'OFF' state and Bridge state is not
260 * 'SLEEP', this means state inconsistency, so return */
261 return 0;
264 /* Send a wakeup message to DSP */
265 sm_interrupt_dsp(dev_context, MBX_PM_DSPWAKEUP);
267 /* Set the device state to RUNNIG */
268 dev_context->dw_brd_state = BRD_RUNNING;
269 #endif /* CONFIG_PM */
270 return status;
274 * ======== dsp_peripheral_clk_ctrl ========
275 * Enable/Disable the DSP peripheral clocks as needed..
277 int dsp_peripheral_clk_ctrl(struct bridge_dev_context *dev_context,
278 void *pargs)
280 u32 ext_clk = 0;
281 u32 ext_clk_id = 0;
282 u32 ext_clk_cmd = 0;
283 u32 clk_id_index = MBX_PM_MAX_RESOURCES;
284 u32 tmp_index;
285 u32 dsp_per_clks_before;
286 int status = 0;
288 dsp_per_clks_before = dev_context->dsp_per_clks;
290 ext_clk = (u32) *((u32 *) pargs);
291 ext_clk_id = ext_clk & MBX_PM_CLK_IDMASK;
293 /* process the power message -- TODO, keep it in a separate function */
294 for (tmp_index = 0; tmp_index < MBX_PM_MAX_RESOURCES; tmp_index++) {
295 if (ext_clk_id == bpwr_clkid[tmp_index]) {
296 clk_id_index = tmp_index;
297 break;
300 /* TODO -- Assert may be a too hard restriction here.. May be we should
301 * just return with failure when the CLK ID does not match */
302 /* DBC_ASSERT(clk_id_index < MBX_PM_MAX_RESOURCES); */
303 if (clk_id_index == MBX_PM_MAX_RESOURCES) {
304 /* return with a more meaningfull error code */
305 return -EPERM;
307 ext_clk_cmd = (ext_clk >> MBX_PM_CLK_CMDSHIFT) & MBX_PM_CLK_CMDMASK;
308 switch (ext_clk_cmd) {
309 case BPWR_DISABLE_CLOCK:
310 status = dsp_clk_disable(bpwr_clks[clk_id_index].clk);
311 dsp_clk_wakeup_event_ctrl(bpwr_clks[clk_id_index].clk_id,
312 false);
313 if (!status) {
314 (dev_context->dsp_per_clks) &=
315 (~((u32) (1 << bpwr_clks[clk_id_index].clk)));
317 break;
318 case BPWR_ENABLE_CLOCK:
319 status = dsp_clk_enable(bpwr_clks[clk_id_index].clk);
320 dsp_clk_wakeup_event_ctrl(bpwr_clks[clk_id_index].clk_id, true);
321 if (!status)
322 (dev_context->dsp_per_clks) |=
323 (1 << bpwr_clks[clk_id_index].clk);
324 break;
325 default:
326 dev_dbg(bridge, "%s: Unsupported CMD\n", __func__);
327 /* unsupported cmd */
328 /* TODO -- provide support for AUTOIDLE Enable/Disable
329 * commands */
331 return status;
335 * ========pre_scale_dsp========
336 * Sends prescale notification to DSP
339 int pre_scale_dsp(struct bridge_dev_context *dev_context, void *pargs)
341 #ifdef CONFIG_TIDSPBRIDGE_DVFS
342 u32 level;
343 u32 voltage_domain;
345 voltage_domain = *((u32 *) pargs);
346 level = *((u32 *) pargs + 1);
348 dev_dbg(bridge, "OPP: %s voltage_domain = %x, level = 0x%x\n",
349 __func__, voltage_domain, level);
350 if ((dev_context->dw_brd_state == BRD_HIBERNATION) ||
351 (dev_context->dw_brd_state == BRD_RETENTION) ||
352 (dev_context->dw_brd_state == BRD_DSP_HIBERNATION)) {
353 dev_dbg(bridge, "OPP: %s IVA in sleep. No message to DSP\n");
354 return 0;
355 } else if ((dev_context->dw_brd_state == BRD_RUNNING)) {
356 /* Send a prenotificatio to DSP */
357 dev_dbg(bridge, "OPP: %s sent notification to DSP\n", __func__);
358 sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_PRENOTIFY);
359 return 0;
360 } else {
361 return -EPERM;
363 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
364 return 0;
368 * ========post_scale_dsp========
369 * Sends postscale notification to DSP
372 int post_scale_dsp(struct bridge_dev_context *dev_context,
373 void *pargs)
375 int status = 0;
376 #ifdef CONFIG_TIDSPBRIDGE_DVFS
377 u32 level;
378 u32 voltage_domain;
379 struct io_mgr *hio_mgr;
381 status = dev_get_io_mgr(dev_context->hdev_obj, &hio_mgr);
382 if (!hio_mgr)
383 return -EFAULT;
385 voltage_domain = *((u32 *) pargs);
386 level = *((u32 *) pargs + 1);
387 dev_dbg(bridge, "OPP: %s voltage_domain = %x, level = 0x%x\n",
388 __func__, voltage_domain, level);
389 if ((dev_context->dw_brd_state == BRD_HIBERNATION) ||
390 (dev_context->dw_brd_state == BRD_RETENTION) ||
391 (dev_context->dw_brd_state == BRD_DSP_HIBERNATION)) {
392 /* Update the OPP value in shared memory */
393 io_sh_msetting(hio_mgr, SHM_CURROPP, &level);
394 dev_dbg(bridge, "OPP: %s IVA in sleep. Wrote to shm\n",
395 __func__);
396 } else if ((dev_context->dw_brd_state == BRD_RUNNING)) {
397 /* Update the OPP value in shared memory */
398 io_sh_msetting(hio_mgr, SHM_CURROPP, &level);
399 /* Send a post notification to DSP */
400 sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_POSTNOTIFY);
401 dev_dbg(bridge, "OPP: %s wrote to shm. Sent post notification "
402 "to DSP\n", __func__);
403 } else {
404 status = -EPERM;
406 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
407 return status;
410 void dsp_clk_wakeup_event_ctrl(u32 clock_id, bool enable)
412 struct cfg_hostres *resources;
413 int status = 0;
414 u32 iva2_grpsel;
415 u32 mpu_grpsel;
416 struct dev_object *hdev_object = NULL;
417 struct bridge_dev_context *bridge_context = NULL;
419 hdev_object = (struct dev_object *)drv_get_first_dev_object();
420 if (!hdev_object)
421 return;
423 status = dev_get_bridge_context(hdev_object, &bridge_context);
424 if (!bridge_context)
425 return;
427 resources = bridge_context->resources;
428 if (!resources)
429 return;
431 switch (clock_id) {
432 case BPWR_GP_TIMER5:
433 iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
434 mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
435 if (enable) {
436 iva2_grpsel |= OMAP3430_GRPSEL_GPT5_MASK;
437 mpu_grpsel &= ~OMAP3430_GRPSEL_GPT5_MASK;
438 } else {
439 mpu_grpsel |= OMAP3430_GRPSEL_GPT5_MASK;
440 iva2_grpsel &= ~OMAP3430_GRPSEL_GPT5_MASK;
442 writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
443 writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
444 break;
445 case BPWR_GP_TIMER6:
446 iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
447 mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
448 if (enable) {
449 iva2_grpsel |= OMAP3430_GRPSEL_GPT6_MASK;
450 mpu_grpsel &= ~OMAP3430_GRPSEL_GPT6_MASK;
451 } else {
452 mpu_grpsel |= OMAP3430_GRPSEL_GPT6_MASK;
453 iva2_grpsel &= ~OMAP3430_GRPSEL_GPT6_MASK;
455 writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
456 writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
457 break;
458 case BPWR_GP_TIMER7:
459 iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
460 mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
461 if (enable) {
462 iva2_grpsel |= OMAP3430_GRPSEL_GPT7_MASK;
463 mpu_grpsel &= ~OMAP3430_GRPSEL_GPT7_MASK;
464 } else {
465 mpu_grpsel |= OMAP3430_GRPSEL_GPT7_MASK;
466 iva2_grpsel &= ~OMAP3430_GRPSEL_GPT7_MASK;
468 writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
469 writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
470 break;
471 case BPWR_GP_TIMER8:
472 iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
473 mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
474 if (enable) {
475 iva2_grpsel |= OMAP3430_GRPSEL_GPT8_MASK;
476 mpu_grpsel &= ~OMAP3430_GRPSEL_GPT8_MASK;
477 } else {
478 mpu_grpsel |= OMAP3430_GRPSEL_GPT8_MASK;
479 iva2_grpsel &= ~OMAP3430_GRPSEL_GPT8_MASK;
481 writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
482 writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
483 break;
484 case BPWR_MCBSP1:
485 iva2_grpsel = readl(resources->dw_core_pm_base + 0xA8);
486 mpu_grpsel = readl(resources->dw_core_pm_base + 0xA4);
487 if (enable) {
488 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP1_MASK;
489 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP1_MASK;
490 } else {
491 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP1_MASK;
492 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP1_MASK;
494 writel(iva2_grpsel, resources->dw_core_pm_base + 0xA8);
495 writel(mpu_grpsel, resources->dw_core_pm_base + 0xA4);
496 break;
497 case BPWR_MCBSP2:
498 iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
499 mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
500 if (enable) {
501 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP2_MASK;
502 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP2_MASK;
503 } else {
504 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP2_MASK;
505 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP2_MASK;
507 writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
508 writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
509 break;
510 case BPWR_MCBSP3:
511 iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
512 mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
513 if (enable) {
514 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP3_MASK;
515 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP3_MASK;
516 } else {
517 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP3_MASK;
518 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP3_MASK;
520 writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
521 writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
522 break;
523 case BPWR_MCBSP4:
524 iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
525 mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
526 if (enable) {
527 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP4_MASK;
528 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP4_MASK;
529 } else {
530 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP4_MASK;
531 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP4_MASK;
533 writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
534 writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
535 break;
536 case BPWR_MCBSP5:
537 iva2_grpsel = readl(resources->dw_per_pm_base + 0xA8);
538 mpu_grpsel = readl(resources->dw_per_pm_base + 0xA4);
539 if (enable) {
540 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP5_MASK;
541 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP5_MASK;
542 } else {
543 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP5_MASK;
544 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP5_MASK;
546 writel(iva2_grpsel, resources->dw_per_pm_base + 0xA8);
547 writel(mpu_grpsel, resources->dw_per_pm_base + 0xA4);
548 break;