aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGirish K S <girish.shivananjappa@linaro.org>2011-09-23 11:11:47 -0400
committerChris Ball <cjb@laptop.org>2011-10-26 16:32:13 -0400
commitb87d8dbf6c410b5f2d9b6893c85baa06aa131c7c (patch)
treef478e5378f259bb75158d5cb08cc459c93f30905
parent199e3f4b419d045e64d5205a6354c5db04d98553 (diff)
mmc: core: eMMC 4.5 Power Class Selection Feature
This patch adds the power class selection feature available for mmc versions 4.0 and above. During the enumeration stage before switching to the lower data bus, check if the power class is supported for the current bus width. If the power class is available then switch to the power class and use the higher data bus. If power class is not supported then switch to the lower data bus in a worst case. Signed-off-by: Girish K S <girish.shivananjappa@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/core/mmc.c96
-rw-r--r--include/linux/mmc/mmc.h14
2 files changed, 110 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 7adc30da8366..c2334d636fe8 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -532,6 +532,86 @@ static struct device_type mmc_type = {
532}; 532};
533 533
534/* 534/*
535 * Select the PowerClass for the current bus width
536 * If power class is defined for 4/8 bit bus in the
537 * extended CSD register, select it by executing the
538 * mmc_switch command.
539 */
540static int mmc_select_powerclass(struct mmc_card *card,
541 unsigned int bus_width, u8 *ext_csd)
542{
543 int err = 0;
544 unsigned int pwrclass_val;
545 unsigned int index = 0;
546 struct mmc_host *host;
547
548 BUG_ON(!card);
549
550 host = card->host;
551 BUG_ON(!host);
552
553 if (ext_csd == NULL)
554 return 0;
555
556 /* Power class selection is supported for versions >= 4.0 */
557 if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
558 return 0;
559
560 /* Power class values are defined only for 4/8 bit bus */
561 if (bus_width == EXT_CSD_BUS_WIDTH_1)
562 return 0;
563
564 switch (1 << host->ios.vdd) {
565 case MMC_VDD_165_195:
566 if (host->ios.clock <= 26000000)
567 index = EXT_CSD_PWR_CL_26_195;
568 else if (host->ios.clock <= 52000000)
569 index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
570 EXT_CSD_PWR_CL_52_195 :
571 EXT_CSD_PWR_CL_DDR_52_195;
572 else if (host->ios.clock <= 200000000)
573 index = EXT_CSD_PWR_CL_200_195;
574 break;
575 case MMC_VDD_32_33:
576 case MMC_VDD_33_34:
577 case MMC_VDD_34_35:
578 case MMC_VDD_35_36:
579 if (host->ios.clock <= 26000000)
580 index = EXT_CSD_PWR_CL_26_360;
581 else if (host->ios.clock <= 52000000)
582 index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
583 EXT_CSD_PWR_CL_52_360 :
584 EXT_CSD_PWR_CL_DDR_52_360;
585 else if (host->ios.clock <= 200000000)
586 index = EXT_CSD_PWR_CL_200_360;
587 break;
588 default:
589 pr_warning("%s: Voltage range not supported "
590 "for power class.\n", mmc_hostname(host));
591 return -EINVAL;
592 }
593
594 pwrclass_val = ext_csd[index];
595
596 if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
597 pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
598 EXT_CSD_PWR_CL_8BIT_SHIFT;
599 else
600 pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
601 EXT_CSD_PWR_CL_4BIT_SHIFT;
602
603 /* If the power class is different from the default value */
604 if (pwrclass_val > 0) {
605 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
606 EXT_CSD_POWER_CLASS,
607 pwrclass_val,
608 0);
609 }
610
611 return err;
612}
613
614/*
535 * Handle the detection and initialisation of a card. 615 * Handle the detection and initialisation of a card.
536 * 616 *
537 * In the case of a resume, "oldcard" will contain the card 617 * In the case of a resume, "oldcard" will contain the card
@@ -787,6 +867,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
787 bus_width = bus_widths[idx]; 867 bus_width = bus_widths[idx];
788 if (bus_width == MMC_BUS_WIDTH_1) 868 if (bus_width == MMC_BUS_WIDTH_1)
789 ddr = 0; /* no DDR for 1-bit width */ 869 ddr = 0; /* no DDR for 1-bit width */
870 err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
871 ext_csd);
872 if (err)
873 pr_err("%s: power class selection to "
874 "bus width %d failed\n",
875 mmc_hostname(card->host),
876 1 << bus_width);
877
790 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 878 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
791 EXT_CSD_BUS_WIDTH, 879 EXT_CSD_BUS_WIDTH,
792 ext_csd_bits[idx][0], 880 ext_csd_bits[idx][0],
@@ -810,6 +898,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
810 } 898 }
811 899
812 if (!err && ddr) { 900 if (!err && ddr) {
901 err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
902 ext_csd);
903 if (err)
904 pr_err("%s: power class selection to "
905 "bus width %d ddr %d failed\n",
906 mmc_hostname(card->host),
907 1 << bus_width, ddr);
908
813 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 909 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
814 EXT_CSD_BUS_WIDTH, 910 EXT_CSD_BUS_WIDTH,
815 ext_csd_bits[idx][1], 911 ext_csd_bits[idx][1],
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index ed8fca890ee2..50af22730c74 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -279,10 +279,15 @@ struct _mmc_csd {
279#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ 279#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
280#define EXT_CSD_BUS_WIDTH 183 /* R/W */ 280#define EXT_CSD_BUS_WIDTH 183 /* R/W */
281#define EXT_CSD_HS_TIMING 185 /* R/W */ 281#define EXT_CSD_HS_TIMING 185 /* R/W */
282#define EXT_CSD_POWER_CLASS 187 /* R/W */
282#define EXT_CSD_REV 192 /* RO */ 283#define EXT_CSD_REV 192 /* RO */
283#define EXT_CSD_STRUCTURE 194 /* RO */ 284#define EXT_CSD_STRUCTURE 194 /* RO */
284#define EXT_CSD_CARD_TYPE 196 /* RO */ 285#define EXT_CSD_CARD_TYPE 196 /* RO */
285#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */ 286#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
287#define EXT_CSD_PWR_CL_52_195 200 /* RO */
288#define EXT_CSD_PWR_CL_26_195 201 /* RO */
289#define EXT_CSD_PWR_CL_52_360 202 /* RO */
290#define EXT_CSD_PWR_CL_26_360 203 /* RO */
286#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ 291#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
287#define EXT_CSD_S_A_TIMEOUT 217 /* RO */ 292#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
288#define EXT_CSD_REL_WR_SEC_C 222 /* RO */ 293#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
@@ -294,6 +299,11 @@ struct _mmc_csd {
294#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */ 299#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
295#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ 300#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
296#define EXT_CSD_TRIM_MULT 232 /* RO */ 301#define EXT_CSD_TRIM_MULT 232 /* RO */
302#define EXT_CSD_PWR_CL_200_195 236 /* RO */
303#define EXT_CSD_PWR_CL_200_360 237 /* RO */
304#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
305#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
306#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
297 307
298/* 308/*
299 * EXT_CSD field definitions 309 * EXT_CSD field definitions
@@ -332,6 +342,10 @@ struct _mmc_csd {
332#define EXT_CSD_RST_N_EN_MASK 0x3 342#define EXT_CSD_RST_N_EN_MASK 0x3
333#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */ 343#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
334 344
345#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */
346#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
347#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
348#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
335/* 349/*
336 * MMC_SWITCH access modes 350 * MMC_SWITCH access modes
337 */ 351 */