1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <dspbridge/host_os.h>
21
22#include <plat/dsp.h>
23
24
25#include <dspbridge/dbdefs.h>
26#include <dspbridge/drv.h>
27#include <dspbridge/io_sm.h>
28
29
30#include <dspbridge/brddefs.h>
31#include <dspbridge/dev.h>
32#include <dspbridge/io.h>
33
34
35#include <hw_defs.h>
36#include <hw_mmu.h>
37
38#include <dspbridge/pwr.h>
39
40
41#include <dspbridge/dspdeh.h>
42#include <dspbridge/wdt.h>
43
44
45#include "_tiomap.h"
46#include "_tiomap_pwr.h"
47#include <mach-omap2/prm-regbits-34xx.h>
48#include <mach-omap2/cm-regbits-34xx.h>
49
50#define PWRSTST_TIMEOUT 200
51
52
53
54
55
56int handle_constraints_set(struct bridge_dev_context *dev_context,
57 void *pargs)
58{
59#ifdef CONFIG_TIDSPBRIDGE_DVFS
60 u32 *constraint_val;
61 struct omap_dsp_platform_data *pdata =
62 omap_dspbridge_dev->dev.platform_data;
63
64 constraint_val = (u32 *) (pargs);
65
66 dev_dbg(bridge, "OPP: %s opp requested = 0x%x\n", __func__,
67 (u32) *(constraint_val + 1));
68
69
70 if (pdata->dsp_set_min_opp)
71 (*pdata->dsp_set_min_opp) ((u32) *(constraint_val + 1));
72#endif
73 return 0;
74}
75
76
77
78
79
80int handle_hibernation_from_dsp(struct bridge_dev_context *dev_context)
81{
82 int status = 0;
83#ifdef CONFIG_PM
84 u16 timeout = PWRSTST_TIMEOUT / 10;
85 u32 pwr_state;
86#ifdef CONFIG_TIDSPBRIDGE_DVFS
87 u32 opplevel;
88 struct io_mgr *hio_mgr;
89#endif
90 struct omap_dsp_platform_data *pdata =
91 omap_dspbridge_dev->dev.platform_data;
92
93 pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
94 OMAP_POWERSTATEST_MASK;
95
96 while ((pwr_state != PWRDM_POWER_OFF) && --timeout) {
97 if (msleep_interruptible(10)) {
98 pr_err("Waiting for DSP OFF mode interrupted\n");
99 return -EPERM;
100 }
101 pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
102 OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
103 }
104 if (timeout == 0) {
105 pr_err("%s: Timed out waiting for DSP off mode\n", __func__);
106 status = -ETIMEDOUT;
107 return status;
108 } else {
109
110
111 omap_mbox_save_ctx(dev_context->mbox);
112
113
114 status = dsp_clock_disable_all(dev_context->dsp_per_clks);
115
116
117 dsp_wdt_enable(false);
118
119 if (!status) {
120
121 dev_context->brd_state = BRD_DSP_HIBERNATION;
122#ifdef CONFIG_TIDSPBRIDGE_DVFS
123 status =
124 dev_get_io_mgr(dev_context->dev_obj, &hio_mgr);
125 if (!hio_mgr) {
126 status = DSP_EHANDLE;
127 return status;
128 }
129 io_sh_msetting(hio_mgr, SHM_GETOPP, &opplevel);
130
131
132
133
134
135 if (pdata->dsp_set_min_opp)
136 (*pdata->dsp_set_min_opp) (VDD1_OPP1);
137 status = 0;
138#endif
139 }
140 }
141#endif
142 return status;
143}
144
145
146
147
148
149int sleep_dsp(struct bridge_dev_context *dev_context, u32 dw_cmd,
150 void *pargs)
151{
152 int status = 0;
153#ifdef CONFIG_PM
154#ifdef CONFIG_TIDSPBRIDGE_NTFY_PWRERR
155 struct deh_mgr *hdeh_mgr;
156#endif
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;
161
162
163 if ((dw_cmd != PWR_DEEPSLEEP) && (dw_cmd != PWR_EMERGENCYDEEPSLEEP))
164 return -EINVAL;
165
166 switch (dev_context->brd_state) {
167 case BRD_RUNNING:
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",
172 __func__);
173 target_pwr_state = PWRDM_POWER_OFF;
174 } else {
175 sm_interrupt_dsp(dev_context, MBX_PM_DSPRETENTION);
176 target_pwr_state = PWRDM_POWER_RET;
177 }
178 break;
179 case BRD_RETENTION:
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;
184 } else
185 return 0;
186 break;
187 case BRD_HIBERNATION:
188 case BRD_DSP_HIBERNATION:
189
190 dev_dbg(bridge, "PM: %s - DSP already in hibernation\n",
191 __func__);
192 return 0;
193 case BRD_STOPPED:
194 dev_dbg(bridge, "PM: %s - Board in STOP state\n", __func__);
195 return 0;
196 default:
197 dev_dbg(bridge, "PM: %s - Bridge in Illegal state\n", __func__);
198 return -EPERM;
199 }
200
201
202 pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, OMAP2_PM_PWSTST) &
203 OMAP_POWERSTATEST_MASK;
204
205
206 while ((pwr_state != target_pwr_state) && --timeout) {
207 if (msleep_interruptible(10)) {
208 pr_err("Waiting for DSP to Suspend interrupted\n");
209 return -EPERM;
210 }
211 pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD,
212 OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK;
213 }
214
215 if (!timeout) {
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
222 return -ETIMEDOUT;
223 } else {
224
225 if (dsp_test_sleepstate == PWRDM_POWER_OFF)
226 dev_context->brd_state = BRD_HIBERNATION;
227 else
228 dev_context->brd_state = BRD_RETENTION;
229
230
231 dsp_wdt_enable(false);
232
233
234 status = dsp_clock_disable_all(dev_context->dsp_per_clks);
235 if (status)
236 return status;
237#ifdef CONFIG_TIDSPBRIDGE_DVFS
238 else if (target_pwr_state == PWRDM_POWER_OFF) {
239
240
241
242 if (pdata->dsp_set_min_opp)
243 (*pdata->dsp_set_min_opp) (VDD1_OPP1);
244 }
245#endif
246 }
247#endif
248 return status;
249}
250
251
252
253
254
255int wake_dsp(struct bridge_dev_context *dev_context, void *pargs)
256{
257 int status = 0;
258#ifdef CONFIG_PM
259
260
261 if (dev_context->brd_state == BRD_RUNNING ||
262 dev_context->brd_state == BRD_STOPPED) {
263
264
265 return 0;
266 }
267
268
269 sm_interrupt_dsp(dev_context, MBX_PM_DSPWAKEUP);
270
271
272 dev_context->brd_state = BRD_RUNNING;
273#endif
274 return status;
275}
276
277
278
279
280
281int dsp_peripheral_clk_ctrl(struct bridge_dev_context *dev_context,
282 void *pargs)
283{
284 u32 ext_clk = 0;
285 u32 ext_clk_id = 0;
286 u32 ext_clk_cmd = 0;
287 u32 clk_id_index = MBX_PM_MAX_RESOURCES;
288 u32 tmp_index;
289 u32 dsp_per_clks_before;
290 int status = 0;
291
292 dsp_per_clks_before = dev_context->dsp_per_clks;
293
294 ext_clk = (u32) *((u32 *) pargs);
295 ext_clk_id = ext_clk & MBX_PM_CLK_IDMASK;
296
297
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;
301 break;
302 }
303 }
304
305
306
307 if (clk_id_index == MBX_PM_MAX_RESOURCES) {
308
309 return -EPERM;
310 }
311 ext_clk_cmd = (ext_clk >> MBX_PM_CLK_CMDSHIFT) & MBX_PM_CLK_CMDMASK;
312 switch (ext_clk_cmd) {
313 case BPWR_DISABLE_CLOCK:
314 status = dsp_clk_disable(bpwr_clks[clk_id_index].clk);
315 dsp_clk_wakeup_event_ctrl(bpwr_clks[clk_id_index].clk_id,
316 false);
317 if (!status) {
318 (dev_context->dsp_per_clks) &=
319 (~((u32) (1 << bpwr_clks[clk_id_index].clk)));
320 }
321 break;
322 case BPWR_ENABLE_CLOCK:
323 status = dsp_clk_enable(bpwr_clks[clk_id_index].clk);
324 dsp_clk_wakeup_event_ctrl(bpwr_clks[clk_id_index].clk_id, true);
325 if (!status)
326 (dev_context->dsp_per_clks) |=
327 (1 << bpwr_clks[clk_id_index].clk);
328 break;
329 default:
330 dev_dbg(bridge, "%s: Unsupported CMD\n", __func__);
331
332
333
334 }
335 return status;
336}
337
338
339
340
341
342
343int pre_scale_dsp(struct bridge_dev_context *dev_context, void *pargs)
344{
345#ifdef CONFIG_TIDSPBRIDGE_DVFS
346 u32 level;
347 u32 voltage_domain;
348
349 voltage_domain = *((u32 *) pargs);
350 level = *((u32 *) pargs + 1);
351
352 dev_dbg(bridge, "OPP: %s voltage_domain = %x, level = 0x%x\n",
353 __func__, voltage_domain, level);
354 if ((dev_context->brd_state == BRD_HIBERNATION) ||
355 (dev_context->brd_state == BRD_RETENTION) ||
356 (dev_context->brd_state == BRD_DSP_HIBERNATION)) {
357 dev_dbg(bridge, "OPP: %s IVA in sleep. No message to DSP\n");
358 return 0;
359 } else if ((dev_context->brd_state == BRD_RUNNING)) {
360
361 dev_dbg(bridge, "OPP: %s sent notification to DSP\n", __func__);
362 sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_PRENOTIFY);
363 return 0;
364 } else {
365 return -EPERM;
366 }
367#endif
368 return 0;
369}
370
371
372
373
374
375
376int post_scale_dsp(struct bridge_dev_context *dev_context,
377 void *pargs)
378{
379 int status = 0;
380#ifdef CONFIG_TIDSPBRIDGE_DVFS
381 u32 level;
382 u32 voltage_domain;
383 struct io_mgr *hio_mgr;
384
385 status = dev_get_io_mgr(dev_context->dev_obj, &hio_mgr);
386 if (!hio_mgr)
387 return -EFAULT;
388
389 voltage_domain = *((u32 *) pargs);
390 level = *((u32 *) pargs + 1);
391 dev_dbg(bridge, "OPP: %s voltage_domain = %x, level = 0x%x\n",
392 __func__, voltage_domain, level);
393 if ((dev_context->brd_state == BRD_HIBERNATION) ||
394 (dev_context->brd_state == BRD_RETENTION) ||
395 (dev_context->brd_state == BRD_DSP_HIBERNATION)) {
396
397 io_sh_msetting(hio_mgr, SHM_CURROPP, &level);
398 dev_dbg(bridge, "OPP: %s IVA in sleep. Wrote to shm\n",
399 __func__);
400 } else if ((dev_context->brd_state == BRD_RUNNING)) {
401
402 io_sh_msetting(hio_mgr, SHM_CURROPP, &level);
403
404 sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_POSTNOTIFY);
405 dev_dbg(bridge, "OPP: %s wrote to shm. Sent post notification "
406 "to DSP\n", __func__);
407 } else {
408 status = -EPERM;
409 }
410#endif
411 return status;
412}
413
414void dsp_clk_wakeup_event_ctrl(u32 clock_id, bool enable)
415{
416 struct cfg_hostres *resources;
417 int status = 0;
418 u32 iva2_grpsel;
419 u32 mpu_grpsel;
420 struct dev_object *hdev_object = NULL;
421 struct bridge_dev_context *bridge_context = NULL;
422
423 hdev_object = (struct dev_object *)drv_get_first_dev_object();
424 if (!hdev_object)
425 return;
426
427 status = dev_get_bridge_context(hdev_object, &bridge_context);
428 if (!bridge_context)
429 return;
430
431 resources = bridge_context->resources;
432 if (!resources)
433 return;
434
435 switch (clock_id) {
436 case BPWR_GP_TIMER5:
437 iva2_grpsel = readl(resources->per_pm_base + 0xA8);
438 mpu_grpsel = readl(resources->per_pm_base + 0xA4);
439 if (enable) {
440 iva2_grpsel |= OMAP3430_GRPSEL_GPT5_MASK;
441 mpu_grpsel &= ~OMAP3430_GRPSEL_GPT5_MASK;
442 } else {
443 mpu_grpsel |= OMAP3430_GRPSEL_GPT5_MASK;
444 iva2_grpsel &= ~OMAP3430_GRPSEL_GPT5_MASK;
445 }
446 writel(iva2_grpsel, resources->per_pm_base + 0xA8);
447 writel(mpu_grpsel, resources->per_pm_base + 0xA4);
448 break;
449 case BPWR_GP_TIMER6:
450 iva2_grpsel = readl(resources->per_pm_base + 0xA8);
451 mpu_grpsel = readl(resources->per_pm_base + 0xA4);
452 if (enable) {
453 iva2_grpsel |= OMAP3430_GRPSEL_GPT6_MASK;
454 mpu_grpsel &= ~OMAP3430_GRPSEL_GPT6_MASK;
455 } else {
456 mpu_grpsel |= OMAP3430_GRPSEL_GPT6_MASK;
457 iva2_grpsel &= ~OMAP3430_GRPSEL_GPT6_MASK;
458 }
459 writel(iva2_grpsel, resources->per_pm_base + 0xA8);
460 writel(mpu_grpsel, resources->per_pm_base + 0xA4);
461 break;
462 case BPWR_GP_TIMER7:
463 iva2_grpsel = readl(resources->per_pm_base + 0xA8);
464 mpu_grpsel = readl(resources->per_pm_base + 0xA4);
465 if (enable) {
466 iva2_grpsel |= OMAP3430_GRPSEL_GPT7_MASK;
467 mpu_grpsel &= ~OMAP3430_GRPSEL_GPT7_MASK;
468 } else {
469 mpu_grpsel |= OMAP3430_GRPSEL_GPT7_MASK;
470 iva2_grpsel &= ~OMAP3430_GRPSEL_GPT7_MASK;
471 }
472 writel(iva2_grpsel, resources->per_pm_base + 0xA8);
473 writel(mpu_grpsel, resources->per_pm_base + 0xA4);
474 break;
475 case BPWR_GP_TIMER8:
476 iva2_grpsel = readl(resources->per_pm_base + 0xA8);
477 mpu_grpsel = readl(resources->per_pm_base + 0xA4);
478 if (enable) {
479 iva2_grpsel |= OMAP3430_GRPSEL_GPT8_MASK;
480 mpu_grpsel &= ~OMAP3430_GRPSEL_GPT8_MASK;
481 } else {
482 mpu_grpsel |= OMAP3430_GRPSEL_GPT8_MASK;
483 iva2_grpsel &= ~OMAP3430_GRPSEL_GPT8_MASK;
484 }
485 writel(iva2_grpsel, resources->per_pm_base + 0xA8);
486 writel(mpu_grpsel, resources->per_pm_base + 0xA4);
487 break;
488 case BPWR_MCBSP1:
489 iva2_grpsel = readl(resources->core_pm_base + 0xA8);
490 mpu_grpsel = readl(resources->core_pm_base + 0xA4);
491 if (enable) {
492 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP1_MASK;
493 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP1_MASK;
494 } else {
495 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP1_MASK;
496 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP1_MASK;
497 }
498 writel(iva2_grpsel, resources->core_pm_base + 0xA8);
499 writel(mpu_grpsel, resources->core_pm_base + 0xA4);
500 break;
501 case BPWR_MCBSP2:
502 iva2_grpsel = readl(resources->per_pm_base + 0xA8);
503 mpu_grpsel = readl(resources->per_pm_base + 0xA4);
504 if (enable) {
505 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP2_MASK;
506 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP2_MASK;
507 } else {
508 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP2_MASK;
509 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP2_MASK;
510 }
511 writel(iva2_grpsel, resources->per_pm_base + 0xA8);
512 writel(mpu_grpsel, resources->per_pm_base + 0xA4);
513 break;
514 case BPWR_MCBSP3:
515 iva2_grpsel = readl(resources->per_pm_base + 0xA8);
516 mpu_grpsel = readl(resources->per_pm_base + 0xA4);
517 if (enable) {
518 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP3_MASK;
519 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP3_MASK;
520 } else {
521 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP3_MASK;
522 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP3_MASK;
523 }
524 writel(iva2_grpsel, resources->per_pm_base + 0xA8);
525 writel(mpu_grpsel, resources->per_pm_base + 0xA4);
526 break;
527 case BPWR_MCBSP4:
528 iva2_grpsel = readl(resources->per_pm_base + 0xA8);
529 mpu_grpsel = readl(resources->per_pm_base + 0xA4);
530 if (enable) {
531 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP4_MASK;
532 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP4_MASK;
533 } else {
534 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP4_MASK;
535 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP4_MASK;
536 }
537 writel(iva2_grpsel, resources->per_pm_base + 0xA8);
538 writel(mpu_grpsel, resources->per_pm_base + 0xA4);
539 break;
540 case BPWR_MCBSP5:
541 iva2_grpsel = readl(resources->per_pm_base + 0xA8);
542 mpu_grpsel = readl(resources->per_pm_base + 0xA4);
543 if (enable) {
544 iva2_grpsel |= OMAP3430_GRPSEL_MCBSP5_MASK;
545 mpu_grpsel &= ~OMAP3430_GRPSEL_MCBSP5_MASK;
546 } else {
547 mpu_grpsel |= OMAP3430_GRPSEL_MCBSP5_MASK;
548 iva2_grpsel &= ~OMAP3430_GRPSEL_MCBSP5_MASK;
549 }
550 writel(iva2_grpsel, resources->per_pm_base + 0xA8);
551 writel(mpu_grpsel, resources->per_pm_base + 0xA4);
552 break;
553 }
554}
555