(GSOC2026) Proper initialization for eMMC device.
[+] Implemented proper initialization and detection for eMMC card at mmc_bus.cpp [+] Extended SD_COMMANDS enum at mmc.h to support eMMC CMD3. some common commands are highlighted removing its specific card type prefix. [+] Reading eMMC Device CID register attributes for initiating mmc disk node. [+] added formal register content wrapper classes. [+] Printing some attrs for debugging and verification. [+] MMCBus and SDHCIBus are aware of the underlying card type, no problem unless more than one device on same mmc bus. i followed the specs on CID stipping, still asking for your validation. Built and tested with success for QEMU emulated sdHC eMMC device, also tested with emulated SD card to verify nothing backfires. my reference is JESD84-B51 document. *log file looks has this: mmc_bus: Trying MMC CMD1 initialization... ... mmc_bus: Detected MMC card after CMD1 ... ... mmc_bus: MMC RCA: 1 Status: 500 mmc_bus: MMC CID: MID=0, name="XQEMU!", PSN=31370686, PRV=201, MDT=14/2028 Change-Id: Ia6e93b154548ff7cf2dfae3bcffe85e6b2aa01fb Reviewed-on: https://review.haiku-os.org/c/haiku/+/10641 Reviewed-by: Adrien Destugues <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
ce845a52d4
commit
4ce5404143
@@ -17,30 +17,36 @@
|
||||
|
||||
struct IOOperation;
|
||||
|
||||
|
||||
enum {
|
||||
typedef enum card_type {
|
||||
CARD_TYPE_UNKNOWN,
|
||||
CARD_TYPE_MMC,
|
||||
CARD_TYPE_SD,
|
||||
CARD_TYPE_SDHC,
|
||||
CARD_TYPE_UHS1,
|
||||
CARD_TYPE_UHS2,
|
||||
CARD_TYPE_SDIO
|
||||
};
|
||||
} card_type;
|
||||
|
||||
|
||||
// Commands for SD cards defined in SD Specifications Part 1:
|
||||
// Physical Layer Simplified Specification Version 8.00
|
||||
// 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.
|
||||
enum SD_COMMANDS {
|
||||
// Basic commands, class 0
|
||||
SD_GO_IDLE_STATE = 0,
|
||||
SD_ALL_SEND_CID = 2,
|
||||
SD_SEND_RELATIVE_ADDR = 3,
|
||||
SD_SELECT_DESELECT_CARD = 7,
|
||||
SD_SEND_IF_COND = 8,
|
||||
SD_SEND_CSD = 9,
|
||||
SD_STOP_TRANSMISSION = 12,
|
||||
GO_IDLE_STATE = 0,
|
||||
MMC_SEND_OP_COND = 1,
|
||||
// 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,
|
||||
SEND_CSD = 9,
|
||||
SD_STOP_TRANSMISSION = 12,
|
||||
|
||||
// Block oriented read and write commands, class 2
|
||||
SD_READ_SINGLE_BLOCK = 17,
|
||||
@@ -89,7 +95,7 @@ typedef struct mmc_bus_interface {
|
||||
void (*set_bus_width)(void* controller, int width);
|
||||
// Set the data bus width to 1, 4 or 8 bit mode.
|
||||
void (*terminate_bus)(void* controller);
|
||||
// Terminate use of the underlying sdhci bus.
|
||||
void (*set_card_type)(void* controller, card_type type);
|
||||
} mmc_bus_interface;
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ MMCBus::MMCBus(device_node* node)
|
||||
fCookie(NULL),
|
||||
fStatus(B_OK),
|
||||
fWorkerThread(-1),
|
||||
fActiveDevice(0)
|
||||
fActiveDevice(0),
|
||||
fCardType(CARD_TYPE_UNKNOWN)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
@@ -115,6 +116,14 @@ MMCBus::SetBusWidth(int width)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MMCBus::SetCardType(card_type type)
|
||||
{
|
||||
fCardType = type;
|
||||
fController->set_card_type(fCookie, type);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MMCBus::_ActivateDevice(uint16_t rca)
|
||||
{
|
||||
@@ -124,8 +133,8 @@ MMCBus::_ActivateDevice(uint16_t rca)
|
||||
|
||||
uint32_t response;
|
||||
status_t result;
|
||||
result = fController->execute_command(fCookie, SD_SELECT_DESELECT_CARD,
|
||||
((uint32)rca) << 16, &response);
|
||||
result = fController->execute_command(fCookie, SELECT_DESELECT_CARD, ((uint32)rca) << 16,
|
||||
&response);
|
||||
|
||||
if (result == B_OK)
|
||||
fActiveDevice = rca;
|
||||
@@ -176,7 +185,7 @@ MMCBus::_WorkerThread(void* cookie)
|
||||
}
|
||||
|
||||
TRACE("Reset the bus...\n");
|
||||
result = bus->ExecuteCommand(0, SD_GO_IDLE_STATE, 0, NULL);
|
||||
result = bus->ExecuteCommand(0, GO_IDLE_STATE, 0, NULL);
|
||||
TRACE("CMD0 result: %s\n", strerror(result));
|
||||
} while (result != B_OK);
|
||||
|
||||
@@ -197,22 +206,45 @@ MMCBus::_WorkerThread(void* cookie)
|
||||
enum {
|
||||
// Table 4-40 in physical layer specification v8.00
|
||||
// All other values are currently reserved
|
||||
HOST_27_36V = 1, //Host supplied voltage 2.7-3.6V
|
||||
HOST_27_36V = 1, // Host supplied voltage 2.7-3.6V
|
||||
};
|
||||
|
||||
// An arbitrary value, we just need to check that the response
|
||||
// containts the same.
|
||||
static const uint8 kVoltageCheckPattern = 0xAA;
|
||||
|
||||
uint8_t cardType = CARD_TYPE_SD;
|
||||
// FIXME MMC cards will not reply to this! They expect CMD1 instead
|
||||
// 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 = (HOST_27_36V << 8) | kVoltageCheckPattern;
|
||||
uint32_t hcs = 1 << 30;
|
||||
if (bus->ExecuteCommand(0, SD_SEND_IF_COND, probe, &response) != B_OK) {
|
||||
TRACE("Card does not implement CMD8, may be a V1 SD card\n");
|
||||
uint32_t ocr;
|
||||
status_t status = bus->ExecuteCommand(0, SD_SEND_IF_COND, probe, &response);
|
||||
if (status != B_OK) {
|
||||
TRACE("Card does not implement CMD8, may be a V1 SD or MMC card\n");
|
||||
// Do not check for SDHC support in this case
|
||||
hcs = 0;
|
||||
uint32_t mmcOcr;
|
||||
TRACE("Trying MMC CMD1 initialization...\n");
|
||||
do {
|
||||
status = bus->ExecuteCommand(0, MMC_SEND_OP_COND, 0xFF8000, &mmcOcr);
|
||||
// full voltage window, byte addressable, should look into this.
|
||||
if (status != B_OK) {
|
||||
TRACE("MMC CMD1 failed\n");
|
||||
break;
|
||||
}
|
||||
if ((mmcOcr & (1 << 31)) == 0) {
|
||||
TRACE("MMC card is busy\n");
|
||||
snooze(100000);
|
||||
}
|
||||
} while ((mmcOcr & (1 << 31)) == 0);
|
||||
|
||||
if (status == B_OK && (mmcOcr & (1 << 31)) != 0) {
|
||||
TRACE("Detected MMC card after CMD1\n");
|
||||
cardType = CARD_TYPE_MMC;
|
||||
// Reuse the probed OCR value for logging and later handling
|
||||
ocr = mmcOcr;
|
||||
}
|
||||
} else if (response != probe) {
|
||||
ERROR("Card does not support voltage range (expected %x, "
|
||||
"reply %x)\n", probe, response);
|
||||
@@ -223,54 +255,84 @@ MMCBus::_WorkerThread(void* cookie)
|
||||
|
||||
// Probe OCR, waiting for card to become ready
|
||||
// We keep repeating ACMD41 until the card replies that it is
|
||||
// initialized.
|
||||
uint32_t ocr;
|
||||
do {
|
||||
uint32_t cardStatus;
|
||||
while (bus->ExecuteCommand(0, SD_APP_CMD, 0, &cardStatus)
|
||||
== B_BUSY) {
|
||||
ERROR("Card locked after CMD8...\n");
|
||||
snooze(1000000);
|
||||
}
|
||||
if ((cardStatus & 0xFFFF8000) != 0)
|
||||
ERROR("SD card reports error %x\n", cardStatus);
|
||||
if ((cardStatus & (1 << 5)) == 0)
|
||||
ERROR("Card did not enter ACMD mode\n");
|
||||
// initialized. For MMC we already probed using CMD1 above.
|
||||
if (cardType != CARD_TYPE_MMC) {
|
||||
do {
|
||||
uint32_t cardStatus;
|
||||
while (bus->ExecuteCommand(0, SD_APP_CMD, 0, &cardStatus) == B_BUSY) {
|
||||
ERROR("Card locked after CMD8...\n");
|
||||
snooze(1000000);
|
||||
}
|
||||
if ((cardStatus & 0xFFFF8000) != 0)
|
||||
ERROR("SD card reports error %x\n", cardStatus);
|
||||
if ((cardStatus & (1 << 5)) == 0)
|
||||
ERROR("Card did not enter ACMD mode\n");
|
||||
|
||||
bus->ExecuteCommand(0, SD_SEND_OP_COND, hcs | 0xFF8000, &ocr);
|
||||
bus->ExecuteCommand(0, SD_SEND_OP_COND, hcs | 0xFF8000, &ocr);
|
||||
|
||||
if ((ocr & (1 << 31)) == 0) {
|
||||
TRACE("Card is busy\n");
|
||||
snooze(100000);
|
||||
}
|
||||
} while (((ocr & (1 << 31)) == 0));
|
||||
if ((ocr & (1 << 31)) == 0) {
|
||||
TRACE("Card is busy\n");
|
||||
snooze(100000);
|
||||
}
|
||||
} while ((ocr & (1 << 31)) == 0);
|
||||
}
|
||||
|
||||
// FIXME this should be asked to each card, when there are multiple
|
||||
// ones. So ACMD41 should be moved inside the probing loop below?
|
||||
uint8_t cardType = CARD_TYPE_SD;
|
||||
|
||||
if ((ocr & hcs) != 0)
|
||||
cardType = CARD_TYPE_SDHC;
|
||||
if ((ocr & (1 << 29)) != 0)
|
||||
cardType = CARD_TYPE_UHS2;
|
||||
if ((ocr & (1 << 24)) != 0)
|
||||
TRACE("Card supports 1.8v");
|
||||
if (cardType == CARD_TYPE_SD) {
|
||||
if ((ocr & hcs) != 0)
|
||||
cardType = CARD_TYPE_SDHC;
|
||||
if ((ocr & (1 << 29)) != 0)
|
||||
cardType = CARD_TYPE_UHS2;
|
||||
if ((ocr & (1 << 24)) != 0)
|
||||
TRACE("Card supports 1.8v");
|
||||
}
|
||||
TRACE("Voltage range: %x\n", ocr & 0xFFFFFF);
|
||||
|
||||
// TODO send CMD11 to switch to low voltage mode if card supports it?
|
||||
|
||||
// We use CMD2 (ALL_SEND_CID) and CMD3 (SEND_RELATIVE_ADDR) to assign
|
||||
// an RCA to all cards. Initially all cards have an RCA of 0 and will
|
||||
// all receive CMD2. But only ne of them will reply (they do collision
|
||||
// all receive CMD2. But only one of them will reply (they do collision
|
||||
// detection while sending the CID in reply). We assign a new RCA to
|
||||
// that first card, and repeat the process with the remaining ones
|
||||
// until no one answers to CMD2. Then we know all cards have an RCA
|
||||
// (and a matching published device on our side).
|
||||
uint32_t cid[4];
|
||||
|
||||
uint32_t vendor;
|
||||
char name[7];
|
||||
uint32_t serial;
|
||||
uint16_t revision;
|
||||
uint8_t month;
|
||||
uint16_t year;
|
||||
uint16_t rca;
|
||||
bool cardFound = false;
|
||||
// This being an if statement as opposed to a while statement restricts
|
||||
// it to one device per bus.
|
||||
if (bus->ExecuteCommand(0, SD_ALL_SEND_CID, 0, cid) == B_OK) {
|
||||
if (cardType == CARD_TYPE_MMC) {
|
||||
if (bus->ExecuteCommand(0, ALL_SEND_CID, 0, cid) == B_OK) {
|
||||
// We currently support only a single card, so use a fixed RCA.
|
||||
rca = 1;
|
||||
status
|
||||
= bus->ExecuteCommand(0, MMC_SET_RELATIVE_ADDR, ((uint32)rca) << 16, &response);
|
||||
TRACE("MMC RCA: %x Status: %x\n", rca, response & 0xFFFF);
|
||||
if (status != B_OK) {
|
||||
TRACE("Failed to set RCA for MMC card\n");
|
||||
} else {
|
||||
MMCCid mmcCid(cid);
|
||||
vendor = mmcCid.VendorID();
|
||||
mmcCid.ProductName(name);
|
||||
serial = mmcCid.ProductSerial();
|
||||
revision = mmcCid.ProductRevision();
|
||||
month = mmcCid.ManufactureMonth();
|
||||
year = mmcCid.ManufactureYear(true);
|
||||
TRACE("MMC CID: MID=%" B_PRIu32 ", name=\"%s\", PSN=%" B_PRIu32
|
||||
", PRV=%u, MDT=%u/%u\n",
|
||||
vendor, name, serial, revision, month, year);
|
||||
cardFound = true;
|
||||
}
|
||||
}
|
||||
} else if (bus->ExecuteCommand(0, ALL_SEND_CID, 0, cid) == B_OK) {
|
||||
bus->ExecuteCommand(0, SD_SEND_RELATIVE_ADDR, 0, &response);
|
||||
|
||||
TRACE("RCA: %x Status: %x\n", response >> 16, response & 0xFFFF);
|
||||
@@ -285,18 +347,20 @@ MMCBus::_WorkerThread(void* cookie)
|
||||
// The card now has an RCA and it entered the data phase, which
|
||||
// means our initializing job is over, we can pass it on to the
|
||||
// mmc_disk driver.
|
||||
|
||||
uint32_t vendor = cid[3] & 0xFFFFFF;
|
||||
char name[6] = {(char)(cid[2] >> 24), (char)(cid[2] >> 16),
|
||||
(char)(cid[2] >> 8), (char)cid[2], (char)(cid[1] >> 24), 0};
|
||||
uint32_t serial = (cid[1] << 16) | (cid[0] >> 16);
|
||||
uint16_t revision = (cid[1] >> 20) & 0xF;
|
||||
revision *= 100;
|
||||
revision += (cid[1] >> 16) & 0xF;
|
||||
uint8_t month = cid[0] & 0xF;
|
||||
uint16_t year = 2000 + ((cid[0] >> 4) & 0xFF);
|
||||
uint16_t rca = response >> 16;
|
||||
|
||||
rca = response >> 16;
|
||||
SDCid sdCid(cid);
|
||||
vendor = sdCid.VendorID();
|
||||
sdCid.ProductName(name);
|
||||
serial = sdCid.ProductSerial();
|
||||
revision = sdCid.ProductRevision();
|
||||
month = sdCid.ManufactureMonth();
|
||||
year = sdCid.ManufactureYear();
|
||||
cardFound = true;
|
||||
}
|
||||
|
||||
if (cardFound) {
|
||||
bus->SetCardType((card_type)cardType);
|
||||
|
||||
device_attr attrs[] = {
|
||||
{ B_DEVICE_BUS, B_STRING_TYPE, {.string = "mmc" }},
|
||||
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "mmc device" }},
|
||||
|
||||
@@ -28,6 +28,102 @@
|
||||
#define ERROR(x...) dprintf("\33[33mmmc_bus:\33[0m " x)
|
||||
#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
|
||||
|
||||
|
||||
class CidWrapper {
|
||||
public:
|
||||
CidWrapper(const uint32 cid[4])
|
||||
{
|
||||
fWords[0] = cid[0];
|
||||
fWords[1] = cid[1];
|
||||
fWords[2] = cid[2];
|
||||
fWords[3] = cid[3];
|
||||
}
|
||||
|
||||
uint32_t VendorID() const
|
||||
{
|
||||
return (fWords[3] >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
uint32_t ProductSerial() const
|
||||
{
|
||||
return (fWords[1] << 16) | (fWords[0] >> 16);
|
||||
}
|
||||
|
||||
uint16_t ProductRevision() const
|
||||
{
|
||||
uint16 rev = (fWords[1] >> 20) & 0xF;
|
||||
rev *= 100;
|
||||
rev += (fWords[1] >> 16) & 0xF;
|
||||
return rev;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t fWords[4];
|
||||
};
|
||||
|
||||
|
||||
// per Physical Layer Simplified Specification Version 9.10
|
||||
// sec 5.2
|
||||
class SDCid : public CidWrapper {
|
||||
public:
|
||||
SDCid(const uint32 cid[4])
|
||||
:
|
||||
CidWrapper(cid)
|
||||
{
|
||||
}
|
||||
|
||||
void ProductName(char out[6]) const
|
||||
{
|
||||
out[0] = (char)(fWords[2] >> 24);
|
||||
out[1] = (char)(fWords[2] >> 16);
|
||||
out[2] = (char)(fWords[2] >> 8);
|
||||
out[3] = (char)(fWords[2]);
|
||||
out[4] = (char)(fWords[1] >> 24);
|
||||
out[5] = '\0';
|
||||
}
|
||||
|
||||
uint8_t ManufactureMonth() const { return (fWords[0] >> 8) & 0xF; }
|
||||
uint16_t ManufactureYear() const { return 2000 + ((fWords[0] >> 12) & 0xFF); }
|
||||
};
|
||||
|
||||
|
||||
// per JEDEC Standard No. 84-B51, sec 7.2
|
||||
class MMCCid : public CidWrapper {
|
||||
public:
|
||||
MMCCid(const uint32 cid[4])
|
||||
:
|
||||
CidWrapper(cid)
|
||||
{
|
||||
}
|
||||
|
||||
void ProductName(char out[7]) const
|
||||
{
|
||||
out[0] = (char)(fWords[3] & 0xFF);
|
||||
out[1] = (char)(fWords[2] >> 24);
|
||||
out[2] = (char)(fWords[2] >> 16);
|
||||
out[3] = (char)(fWords[2] >> 8);
|
||||
out[4] = (char)(fWords[2]);
|
||||
out[5] = (char)(fWords[1] >> 24);
|
||||
out[6] = '\0';
|
||||
}
|
||||
|
||||
uint8_t ManufactureMonth() const
|
||||
{
|
||||
// detailed in sec 7.2.7 MDT[15:8]
|
||||
return (fWords[0] >> 12) & 0x0F;
|
||||
}
|
||||
|
||||
uint16_t ManufactureYear(bool modern) const
|
||||
{
|
||||
// For eMMC 4.41 and later devices,
|
||||
// indicated by a value larger than 4 in EXT_CSD_REV[192]
|
||||
// year offset is 2013 instead of 1997.
|
||||
uint8_t yearOffset = (fWords[0] >> 8) & 0x0F;
|
||||
return yearOffset + (modern? 2013 : 1997);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern device_manager_info *gDeviceManager;
|
||||
|
||||
|
||||
@@ -49,6 +145,7 @@ public:
|
||||
|
||||
void SetClock(int frequency);
|
||||
void SetBusWidth(int width);
|
||||
void SetCardType(card_type type);
|
||||
|
||||
void AcquireBus() { acquire_sem(fLockSemaphore); }
|
||||
void ReleaseBus() { release_sem(fLockSemaphore); }
|
||||
@@ -68,6 +165,13 @@ private:
|
||||
sem_id fScanSemaphore;
|
||||
sem_id fLockSemaphore;
|
||||
uint16 fActiveDevice;
|
||||
card_type fCardType;
|
||||
// FIXME card type shall be extended to map card type to RCA.
|
||||
// In theory RCA is 16 bit allowing for 2^16 devices on signle bus
|
||||
// Practically this is limited by bus max capacitance(ver low speed)
|
||||
// which narrows down to theoritical 40 cards, imperically 10 cards only.
|
||||
// numbers qouted from untrusted sources but seems more than reasonable.
|
||||
// Thus, an array of 40 card_types where RCA is the index shall work.
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@ sdhci_generic_interrupt(void* data)
|
||||
SdhciBus::SdhciBus(struct registers* registers, uint8_t irq, bool poll)
|
||||
:
|
||||
fRegisters(registers),
|
||||
fIrq(irq)
|
||||
fIrq(irq),
|
||||
fCardType(CARD_TYPE_UNKNOWN)
|
||||
{
|
||||
if (irq == 0 || irq == 0xff) {
|
||||
ERROR("IRQ not assigned\n");
|
||||
@@ -219,59 +220,73 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
|
||||
|
||||
uint32_t replyType;
|
||||
uint16 transferMode = 0;
|
||||
bool cmdResolved = false;
|
||||
|
||||
switch (command) {
|
||||
case SD_GO_IDLE_STATE:
|
||||
replyType = Command::kNoReplyType;
|
||||
break;
|
||||
case SD_ALL_SEND_CID:
|
||||
case SD_SEND_CSD:
|
||||
replyType = Command::kR2Type;
|
||||
break;
|
||||
case SD_SEND_RELATIVE_ADDR:
|
||||
replyType = Command::kR6Type;
|
||||
break;
|
||||
case SD_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
|
||||
// Resolve replyType for card type specific commands.
|
||||
if (fCardType == CARD_TYPE_MMC) {
|
||||
if (command == MMC_SET_RELATIVE_ADDR) {
|
||||
replyType = Command::kR1Type;
|
||||
break;
|
||||
case SD_SEND_OP_COND: // SD Application command
|
||||
replyType = Command::kR3Type;
|
||||
break;
|
||||
default:
|
||||
ERROR("Unknown command %x\n", command);
|
||||
return B_BAD_DATA;
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if DATA line is available (if needed)
|
||||
if ((replyType & Command::k32BitResponseCheckBusy) != 0
|
||||
&& command != SD_STOP_TRANSMISSION && command != SD_IO_ABORT) {
|
||||
@@ -582,6 +597,13 @@ SdhciBus::SetBusWidth(int width)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SdhciBus::SetCardType(card_type type)
|
||||
{
|
||||
fCardType = type;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SdhciBus::PowerOn()
|
||||
{
|
||||
@@ -936,6 +958,14 @@ set_bus_width(void* controller, int width)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
set_card_type(void* controller, card_type type)
|
||||
{
|
||||
SdhciBus* bus = (SdhciBus*)controller;
|
||||
bus->SetCardType(type);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
terminate_bus(void* controller)
|
||||
{
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include "mmc.h"
|
||||
|
||||
|
||||
class SdhciBus {
|
||||
public:
|
||||
@@ -34,6 +36,7 @@ class SdhciBus {
|
||||
bool offsetAsSectors);
|
||||
void SetScanSemaphore(sem_id sem);
|
||||
void SetBusWidth(int width);
|
||||
void SetCardType(card_type type);
|
||||
void TerminateBus();
|
||||
|
||||
private:
|
||||
@@ -50,6 +53,7 @@ class SdhciBus {
|
||||
sem_id fScanSemaphore;
|
||||
status_t fStatus;
|
||||
thread_id fWorkerThread;
|
||||
card_type fCardType;
|
||||
};
|
||||
|
||||
|
||||
@@ -518,6 +522,7 @@ status_t do_io(void* controller, uint8_t command,
|
||||
IOOperation* operation, bool offsetAsSectors);
|
||||
void set_scan_semaphore(void* controller, sem_id sem);
|
||||
void set_bus_width(void* controller, int width);
|
||||
void set_card_type(void* controller, card_type type);
|
||||
void terminate_bus(void* controller);
|
||||
|
||||
extern mmc_bus_interface gSDHCIACPIDeviceModule;
|
||||
|
||||
@@ -240,4 +240,5 @@ mmc_bus_interface gSDHCIACPIDeviceModule = {
|
||||
.set_scan_semaphore = set_scan_semaphore,
|
||||
.set_bus_width = set_bus_width,
|
||||
.terminate_bus = terminate_bus,
|
||||
.set_card_type = set_card_type,
|
||||
};
|
||||
|
||||
@@ -328,4 +328,5 @@ mmc_bus_interface gSDHCIPCIDeviceModule = {
|
||||
.set_scan_semaphore = set_scan_semaphore,
|
||||
.set_bus_width = set_bus_width,
|
||||
.terminate_bus = terminate_bus,
|
||||
.set_card_type = set_card_type,
|
||||
};
|
||||
|
||||
@@ -152,8 +152,8 @@ mmc_block_get_geometry(mmc_disk_driver_info* info, device_geometry* geometry)
|
||||
{
|
||||
struct mmc_disk_csd csd;
|
||||
TRACE("Get geometry\n");
|
||||
status_t error = info->mmc->execute_command(info->parent,
|
||||
info->parentCookie, 0, SD_SEND_CSD, info->rca << 16, (uint32_t*)&csd);
|
||||
status_t error = info->mmc->execute_command(info->parent, info->parentCookie, 0, SEND_CSD,
|
||||
info->rca << 16, (uint32_t*)&csd);
|
||||
if (error != B_OK) {
|
||||
TRACE("Could not get CSD! %s\n", strerror(error));
|
||||
return error;
|
||||
|
||||
Reference in New Issue
Block a user