diff options
| author | David Brownell <david-b@pacbell.net> | 2007-08-08 12:11:32 -0400 |
|---|---|---|
| committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-09-23 15:51:30 -0400 |
| commit | af51715079e7fb6b290e1881d63d815dc4de5011 (patch) | |
| tree | 324e81b2346955f130dda8515f2ad4f4ce97c864 /drivers/mmc/core | |
| parent | 7213d175e3b6f6db60f843b72e88857a350e146a (diff) | |
MMC core learns about SPI
Teach the MMC/SD/SDIO core about using SPI mode.
- Use mmc_host_is_spi() so enumeration works through SPI signaling
and protocols, not just the native versions.
- Provide the SPI response type flags with each request issued,
including requests from the new lock/unlock code.
- Understand that cmd->resp[0] and mmc_get_status() results for SPI
return different values than for "native" MMC/SD protocol; this
affects resetting, checking card lock status, and some others.
- Understand that some commands act a bit differently ... notably:
* OP_COND command doesn't return the OCR
* APP_CMD status doesn't have an R1_APP_CMD analogue
Those changes required some new and updated primitives:
- Provide utilities to access two SPI-only requests, and one
request that wasn't previously needed:
* mmc_spi_read_ocr() ... SPI only
* mmc_spi_set_crc() ... SPI only (override by module parm)
* mmc_send_cid() ... for use without broadcast mode
- Updated internal routines:
* Previous mmc_send_csd() modified into mmc_send_cxd_native();
it uses native "R2" responses, which include 16 bytes of data.
* Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data()
helper for command-and-data access
* Bugfix to that mmc_send_cxd_data() code: dma-to-stack is
unsafe/nonportable, so kmalloc a bounce buffer instead.
- Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper
- Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use
those helper routines based on whether they're native or SPI
The newest categories of cards supported by the MMC stack aren't expected
to work yet with SPI: MMC or SD cards with over 4GB data, and SDIO.
All those cards support SPI mode, so eventually they should work too.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core')
| -rw-r--r-- | drivers/mmc/core/bus.c | 24 | ||||
| -rw-r--r-- | drivers/mmc/core/core.c | 28 | ||||
| -rw-r--r-- | drivers/mmc/core/core.h | 2 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 50 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc_ops.c | 166 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc_ops.h | 3 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.c | 48 | ||||
| -rw-r--r-- | drivers/mmc/core/sd_ops.c | 59 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio.c | 29 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio_ops.c | 66 |
10 files changed, 372 insertions, 103 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 733ac95331c7..8d6f6014870f 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c | |||
| @@ -243,10 +243,17 @@ int mmc_add_card(struct mmc_card *card) | |||
| 243 | break; | 243 | break; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | printk(KERN_INFO "%s: new %s%s card at address %04x\n", | 246 | if (mmc_host_is_spi(card->host)) { |
| 247 | mmc_hostname(card->host), | 247 | printk(KERN_INFO "%s: new %s%s card on SPI\n", |
| 248 | mmc_card_highspeed(card) ? "high speed " : "", | 248 | mmc_hostname(card->host), |
| 249 | type, card->rca); | 249 | mmc_card_highspeed(card) ? "high speed " : "", |
| 250 | type); | ||
| 251 | } else { | ||
| 252 | printk(KERN_INFO "%s: new %s%s card at address %04x\n", | ||
| 253 | mmc_hostname(card->host), | ||
| 254 | mmc_card_highspeed(card) ? "high speed " : "", | ||
| 255 | type, card->rca); | ||
| 256 | } | ||
| 250 | 257 | ||
| 251 | card->dev.uevent_suppress = 1; | 258 | card->dev.uevent_suppress = 1; |
| 252 | 259 | ||
| @@ -278,8 +285,13 @@ int mmc_add_card(struct mmc_card *card) | |||
| 278 | void mmc_remove_card(struct mmc_card *card) | 285 | void mmc_remove_card(struct mmc_card *card) |
| 279 | { | 286 | { |
| 280 | if (mmc_card_present(card)) { | 287 | if (mmc_card_present(card)) { |
| 281 | printk(KERN_INFO "%s: card %04x removed\n", | 288 | if (mmc_host_is_spi(card->host)) { |
| 282 | mmc_hostname(card->host), card->rca); | 289 | printk(KERN_INFO "%s: SPI card removed\n", |
| 290 | mmc_hostname(card->host)); | ||
| 291 | } else { | ||
| 292 | printk(KERN_INFO "%s: card %04x removed\n", | ||
| 293 | mmc_hostname(card->host), card->rca); | ||
| 294 | } | ||
| 283 | 295 | ||
| 284 | if (card->host->bus_ops->sysfs_remove) | 296 | if (card->host->bus_ops->sysfs_remove) |
| 285 | card->host->bus_ops->sysfs_remove(card->host, card); | 297 | card->host->bus_ops->sysfs_remove(card->host, card); |
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bffcaf8df352..bad39442f8fe 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
| @@ -42,6 +42,14 @@ extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr); | |||
| 42 | static struct workqueue_struct *workqueue; | 42 | static struct workqueue_struct *workqueue; |
| 43 | 43 | ||
| 44 | /* | 44 | /* |
| 45 | * Enabling software CRCs on the data blocks can be a significant (30%) | ||
| 46 | * performance cost, and for other reasons may not always be desired. | ||
| 47 | * So we allow it it to be disabled. | ||
| 48 | */ | ||
| 49 | int use_spi_crc = 1; | ||
| 50 | module_param(use_spi_crc, bool, 0); | ||
| 51 | |||
| 52 | /* | ||
| 45 | * Internal function. Schedule delayed work in the MMC work queue. | 53 | * Internal function. Schedule delayed work in the MMC work queue. |
| 46 | */ | 54 | */ |
| 47 | static int mmc_schedule_delayed_work(struct delayed_work *work, | 55 | static int mmc_schedule_delayed_work(struct delayed_work *work, |
| @@ -71,6 +79,11 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) | |||
| 71 | struct mmc_command *cmd = mrq->cmd; | 79 | struct mmc_command *cmd = mrq->cmd; |
| 72 | int err = cmd->error; | 80 | int err = cmd->error; |
| 73 | 81 | ||
| 82 | if (err && cmd->retries && mmc_host_is_spi(host)) { | ||
| 83 | if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) | ||
| 84 | cmd->retries = 0; | ||
| 85 | } | ||
| 86 | |||
| 74 | if (err && cmd->retries) { | 87 | if (err && cmd->retries) { |
| 75 | pr_debug("%s: req failed (CMD%u): %d, retrying...\n", | 88 | pr_debug("%s: req failed (CMD%u): %d, retrying...\n", |
| 76 | mmc_hostname(host), cmd->opcode, err); | 89 | mmc_hostname(host), cmd->opcode, err); |
| @@ -453,8 +466,13 @@ static void mmc_power_up(struct mmc_host *host) | |||
| 453 | int bit = fls(host->ocr_avail) - 1; | 466 | int bit = fls(host->ocr_avail) - 1; |
| 454 | 467 | ||
| 455 | host->ios.vdd = bit; | 468 | host->ios.vdd = bit; |
| 456 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | 469 | if (mmc_host_is_spi(host)) { |
| 457 | host->ios.chip_select = MMC_CS_DONTCARE; | 470 | host->ios.chip_select = MMC_CS_HIGH; |
| 471 | host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; | ||
| 472 | } else { | ||
| 473 | host->ios.chip_select = MMC_CS_DONTCARE; | ||
| 474 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | ||
| 475 | } | ||
| 458 | host->ios.power_mode = MMC_POWER_UP; | 476 | host->ios.power_mode = MMC_POWER_UP; |
| 459 | host->ios.bus_width = MMC_BUS_WIDTH_1; | 477 | host->ios.bus_width = MMC_BUS_WIDTH_1; |
| 460 | host->ios.timing = MMC_TIMING_LEGACY; | 478 | host->ios.timing = MMC_TIMING_LEGACY; |
| @@ -481,8 +499,10 @@ static void mmc_power_off(struct mmc_host *host) | |||
| 481 | { | 499 | { |
| 482 | host->ios.clock = 0; | 500 | host->ios.clock = 0; |
| 483 | host->ios.vdd = 0; | 501 | host->ios.vdd = 0; |
| 484 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | 502 | if (!mmc_host_is_spi(host)) { |
| 485 | host->ios.chip_select = MMC_CS_DONTCARE; | 503 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; |
| 504 | host->ios.chip_select = MMC_CS_DONTCARE; | ||
| 505 | } | ||
| 486 | host->ios.power_mode = MMC_POWER_OFF; | 506 | host->ios.power_mode = MMC_POWER_OFF; |
| 487 | host->ios.bus_width = MMC_BUS_WIDTH_1; | 507 | host->ios.bus_width = MMC_BUS_WIDTH_1; |
| 488 | host->ios.timing = MMC_TIMING_LEGACY; | 508 | host->ios.timing = MMC_TIMING_LEGACY; |
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index bb2774af9ea9..39daf2fb5dc4 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h | |||
| @@ -48,5 +48,7 @@ void mmc_rescan(struct work_struct *work); | |||
| 48 | void mmc_start_host(struct mmc_host *host); | 48 | void mmc_start_host(struct mmc_host *host); |
| 49 | void mmc_stop_host(struct mmc_host *host); | 49 | void mmc_stop_host(struct mmc_host *host); |
| 50 | 50 | ||
| 51 | extern int use_spi_crc; | ||
| 52 | |||
| 51 | #endif | 53 | #endif |
| 52 | 54 | ||
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6ba458951d24..65fe28860f54 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
| @@ -165,8 +165,6 @@ static int mmc_read_ext_csd(struct mmc_card *card) | |||
| 165 | 165 | ||
| 166 | BUG_ON(!card); | 166 | BUG_ON(!card); |
| 167 | 167 | ||
| 168 | err = -EIO; | ||
| 169 | |||
| 170 | if (card->csd.mmca_vsn < CSD_SPEC_VER_4) | 168 | if (card->csd.mmca_vsn < CSD_SPEC_VER_4) |
| 171 | return 0; | 169 | return 0; |
| 172 | 170 | ||
| @@ -280,9 +278,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 280 | goto err; | 278 | goto err; |
| 281 | 279 | ||
| 282 | /* | 280 | /* |
| 281 | * For SPI, enable CRC as appropriate. | ||
| 282 | */ | ||
| 283 | if (mmc_host_is_spi(host)) { | ||
| 284 | err = mmc_spi_set_crc(host, use_spi_crc); | ||
| 285 | if (err) | ||
| 286 | goto err; | ||
| 287 | } | ||
| 288 | |||
| 289 | /* | ||
| 283 | * Fetch CID from card. | 290 | * Fetch CID from card. |
| 284 | */ | 291 | */ |
| 285 | err = mmc_all_send_cid(host, cid); | 292 | if (mmc_host_is_spi(host)) |
| 293 | err = mmc_send_cid(host, cid); | ||
| 294 | else | ||
| 295 | err = mmc_all_send_cid(host, cid); | ||
| 286 | if (err) | 296 | if (err) |
| 287 | goto err; | 297 | goto err; |
| 288 | 298 | ||
| @@ -309,13 +319,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 309 | } | 319 | } |
| 310 | 320 | ||
| 311 | /* | 321 | /* |
| 312 | * Set card RCA. | 322 | * For native busses: set card RCA and quit open drain mode. |
| 313 | */ | 323 | */ |
| 314 | err = mmc_set_relative_addr(card); | 324 | if (!mmc_host_is_spi(host)) { |
| 315 | if (err) | 325 | err = mmc_set_relative_addr(card); |
| 316 | goto free_card; | 326 | if (err) |
| 327 | goto free_card; | ||
| 317 | 328 | ||
| 318 | mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); | 329 | mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); |
| 330 | } | ||
| 319 | 331 | ||
| 320 | if (!oldcard) { | 332 | if (!oldcard) { |
| 321 | /* | 333 | /* |
| @@ -336,13 +348,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 336 | /* | 348 | /* |
| 337 | * Select card, as all following commands rely on that. | 349 | * Select card, as all following commands rely on that. |
| 338 | */ | 350 | */ |
| 339 | err = mmc_select_card(card); | 351 | if (!mmc_host_is_spi(host)) { |
| 340 | if (err) | 352 | err = mmc_select_card(card); |
| 341 | goto free_card; | 353 | if (err) |
| 354 | goto free_card; | ||
| 355 | } | ||
| 342 | 356 | ||
| 343 | if (!oldcard) { | 357 | if (!oldcard) { |
| 344 | /* | 358 | /* |
| 345 | * Fetch and process extened CSD. | 359 | * Fetch and process extended CSD. |
| 346 | */ | 360 | */ |
| 347 | err = mmc_read_ext_csd(card); | 361 | err = mmc_read_ext_csd(card); |
| 348 | if (err) | 362 | if (err) |
| @@ -502,7 +516,8 @@ static void mmc_suspend(struct mmc_host *host) | |||
| 502 | BUG_ON(!host->card); | 516 | BUG_ON(!host->card); |
| 503 | 517 | ||
| 504 | mmc_claim_host(host); | 518 | mmc_claim_host(host); |
| 505 | mmc_deselect_cards(host); | 519 | if (!mmc_host_is_spi(host)) |
| 520 | mmc_deselect_cards(host); | ||
| 506 | host->card->state &= ~MMC_STATE_HIGHSPEED; | 521 | host->card->state &= ~MMC_STATE_HIGHSPEED; |
| 507 | mmc_release_host(host); | 522 | mmc_release_host(host); |
| 508 | } | 523 | } |
| @@ -563,6 +578,15 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) | |||
| 563 | mmc_attach_bus(host, &mmc_ops); | 578 | mmc_attach_bus(host, &mmc_ops); |
| 564 | 579 | ||
| 565 | /* | 580 | /* |
| 581 | * We need to get OCR a different way for SPI. | ||
| 582 | */ | ||
| 583 | if (mmc_host_is_spi(host)) { | ||
| 584 | err = mmc_spi_read_ocr(host, 1, &ocr); | ||
| 585 | if (err) | ||
| 586 | goto err; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* | ||
| 566 | * Sanity check the voltages that the card claims to | 590 | * Sanity check the voltages that the card claims to |
| 567 | * support. | 591 | * support. |
| 568 | */ | 592 | */ |
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 39567f91a4b8..bf4bc6adcfef 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c | |||
| @@ -63,23 +63,36 @@ int mmc_go_idle(struct mmc_host *host) | |||
| 63 | int err; | 63 | int err; |
| 64 | struct mmc_command cmd; | 64 | struct mmc_command cmd; |
| 65 | 65 | ||
| 66 | mmc_set_chip_select(host, MMC_CS_HIGH); | 66 | /* |
| 67 | 67 | * Non-SPI hosts need to prevent chipselect going active during | |
| 68 | mmc_delay(1); | 68 | * GO_IDLE; that would put chips into SPI mode. Remind them of |
| 69 | * that in case of hardware that won't pull up DAT3/nCS otherwise. | ||
| 70 | * | ||
| 71 | * SPI hosts ignore ios.chip_select; it's managed according to | ||
| 72 | * rules that must accomodate non-MMC slaves which this layer | ||
| 73 | * won't even know about. | ||
| 74 | */ | ||
| 75 | if (!mmc_host_is_spi(host)) { | ||
| 76 | mmc_set_chip_select(host, MMC_CS_HIGH); | ||
| 77 | mmc_delay(1); | ||
| 78 | } | ||
| 69 | 79 | ||
| 70 | memset(&cmd, 0, sizeof(struct mmc_command)); | 80 | memset(&cmd, 0, sizeof(struct mmc_command)); |
| 71 | 81 | ||
| 72 | cmd.opcode = MMC_GO_IDLE_STATE; | 82 | cmd.opcode = MMC_GO_IDLE_STATE; |
| 73 | cmd.arg = 0; | 83 | cmd.arg = 0; |
| 74 | cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; | 84 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; |
| 75 | 85 | ||
| 76 | err = mmc_wait_for_cmd(host, &cmd, 0); | 86 | err = mmc_wait_for_cmd(host, &cmd, 0); |
| 77 | 87 | ||
| 78 | mmc_delay(1); | 88 | mmc_delay(1); |
| 79 | 89 | ||
| 80 | mmc_set_chip_select(host, MMC_CS_DONTCARE); | 90 | if (!mmc_host_is_spi(host)) { |
| 91 | mmc_set_chip_select(host, MMC_CS_DONTCARE); | ||
| 92 | mmc_delay(1); | ||
| 93 | } | ||
| 81 | 94 | ||
| 82 | mmc_delay(1); | 95 | host->use_spi_crc = 0; |
| 83 | 96 | ||
| 84 | return err; | 97 | return err; |
| 85 | } | 98 | } |
| @@ -94,23 +107,33 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | |||
| 94 | memset(&cmd, 0, sizeof(struct mmc_command)); | 107 | memset(&cmd, 0, sizeof(struct mmc_command)); |
| 95 | 108 | ||
| 96 | cmd.opcode = MMC_SEND_OP_COND; | 109 | cmd.opcode = MMC_SEND_OP_COND; |
| 97 | cmd.arg = ocr; | 110 | cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; |
| 98 | cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; | 111 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; |
| 99 | 112 | ||
| 100 | for (i = 100; i; i--) { | 113 | for (i = 100; i; i--) { |
| 101 | err = mmc_wait_for_cmd(host, &cmd, 0); | 114 | err = mmc_wait_for_cmd(host, &cmd, 0); |
| 102 | if (err) | 115 | if (err) |
| 103 | break; | 116 | break; |
| 104 | 117 | ||
| 105 | if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) | 118 | /* if we're just probing, do a single pass */ |
| 119 | if (ocr == 0) | ||
| 106 | break; | 120 | break; |
| 107 | 121 | ||
| 122 | /* otherwise wait until reset completes */ | ||
| 123 | if (mmc_host_is_spi(host)) { | ||
| 124 | if (!(cmd.resp[0] & R1_SPI_IDLE)) | ||
| 125 | break; | ||
| 126 | } else { | ||
| 127 | if (cmd.resp[0] & MMC_CARD_BUSY) | ||
| 128 | break; | ||
| 129 | } | ||
| 130 | |||
| 108 | err = -ETIMEDOUT; | 131 | err = -ETIMEDOUT; |
| 109 | 132 | ||
| 110 | mmc_delay(10); | 133 | mmc_delay(10); |
| 111 | } | 134 | } |
| 112 | 135 | ||
| 113 | if (rocr) | 136 | if (rocr && !mmc_host_is_spi(host)) |
| 114 | *rocr = cmd.resp[0]; | 137 | *rocr = cmd.resp[0]; |
| 115 | 138 | ||
| 116 | return err; | 139 | return err; |
| @@ -160,40 +183,46 @@ int mmc_set_relative_addr(struct mmc_card *card) | |||
| 160 | return 0; | 183 | return 0; |
| 161 | } | 184 | } |
| 162 | 185 | ||
| 163 | int mmc_send_csd(struct mmc_card *card, u32 *csd) | 186 | static int |
| 187 | mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) | ||
| 164 | { | 188 | { |
| 165 | int err; | 189 | int err; |
| 166 | struct mmc_command cmd; | 190 | struct mmc_command cmd; |
| 167 | 191 | ||
| 168 | BUG_ON(!card); | 192 | BUG_ON(!host); |
| 169 | BUG_ON(!card->host); | 193 | BUG_ON(!cxd); |
| 170 | BUG_ON(!csd); | ||
| 171 | 194 | ||
| 172 | memset(&cmd, 0, sizeof(struct mmc_command)); | 195 | memset(&cmd, 0, sizeof(struct mmc_command)); |
| 173 | 196 | ||
| 174 | cmd.opcode = MMC_SEND_CSD; | 197 | cmd.opcode = opcode; |
| 175 | cmd.arg = card->rca << 16; | 198 | cmd.arg = arg; |
| 176 | cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; | 199 | cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; |
| 177 | 200 | ||
| 178 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | 201 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); |
| 179 | if (err) | 202 | if (err) |
| 180 | return err; | 203 | return err; |
| 181 | 204 | ||
| 182 | memcpy(csd, cmd.resp, sizeof(u32) * 4); | 205 | memcpy(cxd, cmd.resp, sizeof(u32) * 4); |
| 183 | 206 | ||
| 184 | return 0; | 207 | return 0; |
| 185 | } | 208 | } |
| 186 | 209 | ||
| 187 | int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | 210 | static int |
| 211 | mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, | ||
| 212 | u32 opcode, void *buf, unsigned len) | ||
| 188 | { | 213 | { |
| 189 | struct mmc_request mrq; | 214 | struct mmc_request mrq; |
| 190 | struct mmc_command cmd; | 215 | struct mmc_command cmd; |
| 191 | struct mmc_data data; | 216 | struct mmc_data data; |
| 192 | struct scatterlist sg; | 217 | struct scatterlist sg; |
| 218 | void *data_buf; | ||
| 193 | 219 | ||
| 194 | BUG_ON(!card); | 220 | /* dma onto stack is unsafe/nonportable, but callers to this |
| 195 | BUG_ON(!card->host); | 221 | * routine normally provide temporary on-stack buffers ... |
| 196 | BUG_ON(!ext_csd); | 222 | */ |
| 223 | data_buf = kmalloc(len, GFP_KERNEL); | ||
| 224 | if (data_buf == NULL) | ||
| 225 | return -ENOMEM; | ||
| 197 | 226 | ||
| 198 | memset(&mrq, 0, sizeof(struct mmc_request)); | 227 | memset(&mrq, 0, sizeof(struct mmc_request)); |
| 199 | memset(&cmd, 0, sizeof(struct mmc_command)); | 228 | memset(&cmd, 0, sizeof(struct mmc_command)); |
| @@ -202,21 +231,31 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 202 | mrq.cmd = &cmd; | 231 | mrq.cmd = &cmd; |
| 203 | mrq.data = &data; | 232 | mrq.data = &data; |
| 204 | 233 | ||
| 205 | cmd.opcode = MMC_SEND_EXT_CSD; | 234 | cmd.opcode = opcode; |
| 206 | cmd.arg = 0; | 235 | cmd.arg = 0; |
| 207 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
| 208 | 236 | ||
| 209 | data.blksz = 512; | 237 | /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we |
| 238 | * rely on callers to never use this with "native" calls for reading | ||
| 239 | * CSD or CID. Native versions of those commands use the R2 type, | ||
| 240 | * not R1 plus a data block. | ||
| 241 | */ | ||
| 242 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; | ||
| 243 | |||
| 244 | data.blksz = len; | ||
| 210 | data.blocks = 1; | 245 | data.blocks = 1; |
| 211 | data.flags = MMC_DATA_READ; | 246 | data.flags = MMC_DATA_READ; |
| 212 | data.sg = &sg; | 247 | data.sg = &sg; |
| 213 | data.sg_len = 1; | 248 | data.sg_len = 1; |
| 214 | 249 | ||
| 215 | sg_init_one(&sg, ext_csd, 512); | 250 | sg_init_one(&sg, data_buf, len); |
| 216 | 251 | ||
| 217 | mmc_set_data_timeout(&data, card); | 252 | if (card) |
| 253 | mmc_set_data_timeout(&data, card); | ||
| 218 | 254 | ||
| 219 | mmc_wait_for_req(card->host, &mrq); | 255 | mmc_wait_for_req(host, &mrq); |
| 256 | |||
| 257 | memcpy(buf, data_buf, len); | ||
| 258 | kfree(data_buf); | ||
| 220 | 259 | ||
| 221 | if (cmd.error) | 260 | if (cmd.error) |
| 222 | return cmd.error; | 261 | return cmd.error; |
| @@ -226,6 +265,67 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 226 | return 0; | 265 | return 0; |
| 227 | } | 266 | } |
| 228 | 267 | ||
| 268 | int mmc_send_csd(struct mmc_card *card, u32 *csd) | ||
| 269 | { | ||
| 270 | if (!mmc_host_is_spi(card->host)) | ||
| 271 | return mmc_send_cxd_native(card->host, card->rca << 16, | ||
| 272 | csd, MMC_SEND_CSD); | ||
| 273 | |||
| 274 | return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16); | ||
| 275 | } | ||
| 276 | |||
| 277 | int mmc_send_cid(struct mmc_host *host, u32 *cid) | ||
| 278 | { | ||
| 279 | if (!mmc_host_is_spi(host)) { | ||
| 280 | if (!host->card) | ||
| 281 | return -EINVAL; | ||
| 282 | return mmc_send_cxd_native(host, host->card->rca << 16, | ||
| 283 | cid, MMC_SEND_CID); | ||
| 284 | } | ||
| 285 | |||
| 286 | return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16); | ||
| 287 | } | ||
| 288 | |||
| 289 | int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | ||
| 290 | { | ||
| 291 | return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, | ||
| 292 | ext_csd, 512); | ||
| 293 | } | ||
| 294 | |||
| 295 | int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp) | ||
| 296 | { | ||
| 297 | struct mmc_command cmd; | ||
| 298 | int err; | ||
| 299 | |||
| 300 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
| 301 | |||
| 302 | cmd.opcode = MMC_SPI_READ_OCR; | ||
| 303 | cmd.arg = highcap ? (1 << 30) : 0; | ||
| 304 | cmd.flags = MMC_RSP_SPI_R3; | ||
| 305 | |||
| 306 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
| 307 | |||
| 308 | *ocrp = cmd.resp[1]; | ||
| 309 | return err; | ||
| 310 | } | ||
| 311 | |||
| 312 | int mmc_spi_set_crc(struct mmc_host *host, int use_crc) | ||
| 313 | { | ||
| 314 | struct mmc_command cmd; | ||
| 315 | int err; | ||
| 316 | |||
| 317 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
| 318 | |||
| 319 | cmd.opcode = MMC_SPI_CRC_ON_OFF; | ||
| 320 | cmd.flags = MMC_RSP_SPI_R1; | ||
| 321 | cmd.arg = use_crc; | ||
| 322 | |||
| 323 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
| 324 | if (!err) | ||
| 325 | host->use_spi_crc = use_crc; | ||
| 326 | return err; | ||
| 327 | } | ||
| 328 | |||
| 229 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) | 329 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) |
| 230 | { | 330 | { |
| 231 | int err; | 331 | int err; |
| @@ -241,7 +341,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) | |||
| 241 | (index << 16) | | 341 | (index << 16) | |
| 242 | (value << 8) | | 342 | (value << 8) | |
| 243 | set; | 343 | set; |
| 244 | cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; | 344 | cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; |
| 245 | 345 | ||
| 246 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | 346 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); |
| 247 | if (err) | 347 | if (err) |
| @@ -261,13 +361,17 @@ int mmc_send_status(struct mmc_card *card, u32 *status) | |||
| 261 | memset(&cmd, 0, sizeof(struct mmc_command)); | 361 | memset(&cmd, 0, sizeof(struct mmc_command)); |
| 262 | 362 | ||
| 263 | cmd.opcode = MMC_SEND_STATUS; | 363 | cmd.opcode = MMC_SEND_STATUS; |
| 264 | cmd.arg = card->rca << 16; | 364 | if (!mmc_host_is_spi(card->host)) |
| 265 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | 365 | cmd.arg = card->rca << 16; |
| 366 | cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; | ||
| 266 | 367 | ||
| 267 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | 368 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); |
| 268 | if (err) | 369 | if (err) |
| 269 | return err; | 370 | return err; |
| 270 | 371 | ||
| 372 | /* NOTE: callers are required to understand the difference | ||
| 373 | * between "native" and SPI format status words! | ||
| 374 | */ | ||
| 271 | if (status) | 375 | if (status) |
| 272 | *status = cmd.resp[0]; | 376 | *status = cmd.resp[0]; |
| 273 | 377 | ||
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 76d09a93c5d6..17854bf7cf0d 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h | |||
| @@ -22,6 +22,9 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd); | |||
| 22 | int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); | 22 | int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); |
| 23 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); | 23 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); |
| 24 | int mmc_send_status(struct mmc_card *card, u32 *status); | 24 | int mmc_send_status(struct mmc_card *card, u32 *status); |
| 25 | int mmc_send_cid(struct mmc_host *host, u32 *cid); | ||
| 26 | int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); | ||
| 27 | int mmc_spi_set_crc(struct mmc_host *host, int use_crc); | ||
| 25 | 28 | ||
| 26 | #endif | 29 | #endif |
| 27 | 30 | ||
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index c86588fdaae5..d1c1e0f592f1 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c | |||
| @@ -323,9 +323,21 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, | |||
| 323 | goto err; | 323 | goto err; |
| 324 | 324 | ||
| 325 | /* | 325 | /* |
| 326 | * For SPI, enable CRC as appropriate. | ||
| 327 | */ | ||
| 328 | if (mmc_host_is_spi(host)) { | ||
| 329 | err = mmc_spi_set_crc(host, use_spi_crc); | ||
| 330 | if (err) | ||
| 331 | goto err; | ||
| 332 | } | ||
| 333 | |||
| 334 | /* | ||
| 326 | * Fetch CID from card. | 335 | * Fetch CID from card. |
| 327 | */ | 336 | */ |
| 328 | err = mmc_all_send_cid(host, cid); | 337 | if (mmc_host_is_spi(host)) |
| 338 | err = mmc_send_cid(host, cid); | ||
| 339 | else | ||
| 340 | err = mmc_all_send_cid(host, cid); | ||
| 329 | if (err) | 341 | if (err) |
| 330 | goto err; | 342 | goto err; |
| 331 | 343 | ||
| @@ -351,13 +363,15 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, | |||
| 351 | } | 363 | } |
| 352 | 364 | ||
| 353 | /* | 365 | /* |
| 354 | * Set card RCA. | 366 | * For native busses: get card RCA and quit open drain mode. |
| 355 | */ | 367 | */ |
| 356 | err = mmc_send_relative_addr(host, &card->rca); | 368 | if (!mmc_host_is_spi(host)) { |
| 357 | if (err) | 369 | err = mmc_send_relative_addr(host, &card->rca); |
| 358 | goto free_card; | 370 | if (err) |
| 371 | goto free_card; | ||
| 359 | 372 | ||
| 360 | mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); | 373 | mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); |
| 374 | } | ||
| 361 | 375 | ||
| 362 | if (!oldcard) { | 376 | if (!oldcard) { |
| 363 | /* | 377 | /* |
| @@ -377,9 +391,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, | |||
| 377 | /* | 391 | /* |
| 378 | * Select card, as all following commands rely on that. | 392 | * Select card, as all following commands rely on that. |
| 379 | */ | 393 | */ |
| 380 | err = mmc_select_card(card); | 394 | if (!mmc_host_is_spi(host)) { |
| 381 | if (err) | 395 | err = mmc_select_card(card); |
| 382 | goto free_card; | 396 | if (err) |
| 397 | goto free_card; | ||
| 398 | } | ||
| 383 | 399 | ||
| 384 | if (!oldcard) { | 400 | if (!oldcard) { |
| 385 | /* | 401 | /* |
| @@ -562,7 +578,8 @@ static void mmc_sd_suspend(struct mmc_host *host) | |||
| 562 | BUG_ON(!host->card); | 578 | BUG_ON(!host->card); |
| 563 | 579 | ||
| 564 | mmc_claim_host(host); | 580 | mmc_claim_host(host); |
| 565 | mmc_deselect_cards(host); | 581 | if (!mmc_host_is_spi(host)) |
| 582 | mmc_deselect_cards(host); | ||
| 566 | host->card->state &= ~MMC_STATE_HIGHSPEED; | 583 | host->card->state &= ~MMC_STATE_HIGHSPEED; |
| 567 | mmc_release_host(host); | 584 | mmc_release_host(host); |
| 568 | } | 585 | } |
| @@ -623,6 +640,17 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) | |||
| 623 | mmc_attach_bus(host, &mmc_sd_ops); | 640 | mmc_attach_bus(host, &mmc_sd_ops); |
| 624 | 641 | ||
| 625 | /* | 642 | /* |
| 643 | * We need to get OCR a different way for SPI. | ||
| 644 | */ | ||
| 645 | if (mmc_host_is_spi(host)) { | ||
| 646 | mmc_go_idle(host); | ||
| 647 | |||
| 648 | err = mmc_spi_read_ocr(host, 0, &ocr); | ||
| 649 | if (err) | ||
| 650 | goto err; | ||
| 651 | } | ||
| 652 | |||
| 653 | /* | ||
| 626 | * Sanity check the voltages that the card claims to | 654 | * Sanity check the voltages that the card claims to |
| 627 | * support. | 655 | * support. |
| 628 | */ | 656 | */ |
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 491e0306b1b4..ee4029a24efd 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c | |||
| @@ -33,10 +33,10 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) | |||
| 33 | 33 | ||
| 34 | if (card) { | 34 | if (card) { |
| 35 | cmd.arg = card->rca << 16; | 35 | cmd.arg = card->rca << 16; |
| 36 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | 36 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; |
| 37 | } else { | 37 | } else { |
| 38 | cmd.arg = 0; | 38 | cmd.arg = 0; |
| 39 | cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR; | 39 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | err = mmc_wait_for_cmd(host, &cmd, 0); | 42 | err = mmc_wait_for_cmd(host, &cmd, 0); |
| @@ -44,7 +44,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) | |||
| 44 | return err; | 44 | return err; |
| 45 | 45 | ||
| 46 | /* Check that card supported application commands */ | 46 | /* Check that card supported application commands */ |
| 47 | if (!(cmd.resp[0] & R1_APP_CMD)) | 47 | if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) |
| 48 | return -EOPNOTSUPP; | 48 | return -EOPNOTSUPP; |
| 49 | 49 | ||
| 50 | return 0; | 50 | return 0; |
| @@ -83,8 +83,14 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, | |||
| 83 | memset(&mrq, 0, sizeof(struct mmc_request)); | 83 | memset(&mrq, 0, sizeof(struct mmc_request)); |
| 84 | 84 | ||
| 85 | err = mmc_app_cmd(host, card); | 85 | err = mmc_app_cmd(host, card); |
| 86 | if (err) | 86 | if (err) { |
| 87 | /* no point in retrying; no APP commands allowed */ | ||
| 88 | if (mmc_host_is_spi(host)) { | ||
| 89 | if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) | ||
| 90 | break; | ||
| 91 | } | ||
| 87 | continue; | 92 | continue; |
| 93 | } | ||
| 88 | 94 | ||
| 89 | memset(&mrq, 0, sizeof(struct mmc_request)); | 95 | memset(&mrq, 0, sizeof(struct mmc_request)); |
| 90 | 96 | ||
| @@ -99,6 +105,12 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, | |||
| 99 | err = cmd->error; | 105 | err = cmd->error; |
| 100 | if (!cmd->error) | 106 | if (!cmd->error) |
| 101 | break; | 107 | break; |
| 108 | |||
| 109 | /* no point in retrying illegal APP commands */ | ||
| 110 | if (mmc_host_is_spi(host)) { | ||
| 111 | if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) | ||
| 112 | break; | ||
| 113 | } | ||
| 102 | } | 114 | } |
| 103 | 115 | ||
| 104 | return err; | 116 | return err; |
| @@ -147,23 +159,36 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | |||
| 147 | memset(&cmd, 0, sizeof(struct mmc_command)); | 159 | memset(&cmd, 0, sizeof(struct mmc_command)); |
| 148 | 160 | ||
| 149 | cmd.opcode = SD_APP_OP_COND; | 161 | cmd.opcode = SD_APP_OP_COND; |
| 150 | cmd.arg = ocr; | 162 | if (mmc_host_is_spi(host)) |
| 151 | cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; | 163 | cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */ |
| 164 | else | ||
| 165 | cmd.arg = ocr; | ||
| 166 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; | ||
| 152 | 167 | ||
| 153 | for (i = 100; i; i--) { | 168 | for (i = 100; i; i--) { |
| 154 | err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); | 169 | err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); |
| 155 | if (err) | 170 | if (err) |
| 156 | break; | 171 | break; |
| 157 | 172 | ||
| 158 | if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) | 173 | /* if we're just probing, do a single pass */ |
| 174 | if (ocr == 0) | ||
| 159 | break; | 175 | break; |
| 160 | 176 | ||
| 177 | /* otherwise wait until reset completes */ | ||
| 178 | if (mmc_host_is_spi(host)) { | ||
| 179 | if (!(cmd.resp[0] & R1_SPI_IDLE)) | ||
| 180 | break; | ||
| 181 | } else { | ||
| 182 | if (cmd.resp[0] & MMC_CARD_BUSY) | ||
| 183 | break; | ||
| 184 | } | ||
| 185 | |||
| 161 | err = -ETIMEDOUT; | 186 | err = -ETIMEDOUT; |
| 162 | 187 | ||
| 163 | mmc_delay(10); | 188 | mmc_delay(10); |
| 164 | } | 189 | } |
| 165 | 190 | ||
| 166 | if (rocr) | 191 | if (rocr && !mmc_host_is_spi(host)) |
| 167 | *rocr = cmd.resp[0]; | 192 | *rocr = cmd.resp[0]; |
| 168 | 193 | ||
| 169 | return err; | 194 | return err; |
| @@ -174,6 +199,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) | |||
| 174 | struct mmc_command cmd; | 199 | struct mmc_command cmd; |
| 175 | int err; | 200 | int err; |
| 176 | static const u8 test_pattern = 0xAA; | 201 | static const u8 test_pattern = 0xAA; |
| 202 | u8 result_pattern; | ||
| 177 | 203 | ||
| 178 | /* | 204 | /* |
| 179 | * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND | 205 | * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND |
| @@ -182,13 +208,18 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr) | |||
| 182 | */ | 208 | */ |
| 183 | cmd.opcode = SD_SEND_IF_COND; | 209 | cmd.opcode = SD_SEND_IF_COND; |
| 184 | cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; | 210 | cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; |
| 185 | cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; | 211 | cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; |
| 186 | 212 | ||
| 187 | err = mmc_wait_for_cmd(host, &cmd, 0); | 213 | err = mmc_wait_for_cmd(host, &cmd, 0); |
| 188 | if (err) | 214 | if (err) |
| 189 | return err; | 215 | return err; |
| 190 | 216 | ||
| 191 | if ((cmd.resp[0] & 0xFF) != test_pattern) | 217 | if (mmc_host_is_spi(host)) |
| 218 | result_pattern = cmd.resp[1] & 0xFF; | ||
| 219 | else | ||
| 220 | result_pattern = cmd.resp[0] & 0xFF; | ||
| 221 | |||
| 222 | if (result_pattern != test_pattern) | ||
| 192 | return -EIO; | 223 | return -EIO; |
| 193 | 224 | ||
| 194 | return 0; | 225 | return 0; |
| @@ -229,6 +260,8 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) | |||
| 229 | BUG_ON(!card->host); | 260 | BUG_ON(!card->host); |
| 230 | BUG_ON(!scr); | 261 | BUG_ON(!scr); |
| 231 | 262 | ||
| 263 | /* NOTE: caller guarantees scr is heap-allocated */ | ||
| 264 | |||
| 232 | err = mmc_app_cmd(card->host, card); | 265 | err = mmc_app_cmd(card->host, card); |
| 233 | if (err) | 266 | if (err) |
| 234 | return err; | 267 | return err; |
| @@ -242,7 +275,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) | |||
| 242 | 275 | ||
| 243 | cmd.opcode = SD_APP_SEND_SCR; | 276 | cmd.opcode = SD_APP_SEND_SCR; |
| 244 | cmd.arg = 0; | 277 | cmd.arg = 0; |
| 245 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | 278 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; |
| 246 | 279 | ||
| 247 | data.blksz = 8; | 280 | data.blksz = 8; |
| 248 | data.blocks = 1; | 281 | data.blocks = 1; |
| @@ -278,6 +311,8 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, | |||
| 278 | BUG_ON(!card); | 311 | BUG_ON(!card); |
| 279 | BUG_ON(!card->host); | 312 | BUG_ON(!card->host); |
| 280 | 313 | ||
| 314 | /* NOTE: caller guarantees resp is heap-allocated */ | ||
| 315 | |||
| 281 | mode = !!mode; | 316 | mode = !!mode; |
| 282 | value &= 0xF; | 317 | value &= 0xF; |
| 283 | 318 | ||
| @@ -292,7 +327,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, | |||
| 292 | cmd.arg = mode << 31 | 0x00FFFFFF; | 327 | cmd.arg = mode << 31 | 0x00FFFFFF; |
| 293 | cmd.arg &= ~(0xF << (group * 4)); | 328 | cmd.arg &= ~(0xF << (group * 4)); |
| 294 | cmd.arg |= value << (group * 4); | 329 | cmd.arg |= value << (group * 4); |
| 295 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | 330 | cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; |
| 296 | 331 | ||
| 297 | data.blksz = 64; | 332 | data.blksz = 64; |
| 298 | data.blocks = 1; | 333 | data.blocks = 1; |
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2f3fb994c383..87a50f456efc 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
| @@ -270,6 +270,15 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) | |||
| 270 | goto err; | 270 | goto err; |
| 271 | 271 | ||
| 272 | /* | 272 | /* |
| 273 | * For SPI, enable CRC as appropriate. | ||
| 274 | */ | ||
| 275 | if (mmc_host_is_spi(host)) { | ||
| 276 | err = mmc_spi_set_crc(host, use_spi_crc); | ||
| 277 | if (err) | ||
| 278 | goto err; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* | ||
| 273 | * The number of functions on the card is encoded inside | 282 | * The number of functions on the card is encoded inside |
| 274 | * the ocr. | 283 | * the ocr. |
| 275 | */ | 284 | */ |
| @@ -290,20 +299,24 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) | |||
| 290 | host->card = card; | 299 | host->card = card; |
| 291 | 300 | ||
| 292 | /* | 301 | /* |
| 293 | * Set card RCA. | 302 | * For native busses: set card RCA and quit open drain mode. |
| 294 | */ | 303 | */ |
| 295 | err = mmc_send_relative_addr(host, &card->rca); | 304 | if (!mmc_host_is_spi(host)) { |
| 296 | if (err) | 305 | err = mmc_send_relative_addr(host, &card->rca); |
| 297 | goto remove; | 306 | if (err) |
| 307 | goto remove; | ||
| 298 | 308 | ||
| 299 | mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); | 309 | mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); |
| 310 | } | ||
| 300 | 311 | ||
| 301 | /* | 312 | /* |
| 302 | * Select card, as all following commands rely on that. | 313 | * Select card, as all following commands rely on that. |
| 303 | */ | 314 | */ |
| 304 | err = mmc_select_card(card); | 315 | if (!mmc_host_is_spi(host)) { |
| 305 | if (err) | 316 | err = mmc_select_card(card); |
| 306 | goto remove; | 317 | if (err) |
| 318 | goto remove; | ||
| 319 | } | ||
| 307 | 320 | ||
| 308 | /* | 321 | /* |
| 309 | * Read the common registers. | 322 | * Read the common registers. |
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 98e20532452a..4d289b275031 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c | |||
| @@ -30,23 +30,39 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | |||
| 30 | 30 | ||
| 31 | cmd.opcode = SD_IO_SEND_OP_COND; | 31 | cmd.opcode = SD_IO_SEND_OP_COND; |
| 32 | cmd.arg = ocr; | 32 | cmd.arg = ocr; |
| 33 | cmd.flags = MMC_RSP_R4 | MMC_CMD_BCR; | 33 | cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR; |
| 34 | 34 | ||
| 35 | for (i = 100; i; i--) { | 35 | for (i = 100; i; i--) { |
| 36 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); | 36 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); |
| 37 | if (err) | 37 | if (err) |
| 38 | break; | 38 | break; |
| 39 | 39 | ||
| 40 | if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) | 40 | /* if we're just probing, do a single pass */ |
| 41 | if (ocr == 0) | ||
| 41 | break; | 42 | break; |
| 42 | 43 | ||
| 44 | /* otherwise wait until reset completes */ | ||
| 45 | if (mmc_host_is_spi(host)) { | ||
| 46 | /* | ||
| 47 | * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate | ||
| 48 | * an initialized card under SPI, but some cards | ||
| 49 | * (Marvell's) only behave when looking at this | ||
| 50 | * one. | ||
| 51 | */ | ||
| 52 | if (cmd.resp[1] & MMC_CARD_BUSY) | ||
| 53 | break; | ||
| 54 | } else { | ||
| 55 | if (cmd.resp[0] & MMC_CARD_BUSY) | ||
| 56 | break; | ||
| 57 | } | ||
| 58 | |||
| 43 | err = -ETIMEDOUT; | 59 | err = -ETIMEDOUT; |
| 44 | 60 | ||
| 45 | mmc_delay(10); | 61 | mmc_delay(10); |
| 46 | } | 62 | } |
| 47 | 63 | ||
| 48 | if (rocr) | 64 | if (rocr) |
| 49 | *rocr = cmd.resp[0]; | 65 | *rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0]; |
| 50 | 66 | ||
| 51 | return err; | 67 | return err; |
| 52 | } | 68 | } |
| @@ -68,21 +84,29 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | |||
| 68 | cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; | 84 | cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; |
| 69 | cmd.arg |= addr << 9; | 85 | cmd.arg |= addr << 9; |
| 70 | cmd.arg |= in; | 86 | cmd.arg |= in; |
| 71 | cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; | 87 | cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; |
| 72 | 88 | ||
| 73 | err = mmc_wait_for_cmd(card->host, &cmd, 0); | 89 | err = mmc_wait_for_cmd(card->host, &cmd, 0); |
| 74 | if (err) | 90 | if (err) |
| 75 | return err; | 91 | return err; |
| 76 | 92 | ||
| 77 | if (cmd.resp[0] & R5_ERROR) | 93 | if (mmc_host_is_spi(card->host)) { |
| 78 | return -EIO; | 94 | /* host driver already reported errors */ |
| 79 | if (cmd.resp[0] & R5_FUNCTION_NUMBER) | 95 | } else { |
| 80 | return -EINVAL; | 96 | if (cmd.resp[0] & R5_ERROR) |
| 81 | if (cmd.resp[0] & R5_OUT_OF_RANGE) | 97 | return -EIO; |
| 82 | return -ERANGE; | 98 | if (cmd.resp[0] & R5_FUNCTION_NUMBER) |
| 99 | return -EINVAL; | ||
| 100 | if (cmd.resp[0] & R5_OUT_OF_RANGE) | ||
| 101 | return -ERANGE; | ||
| 102 | } | ||
| 83 | 103 | ||
| 84 | if (out) | 104 | if (out) { |
| 85 | *out = cmd.resp[0] & 0xFF; | 105 | if (mmc_host_is_spi(card->host)) |
| 106 | *out = (cmd.resp[0] >> 8) & 0xFF; | ||
| 107 | else | ||
| 108 | *out = cmd.resp[0] & 0xFF; | ||
| 109 | } | ||
| 86 | 110 | ||
| 87 | return 0; | 111 | return 0; |
| 88 | } | 112 | } |
| @@ -117,7 +141,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | |||
| 117 | cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ | 141 | cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ |
| 118 | else | 142 | else |
| 119 | cmd.arg |= 0x08000000 | blocks; /* block mode */ | 143 | cmd.arg |= 0x08000000 | blocks; /* block mode */ |
| 120 | cmd.flags = MMC_RSP_R5 | MMC_CMD_ADTC; | 144 | cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; |
| 121 | 145 | ||
| 122 | data.blksz = blksz; | 146 | data.blksz = blksz; |
| 123 | data.blocks = blocks; | 147 | data.blocks = blocks; |
| @@ -136,12 +160,16 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | |||
| 136 | if (data.error) | 160 | if (data.error) |
| 137 | return data.error; | 161 | return data.error; |
| 138 | 162 | ||
| 139 | if (cmd.resp[0] & R5_ERROR) | 163 | if (mmc_host_is_spi(card->host)) { |
| 140 | return -EIO; | 164 | /* host driver already reported errors */ |
| 141 | if (cmd.resp[0] & R5_FUNCTION_NUMBER) | 165 | } else { |
| 142 | return -EINVAL; | 166 | if (cmd.resp[0] & R5_ERROR) |
| 143 | if (cmd.resp[0] & R5_OUT_OF_RANGE) | 167 | return -EIO; |
| 144 | return -ERANGE; | 168 | if (cmd.resp[0] & R5_FUNCTION_NUMBER) |
| 169 | return -EINVAL; | ||
| 170 | if (cmd.resp[0] & R5_OUT_OF_RANGE) | ||
| 171 | return -ERANGE; | ||
| 172 | } | ||
| 145 | 173 | ||
| 146 | return 0; | 174 | return 0; |
| 147 | } | 175 | } |
