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 */
34 #include <dspbridge/pwr_sh.h>
36 /* ----------------------------------- Bridge Driver */
37 #include <dspbridge/dspdeh.h>
38 #include <dspbridge/wdt.h>
40 /* ----------------------------------- specific to this file */
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
,
55 #ifdef CONFIG_TIDSPBRIDGE_DVFS
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 */
73 * ======== handle_hibernation_from_dsp ========
74 * Handle Hibernation requested from DSP
76 int handle_hibernation_from_dsp(struct bridge_dev_context
*dev_context
)
80 u16 timeout
= PWRSTST_TIMEOUT
/ 10;
82 #ifdef CONFIG_TIDSPBRIDGE_DVFS
84 struct io_mgr
*hio_mgr
;
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");
97 pwr_state
= (*pdata
->dsp_prm_read
)(OMAP3430_IVA2_MOD
,
98 OMAP2_PM_PWSTST
) & OMAP_POWERSTATEST_MASK
;
101 pr_err("%s: Timed out waiting for DSP off mode\n", __func__
);
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);
116 /* Update the Bridger Driver state */
117 dev_context
->dw_brd_state
= BRD_DSP_HIBERNATION
;
118 #ifdef CONFIG_TIDSPBRIDGE_DVFS
120 dev_get_io_mgr(dev_context
->hdev_obj
, &hio_mgr
);
122 status
= DSP_EHANDLE
;
125 io_sh_msetting(hio_mgr
, SHM_GETOPP
, &opplevel
);
128 * Set the OPP to low level before moving to OFF
131 if (pdata
->dsp_set_min_opp
)
132 (*pdata
->dsp_set_min_opp
) (VDD1_OPP1
);
134 #endif /* CONFIG_TIDSPBRIDGE_DVFS */
142 * ======== sleep_dsp ========
143 * Put DSP in low power consuming state.
145 int sleep_dsp(struct bridge_dev_context
*dev_context
, u32 dw_cmd
,
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
))
162 switch (dev_context
->dw_brd_state
) {
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",
169 target_pwr_state
= PWRDM_POWER_OFF
;
171 sm_interrupt_dsp(dev_context
, MBX_PM_DSPRETENTION
);
172 target_pwr_state
= PWRDM_POWER_RET
;
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
;
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",
190 dev_dbg(bridge
, "PM: %s - Board in STOP state\n", __func__
);
193 dev_dbg(bridge
, "PM: %s - Bridge in Illegal state\n", __func__
);
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");
207 pwr_state
= (*pdata
->dsp_prm_read
)(OMAP3430_IVA2_MOD
,
208 OMAP2_PM_PWSTST
) & OMAP_POWERSTATEST_MASK
;
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 */
220 /* Update the Bridger Driver state */
221 if (dsp_test_sleepstate
== PWRDM_POWER_OFF
)
222 dev_context
->dw_brd_state
= BRD_HIBERNATION
;
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
);
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 */
248 * ======== wake_dsp ========
249 * Wake up DSP from sleep.
251 int wake_dsp(struct bridge_dev_context
*dev_context
, void *pargs
)
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 */
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 */
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
,
283 u32 clk_id_index
= MBX_PM_MAX_RESOURCES
;
285 u32 dsp_per_clks_before
;
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
;
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 */
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
,
314 (dev_context
->dsp_per_clks
) &=
315 (~((u32
) (1 << bpwr_clks
[clk_id_index
].clk
)));
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);
322 (dev_context
->dsp_per_clks
) |=
323 (1 << bpwr_clks
[clk_id_index
].clk
);
326 dev_dbg(bridge
, "%s: Unsupported CMD\n", __func__
);
327 /* unsupported cmd */
328 /* TODO -- provide support for AUTOIDLE Enable/Disable
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
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");
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
);
363 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
368 * ========post_scale_dsp========
369 * Sends postscale notification to DSP
372 int post_scale_dsp(struct bridge_dev_context
*dev_context
,
376 #ifdef CONFIG_TIDSPBRIDGE_DVFS
379 struct io_mgr
*hio_mgr
;
381 status
= dev_get_io_mgr(dev_context
->hdev_obj
, &hio_mgr
);
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",
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__
);
406 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
410 void dsp_clk_wakeup_event_ctrl(u32 clock_id
, bool enable
)
412 struct cfg_hostres
*resources
;
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();
423 status
= dev_get_bridge_context(hdev_object
, &bridge_context
);
427 resources
= bridge_context
->resources
;
433 iva2_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA8);
434 mpu_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA4);
436 iva2_grpsel
|= OMAP3430_GRPSEL_GPT5_MASK
;
437 mpu_grpsel
&= ~OMAP3430_GRPSEL_GPT5_MASK
;
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);
446 iva2_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA8);
447 mpu_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA4);
449 iva2_grpsel
|= OMAP3430_GRPSEL_GPT6_MASK
;
450 mpu_grpsel
&= ~OMAP3430_GRPSEL_GPT6_MASK
;
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);
459 iva2_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA8);
460 mpu_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA4);
462 iva2_grpsel
|= OMAP3430_GRPSEL_GPT7_MASK
;
463 mpu_grpsel
&= ~OMAP3430_GRPSEL_GPT7_MASK
;
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);
472 iva2_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA8);
473 mpu_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA4);
475 iva2_grpsel
|= OMAP3430_GRPSEL_GPT8_MASK
;
476 mpu_grpsel
&= ~OMAP3430_GRPSEL_GPT8_MASK
;
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);
485 iva2_grpsel
= readl(resources
->dw_core_pm_base
+ 0xA8);
486 mpu_grpsel
= readl(resources
->dw_core_pm_base
+ 0xA4);
488 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP1_MASK
;
489 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP1_MASK
;
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);
498 iva2_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA8);
499 mpu_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA4);
501 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP2_MASK
;
502 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP2_MASK
;
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);
511 iva2_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA8);
512 mpu_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA4);
514 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP3_MASK
;
515 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP3_MASK
;
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);
524 iva2_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA8);
525 mpu_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA4);
527 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP4_MASK
;
528 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP4_MASK
;
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);
537 iva2_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA8);
538 mpu_grpsel
= readl(resources
->dw_per_pm_base
+ 0xA4);
540 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP5_MASK
;
541 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP5_MASK
;
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);