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 /* ----------------------------------- Host OS */
20 #include <dspbridge/host_os.h>
22 #include <linux/platform_data/dsp-omap.h>
24 /* ----------------------------------- DSP/BIOS Bridge */
25 #include <dspbridge/dbdefs.h>
26 #include <dspbridge/drv.h>
27 #include <dspbridge/io_sm.h>
29 /* ----------------------------------- Platform Manager */
30 #include <dspbridge/brddefs.h>
31 #include <dspbridge/dev.h>
32 #include <dspbridge/io.h>
34 /* ------------------------------------ Hardware Abstraction Layer */
38 #include <dspbridge/pwr.h>
40 /* ----------------------------------- Bridge Driver */
41 #include <dspbridge/dspdeh.h>
42 #include <dspbridge/wdt.h>
44 /* ----------------------------------- specific to this file */
46 #include "_tiomap_pwr.h"
47 #include <mach-omap2/prm-regbits-34xx.h>
48 #include <mach-omap2/cm-regbits-34xx.h>
50 #define PWRSTST_TIMEOUT 200
53 * ======== handle_constraints_set ========
54 * Sets new DSP constraint
56 int handle_constraints_set(struct bridge_dev_context
*dev_context
,
59 #ifdef CONFIG_TIDSPBRIDGE_DVFS
61 struct omap_dsp_platform_data
*pdata
=
62 omap_dspbridge_dev
->dev
.platform_data
;
64 constraint_val
= (u32
*) (pargs
);
65 /* Read the target value requested by DSP */
66 dev_dbg(bridge
, "OPP: %s opp requested = 0x%x\n", __func__
,
67 (u32
) *(constraint_val
+ 1));
69 /* Set the new opp value */
70 if (pdata
->dsp_set_min_opp
)
71 (*pdata
->dsp_set_min_opp
) ((u32
) *(constraint_val
+ 1));
72 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
77 * ======== handle_hibernation_from_dsp ========
78 * Handle Hibernation requested from DSP
80 int handle_hibernation_from_dsp(struct bridge_dev_context
*dev_context
)
84 u16 timeout
= PWRSTST_TIMEOUT
/ 10;
86 #ifdef CONFIG_TIDSPBRIDGE_DVFS
88 struct io_mgr
*hio_mgr
;
90 struct omap_dsp_platform_data
*pdata
=
91 omap_dspbridge_dev
->dev
.platform_data
;
93 pwr_state
= (*pdata
->dsp_prm_read
)(OMAP3430_IVA2_MOD
, OMAP2_PM_PWSTST
) &
94 OMAP_POWERSTATEST_MASK
;
95 /* Wait for DSP to move into OFF state */
96 while ((pwr_state
!= PWRDM_POWER_OFF
) && --timeout
) {
97 if (msleep_interruptible(10)) {
98 pr_err("Waiting for DSP OFF mode interrupted\n");
101 pwr_state
= (*pdata
->dsp_prm_read
)(OMAP3430_IVA2_MOD
,
102 OMAP2_PM_PWSTST
) & OMAP_POWERSTATEST_MASK
;
105 pr_err("%s: Timed out waiting for DSP off mode\n", __func__
);
110 /* Save mailbox settings */
111 omap_mbox_save_ctx(dev_context
->mbox
);
113 /* Turn off DSP Peripheral clocks and DSP Load monitor timer */
114 status
= dsp_clock_disable_all(dev_context
->dsp_per_clks
);
116 /* Disable wdt on hibernation. */
117 dsp_wdt_enable(false);
120 /* Update the Bridger Driver state */
121 dev_context
->brd_state
= BRD_DSP_HIBERNATION
;
122 #ifdef CONFIG_TIDSPBRIDGE_DVFS
124 dev_get_io_mgr(dev_context
->dev_obj
, &hio_mgr
);
126 status
= DSP_EHANDLE
;
129 io_sh_msetting(hio_mgr
, SHM_GETOPP
, &opplevel
);
132 * Set the OPP to low level before moving to OFF
135 if (pdata
->dsp_set_min_opp
)
136 (*pdata
->dsp_set_min_opp
) (VDD1_OPP1
);
138 #endif /* CONFIG_TIDSPBRIDGE_DVFS */
146 * ======== sleep_dsp ========
147 * Put DSP in low power consuming state.
149 int sleep_dsp(struct bridge_dev_context
*dev_context
, u32 dw_cmd
,
154 #ifdef CONFIG_TIDSPBRIDGE_NTFY_PWRERR
155 struct deh_mgr
*hdeh_mgr
;
156 #endif /* CONFIG_TIDSPBRIDGE_NTFY_PWRERR */
157 u16 timeout
= PWRSTST_TIMEOUT
/ 10;
158 u32 pwr_state
, target_pwr_state
;
159 struct omap_dsp_platform_data
*pdata
=
160 omap_dspbridge_dev
->dev
.platform_data
;
162 /* Check if sleep code is valid */
163 if ((dw_cmd
!= PWR_DEEPSLEEP
) && (dw_cmd
!= PWR_EMERGENCYDEEPSLEEP
))
166 switch (dev_context
->brd_state
) {
168 omap_mbox_save_ctx(dev_context
->mbox
);
169 if (dsp_test_sleepstate
== PWRDM_POWER_OFF
) {
170 sm_interrupt_dsp(dev_context
, MBX_PM_DSPHIBERNATE
);
171 dev_dbg(bridge
, "PM: %s - sent hibernate cmd to DSP\n",
173 target_pwr_state
= PWRDM_POWER_OFF
;
175 sm_interrupt_dsp(dev_context
, MBX_PM_DSPRETENTION
);
176 target_pwr_state
= PWRDM_POWER_RET
;
180 omap_mbox_save_ctx(dev_context
->mbox
);
181 if (dsp_test_sleepstate
== PWRDM_POWER_OFF
) {
182 sm_interrupt_dsp(dev_context
, MBX_PM_DSPHIBERNATE
);
183 target_pwr_state
= PWRDM_POWER_OFF
;
187 case BRD_HIBERNATION
:
188 case BRD_DSP_HIBERNATION
:
189 /* Already in Hibernation, so just return */
190 dev_dbg(bridge
, "PM: %s - DSP already in hibernation\n",
194 dev_dbg(bridge
, "PM: %s - Board in STOP state\n", __func__
);
197 dev_dbg(bridge
, "PM: %s - Bridge in Illegal state\n", __func__
);
201 /* Get the PRCM DSP power domain status */
202 pwr_state
= (*pdata
->dsp_prm_read
)(OMAP3430_IVA2_MOD
, OMAP2_PM_PWSTST
) &
203 OMAP_POWERSTATEST_MASK
;
205 /* Wait for DSP to move into target power state */
206 while ((pwr_state
!= target_pwr_state
) && --timeout
) {
207 if (msleep_interruptible(10)) {
208 pr_err("Waiting for DSP to Suspend interrupted\n");
211 pwr_state
= (*pdata
->dsp_prm_read
)(OMAP3430_IVA2_MOD
,
212 OMAP2_PM_PWSTST
) & OMAP_POWERSTATEST_MASK
;
216 pr_err("%s: Timed out waiting for DSP off mode, state %x\n",
217 __func__
, pwr_state
);
218 #ifdef CONFIG_TIDSPBRIDGE_NTFY_PWRERR
219 dev_get_deh_mgr(dev_context
->dev_obj
, &hdeh_mgr
);
220 bridge_deh_notify(hdeh_mgr
, DSP_PWRERROR
, 0);
221 #endif /* CONFIG_TIDSPBRIDGE_NTFY_PWRERR */
224 /* Update the Bridger Driver state */
225 if (dsp_test_sleepstate
== PWRDM_POWER_OFF
)
226 dev_context
->brd_state
= BRD_HIBERNATION
;
228 dev_context
->brd_state
= BRD_RETENTION
;
230 /* Disable wdt on hibernation. */
231 dsp_wdt_enable(false);
233 /* Turn off DSP Peripheral clocks */
234 status
= dsp_clock_disable_all(dev_context
->dsp_per_clks
);
237 #ifdef CONFIG_TIDSPBRIDGE_DVFS
238 else if (target_pwr_state
== PWRDM_POWER_OFF
) {
240 * Set the OPP to low level before moving to OFF mode
242 if (pdata
->dsp_set_min_opp
)
243 (*pdata
->dsp_set_min_opp
) (VDD1_OPP1
);
245 #endif /* CONFIG_TIDSPBRIDGE_DVFS */
247 #endif /* CONFIG_PM */
252 * ======== wake_dsp ========
253 * Wake up DSP from sleep.
255 int wake_dsp(struct bridge_dev_context
*dev_context
, void *pargs
)
260 /* Check the board state, if it is not 'SLEEP' then return */
261 if (dev_context
->brd_state
== BRD_RUNNING
||
262 dev_context
->brd_state
== BRD_STOPPED
) {
263 /* The Device is in 'RET' or 'OFF' state and Bridge state is not
264 * 'SLEEP', this means state inconsistency, so return */
268 /* Send a wakeup message to DSP */
269 sm_interrupt_dsp(dev_context
, MBX_PM_DSPWAKEUP
);
271 /* Set the device state to RUNNIG */
272 dev_context
->brd_state
= BRD_RUNNING
;
273 #endif /* CONFIG_PM */
278 * ======== dsp_peripheral_clk_ctrl ========
279 * Enable/Disable the DSP peripheral clocks as needed..
281 int dsp_peripheral_clk_ctrl(struct bridge_dev_context
*dev_context
,
287 u32 clk_id_index
= MBX_PM_MAX_RESOURCES
;
289 u32 dsp_per_clks_before
;
292 dsp_per_clks_before
= dev_context
->dsp_per_clks
;
294 ext_clk
= (u32
) *((u32
*) pargs
);
295 ext_clk_id
= ext_clk
& MBX_PM_CLK_IDMASK
;
297 /* process the power message -- TODO, keep it in a separate function */
298 for (tmp_index
= 0; tmp_index
< MBX_PM_MAX_RESOURCES
; tmp_index
++) {
299 if (ext_clk_id
== bpwr_clkid
[tmp_index
]) {
300 clk_id_index
= tmp_index
;
304 /* TODO -- Assert may be a too hard restriction here.. May be we should
305 * just return with failure when the CLK ID does not match */
306 if (clk_id_index
== MBX_PM_MAX_RESOURCES
) {
307 /* return with a more meaningfull error code */
310 ext_clk_cmd
= (ext_clk
>> MBX_PM_CLK_CMDSHIFT
) & MBX_PM_CLK_CMDMASK
;
311 switch (ext_clk_cmd
) {
312 case BPWR_DISABLE_CLOCK
:
313 status
= dsp_clk_disable(bpwr_clks
[clk_id_index
].clk
);
314 dsp_clk_wakeup_event_ctrl(bpwr_clks
[clk_id_index
].clk_id
,
317 (dev_context
->dsp_per_clks
) &=
318 (~((u32
) (1 << bpwr_clks
[clk_id_index
].clk
)));
321 case BPWR_ENABLE_CLOCK
:
322 status
= dsp_clk_enable(bpwr_clks
[clk_id_index
].clk
);
323 dsp_clk_wakeup_event_ctrl(bpwr_clks
[clk_id_index
].clk_id
, true);
325 (dev_context
->dsp_per_clks
) |=
326 (1 << bpwr_clks
[clk_id_index
].clk
);
329 dev_dbg(bridge
, "%s: Unsupported CMD\n", __func__
);
330 /* unsupported cmd */
331 /* TODO -- provide support for AUTOIDLE Enable/Disable
338 * ========pre_scale_dsp========
339 * Sends prescale notification to DSP
342 int pre_scale_dsp(struct bridge_dev_context
*dev_context
, void *pargs
)
344 #ifdef CONFIG_TIDSPBRIDGE_DVFS
348 voltage_domain
= *((u32
*) pargs
);
349 level
= *((u32
*) pargs
+ 1);
351 dev_dbg(bridge
, "OPP: %s voltage_domain = %x, level = 0x%x\n",
352 __func__
, voltage_domain
, level
);
353 if ((dev_context
->brd_state
== BRD_HIBERNATION
) ||
354 (dev_context
->brd_state
== BRD_RETENTION
) ||
355 (dev_context
->brd_state
== BRD_DSP_HIBERNATION
)) {
356 dev_dbg(bridge
, "OPP: %s IVA in sleep. No message to DSP\n");
358 } else if ((dev_context
->brd_state
== BRD_RUNNING
)) {
359 /* Send a prenotificatio to DSP */
360 dev_dbg(bridge
, "OPP: %s sent notification to DSP\n", __func__
);
361 sm_interrupt_dsp(dev_context
, MBX_PM_SETPOINT_PRENOTIFY
);
366 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
371 * ========post_scale_dsp========
372 * Sends postscale notification to DSP
375 int post_scale_dsp(struct bridge_dev_context
*dev_context
,
379 #ifdef CONFIG_TIDSPBRIDGE_DVFS
382 struct io_mgr
*hio_mgr
;
384 status
= dev_get_io_mgr(dev_context
->dev_obj
, &hio_mgr
);
388 voltage_domain
= *((u32
*) pargs
);
389 level
= *((u32
*) pargs
+ 1);
390 dev_dbg(bridge
, "OPP: %s voltage_domain = %x, level = 0x%x\n",
391 __func__
, voltage_domain
, level
);
392 if ((dev_context
->brd_state
== BRD_HIBERNATION
) ||
393 (dev_context
->brd_state
== BRD_RETENTION
) ||
394 (dev_context
->brd_state
== BRD_DSP_HIBERNATION
)) {
395 /* Update the OPP value in shared memory */
396 io_sh_msetting(hio_mgr
, SHM_CURROPP
, &level
);
397 dev_dbg(bridge
, "OPP: %s IVA in sleep. Wrote to shm\n",
399 } else if ((dev_context
->brd_state
== BRD_RUNNING
)) {
400 /* Update the OPP value in shared memory */
401 io_sh_msetting(hio_mgr
, SHM_CURROPP
, &level
);
402 /* Send a post notification to DSP */
403 sm_interrupt_dsp(dev_context
, MBX_PM_SETPOINT_POSTNOTIFY
);
404 dev_dbg(bridge
, "OPP: %s wrote to shm. Sent post notification "
405 "to DSP\n", __func__
);
409 #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */
413 void dsp_clk_wakeup_event_ctrl(u32 clock_id
, bool enable
)
415 struct cfg_hostres
*resources
;
419 struct dev_object
*hdev_object
= NULL
;
420 struct bridge_dev_context
*bridge_context
= NULL
;
422 hdev_object
= (struct dev_object
*)drv_get_first_dev_object();
426 status
= dev_get_bridge_context(hdev_object
, &bridge_context
);
430 resources
= bridge_context
->resources
;
436 iva2_grpsel
= readl(resources
->per_pm_base
+ 0xA8);
437 mpu_grpsel
= readl(resources
->per_pm_base
+ 0xA4);
439 iva2_grpsel
|= OMAP3430_GRPSEL_GPT5_MASK
;
440 mpu_grpsel
&= ~OMAP3430_GRPSEL_GPT5_MASK
;
442 mpu_grpsel
|= OMAP3430_GRPSEL_GPT5_MASK
;
443 iva2_grpsel
&= ~OMAP3430_GRPSEL_GPT5_MASK
;
445 writel(iva2_grpsel
, resources
->per_pm_base
+ 0xA8);
446 writel(mpu_grpsel
, resources
->per_pm_base
+ 0xA4);
449 iva2_grpsel
= readl(resources
->per_pm_base
+ 0xA8);
450 mpu_grpsel
= readl(resources
->per_pm_base
+ 0xA4);
452 iva2_grpsel
|= OMAP3430_GRPSEL_GPT6_MASK
;
453 mpu_grpsel
&= ~OMAP3430_GRPSEL_GPT6_MASK
;
455 mpu_grpsel
|= OMAP3430_GRPSEL_GPT6_MASK
;
456 iva2_grpsel
&= ~OMAP3430_GRPSEL_GPT6_MASK
;
458 writel(iva2_grpsel
, resources
->per_pm_base
+ 0xA8);
459 writel(mpu_grpsel
, resources
->per_pm_base
+ 0xA4);
462 iva2_grpsel
= readl(resources
->per_pm_base
+ 0xA8);
463 mpu_grpsel
= readl(resources
->per_pm_base
+ 0xA4);
465 iva2_grpsel
|= OMAP3430_GRPSEL_GPT7_MASK
;
466 mpu_grpsel
&= ~OMAP3430_GRPSEL_GPT7_MASK
;
468 mpu_grpsel
|= OMAP3430_GRPSEL_GPT7_MASK
;
469 iva2_grpsel
&= ~OMAP3430_GRPSEL_GPT7_MASK
;
471 writel(iva2_grpsel
, resources
->per_pm_base
+ 0xA8);
472 writel(mpu_grpsel
, resources
->per_pm_base
+ 0xA4);
475 iva2_grpsel
= readl(resources
->per_pm_base
+ 0xA8);
476 mpu_grpsel
= readl(resources
->per_pm_base
+ 0xA4);
478 iva2_grpsel
|= OMAP3430_GRPSEL_GPT8_MASK
;
479 mpu_grpsel
&= ~OMAP3430_GRPSEL_GPT8_MASK
;
481 mpu_grpsel
|= OMAP3430_GRPSEL_GPT8_MASK
;
482 iva2_grpsel
&= ~OMAP3430_GRPSEL_GPT8_MASK
;
484 writel(iva2_grpsel
, resources
->per_pm_base
+ 0xA8);
485 writel(mpu_grpsel
, resources
->per_pm_base
+ 0xA4);
488 iva2_grpsel
= readl(resources
->core_pm_base
+ 0xA8);
489 mpu_grpsel
= readl(resources
->core_pm_base
+ 0xA4);
491 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP1_MASK
;
492 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP1_MASK
;
494 mpu_grpsel
|= OMAP3430_GRPSEL_MCBSP1_MASK
;
495 iva2_grpsel
&= ~OMAP3430_GRPSEL_MCBSP1_MASK
;
497 writel(iva2_grpsel
, resources
->core_pm_base
+ 0xA8);
498 writel(mpu_grpsel
, resources
->core_pm_base
+ 0xA4);
501 iva2_grpsel
= readl(resources
->per_pm_base
+ 0xA8);
502 mpu_grpsel
= readl(resources
->per_pm_base
+ 0xA4);
504 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP2_MASK
;
505 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP2_MASK
;
507 mpu_grpsel
|= OMAP3430_GRPSEL_MCBSP2_MASK
;
508 iva2_grpsel
&= ~OMAP3430_GRPSEL_MCBSP2_MASK
;
510 writel(iva2_grpsel
, resources
->per_pm_base
+ 0xA8);
511 writel(mpu_grpsel
, resources
->per_pm_base
+ 0xA4);
514 iva2_grpsel
= readl(resources
->per_pm_base
+ 0xA8);
515 mpu_grpsel
= readl(resources
->per_pm_base
+ 0xA4);
517 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP3_MASK
;
518 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP3_MASK
;
520 mpu_grpsel
|= OMAP3430_GRPSEL_MCBSP3_MASK
;
521 iva2_grpsel
&= ~OMAP3430_GRPSEL_MCBSP3_MASK
;
523 writel(iva2_grpsel
, resources
->per_pm_base
+ 0xA8);
524 writel(mpu_grpsel
, resources
->per_pm_base
+ 0xA4);
527 iva2_grpsel
= readl(resources
->per_pm_base
+ 0xA8);
528 mpu_grpsel
= readl(resources
->per_pm_base
+ 0xA4);
530 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP4_MASK
;
531 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP4_MASK
;
533 mpu_grpsel
|= OMAP3430_GRPSEL_MCBSP4_MASK
;
534 iva2_grpsel
&= ~OMAP3430_GRPSEL_MCBSP4_MASK
;
536 writel(iva2_grpsel
, resources
->per_pm_base
+ 0xA8);
537 writel(mpu_grpsel
, resources
->per_pm_base
+ 0xA4);
540 iva2_grpsel
= readl(resources
->per_pm_base
+ 0xA8);
541 mpu_grpsel
= readl(resources
->per_pm_base
+ 0xA4);
543 iva2_grpsel
|= OMAP3430_GRPSEL_MCBSP5_MASK
;
544 mpu_grpsel
&= ~OMAP3430_GRPSEL_MCBSP5_MASK
;
546 mpu_grpsel
|= OMAP3430_GRPSEL_MCBSP5_MASK
;
547 iva2_grpsel
&= ~OMAP3430_GRPSEL_MCBSP5_MASK
;
549 writel(iva2_grpsel
, resources
->per_pm_base
+ 0xA8);
550 writel(mpu_grpsel
, resources
->per_pm_base
+ 0xA4);