diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 404 |
1 files changed, 350 insertions, 54 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 293fa6cd50e1..84cc0bdda3ae 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * omap_hwmod implementation for OMAP2/3/4 | 2 | * omap_hwmod implementation for OMAP2/3/4 |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2011 Nokia Corporation | 4 | * Copyright (C) 2009-2011 Nokia Corporation |
5 | * Copyright (C) 2011 Texas Instruments, Inc. | ||
5 | * | 6 | * |
6 | * Paul Walmsley, Benoît Cousson, Kevin Hilman | 7 | * Paul Walmsley, Benoît Cousson, Kevin Hilman |
7 | * | 8 | * |
@@ -145,9 +146,10 @@ | |||
145 | #include <plat/prcm.h> | 146 | #include <plat/prcm.h> |
146 | 147 | ||
147 | #include "cm2xxx_3xxx.h" | 148 | #include "cm2xxx_3xxx.h" |
148 | #include "cm44xx.h" | 149 | #include "cminst44xx.h" |
149 | #include "prm2xxx_3xxx.h" | 150 | #include "prm2xxx_3xxx.h" |
150 | #include "prm44xx.h" | 151 | #include "prm44xx.h" |
152 | #include "prminst44xx.h" | ||
151 | #include "mux.h" | 153 | #include "mux.h" |
152 | 154 | ||
153 | /* Maximum microseconds to wait for OMAP module to softreset */ | 155 | /* Maximum microseconds to wait for OMAP module to softreset */ |
@@ -387,11 +389,10 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, | |||
387 | */ | 389 | */ |
388 | static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) | 390 | static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) |
389 | { | 391 | { |
390 | u32 wakeup_mask; | ||
391 | |||
392 | if (!oh->class->sysc || | 392 | if (!oh->class->sysc || |
393 | !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || | 393 | !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || |
394 | (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) | 394 | (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || |
395 | (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP))) | ||
395 | return -EINVAL; | 396 | return -EINVAL; |
396 | 397 | ||
397 | if (!oh->class->sysc->sysc_fields) { | 398 | if (!oh->class->sysc->sysc_fields) { |
@@ -399,12 +400,13 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) | |||
399 | return -EINVAL; | 400 | return -EINVAL; |
400 | } | 401 | } |
401 | 402 | ||
402 | wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); | 403 | if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) |
403 | 404 | *v |= 0x1 << oh->class->sysc->sysc_fields->enwkup_shift; | |
404 | *v |= wakeup_mask; | ||
405 | 405 | ||
406 | if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) | 406 | if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) |
407 | _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); | 407 | _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); |
408 | if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) | ||
409 | _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); | ||
408 | 410 | ||
409 | /* XXX test pwrdm_get_wken for this hwmod's subsystem */ | 411 | /* XXX test pwrdm_get_wken for this hwmod's subsystem */ |
410 | 412 | ||
@@ -422,11 +424,10 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) | |||
422 | */ | 424 | */ |
423 | static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) | 425 | static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) |
424 | { | 426 | { |
425 | u32 wakeup_mask; | ||
426 | |||
427 | if (!oh->class->sysc || | 427 | if (!oh->class->sysc || |
428 | !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || | 428 | !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || |
429 | (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) | 429 | (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) || |
430 | (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP))) | ||
430 | return -EINVAL; | 431 | return -EINVAL; |
431 | 432 | ||
432 | if (!oh->class->sysc->sysc_fields) { | 433 | if (!oh->class->sysc->sysc_fields) { |
@@ -434,12 +435,13 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) | |||
434 | return -EINVAL; | 435 | return -EINVAL; |
435 | } | 436 | } |
436 | 437 | ||
437 | wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); | 438 | if (oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) |
438 | 439 | *v &= ~(0x1 << oh->class->sysc->sysc_fields->enwkup_shift); | |
439 | *v &= ~wakeup_mask; | ||
440 | 440 | ||
441 | if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) | 441 | if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) |
442 | _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v); | 442 | _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v); |
443 | if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) | ||
444 | _set_master_standbymode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); | ||
443 | 445 | ||
444 | /* XXX test pwrdm_get_wken for this hwmod's subsystem */ | 446 | /* XXX test pwrdm_get_wken for this hwmod's subsystem */ |
445 | 447 | ||
@@ -678,6 +680,125 @@ static void _disable_optional_clocks(struct omap_hwmod *oh) | |||
678 | } | 680 | } |
679 | 681 | ||
680 | /** | 682 | /** |
683 | * _enable_module - enable CLKCTRL modulemode on OMAP4 | ||
684 | * @oh: struct omap_hwmod * | ||
685 | * | ||
686 | * Enables the PRCM module mode related to the hwmod @oh. | ||
687 | * No return value. | ||
688 | */ | ||
689 | static void _enable_module(struct omap_hwmod *oh) | ||
690 | { | ||
691 | /* The module mode does not exist prior OMAP4 */ | ||
692 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
693 | return; | ||
694 | |||
695 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) | ||
696 | return; | ||
697 | |||
698 | pr_debug("omap_hwmod: %s: _enable_module: %d\n", | ||
699 | oh->name, oh->prcm.omap4.modulemode); | ||
700 | |||
701 | omap4_cminst_module_enable(oh->prcm.omap4.modulemode, | ||
702 | oh->clkdm->prcm_partition, | ||
703 | oh->clkdm->cm_inst, | ||
704 | oh->clkdm->clkdm_offs, | ||
705 | oh->prcm.omap4.clkctrl_offs); | ||
706 | } | ||
707 | |||
708 | /** | ||
709 | * _disable_module - enable CLKCTRL modulemode on OMAP4 | ||
710 | * @oh: struct omap_hwmod * | ||
711 | * | ||
712 | * Disable the PRCM module mode related to the hwmod @oh. | ||
713 | * No return value. | ||
714 | */ | ||
715 | static void _disable_module(struct omap_hwmod *oh) | ||
716 | { | ||
717 | /* The module mode does not exist prior OMAP4 */ | ||
718 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
719 | return; | ||
720 | |||
721 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) | ||
722 | return; | ||
723 | |||
724 | pr_debug("omap_hwmod: %s: _disable_module\n", oh->name); | ||
725 | |||
726 | omap4_cminst_module_disable(oh->clkdm->prcm_partition, | ||
727 | oh->clkdm->cm_inst, | ||
728 | oh->clkdm->clkdm_offs, | ||
729 | oh->prcm.omap4.clkctrl_offs); | ||
730 | } | ||
731 | |||
732 | /** | ||
733 | * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh | ||
734 | * @oh: struct omap_hwmod *oh | ||
735 | * | ||
736 | * Count and return the number of MPU IRQs associated with the hwmod | ||
737 | * @oh. Used to allocate struct resource data. Returns 0 if @oh is | ||
738 | * NULL. | ||
739 | */ | ||
740 | static int _count_mpu_irqs(struct omap_hwmod *oh) | ||
741 | { | ||
742 | struct omap_hwmod_irq_info *ohii; | ||
743 | int i = 0; | ||
744 | |||
745 | if (!oh || !oh->mpu_irqs) | ||
746 | return 0; | ||
747 | |||
748 | do { | ||
749 | ohii = &oh->mpu_irqs[i++]; | ||
750 | } while (ohii->irq != -1); | ||
751 | |||
752 | return i; | ||
753 | } | ||
754 | |||
755 | /** | ||
756 | * _count_sdma_reqs - count the number of SDMA request lines associated with @oh | ||
757 | * @oh: struct omap_hwmod *oh | ||
758 | * | ||
759 | * Count and return the number of SDMA request lines associated with | ||
760 | * the hwmod @oh. Used to allocate struct resource data. Returns 0 | ||
761 | * if @oh is NULL. | ||
762 | */ | ||
763 | static int _count_sdma_reqs(struct omap_hwmod *oh) | ||
764 | { | ||
765 | struct omap_hwmod_dma_info *ohdi; | ||
766 | int i = 0; | ||
767 | |||
768 | if (!oh || !oh->sdma_reqs) | ||
769 | return 0; | ||
770 | |||
771 | do { | ||
772 | ohdi = &oh->sdma_reqs[i++]; | ||
773 | } while (ohdi->dma_req != -1); | ||
774 | |||
775 | return i; | ||
776 | } | ||
777 | |||
778 | /** | ||
779 | * _count_ocp_if_addr_spaces - count the number of address space entries for @oh | ||
780 | * @oh: struct omap_hwmod *oh | ||
781 | * | ||
782 | * Count and return the number of address space ranges associated with | ||
783 | * the hwmod @oh. Used to allocate struct resource data. Returns 0 | ||
784 | * if @oh is NULL. | ||
785 | */ | ||
786 | static int _count_ocp_if_addr_spaces(struct omap_hwmod_ocp_if *os) | ||
787 | { | ||
788 | struct omap_hwmod_addr_space *mem; | ||
789 | int i = 0; | ||
790 | |||
791 | if (!os || !os->addr) | ||
792 | return 0; | ||
793 | |||
794 | do { | ||
795 | mem = &os->addr[i++]; | ||
796 | } while (mem->pa_start != mem->pa_end); | ||
797 | |||
798 | return i; | ||
799 | } | ||
800 | |||
801 | /** | ||
681 | * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use | 802 | * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use |
682 | * @oh: struct omap_hwmod * | 803 | * @oh: struct omap_hwmod * |
683 | * | 804 | * |
@@ -722,8 +843,7 @@ static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index) | |||
722 | { | 843 | { |
723 | struct omap_hwmod_ocp_if *os; | 844 | struct omap_hwmod_ocp_if *os; |
724 | struct omap_hwmod_addr_space *mem; | 845 | struct omap_hwmod_addr_space *mem; |
725 | int i; | 846 | int i = 0, found = 0; |
726 | int found = 0; | ||
727 | void __iomem *va_start; | 847 | void __iomem *va_start; |
728 | 848 | ||
729 | if (!oh || oh->slaves_cnt == 0) | 849 | if (!oh || oh->slaves_cnt == 0) |
@@ -731,12 +851,14 @@ static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index) | |||
731 | 851 | ||
732 | os = oh->slaves[index]; | 852 | os = oh->slaves[index]; |
733 | 853 | ||
734 | for (i = 0, mem = os->addr; i < os->addr_cnt; i++, mem++) { | 854 | if (!os->addr) |
735 | if (mem->flags & ADDR_TYPE_RT) { | 855 | return NULL; |
856 | |||
857 | do { | ||
858 | mem = &os->addr[i++]; | ||
859 | if (mem->flags & ADDR_TYPE_RT) | ||
736 | found = 1; | 860 | found = 1; |
737 | break; | 861 | } while (!found && mem->pa_start != mem->pa_end); |
738 | } | ||
739 | } | ||
740 | 862 | ||
741 | if (found) { | 863 | if (found) { |
742 | va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); | 864 | va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); |
@@ -781,8 +903,16 @@ static void _enable_sysc(struct omap_hwmod *oh) | |||
781 | } | 903 | } |
782 | 904 | ||
783 | if (sf & SYSC_HAS_MIDLEMODE) { | 905 | if (sf & SYSC_HAS_MIDLEMODE) { |
784 | idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? | 906 | if (oh->flags & HWMOD_SWSUP_MSTANDBY) { |
785 | HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART; | 907 | idlemode = HWMOD_IDLEMODE_NO; |
908 | } else { | ||
909 | if (sf & SYSC_HAS_ENAWAKEUP) | ||
910 | _enable_wakeup(oh, &v); | ||
911 | if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) | ||
912 | idlemode = HWMOD_IDLEMODE_SMART_WKUP; | ||
913 | else | ||
914 | idlemode = HWMOD_IDLEMODE_SMART; | ||
915 | } | ||
786 | _set_master_standbymode(oh, idlemode, &v); | 916 | _set_master_standbymode(oh, idlemode, &v); |
787 | } | 917 | } |
788 | 918 | ||
@@ -840,8 +970,16 @@ static void _idle_sysc(struct omap_hwmod *oh) | |||
840 | } | 970 | } |
841 | 971 | ||
842 | if (sf & SYSC_HAS_MIDLEMODE) { | 972 | if (sf & SYSC_HAS_MIDLEMODE) { |
843 | idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? | 973 | if (oh->flags & HWMOD_SWSUP_MSTANDBY) { |
844 | HWMOD_IDLEMODE_FORCE : HWMOD_IDLEMODE_SMART; | 974 | idlemode = HWMOD_IDLEMODE_FORCE; |
975 | } else { | ||
976 | if (sf & SYSC_HAS_ENAWAKEUP) | ||
977 | _enable_wakeup(oh, &v); | ||
978 | if (oh->class->sysc->idlemodes & MSTANDBY_SMART_WKUP) | ||
979 | idlemode = HWMOD_IDLEMODE_SMART_WKUP; | ||
980 | else | ||
981 | idlemode = HWMOD_IDLEMODE_SMART; | ||
982 | } | ||
845 | _set_master_standbymode(oh, idlemode, &v); | 983 | _set_master_standbymode(oh, idlemode, &v); |
846 | } | 984 | } |
847 | 985 | ||
@@ -903,9 +1041,40 @@ static struct omap_hwmod *_lookup(const char *name) | |||
903 | 1041 | ||
904 | return oh; | 1042 | return oh; |
905 | } | 1043 | } |
1044 | /** | ||
1045 | * _init_clkdm - look up a clockdomain name, store pointer in omap_hwmod | ||
1046 | * @oh: struct omap_hwmod * | ||
1047 | * | ||
1048 | * Convert a clockdomain name stored in a struct omap_hwmod into a | ||
1049 | * clockdomain pointer, and save it into the struct omap_hwmod. | ||
1050 | * return -EINVAL if clkdm_name does not exist or if the lookup failed. | ||
1051 | */ | ||
1052 | static int _init_clkdm(struct omap_hwmod *oh) | ||
1053 | { | ||
1054 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
1055 | return 0; | ||
1056 | |||
1057 | if (!oh->clkdm_name) { | ||
1058 | pr_warning("omap_hwmod: %s: no clkdm_name\n", oh->name); | ||
1059 | return -EINVAL; | ||
1060 | } | ||
1061 | |||
1062 | oh->clkdm = clkdm_lookup(oh->clkdm_name); | ||
1063 | if (!oh->clkdm) { | ||
1064 | pr_warning("omap_hwmod: %s: could not associate to clkdm %s\n", | ||
1065 | oh->name, oh->clkdm_name); | ||
1066 | return -EINVAL; | ||
1067 | } | ||
1068 | |||
1069 | pr_debug("omap_hwmod: %s: associated to clkdm %s\n", | ||
1070 | oh->name, oh->clkdm_name); | ||
1071 | |||
1072 | return 0; | ||
1073 | } | ||
906 | 1074 | ||
907 | /** | 1075 | /** |
908 | * _init_clocks - clk_get() all clocks associated with this hwmod | 1076 | * _init_clocks - clk_get() all clocks associated with this hwmod. Retrieve as |
1077 | * well the clockdomain. | ||
909 | * @oh: struct omap_hwmod * | 1078 | * @oh: struct omap_hwmod * |
910 | * @data: not used; pass NULL | 1079 | * @data: not used; pass NULL |
911 | * | 1080 | * |
@@ -925,9 +1094,12 @@ static int _init_clocks(struct omap_hwmod *oh, void *data) | |||
925 | ret |= _init_main_clk(oh); | 1094 | ret |= _init_main_clk(oh); |
926 | ret |= _init_interface_clks(oh); | 1095 | ret |= _init_interface_clks(oh); |
927 | ret |= _init_opt_clks(oh); | 1096 | ret |= _init_opt_clks(oh); |
1097 | ret |= _init_clkdm(oh); | ||
928 | 1098 | ||
929 | if (!ret) | 1099 | if (!ret) |
930 | oh->_state = _HWMOD_STATE_CLKS_INITED; | 1100 | oh->_state = _HWMOD_STATE_CLKS_INITED; |
1101 | else | ||
1102 | pr_warning("omap_hwmod: %s: cannot _init_clocks\n", oh->name); | ||
931 | 1103 | ||
932 | return ret; | 1104 | return ret; |
933 | } | 1105 | } |
@@ -939,7 +1111,7 @@ static int _init_clocks(struct omap_hwmod *oh, void *data) | |||
939 | * Wait for a module @oh to leave slave idle. Returns 0 if the module | 1111 | * Wait for a module @oh to leave slave idle. Returns 0 if the module |
940 | * does not have an IDLEST bit or if the module successfully leaves | 1112 | * does not have an IDLEST bit or if the module successfully leaves |
941 | * slave idle; otherwise, pass along the return value of the | 1113 | * slave idle; otherwise, pass along the return value of the |
942 | * appropriate *_cm_wait_module_ready() function. | 1114 | * appropriate *_cm*_wait_module_ready() function. |
943 | */ | 1115 | */ |
944 | static int _wait_target_ready(struct omap_hwmod *oh) | 1116 | static int _wait_target_ready(struct omap_hwmod *oh) |
945 | { | 1117 | { |
@@ -966,7 +1138,13 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
966 | oh->prcm.omap2.idlest_reg_id, | 1138 | oh->prcm.omap2.idlest_reg_id, |
967 | oh->prcm.omap2.idlest_idle_bit); | 1139 | oh->prcm.omap2.idlest_idle_bit); |
968 | } else if (cpu_is_omap44xx()) { | 1140 | } else if (cpu_is_omap44xx()) { |
969 | ret = omap4_cm_wait_module_ready(oh->prcm.omap4.clkctrl_reg); | 1141 | if (!oh->clkdm) |
1142 | return -EINVAL; | ||
1143 | |||
1144 | ret = omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition, | ||
1145 | oh->clkdm->cm_inst, | ||
1146 | oh->clkdm->clkdm_offs, | ||
1147 | oh->prcm.omap4.clkctrl_offs); | ||
970 | } else { | 1148 | } else { |
971 | BUG(); | 1149 | BUG(); |
972 | }; | 1150 | }; |
@@ -975,6 +1153,36 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
975 | } | 1153 | } |
976 | 1154 | ||
977 | /** | 1155 | /** |
1156 | * _wait_target_disable - wait for a module to be disabled | ||
1157 | * @oh: struct omap_hwmod * | ||
1158 | * | ||
1159 | * Wait for a module @oh to enter slave idle. Returns 0 if the module | ||
1160 | * does not have an IDLEST bit or if the module successfully enters | ||
1161 | * slave idle; otherwise, pass along the return value of the | ||
1162 | * appropriate *_cm*_wait_module_idle() function. | ||
1163 | */ | ||
1164 | static int _wait_target_disable(struct omap_hwmod *oh) | ||
1165 | { | ||
1166 | /* TODO: For now just handle OMAP4+ */ | ||
1167 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
1168 | return 0; | ||
1169 | |||
1170 | if (!oh) | ||
1171 | return -EINVAL; | ||
1172 | |||
1173 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | ||
1174 | return 0; | ||
1175 | |||
1176 | if (oh->flags & HWMOD_NO_IDLEST) | ||
1177 | return 0; | ||
1178 | |||
1179 | return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition, | ||
1180 | oh->clkdm->cm_inst, | ||
1181 | oh->clkdm->clkdm_offs, | ||
1182 | oh->prcm.omap4.clkctrl_offs); | ||
1183 | } | ||
1184 | |||
1185 | /** | ||
978 | * _lookup_hardreset - fill register bit info for this hwmod/reset line | 1186 | * _lookup_hardreset - fill register bit info for this hwmod/reset line |
979 | * @oh: struct omap_hwmod * | 1187 | * @oh: struct omap_hwmod * |
980 | * @name: name of the reset line in the context of this hwmod | 1188 | * @name: name of the reset line in the context of this hwmod |
@@ -1030,8 +1238,10 @@ static int _assert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1030 | return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, | 1238 | return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, |
1031 | ohri.rst_shift); | 1239 | ohri.rst_shift); |
1032 | else if (cpu_is_omap44xx()) | 1240 | else if (cpu_is_omap44xx()) |
1033 | return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg, | 1241 | return omap4_prminst_assert_hardreset(ohri.rst_shift, |
1034 | ohri.rst_shift); | 1242 | oh->clkdm->pwrdm.ptr->prcm_partition, |
1243 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
1244 | oh->prcm.omap4.rstctrl_offs); | ||
1035 | else | 1245 | else |
1036 | return -EINVAL; | 1246 | return -EINVAL; |
1037 | } | 1247 | } |
@@ -1066,8 +1276,10 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1066 | if (ohri.st_shift) | 1276 | if (ohri.st_shift) |
1067 | pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", | 1277 | pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", |
1068 | oh->name, name); | 1278 | oh->name, name); |
1069 | ret = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg, | 1279 | ret = omap4_prminst_deassert_hardreset(ohri.rst_shift, |
1070 | ohri.rst_shift); | 1280 | oh->clkdm->pwrdm.ptr->prcm_partition, |
1281 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
1282 | oh->prcm.omap4.rstctrl_offs); | ||
1071 | } else { | 1283 | } else { |
1072 | return -EINVAL; | 1284 | return -EINVAL; |
1073 | } | 1285 | } |
@@ -1102,8 +1314,10 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) | |||
1102 | return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, | 1314 | return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, |
1103 | ohri.st_shift); | 1315 | ohri.st_shift); |
1104 | } else if (cpu_is_omap44xx()) { | 1316 | } else if (cpu_is_omap44xx()) { |
1105 | return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg, | 1317 | return omap4_prminst_is_hardreset_asserted(ohri.rst_shift, |
1106 | ohri.rst_shift); | 1318 | oh->clkdm->pwrdm.ptr->prcm_partition, |
1319 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
1320 | oh->prcm.omap4.rstctrl_offs); | ||
1107 | } else { | 1321 | } else { |
1108 | return -EINVAL; | 1322 | return -EINVAL; |
1109 | } | 1323 | } |
@@ -1223,6 +1437,9 @@ static int _reset(struct omap_hwmod *oh) | |||
1223 | static int _enable(struct omap_hwmod *oh) | 1437 | static int _enable(struct omap_hwmod *oh) |
1224 | { | 1438 | { |
1225 | int r; | 1439 | int r; |
1440 | int hwsup = 0; | ||
1441 | |||
1442 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); | ||
1226 | 1443 | ||
1227 | if (oh->_state != _HWMOD_STATE_INITIALIZED && | 1444 | if (oh->_state != _HWMOD_STATE_INITIALIZED && |
1228 | oh->_state != _HWMOD_STATE_IDLE && | 1445 | oh->_state != _HWMOD_STATE_IDLE && |
@@ -1232,11 +1449,10 @@ static int _enable(struct omap_hwmod *oh) | |||
1232 | return -EINVAL; | 1449 | return -EINVAL; |
1233 | } | 1450 | } |
1234 | 1451 | ||
1235 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); | ||
1236 | 1452 | ||
1237 | /* | 1453 | /* |
1238 | * If an IP contains only one HW reset line, then de-assert it in order | 1454 | * If an IP contains only one HW reset line, then de-assert it in order |
1239 | * to allow to enable the clocks. Otherwise the PRCM will return | 1455 | * to allow the module state transition. Otherwise the PRCM will return |
1240 | * Intransition status, and the init will failed. | 1456 | * Intransition status, and the init will failed. |
1241 | */ | 1457 | */ |
1242 | if ((oh->_state == _HWMOD_STATE_INITIALIZED || | 1458 | if ((oh->_state == _HWMOD_STATE_INITIALIZED || |
@@ -1250,10 +1466,34 @@ static int _enable(struct omap_hwmod *oh) | |||
1250 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); | 1466 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); |
1251 | 1467 | ||
1252 | _add_initiator_dep(oh, mpu_oh); | 1468 | _add_initiator_dep(oh, mpu_oh); |
1469 | |||
1470 | if (oh->clkdm) { | ||
1471 | /* | ||
1472 | * A clockdomain must be in SW_SUP before enabling | ||
1473 | * completely the module. The clockdomain can be set | ||
1474 | * in HW_AUTO only when the module become ready. | ||
1475 | */ | ||
1476 | hwsup = clkdm_in_hwsup(oh->clkdm); | ||
1477 | r = clkdm_hwmod_enable(oh->clkdm, oh); | ||
1478 | if (r) { | ||
1479 | WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n", | ||
1480 | oh->name, oh->clkdm->name, r); | ||
1481 | return r; | ||
1482 | } | ||
1483 | } | ||
1484 | |||
1253 | _enable_clocks(oh); | 1485 | _enable_clocks(oh); |
1486 | _enable_module(oh); | ||
1254 | 1487 | ||
1255 | r = _wait_target_ready(oh); | 1488 | r = _wait_target_ready(oh); |
1256 | if (!r) { | 1489 | if (!r) { |
1490 | /* | ||
1491 | * Set the clockdomain to HW_AUTO only if the target is ready, | ||
1492 | * assuming that the previous state was HW_AUTO | ||
1493 | */ | ||
1494 | if (oh->clkdm && hwsup) | ||
1495 | clkdm_allow_idle(oh->clkdm); | ||
1496 | |||
1257 | oh->_state = _HWMOD_STATE_ENABLED; | 1497 | oh->_state = _HWMOD_STATE_ENABLED; |
1258 | 1498 | ||
1259 | /* Access the sysconfig only if the target is ready */ | 1499 | /* Access the sysconfig only if the target is ready */ |
@@ -1266,6 +1506,9 @@ static int _enable(struct omap_hwmod *oh) | |||
1266 | _disable_clocks(oh); | 1506 | _disable_clocks(oh); |
1267 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", | 1507 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", |
1268 | oh->name, r); | 1508 | oh->name, r); |
1509 | |||
1510 | if (oh->clkdm) | ||
1511 | clkdm_hwmod_disable(oh->clkdm, oh); | ||
1269 | } | 1512 | } |
1270 | 1513 | ||
1271 | return r; | 1514 | return r; |
@@ -1281,18 +1524,33 @@ static int _enable(struct omap_hwmod *oh) | |||
1281 | */ | 1524 | */ |
1282 | static int _idle(struct omap_hwmod *oh) | 1525 | static int _idle(struct omap_hwmod *oh) |
1283 | { | 1526 | { |
1527 | int ret; | ||
1528 | |||
1529 | pr_debug("omap_hwmod: %s: idling\n", oh->name); | ||
1530 | |||
1284 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 1531 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
1285 | WARN(1, "omap_hwmod: %s: idle state can only be entered from " | 1532 | WARN(1, "omap_hwmod: %s: idle state can only be entered from " |
1286 | "enabled state\n", oh->name); | 1533 | "enabled state\n", oh->name); |
1287 | return -EINVAL; | 1534 | return -EINVAL; |
1288 | } | 1535 | } |
1289 | 1536 | ||
1290 | pr_debug("omap_hwmod: %s: idling\n", oh->name); | ||
1291 | |||
1292 | if (oh->class->sysc) | 1537 | if (oh->class->sysc) |
1293 | _idle_sysc(oh); | 1538 | _idle_sysc(oh); |
1294 | _del_initiator_dep(oh, mpu_oh); | 1539 | _del_initiator_dep(oh, mpu_oh); |
1540 | _disable_module(oh); | ||
1541 | ret = _wait_target_disable(oh); | ||
1542 | if (ret) | ||
1543 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", | ||
1544 | oh->name); | ||
1545 | /* | ||
1546 | * The module must be in idle mode before disabling any parents | ||
1547 | * clocks. Otherwise, the parent clock might be disabled before | ||
1548 | * the module transition is done, and thus will prevent the | ||
1549 | * transition to complete properly. | ||
1550 | */ | ||
1295 | _disable_clocks(oh); | 1551 | _disable_clocks(oh); |
1552 | if (oh->clkdm) | ||
1553 | clkdm_hwmod_disable(oh->clkdm, oh); | ||
1296 | 1554 | ||
1297 | /* Mux pins for device idle if populated */ | 1555 | /* Mux pins for device idle if populated */ |
1298 | if (oh->mux && oh->mux->pads_dynamic) | 1556 | if (oh->mux && oh->mux->pads_dynamic) |
@@ -1374,24 +1632,34 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1374 | } | 1632 | } |
1375 | } | 1633 | } |
1376 | 1634 | ||
1377 | if (oh->class->sysc) | 1635 | if (oh->class->sysc) { |
1636 | if (oh->_state == _HWMOD_STATE_IDLE) | ||
1637 | _enable(oh); | ||
1378 | _shutdown_sysc(oh); | 1638 | _shutdown_sysc(oh); |
1379 | 1639 | } | |
1380 | /* | ||
1381 | * If an IP contains only one HW reset line, then assert it | ||
1382 | * before disabling the clocks and shutting down the IP. | ||
1383 | */ | ||
1384 | if (oh->rst_lines_cnt == 1) | ||
1385 | _assert_hardreset(oh, oh->rst_lines[0].name); | ||
1386 | 1640 | ||
1387 | /* clocks and deps are already disabled in idle */ | 1641 | /* clocks and deps are already disabled in idle */ |
1388 | if (oh->_state == _HWMOD_STATE_ENABLED) { | 1642 | if (oh->_state == _HWMOD_STATE_ENABLED) { |
1389 | _del_initiator_dep(oh, mpu_oh); | 1643 | _del_initiator_dep(oh, mpu_oh); |
1390 | /* XXX what about the other system initiators here? dma, dsp */ | 1644 | /* XXX what about the other system initiators here? dma, dsp */ |
1645 | _disable_module(oh); | ||
1646 | ret = _wait_target_disable(oh); | ||
1647 | if (ret) | ||
1648 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", | ||
1649 | oh->name); | ||
1391 | _disable_clocks(oh); | 1650 | _disable_clocks(oh); |
1651 | if (oh->clkdm) | ||
1652 | clkdm_hwmod_disable(oh->clkdm, oh); | ||
1392 | } | 1653 | } |
1393 | /* XXX Should this code also force-disable the optional clocks? */ | 1654 | /* XXX Should this code also force-disable the optional clocks? */ |
1394 | 1655 | ||
1656 | /* | ||
1657 | * If an IP contains only one HW reset line, then assert it | ||
1658 | * after disabling the clocks and before shutting down the IP. | ||
1659 | */ | ||
1660 | if (oh->rst_lines_cnt == 1) | ||
1661 | _assert_hardreset(oh, oh->rst_lines[0].name); | ||
1662 | |||
1395 | /* Mux pins to safe mode or use populated off mode values */ | 1663 | /* Mux pins to safe mode or use populated off mode values */ |
1396 | if (oh->mux) | 1664 | if (oh->mux) |
1397 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_DISABLED); | 1665 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_DISABLED); |
@@ -1562,6 +1830,33 @@ void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs) | |||
1562 | } | 1830 | } |
1563 | 1831 | ||
1564 | /** | 1832 | /** |
1833 | * omap_hwmod_softreset - reset a module via SYSCONFIG.SOFTRESET bit | ||
1834 | * @oh: struct omap_hwmod * | ||
1835 | * | ||
1836 | * This is a public function exposed to drivers. Some drivers may need to do | ||
1837 | * some settings before and after resetting the device. Those drivers after | ||
1838 | * doing the necessary settings could use this function to start a reset by | ||
1839 | * setting the SYSCONFIG.SOFTRESET bit. | ||
1840 | */ | ||
1841 | int omap_hwmod_softreset(struct omap_hwmod *oh) | ||
1842 | { | ||
1843 | u32 v; | ||
1844 | int ret; | ||
1845 | |||
1846 | if (!oh || !(oh->_sysc_cache)) | ||
1847 | return -EINVAL; | ||
1848 | |||
1849 | v = oh->_sysc_cache; | ||
1850 | ret = _set_softreset(oh, &v); | ||
1851 | if (ret) | ||
1852 | goto error; | ||
1853 | _write_sysconfig(v, oh); | ||
1854 | |||
1855 | error: | ||
1856 | return ret; | ||
1857 | } | ||
1858 | |||
1859 | /** | ||
1565 | * omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode | 1860 | * omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode |
1566 | * @oh: struct omap_hwmod * | 1861 | * @oh: struct omap_hwmod * |
1567 | * @idlemode: SIDLEMODE field bits (shifted to bit 0) | 1862 | * @idlemode: SIDLEMODE field bits (shifted to bit 0) |
@@ -1685,9 +1980,6 @@ static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data) | |||
1685 | return 0; | 1980 | return 0; |
1686 | 1981 | ||
1687 | oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); | 1982 | oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); |
1688 | if (!oh->_mpu_rt_va) | ||
1689 | pr_warning("omap_hwmod: %s found no _mpu_rt_va for %s\n", | ||
1690 | __func__, oh->name); | ||
1691 | 1983 | ||
1692 | return 0; | 1984 | return 0; |
1693 | } | 1985 | } |
@@ -1939,10 +2231,10 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) | |||
1939 | { | 2231 | { |
1940 | int ret, i; | 2232 | int ret, i; |
1941 | 2233 | ||
1942 | ret = oh->mpu_irqs_cnt + oh->sdma_reqs_cnt; | 2234 | ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh); |
1943 | 2235 | ||
1944 | for (i = 0; i < oh->slaves_cnt; i++) | 2236 | for (i = 0; i < oh->slaves_cnt; i++) |
1945 | ret += oh->slaves[i]->addr_cnt; | 2237 | ret += _count_ocp_if_addr_spaces(oh->slaves[i]); |
1946 | 2238 | ||
1947 | return ret; | 2239 | return ret; |
1948 | } | 2240 | } |
@@ -1959,12 +2251,13 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) | |||
1959 | */ | 2251 | */ |
1960 | int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | 2252 | int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) |
1961 | { | 2253 | { |
1962 | int i, j; | 2254 | int i, j, mpu_irqs_cnt, sdma_reqs_cnt; |
1963 | int r = 0; | 2255 | int r = 0; |
1964 | 2256 | ||
1965 | /* For each IRQ, DMA, memory area, fill in array.*/ | 2257 | /* For each IRQ, DMA, memory area, fill in array.*/ |
1966 | 2258 | ||
1967 | for (i = 0; i < oh->mpu_irqs_cnt; i++) { | 2259 | mpu_irqs_cnt = _count_mpu_irqs(oh); |
2260 | for (i = 0; i < mpu_irqs_cnt; i++) { | ||
1968 | (res + r)->name = (oh->mpu_irqs + i)->name; | 2261 | (res + r)->name = (oh->mpu_irqs + i)->name; |
1969 | (res + r)->start = (oh->mpu_irqs + i)->irq; | 2262 | (res + r)->start = (oh->mpu_irqs + i)->irq; |
1970 | (res + r)->end = (oh->mpu_irqs + i)->irq; | 2263 | (res + r)->end = (oh->mpu_irqs + i)->irq; |
@@ -1972,7 +2265,8 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
1972 | r++; | 2265 | r++; |
1973 | } | 2266 | } |
1974 | 2267 | ||
1975 | for (i = 0; i < oh->sdma_reqs_cnt; i++) { | 2268 | sdma_reqs_cnt = _count_sdma_reqs(oh); |
2269 | for (i = 0; i < sdma_reqs_cnt; i++) { | ||
1976 | (res + r)->name = (oh->sdma_reqs + i)->name; | 2270 | (res + r)->name = (oh->sdma_reqs + i)->name; |
1977 | (res + r)->start = (oh->sdma_reqs + i)->dma_req; | 2271 | (res + r)->start = (oh->sdma_reqs + i)->dma_req; |
1978 | (res + r)->end = (oh->sdma_reqs + i)->dma_req; | 2272 | (res + r)->end = (oh->sdma_reqs + i)->dma_req; |
@@ -1982,10 +2276,12 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
1982 | 2276 | ||
1983 | for (i = 0; i < oh->slaves_cnt; i++) { | 2277 | for (i = 0; i < oh->slaves_cnt; i++) { |
1984 | struct omap_hwmod_ocp_if *os; | 2278 | struct omap_hwmod_ocp_if *os; |
2279 | int addr_cnt; | ||
1985 | 2280 | ||
1986 | os = oh->slaves[i]; | 2281 | os = oh->slaves[i]; |
2282 | addr_cnt = _count_ocp_if_addr_spaces(os); | ||
1987 | 2283 | ||
1988 | for (j = 0; j < os->addr_cnt; j++) { | 2284 | for (j = 0; j < addr_cnt; j++) { |
1989 | (res + r)->name = (os->addr + j)->name; | 2285 | (res + r)->name = (os->addr + j)->name; |
1990 | (res + r)->start = (os->addr + j)->pa_start; | 2286 | (res + r)->start = (os->addr + j)->pa_start; |
1991 | (res + r)->end = (os->addr + j)->pa_end; | 2287 | (res + r)->end = (os->addr + j)->pa_end; |