diff options
author | Misael Lopez Cruz | 2015-02-17 21:55:10 -0600 |
---|---|---|
committer | Misael Lopez Cruz | 2015-03-03 13:58:43 -0600 |
commit | b8bd1686a6863d7c457eeecd62802778950b87a8 (patch) | |
tree | d0db27c9a5b808be583e9b8d7b7225b379406409 | |
parent | 9f64013dea00743535fcfc81a5393ecf8c91ab42 (diff) | |
download | kernel-audio-b8bd1686a6863d7c457eeecd62802778950b87a8.tar.gz kernel-audio-b8bd1686a6863d7c457eeecd62802778950b87a8.tar.xz kernel-audio-b8bd1686a6863d7c457eeecd62802778950b87a8.zip |
mmc: omap-hsmmc: WIP: Add ADMA support
Change-Id: Idd91337d865138f4bc20282c89f1b6c0f5b9f94e
Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
-rw-r--r-- | arch/arm/boot/dts/dra7-evm.dts | 2 | ||||
-rw-r--r-- | arch/arm/boot/dts/dra72-evm.dts | 2 | ||||
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 294 | ||||
-rw-r--r-- | include/linux/platform_data/mmc-omap.h | 2 |
4 files changed, 260 insertions, 40 deletions
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts index dda8e0128590..68f9868526b9 100644 --- a/arch/arm/boot/dts/dra7-evm.dts +++ b/arch/arm/boot/dts/dra7-evm.dts | |||
@@ -1039,12 +1039,14 @@ | |||
1039 | vmmc-supply = <&ldo1_reg>; | 1039 | vmmc-supply = <&ldo1_reg>; |
1040 | bus-width = <4>; | 1040 | bus-width = <4>; |
1041 | cd-gpios = <&gpio6 27 0>; | 1041 | cd-gpios = <&gpio6 27 0>; |
1042 | ti,use-adma; | ||
1042 | }; | 1043 | }; |
1043 | 1044 | ||
1044 | &mmc2 { | 1045 | &mmc2 { |
1045 | vmmc-supply = <&vmmc2_fixed>; | 1046 | vmmc-supply = <&vmmc2_fixed>; |
1046 | bus-width = <8>; | 1047 | bus-width = <8>; |
1047 | ti,non-removable; | 1048 | ti,non-removable; |
1049 | ti,use-adma; | ||
1048 | }; | 1050 | }; |
1049 | 1051 | ||
1050 | &mmc3 { | 1052 | &mmc3 { |
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts index fbe3622bb5e2..7c829a67a3a5 100644 --- a/arch/arm/boot/dts/dra72-evm.dts +++ b/arch/arm/boot/dts/dra72-evm.dts | |||
@@ -844,6 +844,7 @@ | |||
844 | vmmc-supply = <&ldo1_reg>; | 844 | vmmc-supply = <&ldo1_reg>; |
845 | bus-width = <4>; | 845 | bus-width = <4>; |
846 | cd-gpios = <&gpio6 27 0>; | 846 | cd-gpios = <&gpio6 27 0>; |
847 | ti,use-adma; | ||
847 | }; | 848 | }; |
848 | 849 | ||
849 | &mmc2 { | 850 | &mmc2 { |
@@ -852,6 +853,7 @@ | |||
852 | max-frequency = <192000000>; | 853 | max-frequency = <192000000>; |
853 | caps2-mmc-hs200-1_8v; | 854 | caps2-mmc-hs200-1_8v; |
854 | ti,non-removable; | 855 | ti,non-removable; |
856 | ti,use-adma; | ||
855 | pinctrl-names = "default"; | 857 | pinctrl-names = "default"; |
856 | pinctrl-0 = <&mmc2_pins>; | 858 | pinctrl-0 = <&mmc2_pins>; |
857 | }; | 859 | }; |
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 346ed86c31ee..6134a712ffdb 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #define OMAP_HSMMC_RSP54 0x0118 | 56 | #define OMAP_HSMMC_RSP54 0x0118 |
57 | #define OMAP_HSMMC_RSP76 0x011C | 57 | #define OMAP_HSMMC_RSP76 0x011C |
58 | #define OMAP_HSMMC_DATA 0x0120 | 58 | #define OMAP_HSMMC_DATA 0x0120 |
59 | #define OMAP_HSMMC_PSTATE 0x0124 | ||
59 | #define OMAP_HSMMC_HCTL 0x0128 | 60 | #define OMAP_HSMMC_HCTL 0x0128 |
60 | #define OMAP_HSMMC_SYSCTL 0x012C | 61 | #define OMAP_HSMMC_SYSCTL 0x012C |
61 | #define OMAP_HSMMC_STAT 0x0130 | 62 | #define OMAP_HSMMC_STAT 0x0130 |
@@ -64,11 +65,14 @@ | |||
64 | #define OMAP_HSMMC_AC12 0x013C | 65 | #define OMAP_HSMMC_AC12 0x013C |
65 | #define OMAP_HSMMC_CAPA 0x0140 | 66 | #define OMAP_HSMMC_CAPA 0x0140 |
66 | #define OMAP_HSMMC_CAPA2 0x0144 | 67 | #define OMAP_HSMMC_CAPA2 0x0144 |
68 | #define OMAP_HSMMC_ADMAES 0x0154 | ||
69 | #define OMAP_HSMMC_ADMASAL 0x0158 | ||
67 | #define OMAP_HSMMC_REV 0x01FC | 70 | #define OMAP_HSMMC_REV 0x01FC |
68 | 71 | ||
69 | #define VS18 (1 << 26) | 72 | #define VS18 (1 << 26) |
70 | #define VS30 (1 << 25) | 73 | #define VS30 (1 << 25) |
71 | #define HSS (1 << 21) | 74 | #define HSS (1 << 21) |
75 | #define AD2S (1 << 19) | ||
72 | #define SDVS18 (0x5 << 9) | 76 | #define SDVS18 (0x5 << 9) |
73 | #define SDVS30 (0x6 << 9) | 77 | #define SDVS30 (0x6 << 9) |
74 | #define SDVS33 (0x7 << 9) | 78 | #define SDVS33 (0x7 << 9) |
@@ -96,6 +100,8 @@ | |||
96 | #define BCE (1 << 1) | 100 | #define BCE (1 << 1) |
97 | #define FOUR_BIT (1 << 1) | 101 | #define FOUR_BIT (1 << 1) |
98 | #define HSPE (1 << 2) | 102 | #define HSPE (1 << 2) |
103 | #define DMAS (0x2 << 3) | ||
104 | #define DMA_MNS (1 << 20) | ||
99 | #define DDR (1 << 19) | 105 | #define DDR (1 << 19) |
100 | #define DW8 (1 << 5) | 106 | #define DW8 (1 << 5) |
101 | #define OD 0x1 | 107 | #define OD 0x1 |
@@ -107,9 +113,25 @@ | |||
107 | #define SOFTRESET (1 << 1) | 113 | #define SOFTRESET (1 << 1) |
108 | #define RESETDONE (1 << 0) | 114 | #define RESETDONE (1 << 0) |
109 | 115 | ||
116 | /* ADMA descriptor attributes: action and parameters */ | ||
117 | #define ADMA_ACT_NOP (0x0 << 4) | ||
118 | #define ADMA_ACT_TRAN (0x2 << 4) | ||
119 | #define ADMA_ACT_LINK (0x3 << 4) | ||
120 | #define ADMA_VALID (1 << 0) | ||
121 | #define ADMA_END (1 << 1) | ||
122 | #define ADMA_INT (1 << 2) | ||
123 | |||
124 | /* ADMA error status */ | ||
125 | #define AES_MASK 0x3 | ||
126 | #define ST_FDS 0x0 | ||
127 | #define ST_STOP 0x1 | ||
128 | #define ST_TFR 0x3 | ||
129 | #define LME (1 << 2) | ||
130 | |||
110 | /* Interrupt masks for IE and ISE register */ | 131 | /* Interrupt masks for IE and ISE register */ |
111 | #define CC_EN (1 << 0) | 132 | #define CC_EN (1 << 0) |
112 | #define TC_EN (1 << 1) | 133 | #define TC_EN (1 << 1) |
134 | #define DMA_EN (1 << 3) | ||
113 | #define BWR_EN (1 << 4) | 135 | #define BWR_EN (1 << 4) |
114 | #define BRR_EN (1 << 5) | 136 | #define BRR_EN (1 << 5) |
115 | #define ERR_EN (1 << 15) | 137 | #define ERR_EN (1 << 15) |
@@ -121,11 +143,12 @@ | |||
121 | #define DCRC_EN (1 << 21) | 143 | #define DCRC_EN (1 << 21) |
122 | #define DEB_EN (1 << 22) | 144 | #define DEB_EN (1 << 22) |
123 | #define ACE_EN (1 << 24) | 145 | #define ACE_EN (1 << 24) |
146 | #define ADMAE_EN (1 << 25) | ||
124 | #define CERR_EN (1 << 28) | 147 | #define CERR_EN (1 << 28) |
125 | #define BADA_EN (1 << 29) | 148 | #define BADA_EN (1 << 29) |
126 | 149 | ||
127 | #define INT_EN_MASK (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\ | 150 | #define INT_EN_MASK (BADA_EN | CERR_EN | ADMAE_EN | DEB_EN | \ |
128 | DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \ | 151 | DCRC_EN | DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \ |
129 | BRR_EN | BWR_EN | TC_EN | CC_EN) | 152 | BRR_EN | BWR_EN | TC_EN | CC_EN) |
130 | 153 | ||
131 | #define CNI (1 << 7) | 154 | #define CNI (1 << 7) |
@@ -166,6 +189,23 @@ | |||
166 | /* HSMMC controller revision on OMAP5, DRA7 */ | 189 | /* HSMMC controller revision on OMAP5, DRA7 */ |
167 | #define OMAP_HSMMC_REV_33 0x33 | 190 | #define OMAP_HSMMC_REV_33 0x33 |
168 | 191 | ||
192 | #define ADMA_TABLE_NUM_ENTRIES 1024 | ||
193 | #define ADMA_TABLE_SZ (ADMA_TABLE_NUM_ENTRIES * \ | ||
194 | sizeof(struct adma_desc_table)) | ||
195 | |||
196 | /* | ||
197 | * According to TRM, it is possible to transfer upto 64kB per ADMA table entry. | ||
198 | * But 64kB = 0x10000 cannot be represented using a 16-bit integer in 1 ADMA | ||
199 | * table row. Hence rounding it to a lesser value. | ||
200 | */ | ||
201 | #define ADMA_MAX_XFER_PER_ROW (63 * 1024) | ||
202 | |||
203 | #define SDMA_XFER 1 | ||
204 | #define ADMA_XFER 2 | ||
205 | |||
206 | #define uses_dma(host) ((host->xfer_type == SDMA_XFER) || \ | ||
207 | (host->xfer_type == ADMA_XFER)) | ||
208 | |||
169 | /* | 209 | /* |
170 | * One controller can have multiple slots, like on some omap boards using | 210 | * One controller can have multiple slots, like on some omap boards using |
171 | * omap.c controller driver. Luckily this is not currently done on any known | 211 | * omap.c controller driver. Luckily this is not currently done on any known |
@@ -182,6 +222,13 @@ | |||
182 | #define OMAP_HSMMC_WRITE(base, reg, val) \ | 222 | #define OMAP_HSMMC_WRITE(base, reg, val) \ |
183 | __raw_writel((val), (base) + OMAP_HSMMC_##reg) | 223 | __raw_writel((val), (base) + OMAP_HSMMC_##reg) |
184 | 224 | ||
225 | /* ADMA descriptor table entry */ | ||
226 | struct adma_desc_table { | ||
227 | u16 attr; | ||
228 | u16 length; | ||
229 | dma_addr_t addr; | ||
230 | }; | ||
231 | |||
185 | struct omap_hsmmc_next { | 232 | struct omap_hsmmc_next { |
186 | unsigned int dma_len; | 233 | unsigned int dma_len; |
187 | s32 cookie; | 234 | s32 cookie; |
@@ -214,7 +261,9 @@ struct omap_hsmmc_host { | |||
214 | unsigned char power_mode; | 261 | unsigned char power_mode; |
215 | int suspended; | 262 | int suspended; |
216 | int irq; | 263 | int irq; |
217 | int use_dma, dma_ch; | 264 | int xfer_type, dma_ch; |
265 | dma_addr_t phy_adma_table; | ||
266 | struct adma_desc_table *adma_table; | ||
218 | struct dma_chan *tx_chan; | 267 | struct dma_chan *tx_chan; |
219 | struct dma_chan *rx_chan; | 268 | struct dma_chan *rx_chan; |
220 | int slot_id; | 269 | int slot_id; |
@@ -259,6 +308,8 @@ static const u32 ref_tuning_8bits[] = { | |||
259 | static int | 308 | static int |
260 | omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req); | 309 | omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req); |
261 | 310 | ||
311 | static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno); | ||
312 | |||
262 | static void set_data_timeout(struct omap_hsmmc_host *host, | 313 | static void set_data_timeout(struct omap_hsmmc_host *host, |
263 | unsigned int timeout_ns, | 314 | unsigned int timeout_ns, |
264 | unsigned int timeout_clks); | 315 | unsigned int timeout_clks); |
@@ -549,7 +600,7 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, | |||
549 | if ((cmd->opcode == MMC_SEND_TUNING_BLOCK) || | 600 | if ((cmd->opcode == MMC_SEND_TUNING_BLOCK) || |
550 | (cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)) | 601 | (cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)) |
551 | irq_mask = INT_EN_MASK | BRR_EN; | 602 | irq_mask = INT_EN_MASK | BRR_EN; |
552 | else if (host->use_dma) | 603 | else if (uses_dma(host)) |
553 | irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN); | 604 | irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN); |
554 | else | 605 | else |
555 | irq_mask = INT_EN_MASK; | 606 | irq_mask = INT_EN_MASK; |
@@ -924,7 +975,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, | |||
924 | cmdreg &= ~(DDIR); | 975 | cmdreg &= ~(DDIR); |
925 | } | 976 | } |
926 | 977 | ||
927 | if (host->use_dma) | 978 | if (uses_dma(host)) |
928 | cmdreg |= DMAE; | 979 | cmdreg |= DMAE; |
929 | 980 | ||
930 | /* Tuning command is special. Data Present Select should be set */ | 981 | /* Tuning command is special. Data Present Select should be set */ |
@@ -967,7 +1018,7 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req | |||
967 | 1018 | ||
968 | omap_hsmmc_disable_irq(host); | 1019 | omap_hsmmc_disable_irq(host); |
969 | /* Do not complete the request if DMA is still in progress */ | 1020 | /* Do not complete the request if DMA is still in progress */ |
970 | if (mrq->data && host->use_dma && dma_ch != -1) | 1021 | if (mrq->data && uses_dma(host) && dma_ch != -1) |
971 | return; | 1022 | return; |
972 | host->mrq = NULL; | 1023 | host->mrq = NULL; |
973 | mmc_request_done(host->mmc, mrq); | 1024 | mmc_request_done(host->mmc, mrq); |
@@ -995,6 +1046,9 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data) | |||
995 | 1046 | ||
996 | host->data = NULL; | 1047 | host->data = NULL; |
997 | 1048 | ||
1049 | if (host->xfer_type == ADMA_XFER) | ||
1050 | omap_hsmmc_dma_cleanup(host, 0); | ||
1051 | |||
998 | if (!data->error) | 1052 | if (!data->error) |
999 | data->bytes_xfered += data->blocks * (data->blksz); | 1053 | data->bytes_xfered += data->blocks * (data->blksz); |
1000 | else | 1054 | else |
@@ -1030,8 +1084,22 @@ static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host) | |||
1030 | | (req->data->blocks << 16)); | 1084 | | (req->data->blocks << 16)); |
1031 | set_data_timeout(host, req->data->timeout_ns, | 1085 | set_data_timeout(host, req->data->timeout_ns, |
1032 | req->data->timeout_clks); | 1086 | req->data->timeout_clks); |
1033 | chan = omap_hsmmc_get_dma_chan(host, req->data); | 1087 | |
1034 | dma_async_issue_pending(chan); | 1088 | switch (host->xfer_type) { |
1089 | case SDMA_XFER: | ||
1090 | chan = omap_hsmmc_get_dma_chan(host, req->data); | ||
1091 | dma_async_issue_pending(chan); | ||
1092 | break; | ||
1093 | |||
1094 | case ADMA_XFER: | ||
1095 | /* Enforcing ordering in write operations */ | ||
1096 | wmb(); | ||
1097 | OMAP_HSMMC_WRITE(host->base, ADMASAL, host->phy_adma_table); | ||
1098 | break; | ||
1099 | |||
1100 | default: | ||
1101 | break; | ||
1102 | } | ||
1035 | } | 1103 | } |
1036 | 1104 | ||
1037 | /* | 1105 | /* |
@@ -1075,27 +1143,43 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) | |||
1075 | */ | 1143 | */ |
1076 | static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) | 1144 | static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) |
1077 | { | 1145 | { |
1146 | struct mmc_data *data = errno ? host->data : host->mrq->data; | ||
1147 | struct dma_chan *chan; | ||
1078 | int dma_ch; | 1148 | int dma_ch; |
1079 | unsigned long flags; | 1149 | unsigned long flags; |
1080 | 1150 | ||
1081 | host->data->error = errno; | 1151 | switch (host->xfer_type) { |
1082 | 1152 | case SDMA_XFER: | |
1083 | spin_lock_irqsave(&host->irq_lock, flags); | 1153 | spin_lock_irqsave(&host->irq_lock, flags); |
1084 | dma_ch = host->dma_ch; | 1154 | dma_ch = host->dma_ch; |
1085 | host->dma_ch = -1; | 1155 | host->dma_ch = -1; |
1086 | spin_unlock_irqrestore(&host->irq_lock, flags); | 1156 | spin_unlock_irqrestore(&host->irq_lock, flags); |
1157 | |||
1158 | if (dma_ch != -1) { | ||
1159 | chan = omap_hsmmc_get_dma_chan(host, host->data); | ||
1160 | dmaengine_terminate_all(chan); | ||
1161 | dma_unmap_sg(mmc_dev(host->mmc), | ||
1162 | data->sg, host->dma_len, | ||
1163 | omap_hsmmc_get_dma_dir(host, data)); | ||
1164 | data->host_cookie = 0; | ||
1165 | } | ||
1166 | break; | ||
1087 | 1167 | ||
1088 | if (host->use_dma && dma_ch != -1) { | 1168 | case ADMA_XFER: |
1089 | struct dma_chan *chan = omap_hsmmc_get_dma_chan(host, host->data); | 1169 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, |
1170 | omap_hsmmc_get_dma_dir(host, data)); | ||
1171 | break; | ||
1090 | 1172 | ||
1091 | dmaengine_terminate_all(chan); | 1173 | default: |
1092 | dma_unmap_sg(chan->device->dev, | 1174 | dev_dbg(mmc_dev(host->mmc), "Unexpected transfer type %d\n", |
1093 | host->data->sg, host->data->sg_len, | 1175 | host->xfer_type); |
1094 | omap_hsmmc_get_dma_dir(host, host->data)); | 1176 | break; |
1177 | } | ||
1095 | 1178 | ||
1096 | host->data->host_cookie = 0; | 1179 | if (errno) { |
1180 | host->data->error = errno; | ||
1181 | host->data = NULL; | ||
1097 | } | 1182 | } |
1098 | host->data = NULL; | ||
1099 | } | 1183 | } |
1100 | 1184 | ||
1101 | /* | 1185 | /* |
@@ -1106,10 +1190,10 @@ static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status) | |||
1106 | { | 1190 | { |
1107 | /* --- means reserved bit without definition at documentation */ | 1191 | /* --- means reserved bit without definition at documentation */ |
1108 | static const char *omap_hsmmc_status_bits[] = { | 1192 | static const char *omap_hsmmc_status_bits[] = { |
1109 | "CC" , "TC" , "BGE", "---", "BWR" , "BRR" , "---" , "---" , | 1193 | "CC" , "TC" , "BGE", "DMA", "BWR" , "BRR" , "CINS", "CREM", |
1110 | "CIRQ", "OBI" , "---", "---", "---" , "---" , "---" , "ERRI", | 1194 | "CIRQ", "OBI" , "BSR", "---", "---" , "---" , "---" , "ERRI", |
1111 | "CTO" , "CCRC", "CEB", "CIE", "DTO" , "DCRC", "DEB" , "---" , | 1195 | "CTO" , "CCRC", "CEB", "CIE", "DTO" , "DCRC", "DEB" , "CLE" , |
1112 | "ACE" , "---" , "---", "---", "CERR", "BADA", "---" , "---" | 1196 | "ACE" , "ADMA", "---", "---", "CERR", "BADA", "---" , "---" |
1113 | }; | 1197 | }; |
1114 | char res[256]; | 1198 | char res[256]; |
1115 | char *buf = res; | 1199 | char *buf = res; |
@@ -1187,6 +1271,35 @@ static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, | |||
1187 | host->mrq->cmd->error = err; | 1271 | host->mrq->cmd->error = err; |
1188 | } | 1272 | } |
1189 | 1273 | ||
1274 | static void omap_hsmmc_adma_err(struct omap_hsmmc_host *host) | ||
1275 | { | ||
1276 | u32 admaes, admasal; | ||
1277 | |||
1278 | admaes = OMAP_HSMMC_READ(host->base, ADMAES); | ||
1279 | admasal = OMAP_HSMMC_READ(host->base, ADMASAL); | ||
1280 | |||
1281 | switch (admaes & AES_MASK) { | ||
1282 | case ST_FDS: | ||
1283 | dev_err(mmc_dev(host->mmc), | ||
1284 | "ADMA err: ST_FDS, erroneous desc at 0x%08x\n", | ||
1285 | admasal); | ||
1286 | break; | ||
1287 | case ST_STOP: | ||
1288 | dev_err(mmc_dev(host->mmc), | ||
1289 | "ADMA err: ST_STOP, desc at 0x%08x follows the erroneous one\n", | ||
1290 | admasal); | ||
1291 | break; | ||
1292 | case ST_TFR: | ||
1293 | dev_err(mmc_dev(host->mmc), | ||
1294 | "ADMA err: ST_TFR, desc at 0x%08x follows the erroneous one\n", | ||
1295 | admasal); | ||
1296 | break; | ||
1297 | default: | ||
1298 | dev_warn(mmc_dev(host->mmc), "Unexpected ADMA error state\n"); | ||
1299 | break; | ||
1300 | } | ||
1301 | } | ||
1302 | |||
1190 | static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) | 1303 | static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) |
1191 | { | 1304 | { |
1192 | struct mmc_data *data; | 1305 | struct mmc_data *data; |
@@ -1234,6 +1347,14 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) | |||
1234 | end_trans = !end_cmd; | 1347 | end_trans = !end_cmd; |
1235 | host->response_busy = 0; | 1348 | host->response_busy = 0; |
1236 | } | 1349 | } |
1350 | |||
1351 | if (status & ADMAE_EN) { | ||
1352 | omap_hsmmc_adma_err(host); | ||
1353 | if (host->cmd) | ||
1354 | end_cmd = 1; | ||
1355 | if (host->data) | ||
1356 | end_trans = 1; | ||
1357 | } | ||
1237 | } | 1358 | } |
1238 | 1359 | ||
1239 | if (status & BRR_EN) { | 1360 | if (status & BRR_EN) { |
@@ -1537,6 +1658,60 @@ static int omap_hsmmc_setup_dma_transfer(struct omap_hsmmc_host *host, | |||
1537 | return 0; | 1658 | return 0; |
1538 | } | 1659 | } |
1539 | 1660 | ||
1661 | static int omap_hsmmc_setup_adma_transfer(struct omap_hsmmc_host *host, | ||
1662 | struct mmc_request *req) | ||
1663 | { | ||
1664 | struct adma_desc_table *pdesc = host->adma_table; | ||
1665 | struct mmc_data *data = req->data; | ||
1666 | int i, j, dmalen; | ||
1667 | int splitseg, xferaddr; | ||
1668 | int total_length = 0; | ||
1669 | dma_addr_t dmaaddr; | ||
1670 | |||
1671 | host->dma_len = dma_map_sg(mmc_dev(host->mmc), | ||
1672 | data->sg, | ||
1673 | data->sg_len, | ||
1674 | omap_hsmmc_get_dma_dir(host, data)); | ||
1675 | |||
1676 | for (i = 0, j = 0; i < host->dma_len; i++) { | ||
1677 | dmaaddr = sg_dma_address(data->sg + i); | ||
1678 | dmalen = sg_dma_len(data->sg + i); | ||
1679 | total_length += dmalen; | ||
1680 | |||
1681 | if (dmalen <= ADMA_MAX_XFER_PER_ROW) { | ||
1682 | pdesc[i + j].length = dmalen; | ||
1683 | pdesc[i + j].addr = dmaaddr; | ||
1684 | pdesc[i + j].attr = ADMA_ACT_TRAN | ADMA_VALID; | ||
1685 | } else { | ||
1686 | /* Each descriptor row can only support | ||
1687 | * transfer upto ADMA_MAX_XFER_PER_ROW. | ||
1688 | * If the current segment is bigger, it has to be | ||
1689 | * split to multiple ADMA table entries. | ||
1690 | */ | ||
1691 | xferaddr = 0; | ||
1692 | do { | ||
1693 | splitseg = min(dmalen, ADMA_MAX_XFER_PER_ROW); | ||
1694 | dmalen -= splitseg; | ||
1695 | pdesc[i + j].length = splitseg; | ||
1696 | pdesc[i + j].addr = dmaaddr + xferaddr; | ||
1697 | xferaddr += splitseg; | ||
1698 | pdesc[i + j].attr = ADMA_ACT_TRAN | ADMA_VALID; | ||
1699 | j++; | ||
1700 | } while (dmalen); | ||
1701 | j--; /* Compensate for i++ */ | ||
1702 | } | ||
1703 | } | ||
1704 | |||
1705 | /* Setup last entry to terminate */ | ||
1706 | pdesc[i + j - 1].attr |= ADMA_END; | ||
1707 | |||
1708 | WARN_ON((i + j - 1) > ADMA_TABLE_NUM_ENTRIES); | ||
1709 | |||
1710 | WARN_ON((total_length / data->blksz) != req->data->blocks); | ||
1711 | |||
1712 | return 0; | ||
1713 | } | ||
1714 | |||
1540 | static void set_data_timeout(struct omap_hsmmc_host *host, | 1715 | static void set_data_timeout(struct omap_hsmmc_host *host, |
1541 | unsigned int timeout_ns, | 1716 | unsigned int timeout_ns, |
1542 | unsigned int timeout_clks) | 1717 | unsigned int timeout_clks) |
@@ -1580,7 +1755,8 @@ static void set_data_timeout(struct omap_hsmmc_host *host, | |||
1580 | static int | 1755 | static int |
1581 | omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req) | 1756 | omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req) |
1582 | { | 1757 | { |
1583 | int ret; | 1758 | int ret = 0; |
1759 | |||
1584 | host->data = req->data; | 1760 | host->data = req->data; |
1585 | 1761 | ||
1586 | if (req->data == NULL) { | 1762 | if (req->data == NULL) { |
@@ -1594,14 +1770,15 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req) | |||
1594 | return 0; | 1770 | return 0; |
1595 | } | 1771 | } |
1596 | 1772 | ||
1597 | if (host->use_dma) { | 1773 | if (host->xfer_type == SDMA_XFER) |
1598 | ret = omap_hsmmc_setup_dma_transfer(host, req); | 1774 | ret = omap_hsmmc_setup_dma_transfer(host, req); |
1599 | if (ret != 0) { | 1775 | else if (host->xfer_type == ADMA_XFER) |
1600 | dev_err(mmc_dev(host->mmc), "MMC start dma failure\n"); | 1776 | ret = omap_hsmmc_setup_adma_transfer(host, req); |
1601 | return ret; | 1777 | |
1602 | } | 1778 | if (ret) |
1603 | } | 1779 | dev_err(mmc_dev(host->mmc), "MMC setup dma failure\n"); |
1604 | return 0; | 1780 | |
1781 | return ret; | ||
1605 | } | 1782 | } |
1606 | 1783 | ||
1607 | static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, | 1784 | static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, |
@@ -1610,7 +1787,7 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, | |||
1610 | struct omap_hsmmc_host *host = mmc_priv(mmc); | 1787 | struct omap_hsmmc_host *host = mmc_priv(mmc); |
1611 | struct mmc_data *data = mrq->data; | 1788 | struct mmc_data *data = mrq->data; |
1612 | 1789 | ||
1613 | if (host->use_dma && data->host_cookie) { | 1790 | if (uses_dma(host) && data->host_cookie) { |
1614 | struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data); | 1791 | struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data); |
1615 | 1792 | ||
1616 | dma_unmap_sg(c->device->dev, data->sg, data->sg_len, | 1793 | dma_unmap_sg(c->device->dev, data->sg, data->sg_len, |
@@ -1629,7 +1806,7 @@ static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, | |||
1629 | return ; | 1806 | return ; |
1630 | } | 1807 | } |
1631 | 1808 | ||
1632 | if (host->use_dma) { | 1809 | if (uses_dma(host)) { |
1633 | struct dma_chan *c = omap_hsmmc_get_dma_chan(host, mrq->data); | 1810 | struct dma_chan *c = omap_hsmmc_get_dma_chan(host, mrq->data); |
1634 | 1811 | ||
1635 | if (omap_hsmmc_pre_dma_transfer(host, mrq->data, | 1812 | if (omap_hsmmc_pre_dma_transfer(host, mrq->data, |
@@ -1789,6 +1966,12 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) | |||
1789 | capa = VS18; | 1966 | capa = VS18; |
1790 | } | 1967 | } |
1791 | 1968 | ||
1969 | if (host->xfer_type == ADMA_XFER) { | ||
1970 | hctl |= DMAS; | ||
1971 | value = OMAP_HSMMC_READ(host->base, CON); | ||
1972 | OMAP_HSMMC_WRITE(host->base, CON, value | DMA_MNS); | ||
1973 | } | ||
1974 | |||
1792 | value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK; | 1975 | value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK; |
1793 | OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl); | 1976 | OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl); |
1794 | 1977 | ||
@@ -2138,6 +2321,9 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) | |||
2138 | if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL)) | 2321 | if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL)) |
2139 | pdata->slots[0].caps2 |= MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS200; | 2322 | pdata->slots[0].caps2 |= MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS200; |
2140 | 2323 | ||
2324 | if (of_find_property(np, "ti,use-adma", NULL)) | ||
2325 | pdata->slots[0].features |= HSMMC_USE_ADMA; | ||
2326 | |||
2141 | return pdata; | 2327 | return pdata; |
2142 | } | 2328 | } |
2143 | #else | 2329 | #else |
@@ -2154,7 +2340,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) | |||
2154 | struct mmc_host *mmc; | 2340 | struct mmc_host *mmc; |
2155 | struct omap_hsmmc_host *host = NULL; | 2341 | struct omap_hsmmc_host *host = NULL; |
2156 | struct resource *res; | 2342 | struct resource *res; |
2157 | int ret, irq; | 2343 | int ret, irq, capa; |
2158 | const struct of_device_id *match; | 2344 | const struct of_device_id *match; |
2159 | dma_cap_mask_t mask; | 2345 | dma_cap_mask_t mask; |
2160 | unsigned tx_req, rx_req; | 2346 | unsigned tx_req, rx_req; |
@@ -2204,7 +2390,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) | |||
2204 | host->mmc = mmc; | 2390 | host->mmc = mmc; |
2205 | host->pdata = pdata; | 2391 | host->pdata = pdata; |
2206 | host->dev = &pdev->dev; | 2392 | host->dev = &pdev->dev; |
2207 | host->use_dma = 1; | 2393 | host->xfer_type = SDMA_XFER; |
2208 | host->dma_ch = -1; | 2394 | host->dma_ch = -1; |
2209 | host->irq = irq; | 2395 | host->irq = irq; |
2210 | host->slot_id = 0; | 2396 | host->slot_id = 0; |
@@ -2265,6 +2451,22 @@ static int omap_hsmmc_probe(struct platform_device *pdev) | |||
2265 | host->dbclk = NULL; | 2451 | host->dbclk = NULL; |
2266 | } | 2452 | } |
2267 | 2453 | ||
2454 | if (mmc_slot(host).features & HSMMC_USE_ADMA) { | ||
2455 | capa = OMAP_HSMMC_READ(host->base, CAPA); | ||
2456 | if (capa & AD2S) { | ||
2457 | /* Allocating memory for ADMA Descriptor Table */ | ||
2458 | host->adma_table = dma_alloc_coherent(mmc_dev(host->mmc), | ||
2459 | ADMA_TABLE_SZ, | ||
2460 | &host->phy_adma_table, 0); | ||
2461 | /* If allocation is success go with ADMA else SDMA */ | ||
2462 | if (host->adma_table) | ||
2463 | host->xfer_type = ADMA_XFER; | ||
2464 | } | ||
2465 | } | ||
2466 | |||
2467 | dev_info(mmc_dev(host->mmc), "%s mode\n", | ||
2468 | (host->xfer_type == SDMA_XFER) ? "sDMA" : "ADMA"); | ||
2469 | |||
2268 | /* Since we do only SG emulation, we can have as many segs | 2470 | /* Since we do only SG emulation, we can have as many segs |
2269 | * as we want. */ | 2471 | * as we want. */ |
2270 | mmc->max_segs = 1024; | 2472 | mmc->max_segs = 1024; |
@@ -2272,7 +2474,11 @@ static int omap_hsmmc_probe(struct platform_device *pdev) | |||
2272 | mmc->max_blk_size = 512; /* Block Length at max can be 1024 */ | 2474 | mmc->max_blk_size = 512; /* Block Length at max can be 1024 */ |
2273 | mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */ | 2475 | mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */ |
2274 | mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; | 2476 | mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; |
2275 | mmc->max_seg_size = mmc->max_req_size; | 2477 | |
2478 | if (host->xfer_type == SDMA_XFER) | ||
2479 | mmc->max_seg_size = mmc->max_req_size; | ||
2480 | else | ||
2481 | mmc->max_seg_size = ADMA_MAX_XFER_PER_ROW; | ||
2276 | 2482 | ||
2277 | mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | | 2483 | mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | |
2278 | MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE; | 2484 | MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE; |
@@ -2337,7 +2543,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev) | |||
2337 | 2543 | ||
2338 | /* Some DMA Engines only handle a limited number of SG segments */ | 2544 | /* Some DMA Engines only handle a limited number of SG segments */ |
2339 | dma_chan_caps = dma_get_channel_caps(host->rx_chan, DMA_DEV_TO_MEM); | 2545 | dma_chan_caps = dma_get_channel_caps(host->rx_chan, DMA_DEV_TO_MEM); |
2340 | if (dma_chan_caps && dma_chan_caps->seg_nr) | 2546 | if (dma_chan_caps && dma_chan_caps->seg_nr && |
2547 | (host->xfer_type != ADMA_XFER)) | ||
2341 | mmc->max_segs = dma_chan_caps->seg_nr; | 2548 | mmc->max_segs = dma_chan_caps->seg_nr; |
2342 | 2549 | ||
2343 | /* Request IRQ for MMC operations */ | 2550 | /* Request IRQ for MMC operations */ |
@@ -2440,6 +2647,9 @@ err_irq: | |||
2440 | clk_put(host->dbclk); | 2647 | clk_put(host->dbclk); |
2441 | } | 2648 | } |
2442 | err1: | 2649 | err1: |
2650 | if (host->adma_table) | ||
2651 | dma_free_coherent(mmc_dev(host->mmc), ADMA_TABLE_SZ, | ||
2652 | host->adma_table, host->phy_adma_table); | ||
2443 | iounmap(host->base); | 2653 | iounmap(host->base); |
2444 | platform_set_drvdata(pdev, NULL); | 2654 | platform_set_drvdata(pdev, NULL); |
2445 | mmc_free_host(mmc); | 2655 | mmc_free_host(mmc); |
@@ -2480,6 +2690,10 @@ static int omap_hsmmc_remove(struct platform_device *pdev) | |||
2480 | clk_put(host->dbclk); | 2690 | clk_put(host->dbclk); |
2481 | } | 2691 | } |
2482 | 2692 | ||
2693 | if (host->adma_table) | ||
2694 | dma_free_coherent(mmc_dev(host->mmc), ADMA_TABLE_SZ, | ||
2695 | host->adma_table, host->phy_adma_table); | ||
2696 | |||
2483 | omap_hsmmc_gpio_free(host->pdata); | 2697 | omap_hsmmc_gpio_free(host->pdata); |
2484 | iounmap(host->base); | 2698 | iounmap(host->base); |
2485 | mmc_free_host(host->mmc); | 2699 | mmc_free_host(host->mmc); |
diff --git a/include/linux/platform_data/mmc-omap.h b/include/linux/platform_data/mmc-omap.h index e104597ddf0b..86d3e0bac15c 100644 --- a/include/linux/platform_data/mmc-omap.h +++ b/include/linux/platform_data/mmc-omap.h | |||
@@ -112,6 +112,8 @@ struct omap_mmc_platform_data { | |||
112 | #define MMC_OMAP7XX (1 << 3) | 112 | #define MMC_OMAP7XX (1 << 3) |
113 | #define MMC_OMAP15XX (1 << 4) | 113 | #define MMC_OMAP15XX (1 << 4) |
114 | #define MMC_OMAP16XX (1 << 5) | 114 | #define MMC_OMAP16XX (1 << 5) |
115 | #define HSMMC_USE_ADMA (1 << 6) | ||
116 | |||
115 | unsigned features; | 117 | unsigned features; |
116 | 118 | ||
117 | int switch_pin; /* gpio (card detect) */ | 119 | int switch_pin; /* gpio (card detect) */ |