diff options
Diffstat (limited to 'drivers/mmc/core/sd.c')
-rw-r--r-- | drivers/mmc/core/sd.c | 152 |
1 files changed, 126 insertions, 26 deletions
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 8285842f19e9..5b7c99855635 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c | |||
@@ -400,6 +400,98 @@ out: | |||
400 | return err; | 400 | return err; |
401 | } | 401 | } |
402 | 402 | ||
403 | static int sd_select_driver_type(struct mmc_card *card, u8 *status) | ||
404 | { | ||
405 | int host_drv_type = 0, card_drv_type = 0; | ||
406 | int err; | ||
407 | |||
408 | /* | ||
409 | * If the host doesn't support any of the Driver Types A,C or D, | ||
410 | * default Driver Type B is used. | ||
411 | */ | ||
412 | if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C | ||
413 | | MMC_CAP_DRIVER_TYPE_D))) | ||
414 | return 0; | ||
415 | |||
416 | if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) { | ||
417 | host_drv_type = MMC_SET_DRIVER_TYPE_A; | ||
418 | if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A) | ||
419 | card_drv_type = MMC_SET_DRIVER_TYPE_A; | ||
420 | else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B) | ||
421 | card_drv_type = MMC_SET_DRIVER_TYPE_B; | ||
422 | else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) | ||
423 | card_drv_type = MMC_SET_DRIVER_TYPE_C; | ||
424 | } else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) { | ||
425 | host_drv_type = MMC_SET_DRIVER_TYPE_C; | ||
426 | if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) | ||
427 | card_drv_type = MMC_SET_DRIVER_TYPE_C; | ||
428 | } else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) { | ||
429 | /* | ||
430 | * If we are here, that means only the default driver type | ||
431 | * B is supported by the host. | ||
432 | */ | ||
433 | host_drv_type = MMC_SET_DRIVER_TYPE_B; | ||
434 | if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B) | ||
435 | card_drv_type = MMC_SET_DRIVER_TYPE_B; | ||
436 | else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) | ||
437 | card_drv_type = MMC_SET_DRIVER_TYPE_C; | ||
438 | } | ||
439 | |||
440 | err = mmc_sd_switch(card, 1, 2, card_drv_type, status); | ||
441 | if (err) | ||
442 | return err; | ||
443 | |||
444 | if ((status[15] & 0xF) != card_drv_type) { | ||
445 | printk(KERN_WARNING "%s: Problem setting driver strength!\n", | ||
446 | mmc_hostname(card->host)); | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | mmc_set_driver_type(card->host, host_drv_type); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | * UHS-I specific initialization procedure | ||
457 | */ | ||
458 | static int mmc_sd_init_uhs_card(struct mmc_card *card) | ||
459 | { | ||
460 | int err; | ||
461 | u8 *status; | ||
462 | |||
463 | if (!card->scr.sda_spec3) | ||
464 | return 0; | ||
465 | |||
466 | if (!(card->csd.cmdclass & CCC_SWITCH)) | ||
467 | return 0; | ||
468 | |||
469 | status = kmalloc(64, GFP_KERNEL); | ||
470 | if (!status) { | ||
471 | printk(KERN_ERR "%s: could not allocate a buffer for " | ||
472 | "switch capabilities.\n", mmc_hostname(card->host)); | ||
473 | return -ENOMEM; | ||
474 | } | ||
475 | |||
476 | /* Set 4-bit bus width */ | ||
477 | if ((card->host->caps & MMC_CAP_4_BIT_DATA) && | ||
478 | (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { | ||
479 | err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); | ||
480 | if (err) | ||
481 | goto out; | ||
482 | |||
483 | mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); | ||
484 | } | ||
485 | |||
486 | /* Set the driver strength for the card */ | ||
487 | err = sd_select_driver_type(card, status); | ||
488 | |||
489 | out: | ||
490 | kfree(status); | ||
491 | |||
492 | return err; | ||
493 | } | ||
494 | |||
403 | MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], | 495 | MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], |
404 | card->raw_cid[2], card->raw_cid[3]); | 496 | card->raw_cid[2], card->raw_cid[3]); |
405 | MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], | 497 | MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], |
@@ -448,10 +540,9 @@ struct device_type sd_type = { | |||
448 | /* | 540 | /* |
449 | * Fetch CID from card. | 541 | * Fetch CID from card. |
450 | */ | 542 | */ |
451 | int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid) | 543 | int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) |
452 | { | 544 | { |
453 | int err; | 545 | int err; |
454 | u32 rocr; | ||
455 | 546 | ||
456 | /* | 547 | /* |
457 | * Since we're changing the OCR value, we seem to | 548 | * Since we're changing the OCR value, we seem to |
@@ -485,7 +576,7 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid) | |||
485 | ocr |= SD_OCR_XPC; | 576 | ocr |= SD_OCR_XPC; |
486 | 577 | ||
487 | try_again: | 578 | try_again: |
488 | err = mmc_send_app_op_cond(host, ocr, &rocr); | 579 | err = mmc_send_app_op_cond(host, ocr, rocr); |
489 | if (err) | 580 | if (err) |
490 | return err; | 581 | return err; |
491 | 582 | ||
@@ -493,7 +584,8 @@ try_again: | |||
493 | * In case CCS and S18A in the response is set, start Signal Voltage | 584 | * In case CCS and S18A in the response is set, start Signal Voltage |
494 | * Switch procedure. SPI mode doesn't support CMD11. | 585 | * Switch procedure. SPI mode doesn't support CMD11. |
495 | */ | 586 | */ |
496 | if (!mmc_host_is_spi(host) && ((rocr & 0x41000000) == 0x41000000)) { | 587 | if (!mmc_host_is_spi(host) && rocr && |
588 | ((*rocr & 0x41000000) == 0x41000000)) { | ||
497 | err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); | 589 | err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); |
498 | if (err) { | 590 | if (err) { |
499 | ocr &= ~SD_OCR_S18R; | 591 | ocr &= ~SD_OCR_S18R; |
@@ -628,11 +720,12 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, | |||
628 | struct mmc_card *card; | 720 | struct mmc_card *card; |
629 | int err; | 721 | int err; |
630 | u32 cid[4]; | 722 | u32 cid[4]; |
723 | u32 rocr = 0; | ||
631 | 724 | ||
632 | BUG_ON(!host); | 725 | BUG_ON(!host); |
633 | WARN_ON(!host->claimed); | 726 | WARN_ON(!host->claimed); |
634 | 727 | ||
635 | err = mmc_sd_get_cid(host, ocr, cid); | 728 | err = mmc_sd_get_cid(host, ocr, cid, &rocr); |
636 | if (err) | 729 | if (err) |
637 | return err; | 730 | return err; |
638 | 731 | ||
@@ -685,30 +778,37 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, | |||
685 | if (err) | 778 | if (err) |
686 | goto free_card; | 779 | goto free_card; |
687 | 780 | ||
688 | /* | 781 | /* Initialization sequence for UHS-I cards */ |
689 | * Attempt to change to high-speed (if supported) | 782 | if (rocr & SD_ROCR_S18A) { |
690 | */ | 783 | err = mmc_sd_init_uhs_card(card); |
691 | err = mmc_sd_switch_hs(card); | ||
692 | if (err > 0) | ||
693 | mmc_sd_go_highspeed(card); | ||
694 | else if (err) | ||
695 | goto free_card; | ||
696 | |||
697 | /* | ||
698 | * Set bus speed. | ||
699 | */ | ||
700 | mmc_set_clock(host, mmc_sd_get_max_clock(card)); | ||
701 | |||
702 | /* | ||
703 | * Switch to wider bus (if supported). | ||
704 | */ | ||
705 | if ((host->caps & MMC_CAP_4_BIT_DATA) && | ||
706 | (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { | ||
707 | err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); | ||
708 | if (err) | 784 | if (err) |
709 | goto free_card; | 785 | goto free_card; |
786 | } else { | ||
787 | /* | ||
788 | * Attempt to change to high-speed (if supported) | ||
789 | */ | ||
790 | err = mmc_sd_switch_hs(card); | ||
791 | if (err > 0) | ||
792 | mmc_sd_go_highspeed(card); | ||
793 | else if (err) | ||
794 | goto free_card; | ||
795 | |||
796 | /* | ||
797 | * Set bus speed. | ||
798 | */ | ||
799 | mmc_set_clock(host, mmc_sd_get_max_clock(card)); | ||
710 | 800 | ||
711 | mmc_set_bus_width(host, MMC_BUS_WIDTH_4); | 801 | /* |
802 | * Switch to wider bus (if supported). | ||
803 | */ | ||
804 | if ((host->caps & MMC_CAP_4_BIT_DATA) && | ||
805 | (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { | ||
806 | err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); | ||
807 | if (err) | ||
808 | goto free_card; | ||
809 | |||
810 | mmc_set_bus_width(host, MMC_BUS_WIDTH_4); | ||
811 | } | ||
712 | } | 812 | } |
713 | 813 | ||
714 | host->card = card; | 814 | host->card = card; |