From 05b7380f791acf75045ace3b0a86a5a62bb624f6 Mon Sep 17 00:00:00 2001 From: PulkoMandy Date: Tue, 5 May 2026 13:25:50 +0200 Subject: [PATCH] sdhci: prepare for MMC EXT_SEND_CSD command This is needed to handle MMC devices larger than 2GB. The protocol used is different from how it's done in SDHC/SDXC. Change-Id: I12edb1a4196c1e8f375886e9e5a5c1cef111e33c Reviewed-on: https://review.haiku-os.org/c/haiku/+/10929 Reviewed-by: Adrien Destugues --- headers/private/drivers/mmc.h | 13 ++- src/add-ons/kernel/busses/mmc/sdhci.cpp | 124 ++++++++++++------------ 2 files changed, 71 insertions(+), 66 deletions(-) diff --git a/headers/private/drivers/mmc.h b/headers/private/drivers/mmc.h index 20cbec4cb0..9ea562af86 100644 --- a/headers/private/drivers/mmc.h +++ b/headers/private/drivers/mmc.h @@ -31,20 +31,27 @@ typedef enum card_type { // Commands for SD/eMMC cards defined in: // SD: Physical Layer Simplified Specification Version 8.00 // eMMC: JEDEC Standard No. 84-B51. Sec 6.10.4 +// // They are in the common .h file for the mmc stack because the SDHCI driver // currently needs to map them to the corresponding expected response types. -// card type prefix to distinguish non common commands. +// +// TODO maybe it would be simpler to have the upper layers (the bus manager and mmc_disk) specify +// the expected response type when sending a command. This would avoid hardcoding command types +// and the corresponding response types in the command sending code. +// +// When the commands are specific to SD or MMC types, the constant is named with the corresponding +// prefix. enum SD_COMMANDS { // Basic commands, class 0 GO_IDLE_STATE = 0, MMC_SEND_OP_COND = 1, - // MMC only,reserved in SD. + // MMC only,reserved in SD. ALL_SEND_CID = 2, SD_SEND_RELATIVE_ADDR = 3, MMC_SET_RELATIVE_ADDR = 3, SELECT_DESELECT_CARD = 7, - // resp can be R1 per mmc spec,keep R1b for now. SD_SEND_IF_COND = 8, + MMC_SEND_EXT_CSD = 8, SEND_CSD = 9, SD_STOP_TRANSMISSION = 12, diff --git a/src/add-ons/kernel/busses/mmc/sdhci.cpp b/src/add-ons/kernel/busses/mmc/sdhci.cpp index dafdde2283..9fad81c46a 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci.cpp +++ b/src/add-ons/kernel/busses/mmc/sdhci.cpp @@ -220,73 +220,71 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) uint32_t replyType; uint16 transferMode = 0; - bool cmdResolved = false; - // Resolve replyType for card type specific commands. - if (fCardType == CARD_TYPE_MMC) { - if (command == MMC_SET_RELATIVE_ADDR) { + switch (command) { + // Basic reply types + case GO_IDLE_STATE: + replyType = Command::kNoReplyType; + break; + 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; - cmdResolved = true; - } - } else if (command == SD_SEND_RELATIVE_ADDR) { - replyType = Command::kR6Type; - cmdResolved = true; - } - if (cmdResolved == false) { - switch (command) { - case GO_IDLE_STATE: - replyType = Command::kNoReplyType; - break; - case ALL_SEND_CID: - case SEND_CSD: - replyType = Command::kR2Type; - break; - case SELECT_DESELECT_CARD: - case SD_ERASE: - replyType = Command::kR1bType; - break; - case SD_SEND_IF_COND: - replyType = Command::kR7Type; - break; - case SD_READ_SINGLE_BLOCK: - transferMode = TransferMode::kRead | TransferMode::kDmaEnable; - replyType = Command::kR1Type | Command::kDataPresent; - break; - case SD_READ_MULTIPLE_BLOCKS: - transferMode = TransferMode::kRead | TransferMode::kMulti - | TransferMode::kAutoCmd12Enable | TransferMode::kBlockCountEnable - | TransferMode::kDmaEnable; - replyType = Command::kR1Type | Command::kDataPresent; - break; - case SD_WRITE_SINGLE_BLOCK: - transferMode = TransferMode::kWrite | TransferMode::kDmaEnable; - replyType = Command::kR1Type | Command::kDataPresent; - break; - case SD_WRITE_MULTIPLE_BLOCKS: - transferMode = TransferMode::kWrite | TransferMode::kMulti - | TransferMode::kAutoCmd12Enable | TransferMode::kBlockCountEnable - | TransferMode::kDmaEnable; - replyType = Command::kR1Type | Command::kDataPresent; - break; - case SD_APP_CMD: - case SD_ERASE_WR_BLK_START: - case SD_ERASE_WR_BLK_END: - case SD_SET_BUS_WIDTH: // SD Application command + break; + case SELECT_DESELECT_CARD: + case SD_ERASE: + replyType = Command::kR1bType; + break; + case ALL_SEND_CID: + case SEND_CSD: + replyType = Command::kR2Type; + break; + case MMC_SEND_OP_COND: + case SD_SEND_OP_COND: // SD Application command + replyType = Command::kR3Type; + break; + + // Commands defined with different reply types in SD and MMC specifications + case SD_SEND_RELATIVE_ADDR: // also MMC_SET_RELATIVE_ADDR + if (fCardType == CARD_TYPE_MMC) replyType = Command::kR1Type; - break; - case SD_SEND_OP_COND: // SD Application command - replyType = Command::kR3Type; - break; - // MMC / eMMC commands - case MMC_SEND_OP_COND: - // MMC/eMMC SEND_OP_COND command, CMD1. - replyType = Command::kR3Type; - break; - default: - ERROR("Unknown command %x\n", command); - return B_BAD_DATA; - } + else + replyType = Command::kR6Type; + break; + case SD_SEND_IF_COND: // also MMC_SEND_EXT_CSD + if (fCardType == CARD_TYPE_MMC) + replyType = Command::kR1Type; + else + replyType = Command::kR7Type; + break; + + // Commands with data transfer replies, also set transferMode + case SD_READ_SINGLE_BLOCK: + transferMode = TransferMode::kRead | TransferMode::kDmaEnable; + replyType = Command::kR1Type | Command::kDataPresent; + break; + case SD_READ_MULTIPLE_BLOCKS: + transferMode = TransferMode::kRead | TransferMode::kMulti + | TransferMode::kAutoCmd12Enable | TransferMode::kBlockCountEnable + | TransferMode::kDmaEnable; + replyType = Command::kR1Type | Command::kDataPresent; + break; + case SD_WRITE_SINGLE_BLOCK: + transferMode = TransferMode::kWrite | TransferMode::kDmaEnable; + replyType = Command::kR1Type | Command::kDataPresent; + break; + case SD_WRITE_MULTIPLE_BLOCKS: + transferMode = TransferMode::kWrite | TransferMode::kMulti + | TransferMode::kAutoCmd12Enable | TransferMode::kBlockCountEnable + | TransferMode::kDmaEnable; + replyType = Command::kR1Type | Command::kDataPresent; + break; + default: + ERROR("Unknown command %x\n", command); + return B_BAD_DATA; } + // Check if DATA line is available (if needed) if ((replyType & Command::k32BitResponseCheckBusy) != 0 && command != SD_STOP_TRANSMISSION && command != SD_IO_ABORT) {