|
@@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
|
|
}
|
|
|
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
|
|
|
switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_ALL:
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
|
|
|
+ card->ext_csd.hs_max_dtr = 200000000;
|
|
|
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
|
|
|
+ break;
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
|
|
|
+ card->ext_csd.hs_max_dtr = 200000000;
|
|
|
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
|
|
|
+ break;
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
|
|
|
+ case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
|
|
|
+ card->ext_csd.hs_max_dtr = 200000000;
|
|
|
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
|
|
|
+ break;
|
|
|
case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
|
|
|
EXT_CSD_CARD_TYPE_26:
|
|
|
card->ext_csd.hs_max_dtr = 52000000;
|
|
@@ -699,6 +720,79 @@ static int mmc_select_powerclass(struct mmc_card *card,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Selects the desired buswidth and switch to the HS200 mode
|
|
|
+ * if bus width set without error
|
|
|
+ */
|
|
|
+static int mmc_select_hs200(struct mmc_card *card)
|
|
|
+{
|
|
|
+ int idx, err = 0;
|
|
|
+ struct mmc_host *host;
|
|
|
+ static unsigned ext_csd_bits[] = {
|
|
|
+ EXT_CSD_BUS_WIDTH_4,
|
|
|
+ EXT_CSD_BUS_WIDTH_8,
|
|
|
+ };
|
|
|
+ static unsigned bus_widths[] = {
|
|
|
+ MMC_BUS_WIDTH_4,
|
|
|
+ MMC_BUS_WIDTH_8,
|
|
|
+ };
|
|
|
+
|
|
|
+ BUG_ON(!card);
|
|
|
+
|
|
|
+ host = card->host;
|
|
|
+
|
|
|
+ if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
|
|
|
+ host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
|
|
|
+ if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
|
|
|
+ err = mmc_set_signal_voltage(host,
|
|
|
+ MMC_SIGNAL_VOLTAGE_180, 0);
|
|
|
+
|
|
|
+ /* If fails try again during next card power cycle */
|
|
|
+ if (err)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Unlike SD, MMC cards dont have a configuration register to notify
|
|
|
+ * supported bus width. So bus test command should be run to identify
|
|
|
+ * the supported bus width or compare the ext csd values of current
|
|
|
+ * bus width and ext csd values of 1 bit mode read earlier.
|
|
|
+ */
|
|
|
+ for (; idx >= 0; idx--) {
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Host is capable of 8bit transfer, then switch
|
|
|
+ * the device to work in 8bit transfer mode. If the
|
|
|
+ * mmc switch command returns error then switch to
|
|
|
+ * 4bit transfer mode. On success set the corresponding
|
|
|
+ * bus width on the host.
|
|
|
+ */
|
|
|
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
|
|
+ EXT_CSD_BUS_WIDTH,
|
|
|
+ ext_csd_bits[idx],
|
|
|
+ card->ext_csd.generic_cmd6_time);
|
|
|
+ if (err)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ mmc_set_bus_width(card->host, bus_widths[idx]);
|
|
|
+
|
|
|
+ if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
|
|
|
+ err = mmc_compare_ext_csds(card, bus_widths[idx]);
|
|
|
+ else
|
|
|
+ err = mmc_bus_test(card, bus_widths[idx]);
|
|
|
+ if (!err)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* switch to HS200 mode if bus width set successfully */
|
|
|
+ if (!err)
|
|
|
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
|
|
+ EXT_CSD_HS_TIMING, 2, 0);
|
|
|
+err:
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Handle the detection and initialisation of a card.
|
|
|
*
|
|
@@ -905,11 +999,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|
|
/*
|
|
|
* Activate high speed (if supported)
|
|
|
*/
|
|
|
- if ((card->ext_csd.hs_max_dtr != 0) &&
|
|
|
- (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
|
|
|
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
|
|
- EXT_CSD_HS_TIMING, 1,
|
|
|
- card->ext_csd.generic_cmd6_time);
|
|
|
+ if (card->ext_csd.hs_max_dtr != 0) {
|
|
|
+ err = 0;
|
|
|
+ if (card->ext_csd.hs_max_dtr > 52000000 &&
|
|
|
+ host->caps2 & MMC_CAP2_HS200)
|
|
|
+ err = mmc_select_hs200(card);
|
|
|
+ else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
|
|
|
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
|
|
+ EXT_CSD_HS_TIMING, 1, 0);
|
|
|
+
|
|
|
if (err && err != -EBADMSG)
|
|
|
goto free_card;
|
|
|
|
|
@@ -918,8 +1016,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|
|
mmc_hostname(card->host));
|
|
|
err = 0;
|
|
|
} else {
|
|
|
- mmc_card_set_highspeed(card);
|
|
|
- mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
|
|
|
+ if (card->ext_csd.hs_max_dtr > 52000000 &&
|
|
|
+ host->caps2 & MMC_CAP2_HS200) {
|
|
|
+ mmc_card_set_hs200(card);
|
|
|
+ mmc_set_timing(card->host,
|
|
|
+ MMC_TIMING_MMC_HS200);
|
|
|
+ } else {
|
|
|
+ mmc_card_set_highspeed(card);
|
|
|
+ mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -944,7 +1049,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|
|
*/
|
|
|
max_dtr = (unsigned int)-1;
|
|
|
|
|
|
- if (mmc_card_highspeed(card)) {
|
|
|
+ if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
|
|
|
if (max_dtr > card->ext_csd.hs_max_dtr)
|
|
|
max_dtr = card->ext_csd.hs_max_dtr;
|
|
|
} else if (max_dtr > card->csd.max_dtr) {
|
|
@@ -969,10 +1074,49 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|
|
ddr = MMC_1_2V_DDR_MODE;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Indicate HS200 SDR mode (if supported).
|
|
|
+ */
|
|
|
+ if (mmc_card_hs200(card)) {
|
|
|
+ u32 ext_csd_bits;
|
|
|
+ u32 bus_width = card->host->ios.bus_width;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * For devices supporting HS200 mode, the bus width has
|
|
|
+ * to be set before executing the tuning function. If
|
|
|
+ * set before tuning, then device will respond with CRC
|
|
|
+ * errors for responses on CMD line. So for HS200 the
|
|
|
+ * sequence will be
|
|
|
+ * 1. set bus width 4bit / 8 bit (1 bit not supported)
|
|
|
+ * 2. switch to HS200 mode
|
|
|
+ * 3. set the clock to > 52Mhz <=200MHz and
|
|
|
+ * 4. execute tuning for HS200
|
|
|
+ */
|
|
|
+ if ((host->caps2 & MMC_CAP2_HS200) &&
|
|
|
+ card->host->ops->execute_tuning)
|
|
|
+ err = card->host->ops->execute_tuning(card->host,
|
|
|
+ MMC_SEND_TUNING_BLOCK_HS200);
|
|
|
+ if (err) {
|
|
|
+ pr_warning("%s: tuning execution failed\n",
|
|
|
+ mmc_hostname(card->host));
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
|
|
|
+ EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
|
|
|
+ err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
|
|
|
+ if (err) {
|
|
|
+ pr_err("%s: power class selection to bus width %d failed\n",
|
|
|
+ mmc_hostname(card->host), 1 << bus_width);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Activate wide bus and DDR (if supported).
|
|
|
*/
|
|
|
- if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
|
|
|
+ if (!mmc_card_hs200(card) &&
|
|
|
+ (card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
|
|
|
(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
|
|
|
static unsigned ext_csd_bits[][2] = {
|
|
|
{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
|