--- zzzz-none-000/linux-4.4.271/drivers/mmc/core/mmc.c 2021-06-03 06:22:09.000000000 +0000 +++ hawkeye-5590-750/linux-4.4.271/drivers/mmc/core/mmc.c 2023-04-19 10:22:29.000000000 +0000 @@ -581,6 +581,13 @@ card->ext_csd.data_sector_size = 512; } + if (card->ext_csd.rev >= 7) { + /* Enhance Strobe is supported since v5.1 which rev should be + * 8 but some eMMC devices can support it with rev 7. So handle + * Enhance Strobe here. + */ + card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT]; + } /* * GENERIC_CMD6_TIME is to be used "unless a specific timeout is defined * when accessing a specific field", so use it here if there is no @@ -1078,9 +1085,28 @@ /* * HS400 mode requires 8-bit bus width */ - if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 && - host->ios.bus_width == MMC_BUS_WIDTH_8)) - return 0; + if (card->ext_csd.strobe_support) { + if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 && + host->caps & MMC_CAP_8_BIT_DATA)) + return 0; + + /* For Enhance Strobe flow. For non Enhance Strobe, signal + * voltage will not be set. + */ + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V) + err = __mmc_set_signal_voltage(host, + MMC_SIGNAL_VOLTAGE_120); + + if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V) + err = __mmc_set_signal_voltage(host, + MMC_SIGNAL_VOLTAGE_180); + if (err) + return err; + } else { + if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 && + host->ios.bus_width == MMC_BUS_WIDTH_8)) + return 0; + } if (host->caps & MMC_CAP_WAIT_WHILE_BUSY) send_status = false; @@ -1110,10 +1136,14 @@ goto out_err; } + val = EXT_CSD_DDR_BUS_WIDTH_8; + if (card->ext_csd.strobe_support) + val |= EXT_CSD_BUS_WIDTH_STROBE; + /* Switch card to DDR */ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, - EXT_CSD_DDR_BUS_WIDTH_8, + val, card->ext_csd.generic_cmd6_time); if (err) { pr_err("%s: switch to bus width for hs400 failed, err:%d\n", @@ -1121,6 +1151,9 @@ return err; } + if (card->ext_csd.strobe_support) + mmc_set_bus_width(host, MMC_BUS_WIDTH_8); + /* Switch card to HS400 */ val = EXT_CSD_TIMING_HS400 | card->drive_strength << EXT_CSD_DRV_STR_SHIFT; @@ -1138,6 +1171,17 @@ mmc_set_timing(host, MMC_TIMING_MMC_HS400); mmc_set_bus_speed(card); + if (card->ext_csd.strobe_support && host->ops->enhanced_strobe) { + err = host->ops->enhanced_strobe(host); + } else if ((host->caps2 & MMC_CAP2_HS400_POST_TUNING) && + host->ops->execute_tuning) { + err = host->ops->execute_tuning(host, + MMC_SEND_TUNING_BLOCK_HS200); + if (err) + pr_warn("%s: post tuning execution failed\n", + mmc_hostname(host)); + } + if (!send_status) { err = mmc_switch_status(card); if (err) @@ -1326,7 +1370,12 @@ if (!mmc_can_ext_csd(card)) goto bus_speed; - if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) + /* For Enhance Strobe HS400 flow */ + if (card->ext_csd.strobe_support && + card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 && + card->host->caps & MMC_CAP_8_BIT_DATA) + err = mmc_select_hs400(card); + else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) err = mmc_select_hs200(card); else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) err = mmc_select_hs(card); @@ -1446,6 +1495,7 @@ card->type = MMC_TYPE_MMC; card->rca = 1; memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); + host->card = card; } /* @@ -1594,7 +1644,7 @@ err = mmc_select_hs400(card); if (err) goto free_card; - } else { + } else if (!mmc_card_hs400(card)) { /* Select the desired bus width optionally */ err = mmc_select_bus_width(card); if (!IS_ERR_VALUE(err) && mmc_card_hs(card)) { @@ -1681,8 +1731,10 @@ return 0; free_card: - if (!oldcard) + if (!oldcard) { + host->card = NULL; mmc_remove_card(card); + } err: return err; }