Commit | Line | Data |
---|---|---|
da7fbe58 | 1 | /* |
70f10482 | 2 | * linux/drivers/mmc/core/sd_ops.h |
da7fbe58 PO |
3 | * |
4 | * Copyright 2006-2007 Pierre Ossman | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or (at | |
9 | * your option) any later version. | |
10 | */ | |
11 | ||
4f665cb6 | 12 | #include <linux/slab.h> |
da7fbe58 | 13 | #include <linux/types.h> |
3ef77af1 | 14 | #include <linux/export.h> |
da7fbe58 PO |
15 | #include <linux/scatterlist.h> |
16 | ||
17 | #include <linux/mmc/host.h> | |
18 | #include <linux/mmc/card.h> | |
19 | #include <linux/mmc/mmc.h> | |
20 | #include <linux/mmc/sd.h> | |
21 | ||
22 | #include "core.h" | |
23 | #include "sd_ops.h" | |
24 | ||
cb87ea28 | 25 | int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) |
39361851 AB |
26 | { |
27 | int err; | |
c7836d15 | 28 | struct mmc_command cmd = {}; |
39361851 | 29 | |
349583d6 SL |
30 | if (WARN_ON(card && card->host != host)) |
31 | return -EINVAL; | |
39361851 AB |
32 | |
33 | cmd.opcode = MMC_APP_CMD; | |
34 | ||
35 | if (card) { | |
36 | cmd.arg = card->rca << 16; | |
af517150 | 37 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; |
39361851 AB |
38 | } else { |
39 | cmd.arg = 0; | |
af517150 | 40 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR; |
39361851 AB |
41 | } |
42 | ||
43 | err = mmc_wait_for_cmd(host, &cmd, 0); | |
17b0429d | 44 | if (err) |
39361851 AB |
45 | return err; |
46 | ||
47 | /* Check that card supported application commands */ | |
af517150 | 48 | if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) |
17b0429d | 49 | return -EOPNOTSUPP; |
39361851 | 50 | |
17b0429d | 51 | return 0; |
39361851 | 52 | } |
cb87ea28 | 53 | EXPORT_SYMBOL_GPL(mmc_app_cmd); |
39361851 | 54 | |
9a4b869b | 55 | static int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, |
da7fbe58 PO |
56 | struct mmc_command *cmd, int retries) |
57 | { | |
c7836d15 | 58 | struct mmc_request mrq = {}; |
da7fbe58 PO |
59 | |
60 | int i, err; | |
61 | ||
349583d6 SL |
62 | if (retries < 0) |
63 | retries = MMC_CMD_RETRIES; | |
da7fbe58 | 64 | |
17b0429d | 65 | err = -EIO; |
da7fbe58 PO |
66 | |
67 | /* | |
68 | * We have to resend MMC_APP_CMD for each attempt so | |
69 | * we cannot use the retries field in mmc_command. | |
70 | */ | |
71 | for (i = 0;i <= retries;i++) { | |
da7fbe58 | 72 | err = mmc_app_cmd(host, card); |
af517150 DB |
73 | if (err) { |
74 | /* no point in retrying; no APP commands allowed */ | |
75 | if (mmc_host_is_spi(host)) { | |
76 | if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) | |
77 | break; | |
78 | } | |
da7fbe58 | 79 | continue; |
af517150 | 80 | } |
da7fbe58 PO |
81 | |
82 | memset(&mrq, 0, sizeof(struct mmc_request)); | |
83 | ||
84 | memset(cmd->resp, 0, sizeof(cmd->resp)); | |
85 | cmd->retries = 0; | |
86 | ||
87 | mrq.cmd = cmd; | |
88 | cmd->data = NULL; | |
89 | ||
90 | mmc_wait_for_req(host, &mrq); | |
91 | ||
92 | err = cmd->error; | |
17b0429d | 93 | if (!cmd->error) |
da7fbe58 | 94 | break; |
af517150 DB |
95 | |
96 | /* no point in retrying illegal APP commands */ | |
97 | if (mmc_host_is_spi(host)) { | |
98 | if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) | |
99 | break; | |
100 | } | |
da7fbe58 PO |
101 | } |
102 | ||
103 | return err; | |
104 | } | |
105 | ||
da7fbe58 PO |
106 | int mmc_app_set_bus_width(struct mmc_card *card, int width) |
107 | { | |
c7836d15 | 108 | struct mmc_command cmd = {}; |
da7fbe58 | 109 | |
da7fbe58 PO |
110 | cmd.opcode = SD_APP_SET_BUS_WIDTH; |
111 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | |
112 | ||
113 | switch (width) { | |
114 | case MMC_BUS_WIDTH_1: | |
115 | cmd.arg = SD_BUS_WIDTH_1; | |
116 | break; | |
117 | case MMC_BUS_WIDTH_4: | |
118 | cmd.arg = SD_BUS_WIDTH_4; | |
119 | break; | |
120 | default: | |
17b0429d | 121 | return -EINVAL; |
da7fbe58 PO |
122 | } |
123 | ||
0899e741 | 124 | return mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); |
da7fbe58 PO |
125 | } |
126 | ||
127 | int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | |
128 | { | |
c7836d15 | 129 | struct mmc_command cmd = {}; |
da7fbe58 PO |
130 | int i, err = 0; |
131 | ||
da7fbe58 | 132 | cmd.opcode = SD_APP_OP_COND; |
af517150 DB |
133 | if (mmc_host_is_spi(host)) |
134 | cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */ | |
135 | else | |
136 | cmd.arg = ocr; | |
137 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; | |
da7fbe58 PO |
138 | |
139 | for (i = 100; i; i--) { | |
140 | err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); | |
17b0429d | 141 | if (err) |
da7fbe58 PO |
142 | break; |
143 | ||
af517150 DB |
144 | /* if we're just probing, do a single pass */ |
145 | if (ocr == 0) | |
da7fbe58 PO |
146 | break; |
147 | ||
af517150 DB |
148 | /* otherwise wait until reset completes */ |
149 | if (mmc_host_is_spi(host)) { | |
150 | if (!(cmd.resp[0] & R1_SPI_IDLE)) | |
151 | break; | |
152 | } else { | |
153 | if (cmd.resp[0] & MMC_CARD_BUSY) | |
154 | break; | |
155 | } | |
156 | ||
17b0429d | 157 | err = -ETIMEDOUT; |
da7fbe58 PO |
158 | |
159 | mmc_delay(10); | |
160 | } | |
161 | ||
5e863662 JR |
162 | if (!i) |
163 | pr_err("%s: card never left busy state\n", mmc_hostname(host)); | |
164 | ||
af517150 | 165 | if (rocr && !mmc_host_is_spi(host)) |
da7fbe58 PO |
166 | *rocr = cmd.resp[0]; |
167 | ||
168 | return err; | |
169 | } | |
170 | ||
171 | int mmc_send_if_cond(struct mmc_host *host, u32 ocr) | |
172 | { | |
c7836d15 | 173 | struct mmc_command cmd = {}; |
da7fbe58 PO |
174 | int err; |
175 | static const u8 test_pattern = 0xAA; | |
af517150 | 176 | u8 result_pattern; |
da7fbe58 PO |
177 | |
178 | /* | |
179 | * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND | |
180 | * before SD_APP_OP_COND. This command will harmlessly fail for | |
181 | * SD 1.0 cards. | |
182 | */ | |
183 | cmd.opcode = SD_SEND_IF_COND; | |
184 | cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; | |
af517150 | 185 | cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; |
da7fbe58 PO |
186 | |
187 | err = mmc_wait_for_cmd(host, &cmd, 0); | |
17b0429d | 188 | if (err) |
da7fbe58 PO |
189 | return err; |
190 | ||
af517150 DB |
191 | if (mmc_host_is_spi(host)) |
192 | result_pattern = cmd.resp[1] & 0xFF; | |
193 | else | |
194 | result_pattern = cmd.resp[0] & 0xFF; | |
195 | ||
196 | if (result_pattern != test_pattern) | |
17b0429d | 197 | return -EIO; |
da7fbe58 | 198 | |
17b0429d | 199 | return 0; |
da7fbe58 PO |
200 | } |
201 | ||
202 | int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) | |
203 | { | |
204 | int err; | |
c7836d15 | 205 | struct mmc_command cmd = {}; |
da7fbe58 | 206 | |
da7fbe58 PO |
207 | cmd.opcode = SD_SEND_RELATIVE_ADDR; |
208 | cmd.arg = 0; | |
209 | cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; | |
210 | ||
211 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); | |
17b0429d | 212 | if (err) |
da7fbe58 PO |
213 | return err; |
214 | ||
215 | *rca = cmd.resp[0] >> 16; | |
216 | ||
17b0429d | 217 | return 0; |
da7fbe58 PO |
218 | } |
219 | ||
06c9ccb7 | 220 | int mmc_app_send_scr(struct mmc_card *card) |
da7fbe58 PO |
221 | { |
222 | int err; | |
c7836d15 MY |
223 | struct mmc_request mrq = {}; |
224 | struct mmc_command cmd = {}; | |
225 | struct mmc_data data = {}; | |
da7fbe58 | 226 | struct scatterlist sg; |
06c9ccb7 | 227 | __be32 *scr; |
da7fbe58 | 228 | |
af517150 DB |
229 | /* NOTE: caller guarantees scr is heap-allocated */ |
230 | ||
da7fbe58 | 231 | err = mmc_app_cmd(card->host, card); |
17b0429d | 232 | if (err) |
da7fbe58 PO |
233 | return err; |
234 | ||
4f665cb6 YS |
235 | /* dma onto stack is unsafe/nonportable, but callers to this |
236 | * routine normally provide temporary on-stack buffers ... | |
237 | */ | |
06c9ccb7 WT |
238 | scr = kmalloc(sizeof(card->raw_scr), GFP_KERNEL); |
239 | if (!scr) | |
4f665cb6 YS |
240 | return -ENOMEM; |
241 | ||
da7fbe58 PO |
242 | mrq.cmd = &cmd; |
243 | mrq.data = &data; | |
244 | ||
245 | cmd.opcode = SD_APP_SEND_SCR; | |
246 | cmd.arg = 0; | |
af517150 | 247 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; |
da7fbe58 PO |
248 | |
249 | data.blksz = 8; | |
250 | data.blocks = 1; | |
251 | data.flags = MMC_DATA_READ; | |
252 | data.sg = &sg; | |
253 | data.sg_len = 1; | |
254 | ||
06c9ccb7 | 255 | sg_init_one(&sg, scr, 8); |
da7fbe58 | 256 | |
b146d26a | 257 | mmc_set_data_timeout(&data, card); |
da7fbe58 PO |
258 | |
259 | mmc_wait_for_req(card->host, &mrq); | |
260 | ||
06c9ccb7 WT |
261 | card->raw_scr[0] = be32_to_cpu(scr[0]); |
262 | card->raw_scr[1] = be32_to_cpu(scr[1]); | |
263 | ||
264 | kfree(scr); | |
4f665cb6 | 265 | |
17b0429d | 266 | if (cmd.error) |
da7fbe58 | 267 | return cmd.error; |
17b0429d | 268 | if (data.error) |
da7fbe58 PO |
269 | return data.error; |
270 | ||
17b0429d | 271 | return 0; |
da7fbe58 PO |
272 | } |
273 | ||
274 | int mmc_sd_switch(struct mmc_card *card, int mode, int group, | |
275 | u8 value, u8 *resp) | |
276 | { | |
c7836d15 MY |
277 | struct mmc_request mrq = {}; |
278 | struct mmc_command cmd = {}; | |
279 | struct mmc_data data = {}; | |
da7fbe58 PO |
280 | struct scatterlist sg; |
281 | ||
af517150 DB |
282 | /* NOTE: caller guarantees resp is heap-allocated */ |
283 | ||
da7fbe58 PO |
284 | mode = !!mode; |
285 | value &= 0xF; | |
286 | ||
da7fbe58 PO |
287 | mrq.cmd = &cmd; |
288 | mrq.data = &data; | |
289 | ||
290 | cmd.opcode = SD_SWITCH; | |
291 | cmd.arg = mode << 31 | 0x00FFFFFF; | |
292 | cmd.arg &= ~(0xF << (group * 4)); | |
293 | cmd.arg |= value << (group * 4); | |
af517150 | 294 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; |
da7fbe58 PO |
295 | |
296 | data.blksz = 64; | |
297 | data.blocks = 1; | |
298 | data.flags = MMC_DATA_READ; | |
299 | data.sg = &sg; | |
300 | data.sg_len = 1; | |
301 | ||
302 | sg_init_one(&sg, resp, 64); | |
303 | ||
b146d26a | 304 | mmc_set_data_timeout(&data, card); |
da7fbe58 PO |
305 | |
306 | mmc_wait_for_req(card->host, &mrq); | |
307 | ||
17b0429d | 308 | if (cmd.error) |
da7fbe58 | 309 | return cmd.error; |
17b0429d | 310 | if (data.error) |
da7fbe58 PO |
311 | return data.error; |
312 | ||
17b0429d | 313 | return 0; |
da7fbe58 PO |
314 | } |
315 | ||
dfe86cba AH |
316 | int mmc_app_sd_status(struct mmc_card *card, void *ssr) |
317 | { | |
318 | int err; | |
c7836d15 MY |
319 | struct mmc_request mrq = {}; |
320 | struct mmc_command cmd = {}; | |
321 | struct mmc_data data = {}; | |
dfe86cba AH |
322 | struct scatterlist sg; |
323 | ||
dfe86cba AH |
324 | /* NOTE: caller guarantees ssr is heap-allocated */ |
325 | ||
326 | err = mmc_app_cmd(card->host, card); | |
327 | if (err) | |
328 | return err; | |
329 | ||
dfe86cba AH |
330 | mrq.cmd = &cmd; |
331 | mrq.data = &data; | |
332 | ||
333 | cmd.opcode = SD_APP_SD_STATUS; | |
334 | cmd.arg = 0; | |
335 | cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC; | |
336 | ||
337 | data.blksz = 64; | |
338 | data.blocks = 1; | |
339 | data.flags = MMC_DATA_READ; | |
340 | data.sg = &sg; | |
341 | data.sg_len = 1; | |
342 | ||
343 | sg_init_one(&sg, ssr, 64); | |
344 | ||
345 | mmc_set_data_timeout(&data, card); | |
346 | ||
347 | mmc_wait_for_req(card->host, &mrq); | |
348 | ||
349 | if (cmd.error) | |
350 | return cmd.error; | |
351 | if (data.error) | |
352 | return data.error; | |
353 | ||
354 | return 0; | |
355 | } |