diff options
Diffstat (limited to 'arch/arm/mach-omap2/prm44xx.c')
-rw-r--r-- | arch/arm/mach-omap2/prm44xx.c | 355 |
1 files changed, 349 insertions, 6 deletions
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index f0c4d5f4a174..a799e9552fbf 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c | |||
@@ -1,10 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * OMAP4 PRM module functions | 2 | * OMAP4 PRM module functions |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Texas Instruments, Inc. | 4 | * Copyright (C) 2011-2012 Texas Instruments, Inc. |
5 | * Copyright (C) 2010 Nokia Corporation | 5 | * Copyright (C) 2010 Nokia Corporation |
6 | * Benoît Cousson | 6 | * Benoît Cousson |
7 | * Paul Walmsley | 7 | * Paul Walmsley |
8 | * Rajendra Nayak <rnayak@ti.com> | ||
8 | * | 9 | * |
9 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
@@ -27,6 +28,9 @@ | |||
27 | #include "prm-regbits-44xx.h" | 28 | #include "prm-regbits-44xx.h" |
28 | #include "prcm44xx.h" | 29 | #include "prcm44xx.h" |
29 | #include "prminst44xx.h" | 30 | #include "prminst44xx.h" |
31 | #include "powerdomain.h" | ||
32 | |||
33 | /* Static data */ | ||
30 | 34 | ||
31 | static const struct omap_prcm_irq omap4_prcm_irqs[] = { | 35 | static const struct omap_prcm_irq omap4_prcm_irqs[] = { |
32 | OMAP_PRCM_IRQ("wkup", 0, 0), | 36 | OMAP_PRCM_IRQ("wkup", 0, 0), |
@@ -46,6 +50,33 @@ static struct omap_prcm_irq_setup omap4_prcm_irq_setup = { | |||
46 | .restore_irqen = &omap44xx_prm_restore_irqen, | 50 | .restore_irqen = &omap44xx_prm_restore_irqen, |
47 | }; | 51 | }; |
48 | 52 | ||
53 | /* | ||
54 | * omap44xx_prm_reset_src_map - map from bits in the PRM_RSTST | ||
55 | * hardware register (which are specific to OMAP44xx SoCs) to reset | ||
56 | * source ID bit shifts (which is an OMAP SoC-independent | ||
57 | * enumeration) | ||
58 | */ | ||
59 | static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = { | ||
60 | { OMAP4430_RST_GLOBAL_WARM_SW_SHIFT, | ||
61 | OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT }, | ||
62 | { OMAP4430_RST_GLOBAL_COLD_SW_SHIFT, | ||
63 | OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT }, | ||
64 | { OMAP4430_MPU_SECURITY_VIOL_RST_SHIFT, | ||
65 | OMAP_SECU_VIOL_RST_SRC_ID_SHIFT }, | ||
66 | { OMAP4430_MPU_WDT_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT }, | ||
67 | { OMAP4430_SECURE_WDT_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT }, | ||
68 | { OMAP4430_EXTERNAL_WARM_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT }, | ||
69 | { OMAP4430_VDD_MPU_VOLT_MGR_RST_SHIFT, | ||
70 | OMAP_VDD_MPU_VM_RST_SRC_ID_SHIFT }, | ||
71 | { OMAP4430_VDD_IVA_VOLT_MGR_RST_SHIFT, | ||
72 | OMAP_VDD_IVA_VM_RST_SRC_ID_SHIFT }, | ||
73 | { OMAP4430_VDD_CORE_VOLT_MGR_RST_SHIFT, | ||
74 | OMAP_VDD_CORE_VM_RST_SRC_ID_SHIFT }, | ||
75 | { OMAP4430_ICEPICK_RST_SHIFT, OMAP_ICEPICK_RST_SRC_ID_SHIFT }, | ||
76 | { OMAP4430_C2C_RST_SHIFT, OMAP_C2C_RST_SRC_ID_SHIFT }, | ||
77 | { -1, -1 }, | ||
78 | }; | ||
79 | |||
49 | /* PRM low-level functions */ | 80 | /* PRM low-level functions */ |
50 | 81 | ||
51 | /* Read a register in a CM/PRM instance in the PRM module */ | 82 | /* Read a register in a CM/PRM instance in the PRM module */ |
@@ -291,12 +322,324 @@ static void __init omap44xx_prm_enable_io_wakeup(void) | |||
291 | OMAP4_PRM_IO_PMCTRL_OFFSET); | 322 | OMAP4_PRM_IO_PMCTRL_OFFSET); |
292 | } | 323 | } |
293 | 324 | ||
294 | static int __init omap4xxx_prcm_init(void) | 325 | /** |
326 | * omap44xx_prm_read_reset_sources - return the last SoC reset source | ||
327 | * | ||
328 | * Return a u32 representing the last reset sources of the SoC. The | ||
329 | * returned reset source bits are standardized across OMAP SoCs. | ||
330 | */ | ||
331 | static u32 omap44xx_prm_read_reset_sources(void) | ||
332 | { | ||
333 | struct prm_reset_src_map *p; | ||
334 | u32 r = 0; | ||
335 | u32 v; | ||
336 | |||
337 | v = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, | ||
338 | OMAP4_RM_RSTST); | ||
339 | |||
340 | p = omap44xx_prm_reset_src_map; | ||
341 | while (p->reg_shift >= 0 && p->std_shift >= 0) { | ||
342 | if (v & (1 << p->reg_shift)) | ||
343 | r |= 1 << p->std_shift; | ||
344 | p++; | ||
345 | } | ||
346 | |||
347 | return r; | ||
348 | } | ||
349 | |||
350 | /* Powerdomain low-level functions */ | ||
351 | |||
352 | static int omap4_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) | ||
353 | { | ||
354 | omap4_prminst_rmw_inst_reg_bits(OMAP_POWERSTATE_MASK, | ||
355 | (pwrst << OMAP_POWERSTATE_SHIFT), | ||
356 | pwrdm->prcm_partition, | ||
357 | pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL); | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | static int omap4_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) | ||
362 | { | ||
363 | u32 v; | ||
364 | |||
365 | v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs, | ||
366 | OMAP4_PM_PWSTCTRL); | ||
367 | v &= OMAP_POWERSTATE_MASK; | ||
368 | v >>= OMAP_POWERSTATE_SHIFT; | ||
369 | |||
370 | return v; | ||
371 | } | ||
372 | |||
373 | static int omap4_pwrdm_read_pwrst(struct powerdomain *pwrdm) | ||
374 | { | ||
375 | u32 v; | ||
376 | |||
377 | v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs, | ||
378 | OMAP4_PM_PWSTST); | ||
379 | v &= OMAP_POWERSTATEST_MASK; | ||
380 | v >>= OMAP_POWERSTATEST_SHIFT; | ||
381 | |||
382 | return v; | ||
383 | } | ||
384 | |||
385 | static int omap4_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm) | ||
386 | { | ||
387 | u32 v; | ||
388 | |||
389 | v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs, | ||
390 | OMAP4_PM_PWSTST); | ||
391 | v &= OMAP4430_LASTPOWERSTATEENTERED_MASK; | ||
392 | v >>= OMAP4430_LASTPOWERSTATEENTERED_SHIFT; | ||
393 | |||
394 | return v; | ||
395 | } | ||
396 | |||
397 | static int omap4_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) | ||
398 | { | ||
399 | omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOWPOWERSTATECHANGE_MASK, | ||
400 | (1 << OMAP4430_LOWPOWERSTATECHANGE_SHIFT), | ||
401 | pwrdm->prcm_partition, | ||
402 | pwrdm->prcm_offs, OMAP4_PM_PWSTCTRL); | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int omap4_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm) | ||
407 | { | ||
408 | omap4_prminst_rmw_inst_reg_bits(OMAP4430_LASTPOWERSTATEENTERED_MASK, | ||
409 | OMAP4430_LASTPOWERSTATEENTERED_MASK, | ||
410 | pwrdm->prcm_partition, | ||
411 | pwrdm->prcm_offs, OMAP4_PM_PWSTST); | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static int omap4_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst) | ||
416 | { | ||
417 | u32 v; | ||
418 | |||
419 | v = pwrst << __ffs(OMAP4430_LOGICRETSTATE_MASK); | ||
420 | omap4_prminst_rmw_inst_reg_bits(OMAP4430_LOGICRETSTATE_MASK, v, | ||
421 | pwrdm->prcm_partition, pwrdm->prcm_offs, | ||
422 | OMAP4_PM_PWSTCTRL); | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int omap4_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, | ||
428 | u8 pwrst) | ||
429 | { | ||
430 | u32 m; | ||
431 | |||
432 | m = omap2_pwrdm_get_mem_bank_onstate_mask(bank); | ||
433 | |||
434 | omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)), | ||
435 | pwrdm->prcm_partition, pwrdm->prcm_offs, | ||
436 | OMAP4_PM_PWSTCTRL); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int omap4_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, | ||
442 | u8 pwrst) | ||
443 | { | ||
444 | u32 m; | ||
445 | |||
446 | m = omap2_pwrdm_get_mem_bank_retst_mask(bank); | ||
447 | |||
448 | omap4_prminst_rmw_inst_reg_bits(m, (pwrst << __ffs(m)), | ||
449 | pwrdm->prcm_partition, pwrdm->prcm_offs, | ||
450 | OMAP4_PM_PWSTCTRL); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int omap4_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm) | ||
456 | { | ||
457 | u32 v; | ||
458 | |||
459 | v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs, | ||
460 | OMAP4_PM_PWSTST); | ||
461 | v &= OMAP4430_LOGICSTATEST_MASK; | ||
462 | v >>= OMAP4430_LOGICSTATEST_SHIFT; | ||
463 | |||
464 | return v; | ||
465 | } | ||
466 | |||
467 | static int omap4_pwrdm_read_logic_retst(struct powerdomain *pwrdm) | ||
295 | { | 468 | { |
296 | if (cpu_is_omap44xx()) { | 469 | u32 v; |
297 | omap44xx_prm_enable_io_wakeup(); | 470 | |
298 | return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup); | 471 | v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs, |
472 | OMAP4_PM_PWSTCTRL); | ||
473 | v &= OMAP4430_LOGICRETSTATE_MASK; | ||
474 | v >>= OMAP4430_LOGICRETSTATE_SHIFT; | ||
475 | |||
476 | return v; | ||
477 | } | ||
478 | |||
479 | /** | ||
480 | * omap4_pwrdm_read_prev_logic_pwrst - read the previous logic powerstate | ||
481 | * @pwrdm: struct powerdomain * to read the state for | ||
482 | * | ||
483 | * Reads the previous logic powerstate for a powerdomain. This | ||
484 | * function must determine the previous logic powerstate by first | ||
485 | * checking the previous powerstate for the domain. If that was OFF, | ||
486 | * then logic has been lost. If previous state was RETENTION, the | ||
487 | * function reads the setting for the next retention logic state to | ||
488 | * see the actual value. In every other case, the logic is | ||
489 | * retained. Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET | ||
490 | * depending whether the logic was retained or not. | ||
491 | */ | ||
492 | static int omap4_pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm) | ||
493 | { | ||
494 | int state; | ||
495 | |||
496 | state = omap4_pwrdm_read_prev_pwrst(pwrdm); | ||
497 | |||
498 | if (state == PWRDM_POWER_OFF) | ||
499 | return PWRDM_POWER_OFF; | ||
500 | |||
501 | if (state != PWRDM_POWER_RET) | ||
502 | return PWRDM_POWER_RET; | ||
503 | |||
504 | return omap4_pwrdm_read_logic_retst(pwrdm); | ||
505 | } | ||
506 | |||
507 | static int omap4_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank) | ||
508 | { | ||
509 | u32 m, v; | ||
510 | |||
511 | m = omap2_pwrdm_get_mem_bank_stst_mask(bank); | ||
512 | |||
513 | v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs, | ||
514 | OMAP4_PM_PWSTST); | ||
515 | v &= m; | ||
516 | v >>= __ffs(m); | ||
517 | |||
518 | return v; | ||
519 | } | ||
520 | |||
521 | static int omap4_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank) | ||
522 | { | ||
523 | u32 m, v; | ||
524 | |||
525 | m = omap2_pwrdm_get_mem_bank_retst_mask(bank); | ||
526 | |||
527 | v = omap4_prminst_read_inst_reg(pwrdm->prcm_partition, pwrdm->prcm_offs, | ||
528 | OMAP4_PM_PWSTCTRL); | ||
529 | v &= m; | ||
530 | v >>= __ffs(m); | ||
531 | |||
532 | return v; | ||
533 | } | ||
534 | |||
535 | /** | ||
536 | * omap4_pwrdm_read_prev_mem_pwrst - reads the previous memory powerstate | ||
537 | * @pwrdm: struct powerdomain * to read mem powerstate for | ||
538 | * @bank: memory bank index | ||
539 | * | ||
540 | * Reads the previous memory powerstate for a powerdomain. This | ||
541 | * function must determine the previous memory powerstate by first | ||
542 | * checking the previous powerstate for the domain. If that was OFF, | ||
543 | * then logic has been lost. If previous state was RETENTION, the | ||
544 | * function reads the setting for the next memory retention state to | ||
545 | * see the actual value. In every other case, the logic is | ||
546 | * retained. Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET | ||
547 | * depending whether logic was retained or not. | ||
548 | */ | ||
549 | static int omap4_pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank) | ||
550 | { | ||
551 | int state; | ||
552 | |||
553 | state = omap4_pwrdm_read_prev_pwrst(pwrdm); | ||
554 | |||
555 | if (state == PWRDM_POWER_OFF) | ||
556 | return PWRDM_POWER_OFF; | ||
557 | |||
558 | if (state != PWRDM_POWER_RET) | ||
559 | return PWRDM_POWER_RET; | ||
560 | |||
561 | return omap4_pwrdm_read_mem_retst(pwrdm, bank); | ||
562 | } | ||
563 | |||
564 | static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) | ||
565 | { | ||
566 | u32 c = 0; | ||
567 | |||
568 | /* | ||
569 | * REVISIT: pwrdm_wait_transition() may be better implemented | ||
570 | * via a callback and a periodic timer check -- how long do we expect | ||
571 | * powerdomain transitions to take? | ||
572 | */ | ||
573 | |||
574 | /* XXX Is this udelay() value meaningful? */ | ||
575 | while ((omap4_prminst_read_inst_reg(pwrdm->prcm_partition, | ||
576 | pwrdm->prcm_offs, | ||
577 | OMAP4_PM_PWSTST) & | ||
578 | OMAP_INTRANSITION_MASK) && | ||
579 | (c++ < PWRDM_TRANSITION_BAILOUT)) | ||
580 | udelay(1); | ||
581 | |||
582 | if (c > PWRDM_TRANSITION_BAILOUT) { | ||
583 | pr_err("powerdomain: %s: waited too long to complete transition\n", | ||
584 | pwrdm->name); | ||
585 | return -EAGAIN; | ||
299 | } | 586 | } |
587 | |||
588 | pr_debug("powerdomain: completed transition in %d loops\n", c); | ||
589 | |||
300 | return 0; | 590 | return 0; |
301 | } | 591 | } |
302 | subsys_initcall(omap4xxx_prcm_init); | 592 | |
593 | struct pwrdm_ops omap4_pwrdm_operations = { | ||
594 | .pwrdm_set_next_pwrst = omap4_pwrdm_set_next_pwrst, | ||
595 | .pwrdm_read_next_pwrst = omap4_pwrdm_read_next_pwrst, | ||
596 | .pwrdm_read_pwrst = omap4_pwrdm_read_pwrst, | ||
597 | .pwrdm_read_prev_pwrst = omap4_pwrdm_read_prev_pwrst, | ||
598 | .pwrdm_set_lowpwrstchange = omap4_pwrdm_set_lowpwrstchange, | ||
599 | .pwrdm_clear_all_prev_pwrst = omap4_pwrdm_clear_all_prev_pwrst, | ||
600 | .pwrdm_set_logic_retst = omap4_pwrdm_set_logic_retst, | ||
601 | .pwrdm_read_logic_pwrst = omap4_pwrdm_read_logic_pwrst, | ||
602 | .pwrdm_read_prev_logic_pwrst = omap4_pwrdm_read_prev_logic_pwrst, | ||
603 | .pwrdm_read_logic_retst = omap4_pwrdm_read_logic_retst, | ||
604 | .pwrdm_read_mem_pwrst = omap4_pwrdm_read_mem_pwrst, | ||
605 | .pwrdm_read_mem_retst = omap4_pwrdm_read_mem_retst, | ||
606 | .pwrdm_read_prev_mem_pwrst = omap4_pwrdm_read_prev_mem_pwrst, | ||
607 | .pwrdm_set_mem_onst = omap4_pwrdm_set_mem_onst, | ||
608 | .pwrdm_set_mem_retst = omap4_pwrdm_set_mem_retst, | ||
609 | .pwrdm_wait_transition = omap4_pwrdm_wait_transition, | ||
610 | }; | ||
611 | |||
612 | /* | ||
613 | * XXX document | ||
614 | */ | ||
615 | static struct prm_ll_data omap44xx_prm_ll_data = { | ||
616 | .read_reset_sources = &omap44xx_prm_read_reset_sources, | ||
617 | }; | ||
618 | |||
619 | static int __init omap44xx_prm_init(void) | ||
620 | { | ||
621 | int ret; | ||
622 | |||
623 | if (!cpu_is_omap44xx()) | ||
624 | return 0; | ||
625 | |||
626 | ret = prm_register(&omap44xx_prm_ll_data); | ||
627 | if (ret) | ||
628 | return ret; | ||
629 | |||
630 | omap44xx_prm_enable_io_wakeup(); | ||
631 | |||
632 | return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup); | ||
633 | } | ||
634 | subsys_initcall(omap44xx_prm_init); | ||
635 | |||
636 | static void __exit omap44xx_prm_exit(void) | ||
637 | { | ||
638 | if (!cpu_is_omap44xx()) | ||
639 | return; | ||
640 | |||
641 | /* Should never happen */ | ||
642 | WARN(prm_unregister(&omap44xx_prm_ll_data), | ||
643 | "%s: prm_ll_data function pointer mismatch\n", __func__); | ||
644 | } | ||
645 | __exitcall(omap44xx_prm_exit); | ||