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:
committed by
Adrien Destugues
parent
1e9473f97e
commit
5efaab5061
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
// TODO have the card type at hand instead of using the csd version here
|
||||||
|
if (csd.structure_version() < 3) {
|
||||||
const uint32 k4BitMode = 2;
|
const uint32 k4BitMode = 2;
|
||||||
info->mmc->execute_command(info->parent, info->parentCookie, info->rca,
|
info->mmc->execute_command(info->parent, info->parentCookie, info->rca,
|
||||||
SD_APP_CMD, info->rca << 16, &cardStatus);
|
SD_APP_CMD, info->rca << 16, &cardStatus);
|
||||||
info->mmc->execute_command(info->parent, info->parentCookie, info->rca,
|
status = info->mmc->execute_command(info->parent, info->parentCookie, info->rca,
|
||||||
SD_SET_BUS_WIDTH, k4BitMode, &cardStatus);
|
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
|
// 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);
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user