diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 1143 |
1 files changed, 878 insertions, 265 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 7144ae651d3d..bf86f7e8f91f 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -2,7 +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 | * Copyright (C) 2011-2012 Texas Instruments, Inc. |
6 | * | 6 | * |
7 | * Paul Walmsley, Benoît Cousson, Kevin Hilman | 7 | * Paul Walmsley, Benoît Cousson, Kevin Hilman |
8 | * | 8 | * |
@@ -137,6 +137,7 @@ | |||
137 | #include <linux/mutex.h> | 137 | #include <linux/mutex.h> |
138 | #include <linux/spinlock.h> | 138 | #include <linux/spinlock.h> |
139 | #include <linux/slab.h> | 139 | #include <linux/slab.h> |
140 | #include <linux/bootmem.h> | ||
140 | 141 | ||
141 | #include "common.h" | 142 | #include "common.h" |
142 | #include <plat/cpu.h> | 143 | #include <plat/cpu.h> |
@@ -159,16 +160,58 @@ | |||
159 | /* Name of the OMAP hwmod for the MPU */ | 160 | /* Name of the OMAP hwmod for the MPU */ |
160 | #define MPU_INITIATOR_NAME "mpu" | 161 | #define MPU_INITIATOR_NAME "mpu" |
161 | 162 | ||
163 | /* | ||
164 | * Number of struct omap_hwmod_link records per struct | ||
165 | * omap_hwmod_ocp_if record (master->slave and slave->master) | ||
166 | */ | ||
167 | #define LINKS_PER_OCP_IF 2 | ||
168 | |||
162 | /* omap_hwmod_list contains all registered struct omap_hwmods */ | 169 | /* omap_hwmod_list contains all registered struct omap_hwmods */ |
163 | static LIST_HEAD(omap_hwmod_list); | 170 | static LIST_HEAD(omap_hwmod_list); |
164 | 171 | ||
165 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ | 172 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ |
166 | static struct omap_hwmod *mpu_oh; | 173 | static struct omap_hwmod *mpu_oh; |
167 | 174 | ||
175 | /* | ||
176 | * linkspace: ptr to a buffer that struct omap_hwmod_link records are | ||
177 | * allocated from - used to reduce the number of small memory | ||
178 | * allocations, which has a significant impact on performance | ||
179 | */ | ||
180 | static struct omap_hwmod_link *linkspace; | ||
181 | |||
182 | /* | ||
183 | * free_ls, max_ls: array indexes into linkspace; representing the | ||
184 | * next free struct omap_hwmod_link index, and the maximum number of | ||
185 | * struct omap_hwmod_link records allocated (respectively) | ||
186 | */ | ||
187 | static unsigned short free_ls, max_ls, ls_supp; | ||
168 | 188 | ||
169 | /* Private functions */ | 189 | /* Private functions */ |
170 | 190 | ||
171 | /** | 191 | /** |
192 | * _fetch_next_ocp_if - return the next OCP interface in a list | ||
193 | * @p: ptr to a ptr to the list_head inside the ocp_if to return | ||
194 | * @i: pointer to the index of the element pointed to by @p in the list | ||
195 | * | ||
196 | * Return a pointer to the struct omap_hwmod_ocp_if record | ||
197 | * containing the struct list_head pointed to by @p, and increment | ||
198 | * @p such that a future call to this routine will return the next | ||
199 | * record. | ||
200 | */ | ||
201 | static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p, | ||
202 | int *i) | ||
203 | { | ||
204 | struct omap_hwmod_ocp_if *oi; | ||
205 | |||
206 | oi = list_entry(*p, struct omap_hwmod_link, node)->ocp_if; | ||
207 | *p = (*p)->next; | ||
208 | |||
209 | *i = *i + 1; | ||
210 | |||
211 | return oi; | ||
212 | } | ||
213 | |||
214 | /** | ||
172 | * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy | 215 | * _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy |
173 | * @oh: struct omap_hwmod * | 216 | * @oh: struct omap_hwmod * |
174 | * | 217 | * |
@@ -582,16 +625,16 @@ static int _init_main_clk(struct omap_hwmod *oh) | |||
582 | */ | 625 | */ |
583 | static int _init_interface_clks(struct omap_hwmod *oh) | 626 | static int _init_interface_clks(struct omap_hwmod *oh) |
584 | { | 627 | { |
628 | struct omap_hwmod_ocp_if *os; | ||
629 | struct list_head *p; | ||
585 | struct clk *c; | 630 | struct clk *c; |
586 | int i; | 631 | int i = 0; |
587 | int ret = 0; | 632 | int ret = 0; |
588 | 633 | ||
589 | if (oh->slaves_cnt == 0) | 634 | p = oh->slave_ports.next; |
590 | return 0; | ||
591 | |||
592 | for (i = 0; i < oh->slaves_cnt; i++) { | ||
593 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
594 | 635 | ||
636 | while (i < oh->slaves_cnt) { | ||
637 | os = _fetch_next_ocp_if(&p, &i); | ||
595 | if (!os->clk) | 638 | if (!os->clk) |
596 | continue; | 639 | continue; |
597 | 640 | ||
@@ -643,21 +686,22 @@ static int _init_opt_clks(struct omap_hwmod *oh) | |||
643 | */ | 686 | */ |
644 | static int _enable_clocks(struct omap_hwmod *oh) | 687 | static int _enable_clocks(struct omap_hwmod *oh) |
645 | { | 688 | { |
646 | int i; | 689 | struct omap_hwmod_ocp_if *os; |
690 | struct list_head *p; | ||
691 | int i = 0; | ||
647 | 692 | ||
648 | pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); | 693 | pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); |
649 | 694 | ||
650 | if (oh->_clk) | 695 | if (oh->_clk) |
651 | clk_enable(oh->_clk); | 696 | clk_enable(oh->_clk); |
652 | 697 | ||
653 | if (oh->slaves_cnt > 0) { | 698 | p = oh->slave_ports.next; |
654 | for (i = 0; i < oh->slaves_cnt; i++) { | ||
655 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
656 | struct clk *c = os->_clk; | ||
657 | 699 | ||
658 | if (c && (os->flags & OCPIF_SWSUP_IDLE)) | 700 | while (i < oh->slaves_cnt) { |
659 | clk_enable(c); | 701 | os = _fetch_next_ocp_if(&p, &i); |
660 | } | 702 | |
703 | if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) | ||
704 | clk_enable(os->_clk); | ||
661 | } | 705 | } |
662 | 706 | ||
663 | /* The opt clocks are controlled by the device driver. */ | 707 | /* The opt clocks are controlled by the device driver. */ |
@@ -673,21 +717,22 @@ static int _enable_clocks(struct omap_hwmod *oh) | |||
673 | */ | 717 | */ |
674 | static int _disable_clocks(struct omap_hwmod *oh) | 718 | static int _disable_clocks(struct omap_hwmod *oh) |
675 | { | 719 | { |
676 | int i; | 720 | struct omap_hwmod_ocp_if *os; |
721 | struct list_head *p; | ||
722 | int i = 0; | ||
677 | 723 | ||
678 | pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); | 724 | pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); |
679 | 725 | ||
680 | if (oh->_clk) | 726 | if (oh->_clk) |
681 | clk_disable(oh->_clk); | 727 | clk_disable(oh->_clk); |
682 | 728 | ||
683 | if (oh->slaves_cnt > 0) { | 729 | p = oh->slave_ports.next; |
684 | for (i = 0; i < oh->slaves_cnt; i++) { | ||
685 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
686 | struct clk *c = os->_clk; | ||
687 | 730 | ||
688 | if (c && (os->flags & OCPIF_SWSUP_IDLE)) | 731 | while (i < oh->slaves_cnt) { |
689 | clk_disable(c); | 732 | os = _fetch_next_ocp_if(&p, &i); |
690 | } | 733 | |
734 | if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) | ||
735 | clk_disable(os->_clk); | ||
691 | } | 736 | } |
692 | 737 | ||
693 | /* The opt clocks are controlled by the device driver. */ | 738 | /* The opt clocks are controlled by the device driver. */ |
@@ -781,39 +826,6 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) | |||
781 | } | 826 | } |
782 | 827 | ||
783 | /** | 828 | /** |
784 | * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4 | ||
785 | * @oh: struct omap_hwmod * | ||
786 | * | ||
787 | * Disable the PRCM module mode related to the hwmod @oh. | ||
788 | * Return EINVAL if the modulemode is not supported and 0 in case of success. | ||
789 | */ | ||
790 | static int _omap4_disable_module(struct omap_hwmod *oh) | ||
791 | { | ||
792 | int v; | ||
793 | |||
794 | /* The module mode does not exist prior OMAP4 */ | ||
795 | if (!cpu_is_omap44xx()) | ||
796 | return -EINVAL; | ||
797 | |||
798 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) | ||
799 | return -EINVAL; | ||
800 | |||
801 | pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); | ||
802 | |||
803 | omap4_cminst_module_disable(oh->clkdm->prcm_partition, | ||
804 | oh->clkdm->cm_inst, | ||
805 | oh->clkdm->clkdm_offs, | ||
806 | oh->prcm.omap4.clkctrl_offs); | ||
807 | |||
808 | v = _omap4_wait_target_disable(oh); | ||
809 | if (v) | ||
810 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", | ||
811 | oh->name); | ||
812 | |||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | /** | ||
817 | * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh | 829 | * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh |
818 | * @oh: struct omap_hwmod *oh | 830 | * @oh: struct omap_hwmod *oh |
819 | * | 831 | * |
@@ -883,59 +895,220 @@ static int _count_ocp_if_addr_spaces(struct omap_hwmod_ocp_if *os) | |||
883 | } | 895 | } |
884 | 896 | ||
885 | /** | 897 | /** |
886 | * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use | 898 | * _get_mpu_irq_by_name - fetch MPU interrupt line number by name |
887 | * @oh: struct omap_hwmod * | 899 | * @oh: struct omap_hwmod * to operate on |
900 | * @name: pointer to the name of the MPU interrupt number to fetch (optional) | ||
901 | * @irq: pointer to an unsigned int to store the MPU IRQ number to | ||
888 | * | 902 | * |
889 | * Returns the array index of the OCP slave port that the MPU | 903 | * Retrieve a MPU hardware IRQ line number named by @name associated |
890 | * addresses the device on, or -EINVAL upon error or not found. | 904 | * with the IP block pointed to by @oh. The IRQ number will be filled |
905 | * into the address pointed to by @dma. When @name is non-null, the | ||
906 | * IRQ line number associated with the named entry will be returned. | ||
907 | * If @name is null, the first matching entry will be returned. Data | ||
908 | * order is not meaningful in hwmod data, so callers are strongly | ||
909 | * encouraged to use a non-null @name whenever possible to avoid | ||
910 | * unpredictable effects if hwmod data is later added that causes data | ||
911 | * ordering to change. Returns 0 upon success or a negative error | ||
912 | * code upon error. | ||
891 | */ | 913 | */ |
892 | static int __init _find_mpu_port_index(struct omap_hwmod *oh) | 914 | static int _get_mpu_irq_by_name(struct omap_hwmod *oh, const char *name, |
915 | unsigned int *irq) | ||
893 | { | 916 | { |
894 | int i; | 917 | int i; |
895 | int found = 0; | 918 | bool found = false; |
896 | 919 | ||
897 | if (!oh || oh->slaves_cnt == 0) | 920 | if (!oh->mpu_irqs) |
898 | return -EINVAL; | 921 | return -ENOENT; |
899 | 922 | ||
900 | for (i = 0; i < oh->slaves_cnt; i++) { | 923 | i = 0; |
901 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | 924 | while (oh->mpu_irqs[i].irq != -1) { |
925 | if (name == oh->mpu_irqs[i].name || | ||
926 | !strcmp(name, oh->mpu_irqs[i].name)) { | ||
927 | found = true; | ||
928 | break; | ||
929 | } | ||
930 | i++; | ||
931 | } | ||
902 | 932 | ||
903 | if (os->user & OCP_USER_MPU) { | 933 | if (!found) |
904 | found = 1; | 934 | return -ENOENT; |
935 | |||
936 | *irq = oh->mpu_irqs[i].irq; | ||
937 | |||
938 | return 0; | ||
939 | } | ||
940 | |||
941 | /** | ||
942 | * _get_sdma_req_by_name - fetch SDMA request line ID by name | ||
943 | * @oh: struct omap_hwmod * to operate on | ||
944 | * @name: pointer to the name of the SDMA request line to fetch (optional) | ||
945 | * @dma: pointer to an unsigned int to store the request line ID to | ||
946 | * | ||
947 | * Retrieve an SDMA request line ID named by @name on the IP block | ||
948 | * pointed to by @oh. The ID will be filled into the address pointed | ||
949 | * to by @dma. When @name is non-null, the request line ID associated | ||
950 | * with the named entry will be returned. If @name is null, the first | ||
951 | * matching entry will be returned. Data order is not meaningful in | ||
952 | * hwmod data, so callers are strongly encouraged to use a non-null | ||
953 | * @name whenever possible to avoid unpredictable effects if hwmod | ||
954 | * data is later added that causes data ordering to change. Returns 0 | ||
955 | * upon success or a negative error code upon error. | ||
956 | */ | ||
957 | static int _get_sdma_req_by_name(struct omap_hwmod *oh, const char *name, | ||
958 | unsigned int *dma) | ||
959 | { | ||
960 | int i; | ||
961 | bool found = false; | ||
962 | |||
963 | if (!oh->sdma_reqs) | ||
964 | return -ENOENT; | ||
965 | |||
966 | i = 0; | ||
967 | while (oh->sdma_reqs[i].dma_req != -1) { | ||
968 | if (name == oh->sdma_reqs[i].name || | ||
969 | !strcmp(name, oh->sdma_reqs[i].name)) { | ||
970 | found = true; | ||
905 | break; | 971 | break; |
906 | } | 972 | } |
973 | i++; | ||
907 | } | 974 | } |
908 | 975 | ||
909 | if (found) | 976 | if (!found) |
910 | pr_debug("omap_hwmod: %s: MPU OCP slave port ID %d\n", | 977 | return -ENOENT; |
911 | oh->name, i); | 978 | |
912 | else | 979 | *dma = oh->sdma_reqs[i].dma_req; |
913 | pr_debug("omap_hwmod: %s: no MPU OCP slave port found\n", | ||
914 | oh->name); | ||
915 | 980 | ||
916 | return (found) ? i : -EINVAL; | 981 | return 0; |
917 | } | 982 | } |
918 | 983 | ||
919 | /** | 984 | /** |
920 | * _find_mpu_rt_base - find hwmod register target base addr accessible by MPU | 985 | * _get_addr_space_by_name - fetch address space start & end by name |
921 | * @oh: struct omap_hwmod * | 986 | * @oh: struct omap_hwmod * to operate on |
987 | * @name: pointer to the name of the address space to fetch (optional) | ||
988 | * @pa_start: pointer to a u32 to store the starting address to | ||
989 | * @pa_end: pointer to a u32 to store the ending address to | ||
922 | * | 990 | * |
923 | * Return the virtual address of the base of the register target of | 991 | * Retrieve address space start and end addresses for the IP block |
924 | * device @oh, or NULL on error. | 992 | * pointed to by @oh. The data will be filled into the addresses |
993 | * pointed to by @pa_start and @pa_end. When @name is non-null, the | ||
994 | * address space data associated with the named entry will be | ||
995 | * returned. If @name is null, the first matching entry will be | ||
996 | * returned. Data order is not meaningful in hwmod data, so callers | ||
997 | * are strongly encouraged to use a non-null @name whenever possible | ||
998 | * to avoid unpredictable effects if hwmod data is later added that | ||
999 | * causes data ordering to change. Returns 0 upon success or a | ||
1000 | * negative error code upon error. | ||
925 | */ | 1001 | */ |
926 | static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index) | 1002 | static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name, |
1003 | u32 *pa_start, u32 *pa_end) | ||
927 | { | 1004 | { |
1005 | int i, j; | ||
928 | struct omap_hwmod_ocp_if *os; | 1006 | struct omap_hwmod_ocp_if *os; |
929 | struct omap_hwmod_addr_space *mem; | 1007 | struct list_head *p = NULL; |
930 | int i = 0, found = 0; | 1008 | bool found = false; |
931 | void __iomem *va_start; | 1009 | |
1010 | p = oh->slave_ports.next; | ||
1011 | |||
1012 | i = 0; | ||
1013 | while (i < oh->slaves_cnt) { | ||
1014 | os = _fetch_next_ocp_if(&p, &i); | ||
1015 | |||
1016 | if (!os->addr) | ||
1017 | return -ENOENT; | ||
1018 | |||
1019 | j = 0; | ||
1020 | while (os->addr[j].pa_start != os->addr[j].pa_end) { | ||
1021 | if (name == os->addr[j].name || | ||
1022 | !strcmp(name, os->addr[j].name)) { | ||
1023 | found = true; | ||
1024 | break; | ||
1025 | } | ||
1026 | j++; | ||
1027 | } | ||
1028 | |||
1029 | if (found) | ||
1030 | break; | ||
1031 | } | ||
1032 | |||
1033 | if (!found) | ||
1034 | return -ENOENT; | ||
1035 | |||
1036 | *pa_start = os->addr[j].pa_start; | ||
1037 | *pa_end = os->addr[j].pa_end; | ||
1038 | |||
1039 | return 0; | ||
1040 | } | ||
1041 | |||
1042 | /** | ||
1043 | * _save_mpu_port_index - find and save the index to @oh's MPU port | ||
1044 | * @oh: struct omap_hwmod * | ||
1045 | * | ||
1046 | * Determines the array index of the OCP slave port that the MPU uses | ||
1047 | * to address the device, and saves it into the struct omap_hwmod. | ||
1048 | * Intended to be called during hwmod registration only. No return | ||
1049 | * value. | ||
1050 | */ | ||
1051 | static void __init _save_mpu_port_index(struct omap_hwmod *oh) | ||
1052 | { | ||
1053 | struct omap_hwmod_ocp_if *os = NULL; | ||
1054 | struct list_head *p; | ||
1055 | int i = 0; | ||
1056 | |||
1057 | if (!oh) | ||
1058 | return; | ||
932 | 1059 | ||
933 | if (!oh || oh->slaves_cnt == 0) | 1060 | oh->_int_flags |= _HWMOD_NO_MPU_PORT; |
1061 | |||
1062 | p = oh->slave_ports.next; | ||
1063 | |||
1064 | while (i < oh->slaves_cnt) { | ||
1065 | os = _fetch_next_ocp_if(&p, &i); | ||
1066 | if (os->user & OCP_USER_MPU) { | ||
1067 | oh->_mpu_port = os; | ||
1068 | oh->_int_flags &= ~_HWMOD_NO_MPU_PORT; | ||
1069 | break; | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | return; | ||
1074 | } | ||
1075 | |||
1076 | /** | ||
1077 | * _find_mpu_rt_port - return omap_hwmod_ocp_if accessible by the MPU | ||
1078 | * @oh: struct omap_hwmod * | ||
1079 | * | ||
1080 | * Given a pointer to a struct omap_hwmod record @oh, return a pointer | ||
1081 | * to the struct omap_hwmod_ocp_if record that is used by the MPU to | ||
1082 | * communicate with the IP block. This interface need not be directly | ||
1083 | * connected to the MPU (and almost certainly is not), but is directly | ||
1084 | * connected to the IP block represented by @oh. Returns a pointer | ||
1085 | * to the struct omap_hwmod_ocp_if * upon success, or returns NULL upon | ||
1086 | * error or if there does not appear to be a path from the MPU to this | ||
1087 | * IP block. | ||
1088 | */ | ||
1089 | static struct omap_hwmod_ocp_if *_find_mpu_rt_port(struct omap_hwmod *oh) | ||
1090 | { | ||
1091 | if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0) | ||
934 | return NULL; | 1092 | return NULL; |
935 | 1093 | ||
936 | os = oh->slaves[index]; | 1094 | return oh->_mpu_port; |
1095 | }; | ||
1096 | |||
1097 | /** | ||
1098 | * _find_mpu_rt_addr_space - return MPU register target address space for @oh | ||
1099 | * @oh: struct omap_hwmod * | ||
1100 | * | ||
1101 | * Returns a pointer to the struct omap_hwmod_addr_space record representing | ||
1102 | * the register target MPU address space; or returns NULL upon error. | ||
1103 | */ | ||
1104 | static struct omap_hwmod_addr_space * __init _find_mpu_rt_addr_space(struct omap_hwmod *oh) | ||
1105 | { | ||
1106 | struct omap_hwmod_ocp_if *os; | ||
1107 | struct omap_hwmod_addr_space *mem; | ||
1108 | int found = 0, i = 0; | ||
937 | 1109 | ||
938 | if (!os->addr) | 1110 | os = _find_mpu_rt_port(oh); |
1111 | if (!os || !os->addr) | ||
939 | return NULL; | 1112 | return NULL; |
940 | 1113 | ||
941 | do { | 1114 | do { |
@@ -944,20 +1117,7 @@ static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index) | |||
944 | found = 1; | 1117 | found = 1; |
945 | } while (!found && mem->pa_start != mem->pa_end); | 1118 | } while (!found && mem->pa_start != mem->pa_end); |
946 | 1119 | ||
947 | if (found) { | 1120 | return (found) ? mem : NULL; |
948 | va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); | ||
949 | if (!va_start) { | ||
950 | pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name); | ||
951 | return NULL; | ||
952 | } | ||
953 | pr_debug("omap_hwmod: %s: MPU register target at va %p\n", | ||
954 | oh->name, va_start); | ||
955 | } else { | ||
956 | pr_debug("omap_hwmod: %s: no MPU register target found\n", | ||
957 | oh->name); | ||
958 | } | ||
959 | |||
960 | return (found) ? va_start : NULL; | ||
961 | } | 1121 | } |
962 | 1122 | ||
963 | /** | 1123 | /** |
@@ -1205,12 +1365,11 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
1205 | if (!oh) | 1365 | if (!oh) |
1206 | return -EINVAL; | 1366 | return -EINVAL; |
1207 | 1367 | ||
1208 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | 1368 | if (oh->flags & HWMOD_NO_IDLEST) |
1209 | return 0; | 1369 | return 0; |
1210 | 1370 | ||
1211 | os = oh->slaves[oh->_mpu_port_index]; | 1371 | os = _find_mpu_rt_port(oh); |
1212 | 1372 | if (!os) | |
1213 | if (oh->flags & HWMOD_NO_IDLEST) | ||
1214 | return 0; | 1373 | return 0; |
1215 | 1374 | ||
1216 | /* XXX check module SIDLEMODE */ | 1375 | /* XXX check module SIDLEMODE */ |
@@ -1378,13 +1537,73 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) | |||
1378 | } | 1537 | } |
1379 | 1538 | ||
1380 | /** | 1539 | /** |
1540 | * _are_any_hardreset_lines_asserted - return true if part of @oh is hard-reset | ||
1541 | * @oh: struct omap_hwmod * | ||
1542 | * | ||
1543 | * If any hardreset line associated with @oh is asserted, then return true. | ||
1544 | * Otherwise, if @oh has no hardreset lines associated with it, or if | ||
1545 | * no hardreset lines associated with @oh are asserted, then return false. | ||
1546 | * This function is used to avoid executing some parts of the IP block | ||
1547 | * enable/disable sequence if a hardreset line is set. | ||
1548 | */ | ||
1549 | static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh) | ||
1550 | { | ||
1551 | int i; | ||
1552 | |||
1553 | if (oh->rst_lines_cnt == 0) | ||
1554 | return false; | ||
1555 | |||
1556 | for (i = 0; i < oh->rst_lines_cnt; i++) | ||
1557 | if (_read_hardreset(oh, oh->rst_lines[i].name) > 0) | ||
1558 | return true; | ||
1559 | |||
1560 | return false; | ||
1561 | } | ||
1562 | |||
1563 | /** | ||
1564 | * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4 | ||
1565 | * @oh: struct omap_hwmod * | ||
1566 | * | ||
1567 | * Disable the PRCM module mode related to the hwmod @oh. | ||
1568 | * Return EINVAL if the modulemode is not supported and 0 in case of success. | ||
1569 | */ | ||
1570 | static int _omap4_disable_module(struct omap_hwmod *oh) | ||
1571 | { | ||
1572 | int v; | ||
1573 | |||
1574 | /* The module mode does not exist prior OMAP4 */ | ||
1575 | if (!cpu_is_omap44xx()) | ||
1576 | return -EINVAL; | ||
1577 | |||
1578 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) | ||
1579 | return -EINVAL; | ||
1580 | |||
1581 | pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); | ||
1582 | |||
1583 | omap4_cminst_module_disable(oh->clkdm->prcm_partition, | ||
1584 | oh->clkdm->cm_inst, | ||
1585 | oh->clkdm->clkdm_offs, | ||
1586 | oh->prcm.omap4.clkctrl_offs); | ||
1587 | |||
1588 | if (_are_any_hardreset_lines_asserted(oh)) | ||
1589 | return 0; | ||
1590 | |||
1591 | v = _omap4_wait_target_disable(oh); | ||
1592 | if (v) | ||
1593 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", | ||
1594 | oh->name); | ||
1595 | |||
1596 | return 0; | ||
1597 | } | ||
1598 | |||
1599 | /** | ||
1381 | * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit | 1600 | * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit |
1382 | * @oh: struct omap_hwmod * | 1601 | * @oh: struct omap_hwmod * |
1383 | * | 1602 | * |
1384 | * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be | 1603 | * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be |
1385 | * enabled for this to work. Returns -EINVAL if the hwmod cannot be | 1604 | * enabled for this to work. Returns -ENOENT if the hwmod cannot be |
1386 | * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if | 1605 | * reset this way, -EINVAL if the hwmod is in the wrong state, |
1387 | * the module did not reset in time, or 0 upon success. | 1606 | * -ETIMEDOUT if the module did not reset in time, or 0 upon success. |
1388 | * | 1607 | * |
1389 | * In OMAP3 a specific SYSSTATUS register is used to get the reset status. | 1608 | * In OMAP3 a specific SYSSTATUS register is used to get the reset status. |
1390 | * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead | 1609 | * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead |
@@ -1401,7 +1620,7 @@ static int _ocp_softreset(struct omap_hwmod *oh) | |||
1401 | 1620 | ||
1402 | if (!oh->class->sysc || | 1621 | if (!oh->class->sysc || |
1403 | !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) | 1622 | !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) |
1404 | return -EINVAL; | 1623 | return -ENOENT; |
1405 | 1624 | ||
1406 | /* clocks must be on for this operation */ | 1625 | /* clocks must be on for this operation */ |
1407 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 1626 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
@@ -1462,32 +1681,60 @@ dis_opt_clks: | |||
1462 | * _reset - reset an omap_hwmod | 1681 | * _reset - reset an omap_hwmod |
1463 | * @oh: struct omap_hwmod * | 1682 | * @oh: struct omap_hwmod * |
1464 | * | 1683 | * |
1465 | * Resets an omap_hwmod @oh. The default software reset mechanism for | 1684 | * Resets an omap_hwmod @oh. If the module has a custom reset |
1466 | * most OMAP IP blocks is triggered via the OCP_SYSCONFIG.SOFTRESET | 1685 | * function pointer defined, then call it to reset the IP block, and |
1467 | * bit. However, some hwmods cannot be reset via this method: some | 1686 | * pass along its return value to the caller. Otherwise, if the IP |
1468 | * are not targets and therefore have no OCP header registers to | 1687 | * block has an OCP_SYSCONFIG register with a SOFTRESET bitfield |
1469 | * access; others (like the IVA) have idiosyncratic reset sequences. | 1688 | * associated with it, call a function to reset the IP block via that |
1470 | * So for these relatively rare cases, custom reset code can be | 1689 | * method, and pass along the return value to the caller. Finally, if |
1471 | * supplied in the struct omap_hwmod_class .reset function pointer. | 1690 | * the IP block has some hardreset lines associated with it, assert |
1472 | * Passes along the return value from either _reset() or the custom | 1691 | * all of those, but do _not_ deassert them. (This is because driver |
1473 | * reset function - these must return -EINVAL if the hwmod cannot be | 1692 | * authors have expressed an apparent requirement to control the |
1474 | * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if | 1693 | * deassertion of the hardreset lines themselves.) |
1475 | * the module did not reset in time, or 0 upon success. | 1694 | * |
1695 | * The default software reset mechanism for most OMAP IP blocks is | ||
1696 | * triggered via the OCP_SYSCONFIG.SOFTRESET bit. However, some | ||
1697 | * hwmods cannot be reset via this method. Some are not targets and | ||
1698 | * therefore have no OCP header registers to access. Others (like the | ||
1699 | * IVA) have idiosyncratic reset sequences. So for these relatively | ||
1700 | * rare cases, custom reset code can be supplied in the struct | ||
1701 | * omap_hwmod_class .reset function pointer. Passes along the return | ||
1702 | * value from either _ocp_softreset() or the custom reset function - | ||
1703 | * these must return -EINVAL if the hwmod cannot be reset this way or | ||
1704 | * if the hwmod is in the wrong state, -ETIMEDOUT if the module did | ||
1705 | * not reset in time, or 0 upon success. | ||
1476 | */ | 1706 | */ |
1477 | static int _reset(struct omap_hwmod *oh) | 1707 | static int _reset(struct omap_hwmod *oh) |
1478 | { | 1708 | { |
1479 | int ret; | 1709 | int i, r; |
1480 | 1710 | ||
1481 | pr_debug("omap_hwmod: %s: resetting\n", oh->name); | 1711 | pr_debug("omap_hwmod: %s: resetting\n", oh->name); |
1482 | 1712 | ||
1483 | ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh); | 1713 | if (oh->class->reset) { |
1714 | r = oh->class->reset(oh); | ||
1715 | } else { | ||
1716 | if (oh->rst_lines_cnt > 0) { | ||
1717 | for (i = 0; i < oh->rst_lines_cnt; i++) | ||
1718 | _assert_hardreset(oh, oh->rst_lines[i].name); | ||
1719 | return 0; | ||
1720 | } else { | ||
1721 | r = _ocp_softreset(oh); | ||
1722 | if (r == -ENOENT) | ||
1723 | r = 0; | ||
1724 | } | ||
1725 | } | ||
1484 | 1726 | ||
1727 | /* | ||
1728 | * OCP_SYSCONFIG bits need to be reprogrammed after a | ||
1729 | * softreset. The _enable() function should be split to avoid | ||
1730 | * the rewrite of the OCP_SYSCONFIG register. | ||
1731 | */ | ||
1485 | if (oh->class->sysc) { | 1732 | if (oh->class->sysc) { |
1486 | _update_sysc_cache(oh); | 1733 | _update_sysc_cache(oh); |
1487 | _enable_sysc(oh); | 1734 | _enable_sysc(oh); |
1488 | } | 1735 | } |
1489 | 1736 | ||
1490 | return ret; | 1737 | return r; |
1491 | } | 1738 | } |
1492 | 1739 | ||
1493 | /** | 1740 | /** |
@@ -1506,10 +1753,9 @@ static int _enable(struct omap_hwmod *oh) | |||
1506 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); | 1753 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); |
1507 | 1754 | ||
1508 | /* | 1755 | /* |
1509 | * hwmods with HWMOD_INIT_NO_IDLE flag set are left | 1756 | * hwmods with HWMOD_INIT_NO_IDLE flag set are left in enabled |
1510 | * in enabled state at init. | 1757 | * state at init. Now that someone is really trying to enable |
1511 | * Now that someone is really trying to enable them, | 1758 | * them, just ensure that the hwmod mux is set. |
1512 | * just ensure that the hwmod mux is set. | ||
1513 | */ | 1759 | */ |
1514 | if (oh->_int_flags & _HWMOD_SKIP_ENABLE) { | 1760 | if (oh->_int_flags & _HWMOD_SKIP_ENABLE) { |
1515 | /* | 1761 | /* |
@@ -1532,15 +1778,17 @@ static int _enable(struct omap_hwmod *oh) | |||
1532 | return -EINVAL; | 1778 | return -EINVAL; |
1533 | } | 1779 | } |
1534 | 1780 | ||
1535 | |||
1536 | /* | 1781 | /* |
1537 | * If an IP contains only one HW reset line, then de-assert it in order | 1782 | * If an IP block contains HW reset lines and any of them are |
1538 | * to allow the module state transition. Otherwise the PRCM will return | 1783 | * asserted, we let integration code associated with that |
1539 | * Intransition status, and the init will failed. | 1784 | * block handle the enable. We've received very little |
1785 | * information on what those driver authors need, and until | ||
1786 | * detailed information is provided and the driver code is | ||
1787 | * posted to the public lists, this is probably the best we | ||
1788 | * can do. | ||
1540 | */ | 1789 | */ |
1541 | if ((oh->_state == _HWMOD_STATE_INITIALIZED || | 1790 | if (_are_any_hardreset_lines_asserted(oh)) |
1542 | oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) | 1791 | return 0; |
1543 | _deassert_hardreset(oh, oh->rst_lines[0].name); | ||
1544 | 1792 | ||
1545 | /* Mux pins for device runtime if populated */ | 1793 | /* Mux pins for device runtime if populated */ |
1546 | if (oh->mux && (!oh->mux->enabled || | 1794 | if (oh->mux && (!oh->mux->enabled || |
@@ -1615,6 +1863,9 @@ static int _idle(struct omap_hwmod *oh) | |||
1615 | return -EINVAL; | 1863 | return -EINVAL; |
1616 | } | 1864 | } |
1617 | 1865 | ||
1866 | if (_are_any_hardreset_lines_asserted(oh)) | ||
1867 | return 0; | ||
1868 | |||
1618 | if (oh->class->sysc) | 1869 | if (oh->class->sysc) |
1619 | _idle_sysc(oh); | 1870 | _idle_sysc(oh); |
1620 | _del_initiator_dep(oh, mpu_oh); | 1871 | _del_initiator_dep(oh, mpu_oh); |
@@ -1687,7 +1938,7 @@ int omap_hwmod_set_ocp_autoidle(struct omap_hwmod *oh, u8 autoidle) | |||
1687 | */ | 1938 | */ |
1688 | static int _shutdown(struct omap_hwmod *oh) | 1939 | static int _shutdown(struct omap_hwmod *oh) |
1689 | { | 1940 | { |
1690 | int ret; | 1941 | int ret, i; |
1691 | u8 prev_state; | 1942 | u8 prev_state; |
1692 | 1943 | ||
1693 | if (oh->_state != _HWMOD_STATE_IDLE && | 1944 | if (oh->_state != _HWMOD_STATE_IDLE && |
@@ -1697,6 +1948,9 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1697 | return -EINVAL; | 1948 | return -EINVAL; |
1698 | } | 1949 | } |
1699 | 1950 | ||
1951 | if (_are_any_hardreset_lines_asserted(oh)) | ||
1952 | return 0; | ||
1953 | |||
1700 | pr_debug("omap_hwmod: %s: disabling\n", oh->name); | 1954 | pr_debug("omap_hwmod: %s: disabling\n", oh->name); |
1701 | 1955 | ||
1702 | if (oh->class->pre_shutdown) { | 1956 | if (oh->class->pre_shutdown) { |
@@ -1728,12 +1982,8 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1728 | } | 1982 | } |
1729 | /* XXX Should this code also force-disable the optional clocks? */ | 1983 | /* XXX Should this code also force-disable the optional clocks? */ |
1730 | 1984 | ||
1731 | /* | 1985 | for (i = 0; i < oh->rst_lines_cnt; i++) |
1732 | * If an IP contains only one HW reset line, then assert it | 1986 | _assert_hardreset(oh, oh->rst_lines[i].name); |
1733 | * after disabling the clocks and before shutting down the IP. | ||
1734 | */ | ||
1735 | if (oh->rst_lines_cnt == 1) | ||
1736 | _assert_hardreset(oh, oh->rst_lines[0].name); | ||
1737 | 1987 | ||
1738 | /* Mux pins to safe mode or use populated off mode values */ | 1988 | /* Mux pins to safe mode or use populated off mode values */ |
1739 | if (oh->mux) | 1989 | if (oh->mux) |
@@ -1745,59 +1995,186 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1745 | } | 1995 | } |
1746 | 1996 | ||
1747 | /** | 1997 | /** |
1748 | * _setup - do initial configuration of omap_hwmod | 1998 | * _init_mpu_rt_base - populate the virtual address for a hwmod |
1749 | * @oh: struct omap_hwmod * | 1999 | * @oh: struct omap_hwmod * to locate the virtual address |
1750 | * | 2000 | * |
1751 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh | 2001 | * Cache the virtual address used by the MPU to access this IP block's |
1752 | * OCP_SYSCONFIG register. Returns 0. | 2002 | * registers. This address is needed early so the OCP registers that |
2003 | * are part of the device's address space can be ioremapped properly. | ||
2004 | * No return value. | ||
1753 | */ | 2005 | */ |
1754 | static int _setup(struct omap_hwmod *oh, void *data) | 2006 | static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data) |
1755 | { | 2007 | { |
1756 | int i, r; | 2008 | struct omap_hwmod_addr_space *mem; |
1757 | u8 postsetup_state; | 2009 | void __iomem *va_start; |
2010 | |||
2011 | if (!oh) | ||
2012 | return; | ||
2013 | |||
2014 | _save_mpu_port_index(oh); | ||
1758 | 2015 | ||
1759 | if (oh->_state != _HWMOD_STATE_CLKS_INITED) | 2016 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) |
2017 | return; | ||
2018 | |||
2019 | mem = _find_mpu_rt_addr_space(oh); | ||
2020 | if (!mem) { | ||
2021 | pr_debug("omap_hwmod: %s: no MPU register target found\n", | ||
2022 | oh->name); | ||
2023 | return; | ||
2024 | } | ||
2025 | |||
2026 | va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start); | ||
2027 | if (!va_start) { | ||
2028 | pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name); | ||
2029 | return; | ||
2030 | } | ||
2031 | |||
2032 | pr_debug("omap_hwmod: %s: MPU register target at va %p\n", | ||
2033 | oh->name, va_start); | ||
2034 | |||
2035 | oh->_mpu_rt_va = va_start; | ||
2036 | } | ||
2037 | |||
2038 | /** | ||
2039 | * _init - initialize internal data for the hwmod @oh | ||
2040 | * @oh: struct omap_hwmod * | ||
2041 | * @n: (unused) | ||
2042 | * | ||
2043 | * Look up the clocks and the address space used by the MPU to access | ||
2044 | * registers belonging to the hwmod @oh. @oh must already be | ||
2045 | * registered at this point. This is the first of two phases for | ||
2046 | * hwmod initialization. Code called here does not touch any hardware | ||
2047 | * registers, it simply prepares internal data structures. Returns 0 | ||
2048 | * upon success or if the hwmod isn't registered, or -EINVAL upon | ||
2049 | * failure. | ||
2050 | */ | ||
2051 | static int __init _init(struct omap_hwmod *oh, void *data) | ||
2052 | { | ||
2053 | int r; | ||
2054 | |||
2055 | if (oh->_state != _HWMOD_STATE_REGISTERED) | ||
1760 | return 0; | 2056 | return 0; |
1761 | 2057 | ||
1762 | /* Set iclk autoidle mode */ | 2058 | _init_mpu_rt_base(oh, NULL); |
1763 | if (oh->slaves_cnt > 0) { | ||
1764 | for (i = 0; i < oh->slaves_cnt; i++) { | ||
1765 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
1766 | struct clk *c = os->_clk; | ||
1767 | 2059 | ||
1768 | if (!c) | 2060 | r = _init_clocks(oh, NULL); |
1769 | continue; | 2061 | if (IS_ERR_VALUE(r)) { |
2062 | WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name); | ||
2063 | return -EINVAL; | ||
2064 | } | ||
1770 | 2065 | ||
1771 | if (os->flags & OCPIF_SWSUP_IDLE) { | 2066 | oh->_state = _HWMOD_STATE_INITIALIZED; |
1772 | /* XXX omap_iclk_deny_idle(c); */ | 2067 | |
1773 | } else { | 2068 | return 0; |
1774 | /* XXX omap_iclk_allow_idle(c); */ | 2069 | } |
1775 | clk_enable(c); | 2070 | |
1776 | } | 2071 | /** |
2072 | * _setup_iclk_autoidle - configure an IP block's interface clocks | ||
2073 | * @oh: struct omap_hwmod * | ||
2074 | * | ||
2075 | * Set up the module's interface clocks. XXX This function is still mostly | ||
2076 | * a stub; implementing this properly requires iclk autoidle usecounting in | ||
2077 | * the clock code. No return value. | ||
2078 | */ | ||
2079 | static void __init _setup_iclk_autoidle(struct omap_hwmod *oh) | ||
2080 | { | ||
2081 | struct omap_hwmod_ocp_if *os; | ||
2082 | struct list_head *p; | ||
2083 | int i = 0; | ||
2084 | if (oh->_state != _HWMOD_STATE_INITIALIZED) | ||
2085 | return; | ||
2086 | |||
2087 | p = oh->slave_ports.next; | ||
2088 | |||
2089 | while (i < oh->slaves_cnt) { | ||
2090 | os = _fetch_next_ocp_if(&p, &i); | ||
2091 | if (!os->_clk) | ||
2092 | continue; | ||
2093 | |||
2094 | if (os->flags & OCPIF_SWSUP_IDLE) { | ||
2095 | /* XXX omap_iclk_deny_idle(c); */ | ||
2096 | } else { | ||
2097 | /* XXX omap_iclk_allow_idle(c); */ | ||
2098 | clk_enable(os->_clk); | ||
1777 | } | 2099 | } |
1778 | } | 2100 | } |
1779 | 2101 | ||
1780 | oh->_state = _HWMOD_STATE_INITIALIZED; | 2102 | return; |
2103 | } | ||
1781 | 2104 | ||
1782 | /* | 2105 | /** |
1783 | * In the case of hwmod with hardreset that should not be | 2106 | * _setup_reset - reset an IP block during the setup process |
1784 | * de-assert at boot time, we have to keep the module | 2107 | * @oh: struct omap_hwmod * |
1785 | * initialized, because we cannot enable it properly with the | 2108 | * |
1786 | * reset asserted. Exit without warning because that behavior is | 2109 | * Reset the IP block corresponding to the hwmod @oh during the setup |
1787 | * expected. | 2110 | * process. The IP block is first enabled so it can be successfully |
1788 | */ | 2111 | * reset. Returns 0 upon success or a negative error code upon |
1789 | if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) | 2112 | * failure. |
1790 | return 0; | 2113 | */ |
2114 | static int __init _setup_reset(struct omap_hwmod *oh) | ||
2115 | { | ||
2116 | int r; | ||
1791 | 2117 | ||
1792 | r = _enable(oh); | 2118 | if (oh->_state != _HWMOD_STATE_INITIALIZED) |
1793 | if (r) { | 2119 | return -EINVAL; |
1794 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", | 2120 | |
1795 | oh->name, oh->_state); | 2121 | if (oh->rst_lines_cnt == 0) { |
1796 | return 0; | 2122 | r = _enable(oh); |
2123 | if (r) { | ||
2124 | pr_warning("omap_hwmod: %s: cannot be enabled for reset (%d)\n", | ||
2125 | oh->name, oh->_state); | ||
2126 | return -EINVAL; | ||
2127 | } | ||
1797 | } | 2128 | } |
1798 | 2129 | ||
1799 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) | 2130 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) |
1800 | _reset(oh); | 2131 | r = _reset(oh); |
2132 | |||
2133 | return r; | ||
2134 | } | ||
2135 | |||
2136 | /** | ||
2137 | * _setup_postsetup - transition to the appropriate state after _setup | ||
2138 | * @oh: struct omap_hwmod * | ||
2139 | * | ||
2140 | * Place an IP block represented by @oh into a "post-setup" state -- | ||
2141 | * either IDLE, ENABLED, or DISABLED. ("post-setup" simply means that | ||
2142 | * this function is called at the end of _setup().) The postsetup | ||
2143 | * state for an IP block can be changed by calling | ||
2144 | * omap_hwmod_enter_postsetup_state() early in the boot process, | ||
2145 | * before one of the omap_hwmod_setup*() functions are called for the | ||
2146 | * IP block. | ||
2147 | * | ||
2148 | * The IP block stays in this state until a PM runtime-based driver is | ||
2149 | * loaded for that IP block. A post-setup state of IDLE is | ||
2150 | * appropriate for almost all IP blocks with runtime PM-enabled | ||
2151 | * drivers, since those drivers are able to enable the IP block. A | ||
2152 | * post-setup state of ENABLED is appropriate for kernels with PM | ||
2153 | * runtime disabled. The DISABLED state is appropriate for unusual IP | ||
2154 | * blocks such as the MPU WDTIMER on kernels without WDTIMER drivers | ||
2155 | * included, since the WDTIMER starts running on reset and will reset | ||
2156 | * the MPU if left active. | ||
2157 | * | ||
2158 | * This post-setup mechanism is deprecated. Once all of the OMAP | ||
2159 | * drivers have been converted to use PM runtime, and all of the IP | ||
2160 | * block data and interconnect data is available to the hwmod code, it | ||
2161 | * should be possible to replace this mechanism with a "lazy reset" | ||
2162 | * arrangement. In a "lazy reset" setup, each IP block is enabled | ||
2163 | * when the driver first probes, then all remaining IP blocks without | ||
2164 | * drivers are either shut down or enabled after the drivers have | ||
2165 | * loaded. However, this cannot take place until the above | ||
2166 | * preconditions have been met, since otherwise the late reset code | ||
2167 | * has no way of knowing which IP blocks are in use by drivers, and | ||
2168 | * which ones are unused. | ||
2169 | * | ||
2170 | * No return value. | ||
2171 | */ | ||
2172 | static void __init _setup_postsetup(struct omap_hwmod *oh) | ||
2173 | { | ||
2174 | u8 postsetup_state; | ||
2175 | |||
2176 | if (oh->rst_lines_cnt > 0) | ||
2177 | return; | ||
1801 | 2178 | ||
1802 | postsetup_state = oh->_postsetup_state; | 2179 | postsetup_state = oh->_postsetup_state; |
1803 | if (postsetup_state == _HWMOD_STATE_UNKNOWN) | 2180 | if (postsetup_state == _HWMOD_STATE_UNKNOWN) |
@@ -1821,6 +2198,35 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1821 | WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n", | 2198 | WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n", |
1822 | oh->name, postsetup_state); | 2199 | oh->name, postsetup_state); |
1823 | 2200 | ||
2201 | return; | ||
2202 | } | ||
2203 | |||
2204 | /** | ||
2205 | * _setup - prepare IP block hardware for use | ||
2206 | * @oh: struct omap_hwmod * | ||
2207 | * @n: (unused, pass NULL) | ||
2208 | * | ||
2209 | * Configure the IP block represented by @oh. This may include | ||
2210 | * enabling the IP block, resetting it, and placing it into a | ||
2211 | * post-setup state, depending on the type of IP block and applicable | ||
2212 | * flags. IP blocks are reset to prevent any previous configuration | ||
2213 | * by the bootloader or previous operating system from interfering | ||
2214 | * with power management or other parts of the system. The reset can | ||
2215 | * be avoided; see omap_hwmod_no_setup_reset(). This is the second of | ||
2216 | * two phases for hwmod initialization. Code called here generally | ||
2217 | * affects the IP block hardware, or system integration hardware | ||
2218 | * associated with the IP block. Returns 0. | ||
2219 | */ | ||
2220 | static int __init _setup(struct omap_hwmod *oh, void *data) | ||
2221 | { | ||
2222 | if (oh->_state != _HWMOD_STATE_INITIALIZED) | ||
2223 | return 0; | ||
2224 | |||
2225 | _setup_iclk_autoidle(oh); | ||
2226 | |||
2227 | if (!_setup_reset(oh)) | ||
2228 | _setup_postsetup(oh); | ||
2229 | |||
1824 | return 0; | 2230 | return 0; |
1825 | } | 2231 | } |
1826 | 2232 | ||
@@ -1843,8 +2249,6 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1843 | */ | 2249 | */ |
1844 | static int __init _register(struct omap_hwmod *oh) | 2250 | static int __init _register(struct omap_hwmod *oh) |
1845 | { | 2251 | { |
1846 | int ms_id; | ||
1847 | |||
1848 | if (!oh || !oh->name || !oh->class || !oh->class->name || | 2252 | if (!oh || !oh->name || !oh->class || !oh->class->name || |
1849 | (oh->_state != _HWMOD_STATE_UNKNOWN)) | 2253 | (oh->_state != _HWMOD_STATE_UNKNOWN)) |
1850 | return -EINVAL; | 2254 | return -EINVAL; |
@@ -1854,14 +2258,10 @@ static int __init _register(struct omap_hwmod *oh) | |||
1854 | if (_lookup(oh->name)) | 2258 | if (_lookup(oh->name)) |
1855 | return -EEXIST; | 2259 | return -EEXIST; |
1856 | 2260 | ||
1857 | ms_id = _find_mpu_port_index(oh); | ||
1858 | if (!IS_ERR_VALUE(ms_id)) | ||
1859 | oh->_mpu_port_index = ms_id; | ||
1860 | else | ||
1861 | oh->_int_flags |= _HWMOD_NO_MPU_PORT; | ||
1862 | |||
1863 | list_add_tail(&oh->node, &omap_hwmod_list); | 2261 | list_add_tail(&oh->node, &omap_hwmod_list); |
1864 | 2262 | ||
2263 | INIT_LIST_HEAD(&oh->master_ports); | ||
2264 | INIT_LIST_HEAD(&oh->slave_ports); | ||
1865 | spin_lock_init(&oh->_lock); | 2265 | spin_lock_init(&oh->_lock); |
1866 | 2266 | ||
1867 | oh->_state = _HWMOD_STATE_REGISTERED; | 2267 | oh->_state = _HWMOD_STATE_REGISTERED; |
@@ -1876,6 +2276,160 @@ static int __init _register(struct omap_hwmod *oh) | |||
1876 | return 0; | 2276 | return 0; |
1877 | } | 2277 | } |
1878 | 2278 | ||
2279 | /** | ||
2280 | * _alloc_links - return allocated memory for hwmod links | ||
2281 | * @ml: pointer to a struct omap_hwmod_link * for the master link | ||
2282 | * @sl: pointer to a struct omap_hwmod_link * for the slave link | ||
2283 | * | ||
2284 | * Return pointers to two struct omap_hwmod_link records, via the | ||
2285 | * addresses pointed to by @ml and @sl. Will first attempt to return | ||
2286 | * memory allocated as part of a large initial block, but if that has | ||
2287 | * been exhausted, will allocate memory itself. Since ideally this | ||
2288 | * second allocation path will never occur, the number of these | ||
2289 | * 'supplemental' allocations will be logged when debugging is | ||
2290 | * enabled. Returns 0. | ||
2291 | */ | ||
2292 | static int __init _alloc_links(struct omap_hwmod_link **ml, | ||
2293 | struct omap_hwmod_link **sl) | ||
2294 | { | ||
2295 | unsigned int sz; | ||
2296 | |||
2297 | if ((free_ls + LINKS_PER_OCP_IF) <= max_ls) { | ||
2298 | *ml = &linkspace[free_ls++]; | ||
2299 | *sl = &linkspace[free_ls++]; | ||
2300 | return 0; | ||
2301 | } | ||
2302 | |||
2303 | sz = sizeof(struct omap_hwmod_link) * LINKS_PER_OCP_IF; | ||
2304 | |||
2305 | *sl = NULL; | ||
2306 | *ml = alloc_bootmem(sz); | ||
2307 | |||
2308 | memset(*ml, 0, sz); | ||
2309 | |||
2310 | *sl = (void *)(*ml) + sizeof(struct omap_hwmod_link); | ||
2311 | |||
2312 | ls_supp++; | ||
2313 | pr_debug("omap_hwmod: supplemental link allocations needed: %d\n", | ||
2314 | ls_supp * LINKS_PER_OCP_IF); | ||
2315 | |||
2316 | return 0; | ||
2317 | }; | ||
2318 | |||
2319 | /** | ||
2320 | * _add_link - add an interconnect between two IP blocks | ||
2321 | * @oi: pointer to a struct omap_hwmod_ocp_if record | ||
2322 | * | ||
2323 | * Add struct omap_hwmod_link records connecting the master IP block | ||
2324 | * specified in @oi->master to @oi, and connecting the slave IP block | ||
2325 | * specified in @oi->slave to @oi. This code is assumed to run before | ||
2326 | * preemption or SMP has been enabled, thus avoiding the need for | ||
2327 | * locking in this code. Changes to this assumption will require | ||
2328 | * additional locking. Returns 0. | ||
2329 | */ | ||
2330 | static int __init _add_link(struct omap_hwmod_ocp_if *oi) | ||
2331 | { | ||
2332 | struct omap_hwmod_link *ml, *sl; | ||
2333 | |||
2334 | pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name, | ||
2335 | oi->slave->name); | ||
2336 | |||
2337 | _alloc_links(&ml, &sl); | ||
2338 | |||
2339 | ml->ocp_if = oi; | ||
2340 | INIT_LIST_HEAD(&ml->node); | ||
2341 | list_add(&ml->node, &oi->master->master_ports); | ||
2342 | oi->master->masters_cnt++; | ||
2343 | |||
2344 | sl->ocp_if = oi; | ||
2345 | INIT_LIST_HEAD(&sl->node); | ||
2346 | list_add(&sl->node, &oi->slave->slave_ports); | ||
2347 | oi->slave->slaves_cnt++; | ||
2348 | |||
2349 | return 0; | ||
2350 | } | ||
2351 | |||
2352 | /** | ||
2353 | * _register_link - register a struct omap_hwmod_ocp_if | ||
2354 | * @oi: struct omap_hwmod_ocp_if * | ||
2355 | * | ||
2356 | * Registers the omap_hwmod_ocp_if record @oi. Returns -EEXIST if it | ||
2357 | * has already been registered; -EINVAL if @oi is NULL or if the | ||
2358 | * record pointed to by @oi is missing required fields; or 0 upon | ||
2359 | * success. | ||
2360 | * | ||
2361 | * XXX The data should be copied into bootmem, so the original data | ||
2362 | * should be marked __initdata and freed after init. This would allow | ||
2363 | * unneeded omap_hwmods to be freed on multi-OMAP configurations. | ||
2364 | */ | ||
2365 | static int __init _register_link(struct omap_hwmod_ocp_if *oi) | ||
2366 | { | ||
2367 | if (!oi || !oi->master || !oi->slave || !oi->user) | ||
2368 | return -EINVAL; | ||
2369 | |||
2370 | if (oi->_int_flags & _OCPIF_INT_FLAGS_REGISTERED) | ||
2371 | return -EEXIST; | ||
2372 | |||
2373 | pr_debug("omap_hwmod: registering link from %s to %s\n", | ||
2374 | oi->master->name, oi->slave->name); | ||
2375 | |||
2376 | /* | ||
2377 | * Register the connected hwmods, if they haven't been | ||
2378 | * registered already | ||
2379 | */ | ||
2380 | if (oi->master->_state != _HWMOD_STATE_REGISTERED) | ||
2381 | _register(oi->master); | ||
2382 | |||
2383 | if (oi->slave->_state != _HWMOD_STATE_REGISTERED) | ||
2384 | _register(oi->slave); | ||
2385 | |||
2386 | _add_link(oi); | ||
2387 | |||
2388 | oi->_int_flags |= _OCPIF_INT_FLAGS_REGISTERED; | ||
2389 | |||
2390 | return 0; | ||
2391 | } | ||
2392 | |||
2393 | /** | ||
2394 | * _alloc_linkspace - allocate large block of hwmod links | ||
2395 | * @ois: pointer to an array of struct omap_hwmod_ocp_if records to count | ||
2396 | * | ||
2397 | * Allocate a large block of struct omap_hwmod_link records. This | ||
2398 | * improves boot time significantly by avoiding the need to allocate | ||
2399 | * individual records one by one. If the number of records to | ||
2400 | * allocate in the block hasn't been manually specified, this function | ||
2401 | * will count the number of struct omap_hwmod_ocp_if records in @ois | ||
2402 | * and use that to determine the allocation size. For SoC families | ||
2403 | * that require multiple list registrations, such as OMAP3xxx, this | ||
2404 | * estimation process isn't optimal, so manual estimation is advised | ||
2405 | * in those cases. Returns -EEXIST if the allocation has already occurred | ||
2406 | * or 0 upon success. | ||
2407 | */ | ||
2408 | static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois) | ||
2409 | { | ||
2410 | unsigned int i = 0; | ||
2411 | unsigned int sz; | ||
2412 | |||
2413 | if (linkspace) { | ||
2414 | WARN(1, "linkspace already allocated\n"); | ||
2415 | return -EEXIST; | ||
2416 | } | ||
2417 | |||
2418 | if (max_ls == 0) | ||
2419 | while (ois[i++]) | ||
2420 | max_ls += LINKS_PER_OCP_IF; | ||
2421 | |||
2422 | sz = sizeof(struct omap_hwmod_link) * max_ls; | ||
2423 | |||
2424 | pr_debug("omap_hwmod: %s: allocating %d byte linkspace (%d links)\n", | ||
2425 | __func__, sz, max_ls); | ||
2426 | |||
2427 | linkspace = alloc_bootmem(sz); | ||
2428 | |||
2429 | memset(linkspace, 0, sz); | ||
2430 | |||
2431 | return 0; | ||
2432 | } | ||
1879 | 2433 | ||
1880 | /* Public functions */ | 2434 | /* Public functions */ |
1881 | 2435 | ||
@@ -2004,120 +2558,101 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), | |||
2004 | } | 2558 | } |
2005 | 2559 | ||
2006 | /** | 2560 | /** |
2007 | * omap_hwmod_register - register an array of hwmods | 2561 | * omap_hwmod_register_links - register an array of hwmod links |
2008 | * @ohs: pointer to an array of omap_hwmods to register | 2562 | * @ois: pointer to an array of omap_hwmod_ocp_if to register |
2009 | * | 2563 | * |
2010 | * Intended to be called early in boot before the clock framework is | 2564 | * Intended to be called early in boot before the clock framework is |
2011 | * initialized. If @ohs is not null, will register all omap_hwmods | 2565 | * initialized. If @ois is not null, will register all omap_hwmods |
2012 | * listed in @ohs that are valid for this chip. Returns 0. | 2566 | * listed in @ois that are valid for this chip. Returns 0. |
2013 | */ | 2567 | */ |
2014 | int __init omap_hwmod_register(struct omap_hwmod **ohs) | 2568 | int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois) |
2015 | { | 2569 | { |
2016 | int r, i; | 2570 | int r, i; |
2017 | 2571 | ||
2018 | if (!ohs) | 2572 | if (!ois) |
2019 | return 0; | 2573 | return 0; |
2020 | 2574 | ||
2575 | if (!linkspace) { | ||
2576 | if (_alloc_linkspace(ois)) { | ||
2577 | pr_err("omap_hwmod: could not allocate link space\n"); | ||
2578 | return -ENOMEM; | ||
2579 | } | ||
2580 | } | ||
2581 | |||
2021 | i = 0; | 2582 | i = 0; |
2022 | do { | 2583 | do { |
2023 | r = _register(ohs[i]); | 2584 | r = _register_link(ois[i]); |
2024 | WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name, | 2585 | WARN(r && r != -EEXIST, |
2025 | r); | 2586 | "omap_hwmod: _register_link(%s -> %s) returned %d\n", |
2026 | } while (ohs[++i]); | 2587 | ois[i]->master->name, ois[i]->slave->name, r); |
2588 | } while (ois[++i]); | ||
2027 | 2589 | ||
2028 | return 0; | 2590 | return 0; |
2029 | } | 2591 | } |
2030 | 2592 | ||
2031 | /* | 2593 | /** |
2032 | * _populate_mpu_rt_base - populate the virtual address for a hwmod | 2594 | * _ensure_mpu_hwmod_is_setup - ensure the MPU SS hwmod is init'ed and set up |
2595 | * @oh: pointer to the hwmod currently being set up (usually not the MPU) | ||
2033 | * | 2596 | * |
2034 | * Must be called only from omap_hwmod_setup_*() so ioremap works properly. | 2597 | * If the hwmod data corresponding to the MPU subsystem IP block |
2035 | * Assumes the caller takes care of locking if needed. | 2598 | * hasn't been initialized and set up yet, do so now. This must be |
2599 | * done first since sleep dependencies may be added from other hwmods | ||
2600 | * to the MPU. Intended to be called only by omap_hwmod_setup*(). No | ||
2601 | * return value. | ||
2036 | */ | 2602 | */ |
2037 | static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data) | 2603 | static void __init _ensure_mpu_hwmod_is_setup(struct omap_hwmod *oh) |
2038 | { | 2604 | { |
2039 | if (oh->_state != _HWMOD_STATE_REGISTERED) | 2605 | if (!mpu_oh || mpu_oh->_state == _HWMOD_STATE_UNKNOWN) |
2040 | return 0; | 2606 | pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n", |
2041 | 2607 | __func__, MPU_INITIATOR_NAME); | |
2042 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | 2608 | else if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh) |
2043 | return 0; | 2609 | omap_hwmod_setup_one(MPU_INITIATOR_NAME); |
2044 | |||
2045 | oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); | ||
2046 | |||
2047 | return 0; | ||
2048 | } | 2610 | } |
2049 | 2611 | ||
2050 | /** | 2612 | /** |
2051 | * omap_hwmod_setup_one - set up a single hwmod | 2613 | * omap_hwmod_setup_one - set up a single hwmod |
2052 | * @oh_name: const char * name of the already-registered hwmod to set up | 2614 | * @oh_name: const char * name of the already-registered hwmod to set up |
2053 | * | 2615 | * |
2054 | * Must be called after omap2_clk_init(). Resolves the struct clk | 2616 | * Initialize and set up a single hwmod. Intended to be used for a |
2055 | * names to struct clk pointers for each registered omap_hwmod. Also | 2617 | * small number of early devices, such as the timer IP blocks used for |
2056 | * calls _setup() on each hwmod. Returns -EINVAL upon error or 0 upon | 2618 | * the scheduler clock. Must be called after omap2_clk_init(). |
2057 | * success. | 2619 | * Resolves the struct clk names to struct clk pointers for each |
2620 | * registered omap_hwmod. Also calls _setup() on each hwmod. Returns | ||
2621 | * -EINVAL upon error or 0 upon success. | ||
2058 | */ | 2622 | */ |
2059 | int __init omap_hwmod_setup_one(const char *oh_name) | 2623 | int __init omap_hwmod_setup_one(const char *oh_name) |
2060 | { | 2624 | { |
2061 | struct omap_hwmod *oh; | 2625 | struct omap_hwmod *oh; |
2062 | int r; | ||
2063 | 2626 | ||
2064 | pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__); | 2627 | pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__); |
2065 | 2628 | ||
2066 | if (!mpu_oh) { | ||
2067 | pr_err("omap_hwmod: %s: cannot setup_one: MPU initiator hwmod %s not yet registered\n", | ||
2068 | oh_name, MPU_INITIATOR_NAME); | ||
2069 | return -EINVAL; | ||
2070 | } | ||
2071 | |||
2072 | oh = _lookup(oh_name); | 2629 | oh = _lookup(oh_name); |
2073 | if (!oh) { | 2630 | if (!oh) { |
2074 | WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name); | 2631 | WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name); |
2075 | return -EINVAL; | 2632 | return -EINVAL; |
2076 | } | 2633 | } |
2077 | 2634 | ||
2078 | if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh) | 2635 | _ensure_mpu_hwmod_is_setup(oh); |
2079 | omap_hwmod_setup_one(MPU_INITIATOR_NAME); | ||
2080 | |||
2081 | r = _populate_mpu_rt_base(oh, NULL); | ||
2082 | if (IS_ERR_VALUE(r)) { | ||
2083 | WARN(1, "omap_hwmod: %s: couldn't set mpu_rt_base\n", oh_name); | ||
2084 | return -EINVAL; | ||
2085 | } | ||
2086 | |||
2087 | r = _init_clocks(oh, NULL); | ||
2088 | if (IS_ERR_VALUE(r)) { | ||
2089 | WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh_name); | ||
2090 | return -EINVAL; | ||
2091 | } | ||
2092 | 2636 | ||
2637 | _init(oh, NULL); | ||
2093 | _setup(oh, NULL); | 2638 | _setup(oh, NULL); |
2094 | 2639 | ||
2095 | return 0; | 2640 | return 0; |
2096 | } | 2641 | } |
2097 | 2642 | ||
2098 | /** | 2643 | /** |
2099 | * omap_hwmod_setup - do some post-clock framework initialization | 2644 | * omap_hwmod_setup_all - set up all registered IP blocks |
2100 | * | 2645 | * |
2101 | * Must be called after omap2_clk_init(). Resolves the struct clk names | 2646 | * Initialize and set up all IP blocks registered with the hwmod code. |
2102 | * to struct clk pointers for each registered omap_hwmod. Also calls | 2647 | * Must be called after omap2_clk_init(). Resolves the struct clk |
2103 | * _setup() on each hwmod. Returns 0 upon success. | 2648 | * names to struct clk pointers for each registered omap_hwmod. Also |
2649 | * calls _setup() on each hwmod. Returns 0 upon success. | ||
2104 | */ | 2650 | */ |
2105 | static int __init omap_hwmod_setup_all(void) | 2651 | static int __init omap_hwmod_setup_all(void) |
2106 | { | 2652 | { |
2107 | int r; | 2653 | _ensure_mpu_hwmod_is_setup(NULL); |
2108 | |||
2109 | if (!mpu_oh) { | ||
2110 | pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n", | ||
2111 | __func__, MPU_INITIATOR_NAME); | ||
2112 | return -EINVAL; | ||
2113 | } | ||
2114 | |||
2115 | r = omap_hwmod_for_each(_populate_mpu_rt_base, NULL); | ||
2116 | |||
2117 | r = omap_hwmod_for_each(_init_clocks, NULL); | ||
2118 | WARN(IS_ERR_VALUE(r), | ||
2119 | "omap_hwmod: %s: _init_clocks failed\n", __func__); | ||
2120 | 2654 | ||
2655 | omap_hwmod_for_each(_init, NULL); | ||
2121 | omap_hwmod_for_each(_setup, NULL); | 2656 | omap_hwmod_for_each(_setup, NULL); |
2122 | 2657 | ||
2123 | return 0; | 2658 | return 0; |
@@ -2274,6 +2809,10 @@ int omap_hwmod_reset(struct omap_hwmod *oh) | |||
2274 | return r; | 2809 | return r; |
2275 | } | 2810 | } |
2276 | 2811 | ||
2812 | /* | ||
2813 | * IP block data retrieval functions | ||
2814 | */ | ||
2815 | |||
2277 | /** | 2816 | /** |
2278 | * omap_hwmod_count_resources - count number of struct resources needed by hwmod | 2817 | * omap_hwmod_count_resources - count number of struct resources needed by hwmod |
2279 | * @oh: struct omap_hwmod * | 2818 | * @oh: struct omap_hwmod * |
@@ -2292,12 +2831,19 @@ int omap_hwmod_reset(struct omap_hwmod *oh) | |||
2292 | */ | 2831 | */ |
2293 | int omap_hwmod_count_resources(struct omap_hwmod *oh) | 2832 | int omap_hwmod_count_resources(struct omap_hwmod *oh) |
2294 | { | 2833 | { |
2295 | int ret, i; | 2834 | struct omap_hwmod_ocp_if *os; |
2835 | struct list_head *p; | ||
2836 | int ret; | ||
2837 | int i = 0; | ||
2296 | 2838 | ||
2297 | ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh); | 2839 | ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh); |
2298 | 2840 | ||
2299 | for (i = 0; i < oh->slaves_cnt; i++) | 2841 | p = oh->slave_ports.next; |
2300 | ret += _count_ocp_if_addr_spaces(oh->slaves[i]); | 2842 | |
2843 | while (i < oh->slaves_cnt) { | ||
2844 | os = _fetch_next_ocp_if(&p, &i); | ||
2845 | ret += _count_ocp_if_addr_spaces(os); | ||
2846 | } | ||
2301 | 2847 | ||
2302 | return ret; | 2848 | return ret; |
2303 | } | 2849 | } |
@@ -2314,7 +2860,9 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) | |||
2314 | */ | 2860 | */ |
2315 | int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | 2861 | int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) |
2316 | { | 2862 | { |
2317 | int i, j, mpu_irqs_cnt, sdma_reqs_cnt; | 2863 | struct omap_hwmod_ocp_if *os; |
2864 | struct list_head *p; | ||
2865 | int i, j, mpu_irqs_cnt, sdma_reqs_cnt, addr_cnt; | ||
2318 | int r = 0; | 2866 | int r = 0; |
2319 | 2867 | ||
2320 | /* For each IRQ, DMA, memory area, fill in array.*/ | 2868 | /* For each IRQ, DMA, memory area, fill in array.*/ |
@@ -2337,11 +2885,11 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
2337 | r++; | 2885 | r++; |
2338 | } | 2886 | } |
2339 | 2887 | ||
2340 | for (i = 0; i < oh->slaves_cnt; i++) { | 2888 | p = oh->slave_ports.next; |
2341 | struct omap_hwmod_ocp_if *os; | ||
2342 | int addr_cnt; | ||
2343 | 2889 | ||
2344 | os = oh->slaves[i]; | 2890 | i = 0; |
2891 | while (i < oh->slaves_cnt) { | ||
2892 | os = _fetch_next_ocp_if(&p, &i); | ||
2345 | addr_cnt = _count_ocp_if_addr_spaces(os); | 2893 | addr_cnt = _count_ocp_if_addr_spaces(os); |
2346 | 2894 | ||
2347 | for (j = 0; j < addr_cnt; j++) { | 2895 | for (j = 0; j < addr_cnt; j++) { |
@@ -2357,6 +2905,69 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
2357 | } | 2905 | } |
2358 | 2906 | ||
2359 | /** | 2907 | /** |
2908 | * omap_hwmod_get_resource_byname - fetch IP block integration data by name | ||
2909 | * @oh: struct omap_hwmod * to operate on | ||
2910 | * @type: one of the IORESOURCE_* constants from include/linux/ioport.h | ||
2911 | * @name: pointer to the name of the data to fetch (optional) | ||
2912 | * @rsrc: pointer to a struct resource, allocated by the caller | ||
2913 | * | ||
2914 | * Retrieve MPU IRQ, SDMA request line, or address space start/end | ||
2915 | * data for the IP block pointed to by @oh. The data will be filled | ||
2916 | * into a struct resource record pointed to by @rsrc. The struct | ||
2917 | * resource must be allocated by the caller. When @name is non-null, | ||
2918 | * the data associated with the matching entry in the IRQ/SDMA/address | ||
2919 | * space hwmod data arrays will be returned. If @name is null, the | ||
2920 | * first array entry will be returned. Data order is not meaningful | ||
2921 | * in hwmod data, so callers are strongly encouraged to use a non-null | ||
2922 | * @name whenever possible to avoid unpredictable effects if hwmod | ||
2923 | * data is later added that causes data ordering to change. This | ||
2924 | * function is only intended for use by OMAP core code. Device | ||
2925 | * drivers should not call this function - the appropriate bus-related | ||
2926 | * data accessor functions should be used instead. Returns 0 upon | ||
2927 | * success or a negative error code upon error. | ||
2928 | */ | ||
2929 | int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type, | ||
2930 | const char *name, struct resource *rsrc) | ||
2931 | { | ||
2932 | int r; | ||
2933 | unsigned int irq, dma; | ||
2934 | u32 pa_start, pa_end; | ||
2935 | |||
2936 | if (!oh || !rsrc) | ||
2937 | return -EINVAL; | ||
2938 | |||
2939 | if (type == IORESOURCE_IRQ) { | ||
2940 | r = _get_mpu_irq_by_name(oh, name, &irq); | ||
2941 | if (r) | ||
2942 | return r; | ||
2943 | |||
2944 | rsrc->start = irq; | ||
2945 | rsrc->end = irq; | ||
2946 | } else if (type == IORESOURCE_DMA) { | ||
2947 | r = _get_sdma_req_by_name(oh, name, &dma); | ||
2948 | if (r) | ||
2949 | return r; | ||
2950 | |||
2951 | rsrc->start = dma; | ||
2952 | rsrc->end = dma; | ||
2953 | } else if (type == IORESOURCE_MEM) { | ||
2954 | r = _get_addr_space_by_name(oh, name, &pa_start, &pa_end); | ||
2955 | if (r) | ||
2956 | return r; | ||
2957 | |||
2958 | rsrc->start = pa_start; | ||
2959 | rsrc->end = pa_end; | ||
2960 | } else { | ||
2961 | return -EINVAL; | ||
2962 | } | ||
2963 | |||
2964 | rsrc->flags = type; | ||
2965 | rsrc->name = name; | ||
2966 | |||
2967 | return 0; | ||
2968 | } | ||
2969 | |||
2970 | /** | ||
2360 | * omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain | 2971 | * omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain |
2361 | * @oh: struct omap_hwmod * | 2972 | * @oh: struct omap_hwmod * |
2362 | * | 2973 | * |
@@ -2370,6 +2981,7 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
2370 | struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh) | 2981 | struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh) |
2371 | { | 2982 | { |
2372 | struct clk *c; | 2983 | struct clk *c; |
2984 | struct omap_hwmod_ocp_if *oi; | ||
2373 | 2985 | ||
2374 | if (!oh) | 2986 | if (!oh) |
2375 | return NULL; | 2987 | return NULL; |
@@ -2377,9 +2989,10 @@ struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh) | |||
2377 | if (oh->_clk) { | 2989 | if (oh->_clk) { |
2378 | c = oh->_clk; | 2990 | c = oh->_clk; |
2379 | } else { | 2991 | } else { |
2380 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | 2992 | oi = _find_mpu_rt_port(oh); |
2993 | if (!oi) | ||
2381 | return NULL; | 2994 | return NULL; |
2382 | c = oh->slaves[oh->_mpu_port_index]->_clk; | 2995 | c = oi->_clk; |
2383 | } | 2996 | } |
2384 | 2997 | ||
2385 | if (!c->clkdm) | 2998 | if (!c->clkdm) |
@@ -2653,10 +3266,10 @@ int omap_hwmod_for_each_by_class(const char *classname, | |||
2653 | * @state: state that _setup() should leave the hwmod in | 3266 | * @state: state that _setup() should leave the hwmod in |
2654 | * | 3267 | * |
2655 | * Sets the hwmod state that @oh will enter at the end of _setup() | 3268 | * Sets the hwmod state that @oh will enter at the end of _setup() |
2656 | * (called by omap_hwmod_setup_*()). Only valid to call between | 3269 | * (called by omap_hwmod_setup_*()). See also the documentation |
2657 | * calling omap_hwmod_register() and omap_hwmod_setup_*(). Returns | 3270 | * for _setup_postsetup(), above. Returns 0 upon success or |
2658 | * 0 upon success or -EINVAL if there is a problem with the arguments | 3271 | * -EINVAL if there is a problem with the arguments or if the hwmod is |
2659 | * or if the hwmod is in the wrong state. | 3272 | * in the wrong state. |
2660 | */ | 3273 | */ |
2661 | int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) | 3274 | int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) |
2662 | { | 3275 | { |