mmc/sd: support for SD v2.0 cards

Older cards did not implement CMD8, so handle the command stalling, and
proceed with initialization (not querying about SDHC support in that
case, as per the spec).

Change-Id: Ie842effc2f99e1adf1990b3215be79db493138b5
Reviewed-on: https://review.haiku-os.org/c/1056
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Adrien Destugues 2019-02-16 22:18:08 +01:00 committed by waddlesplash
parent ff76d2df8e
commit 518af33f33
3 changed files with 29 additions and 8 deletions

View File

@ -89,8 +89,12 @@ MMCBus::WorkerThread(void* cookie)
// SD v1 cards will also not reply, but we can proceed to ACMD41
// If ACMD41 also does not work, it may be an SDIO card, too
uint32_t probe = (1 << 8) | 0x55;
bus->ExecuteCommand(8, probe, &response);
if (response != probe) {
uint32_t hcs = 1 << 30;
if (bus->ExecuteCommand(8, probe, &response) != B_OK) {
TRACE("Card does not implement CMD8, may be a V1 SD card\n");
// Do not check for SDHC support in this case
hcs = 0;
} else if (response != probe) {
ERROR("Card does not support voltage range (expected %x, reply %x)\n",
probe, response);
// TODO what now?
@ -111,7 +115,7 @@ MMCBus::WorkerThread(void* cookie)
if ((cardStatus & (1 << 5)) == 0)
ERROR("Card did not enter ACMD mode");
bus->ExecuteCommand(41, (1 << 30) | 0xFF8000, &ocr);
bus->ExecuteCommand(41, hcs | 0xFF8000, &ocr);
if ((ocr & (1 << 31)) == 0) {
TRACE("Card is busy\n");
@ -119,11 +123,11 @@ MMCBus::WorkerThread(void* cookie)
}
} while (((ocr & (1 << 31)) == 0));
if (ocr & (1 << 30))
if (ocr & hcs != 0)
TRACE("Card is SDHC");
if (ocr & (1 << 29))
if (ocr & (1 << 29) != 0)
TRACE("Card supports UHS-II");
if (ocr & (1 << 24))
if (ocr & (1 << 24) != 0)
TRACE("Card supports 1.8v");
TRACE("Voltage range: %x\n", ocr & 0xFFFFFF);

View File

@ -120,6 +120,7 @@ SdhciBus::SdhciBus(struct registers* registers, uint8_t irq)
| SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_INDEX
| SDHCI_INT_BUS_POWER | SDHCI_INT_END_BIT);
fRegisters->interrupt_status_enable |= SDHCI_INT_ERROR;
}
@ -224,6 +225,21 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
fRegisters->command.SendCommand(command, replyType);
acquire_sem(fSemaphore);
if (fRegisters->interrupt_status & SDHCI_INT_ERROR) {
fRegisters->interrupt_status |= SDHCI_INT_ERROR;
ERROR("Command execution failed\n");
// TODO look at errors in interrupt_status register for more details
// and return a more appropriate error code
return B_ERROR;
}
if (fRegisters->present_state.CommandInhibit()) {
TRACE("Command execution failed, card stalled\n");
// Clear the stall
fRegisters->software_reset.ResetCommandLine();
return B_ERROR;
}
if (replyType == Command::kNoReplyType) {
// No response
} else if (replyType == Command::kR2Type) {
@ -437,7 +453,7 @@ SdhciBus::RecoverError()
| SDHCI_INT_TRANS_CMP | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM);
if (fRegisters->interrupt_status & 7)
fRegisters->software_reset.ResetTransaction();
fRegisters->software_reset.ResetCommandLine();
int16_t error_status = fRegisters->interrupt_status;
fRegisters->interrupt_status &= ~(error_status);

View File

@ -113,7 +113,7 @@ class SoftwareReset {
while(fBits & 1);
}
void ResetTransaction() {
void ResetCommandLine() {
fBits |= 2;
while(fBits & 2);
}
@ -128,6 +128,7 @@ class SoftwareReset {
#define SDHCI_INT_TRANS_CMP 0x00000002 // transfer complete enable
#define SDHCI_INT_CARD_INS 0x00000040 // card insertion enable
#define SDHCI_INT_CARD_REM 0x00000080 // card removal enable
#define SDHCI_INT_ERROR 0x00008000 // error
#define SDHCI_INT_TIMEOUT 0x00010000 // Timeout error
#define SDHCI_INT_CRC 0x00020000 // CRC error
#define SDHCI_INT_END_BIT 0x00040000 // end bit error