mmc: adjust switching to 4-bit mode for MMC devices

CMD6 is a normal command on MMC, but an application command on SD. And
the parameters and response type are different.

Change-Id: I0583b8a98cf18dc4d77d28066673d0d07229e161
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10934
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
PulkoMandy
2026-05-07 07:22:21 +00:00
committed by Adrien Destugues
parent 1e9473f97e
commit 5efaab5061
3 changed files with 47 additions and 10 deletions
+2 -1
View File
@@ -46,10 +46,10 @@ enum SD_COMMANDS {
// Basic commands, class 0 // Basic commands, class 0
GO_IDLE_STATE = 0, GO_IDLE_STATE = 0,
MMC_SEND_OP_COND = 1, MMC_SEND_OP_COND = 1,
// MMC only,reserved in SD.
ALL_SEND_CID = 2, ALL_SEND_CID = 2,
SD_SEND_RELATIVE_ADDR = 3, SD_SEND_RELATIVE_ADDR = 3,
MMC_SET_RELATIVE_ADDR = 3, MMC_SET_RELATIVE_ADDR = 3,
MMC_SWITCH = 6, // Same command number as SD_SET_BUS_WIDTH, but this one is not an ACMD
SELECT_DESELECT_CARD = 7, SELECT_DESELECT_CARD = 7,
SD_SEND_IF_COND = 8, SD_SEND_IF_COND = 8,
MMC_SEND_EXT_CSD = 8, MMC_SEND_EXT_CSD = 8,
@@ -76,6 +76,7 @@ enum SD_COMMANDS {
}; };
// Application commands are sent with a prefix CMD55 (SD_APP_CMD)
enum SDHCI_APPLICATION_COMMANDS { enum SDHCI_APPLICATION_COMMANDS {
SD_SET_BUS_WIDTH = 6, SD_SET_BUS_WIDTH = 6,
SD_SEND_OP_COND = 41, SD_SEND_OP_COND = 41,
+6 -1
View File
@@ -229,7 +229,6 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
case SD_APP_CMD: case SD_APP_CMD:
case SD_ERASE_WR_BLK_START: case SD_ERASE_WR_BLK_START:
case SD_ERASE_WR_BLK_END: case SD_ERASE_WR_BLK_END:
case SD_SET_BUS_WIDTH: // SD Application command
replyType = Command::kR1Type; replyType = Command::kR1Type;
break; break;
case SELECT_DESELECT_CARD: case SELECT_DESELECT_CARD:
@@ -246,6 +245,12 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
break; break;
// Commands defined with different reply types in SD and MMC specifications // Commands defined with different reply types in SD and MMC specifications
case SD_SET_BUS_WIDTH: // SD application command. Also MMC_SWITCH, which is not.
if (fCardType == CARD_TYPE_MMC)
replyType = Command::kR1bType;
else
replyType = Command::kR1Type;
break;
case SD_SEND_RELATIVE_ADDR: // also MMC_SET_RELATIVE_ADDR case SD_SEND_RELATIVE_ADDR: // also MMC_SET_RELATIVE_ADDR
if (fCardType == CARD_TYPE_MMC) if (fCardType == CARD_TYPE_MMC)
replyType = Command::kR1Type; replyType = Command::kR1Type;
@@ -181,15 +181,46 @@ mmc_block_get_geometry(mmc_disk_driver_info* info, device_geometry* geometry)
// This function will be called before all data transfers, so we use this // This function will be called before all data transfers, so we use this
// opportunity to switch the card to 4-bit data transfers (instead of the // opportunity to switch the card to 4-bit data transfers (instead of the
// default 1 bit mode) // default 1 bit mode)
uint32_t cardStatus; uint32_t cardStatus = 0;
const uint32 k4BitMode = 2; status_t status = B_OK;
info->mmc->execute_command(info->parent, info->parentCookie, info->rca,
SD_APP_CMD, info->rca << 16, &cardStatus);
info->mmc->execute_command(info->parent, info->parentCookie, info->rca,
SD_SET_BUS_WIDTH, k4BitMode, &cardStatus);
// From now on we use 4 bit mode // TODO have the card type at hand instead of using the csd version here
info->mmc->set_bus_width(info->parent, info->parentCookie, 4); if (csd.structure_version() < 3) {
const uint32 k4BitMode = 2;
info->mmc->execute_command(info->parent, info->parentCookie, info->rca,
SD_APP_CMD, info->rca << 16, &cardStatus);
status = info->mmc->execute_command(info->parent, info->parentCookie, info->rca,
SD_SET_BUS_WIDTH, k4BitMode, &cardStatus);
} else {
// TODO according to the eMMC spec, we should first run a test with CMD19 and CMD14 to
// determine if the 4-bit (and possibly the 8-bit) bus is wired, and also check if we need
// to switch to a different POWER_CLASS. See Jedec 84-B50 appendix A.6.3
//
// Command parameters for CMD6 (SWITCH):
// bits 31-26: set to 0
// bits 25-24: access (3 = write byte)
// bits 23-16: index (B7 = 183 in decimal is the offset of BUS_WIDTH in the EXT_CSD register)
// bits 15-8: value (1 = 4 bit mode)
// bits 7-3: set to 0
// bits 2-0: command set (kee using command set 0)
//
// See chapter 7.4.61 of the JEDEC spec as well as table 41 in section 6.10.4.
//
// The application note A.6.3 just gives the "magic" value to use without details as below:
const uint32 k4BitMode = 0x3B70100;
status = info->mmc->execute_command(info->parent, info->parentCookie, info->rca,
MMC_SWITCH, k4BitMode, &cardStatus);
}
TRACE("Card status after switching to 4 bit mode: %08x\n", cardStatus);
if (status == B_OK) {
// From now on we use 4 bit mode
TRACE("Switch to 4 bit mode for data transfers\n");
info->mmc->set_bus_width(info->parent, info->parentCookie, 4);
} else {
TRACE("Switching to 4 bit mode failed: %s\n", strerror(status));
}
return B_OK; return B_OK;
} }