aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilip Rakity <prakity@marvell.com>2011-05-24 21:14:58 -0400
committerChris Ball <cjb@laptop.org>2011-05-25 16:52:32 -0400
commit08ee80cc397ac1a306ca689a22ede954d92d0db1 (patch)
treeb36819e6b52c9fd939dd6c886af734cb6ccbc45f
parent4f3d3e9b50931a3ec70f324d53fb7437e2a39388 (diff)
mmc: core: eMMC bus width may not work on all platforms
CMD19 -- The offical way to validate bus widths from the JEDEC spec does not work on all platforms. Some platforms that use PCI/PCIe to connect their SD controllers are known to fail. If the quirk MMC_BUS_WIDTH_TEST is not defined we try to figure out the bus width by reading the ext_csd at different bus widths and compare this against the ext_csd read in 1 bit mode. If no ext_csd is available we default to 1 bit operations. Code has been tested on mmp2 against 8 bit eMMC and Transcend 2GB card that is known to not work in 4 bit mode. The physical pins on the card are not present to support 4 bit operation. Signed-off-by: Philip Rakity <prakity@marvell.com> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/core/mmc.c112
1 files changed, 102 insertions, 10 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0433fe66cbad..2a7e43bc796d 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -174,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
174} 174}
175 175
176/* 176/*
177 * Read and decode extended CSD. 177 * Read extended CSD.
178 */ 178 */
179static int mmc_read_ext_csd(struct mmc_card *card) 179static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
180{ 180{
181 int err; 181 int err;
182 u8 *ext_csd; 182 u8 *ext_csd;
183 183
184 BUG_ON(!card); 184 BUG_ON(!card);
185 BUG_ON(!new_ext_csd);
186
187 *new_ext_csd = NULL;
185 188
186 if (card->csd.mmca_vsn < CSD_SPEC_VER_4) 189 if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
187 return 0; 190 return 0;
@@ -199,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
199 202
200 err = mmc_send_ext_csd(card, ext_csd); 203 err = mmc_send_ext_csd(card, ext_csd);
201 if (err) { 204 if (err) {
205 kfree(ext_csd);
206 *new_ext_csd = NULL;
207
202 /* If the host or the card can't do the switch, 208 /* If the host or the card can't do the switch,
203 * fail more gracefully. */ 209 * fail more gracefully. */
204 if ((err != -EINVAL) 210 if ((err != -EINVAL)
205 && (err != -ENOSYS) 211 && (err != -ENOSYS)
206 && (err != -EFAULT)) 212 && (err != -EFAULT))
207 goto out; 213 return err;
208 214
209 /* 215 /*
210 * High capacity cards should have this "magic" size 216 * High capacity cards should have this "magic" size
@@ -222,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
222 mmc_hostname(card->host)); 228 mmc_hostname(card->host));
223 err = 0; 229 err = 0;
224 } 230 }
231 } else
232 *new_ext_csd = ext_csd;
225 233
226 goto out; 234 return err;
227 } 235}
236
237/*
238 * Decode extended CSD.
239 */
240static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
241{
242 int err = 0;
243
244 BUG_ON(!card);
245
246 if (!ext_csd)
247 return 0;
228 248
229 /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */ 249 /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
230 if (card->csd.structure == 3) { 250 if (card->csd.structure == 3) {
@@ -372,8 +392,69 @@ static int mmc_read_ext_csd(struct mmc_card *card)
372 card->erased_byte = 0x0; 392 card->erased_byte = 0x0;
373 393
374out: 394out:
395 return err;
396}
397
398static inline void mmc_free_ext_csd(u8 *ext_csd)
399{
375 kfree(ext_csd); 400 kfree(ext_csd);
401}
402
376 403
404static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
405 unsigned bus_width)
406{
407 u8 *bw_ext_csd;
408 int err;
409
410 err = mmc_get_ext_csd(card, &bw_ext_csd);
411 if (err)
412 return err;
413
414 if ((ext_csd == NULL || bw_ext_csd == NULL)) {
415 if (bus_width != MMC_BUS_WIDTH_1)
416 err = -EINVAL;
417 goto out;
418 }
419
420 if (bus_width == MMC_BUS_WIDTH_1)
421 goto out;
422
423 /* only compare read only fields */
424 err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
425 bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
426 (ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
427 bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
428 (ext_csd[EXT_CSD_REV] ==
429 bw_ext_csd[EXT_CSD_REV]) &&
430 (ext_csd[EXT_CSD_STRUCTURE] ==
431 bw_ext_csd[EXT_CSD_STRUCTURE]) &&
432 (ext_csd[EXT_CSD_CARD_TYPE] ==
433 bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
434 (ext_csd[EXT_CSD_S_A_TIMEOUT] ==
435 bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
436 (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
437 bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
438 (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
439 bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
440 (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
441 bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
442 (ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
443 bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
444 (ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
445 bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
446 (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
447 bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
448 (ext_csd[EXT_CSD_TRIM_MULT] ==
449 bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
450 memcmp(&ext_csd[EXT_CSD_SEC_CNT],
451 &bw_ext_csd[EXT_CSD_SEC_CNT],
452 4) != 0);
453 if (err)
454 err = -EINVAL;
455
456out:
457 mmc_free_ext_csd(bw_ext_csd);
377 return err; 458 return err;
378} 459}
379 460
@@ -438,6 +519,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
438 u32 cid[4]; 519 u32 cid[4];
439 unsigned int max_dtr; 520 unsigned int max_dtr;
440 u32 rocr; 521 u32 rocr;
522 u8 *ext_csd = NULL;
441 523
442 BUG_ON(!host); 524 BUG_ON(!host);
443 WARN_ON(!host->claimed); 525 WARN_ON(!host->claimed);
@@ -536,7 +618,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
536 /* 618 /*
537 * Fetch and process extended CSD. 619 * Fetch and process extended CSD.
538 */ 620 */
539 err = mmc_read_ext_csd(card); 621
622 err = mmc_get_ext_csd(card, &ext_csd);
623 if (err)
624 goto free_card;
625 err = mmc_read_ext_csd(card, ext_csd);
540 if (err) 626 if (err)
541 goto free_card; 627 goto free_card;
542 628
@@ -676,14 +762,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
676 0); 762 0);
677 if (!err) { 763 if (!err) {
678 mmc_set_bus_width(card->host, bus_width); 764 mmc_set_bus_width(card->host, bus_width);
765
679 /* 766 /*
680 * If controller can't handle bus width test, 767 * If controller can't handle bus width test,
681 * use the highest bus width to maintain 768 * compare ext_csd previously read in 1 bit mode
682 * compatibility with previous MMC behavior. 769 * against ext_csd at new bus width
683 */ 770 */
684 if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) 771 if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
685 break; 772 err = mmc_compare_ext_csds(card,
686 err = mmc_bus_test(card, bus_width); 773 ext_csd,
774 bus_width);
775 else
776 err = mmc_bus_test(card, bus_width);
687 if (!err) 777 if (!err)
688 break; 778 break;
689 } 779 }
@@ -730,12 +820,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
730 if (!oldcard) 820 if (!oldcard)
731 host->card = card; 821 host->card = card;
732 822
823 mmc_free_ext_csd(ext_csd);
733 return 0; 824 return 0;
734 825
735free_card: 826free_card:
736 if (!oldcard) 827 if (!oldcard)
737 mmc_remove_card(card); 828 mmc_remove_card(card);
738err: 829err:
830 mmc_free_ext_csd(ext_csd);
739 831
740 return err; 832 return err;
741} 833}