diff --git a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp index fbebd76a13..e4d9b6a946 100644 --- a/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp +++ b/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp @@ -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); diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp index 4e045192d3..2b3ffcb921 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp @@ -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); diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.h b/src/add-ons/kernel/busses/mmc/sdhci_pci.h index 7831c0c6da..68bf7e587f 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.h +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.h @@ -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