From 518af33f3334f0d18de16ae880a865118592bd38 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sat, 16 Feb 2019 22:18:08 +0100 Subject: [PATCH] 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 --- .../kernel/bus_managers/mmc/mmc_bus.cpp | 16 ++++++++++------ src/add-ons/kernel/busses/mmc/sdhci_pci.cpp | 18 +++++++++++++++++- src/add-ons/kernel/busses/mmc/sdhci_pci.h | 3 ++- 3 files changed, 29 insertions(+), 8 deletions(-) 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