From 5efaab5061b5bb7cf789ecc0547e1bf27801eec8 Mon Sep 17 00:00:00 2001 From: PulkoMandy Date: Tue, 5 May 2026 21:30:13 +0200 Subject: [PATCH] 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 --- headers/private/drivers/mmc.h | 3 +- src/add-ons/kernel/busses/mmc/sdhci.cpp | 7 ++- .../kernel/drivers/disk/mmc/mmc_disk.cpp | 47 +++++++++++++++---- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/headers/private/drivers/mmc.h b/headers/private/drivers/mmc.h index 1cd014e80c..e81947f0c9 100644 --- a/headers/private/drivers/mmc.h +++ b/headers/private/drivers/mmc.h @@ -46,10 +46,10 @@ enum SD_COMMANDS { // Basic commands, class 0 GO_IDLE_STATE = 0, MMC_SEND_OP_COND = 1, - // MMC only,reserved in SD. ALL_SEND_CID = 2, SD_SEND_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, SD_SEND_IF_COND = 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 { SD_SET_BUS_WIDTH = 6, SD_SEND_OP_COND = 41, diff --git a/src/add-ons/kernel/busses/mmc/sdhci.cpp b/src/add-ons/kernel/busses/mmc/sdhci.cpp index 945b1ab77c..95168841fa 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci.cpp +++ b/src/add-ons/kernel/busses/mmc/sdhci.cpp @@ -229,7 +229,6 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) case SD_APP_CMD: case SD_ERASE_WR_BLK_START: case SD_ERASE_WR_BLK_END: - case SD_SET_BUS_WIDTH: // SD Application command replyType = Command::kR1Type; break; case SELECT_DESELECT_CARD: @@ -246,6 +245,12 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) break; // 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 if (fCardType == CARD_TYPE_MMC) replyType = Command::kR1Type; diff --git a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp index c69de71010..61474cba8b 100644 --- a/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/mmc/mmc_disk.cpp @@ -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 // opportunity to switch the card to 4-bit data transfers (instead of the // default 1 bit mode) - uint32_t cardStatus; - const uint32 k4BitMode = 2; - 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); + uint32_t cardStatus = 0; + status_t status = B_OK; - // From now on we use 4 bit mode - info->mmc->set_bus_width(info->parent, info->parentCookie, 4); + // TODO have the card type at hand instead of using the csd version here + 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; }