#include "mmc_bus.h"
#include <Errors.h>
#include <stdint.h>
MMCBus::MMCBus(device_node* node)
:
fNode(node),
fController(NULL),
fCookie(NULL),
fStatus(B_OK),
fWorkerThread(-1),
fActiveDevice(0),
fCardType(CARD_TYPE_UNKNOWN)
{
CALLED();
device_node* parent = gDeviceManager->get_parent_node(node);
fStatus = gDeviceManager->get_driver(parent,
(driver_module_info**)&fController, &fCookie);
gDeviceManager->put_node(parent);
if (fStatus != B_OK) {
ERROR("Not able to establish the bus %s\n",
strerror(fStatus));
return;
}
fScanSemaphore = create_sem(0, "MMC bus scan");
fLockSemaphore = create_sem(1, "MMC bus lock");
fWorkerThread = spawn_kernel_thread(_WorkerThread, "SD bus controller",
B_NORMAL_PRIORITY, this);
resume_thread(fWorkerThread);
fController->set_scan_semaphore(fCookie, fScanSemaphore);
}
MMCBus::~MMCBus()
{
CALLED();
fStatus = B_SHUTTING_DOWN;
delete_sem(fScanSemaphore);
delete_sem(fLockSemaphore);
status_t result;
if (fWorkerThread != 0)
wait_for_thread(fWorkerThread, &result);
}
status_t
MMCBus::InitCheck()
{
return fStatus;
}
void
MMCBus::Rescan()
{
release_sem(fScanSemaphore);
}
status_t
MMCBus::ExecuteCommand(uint16_t rca, uint8_t command, uint32_t argument,
uint32_t* response)
{
status_t status = _ActivateDevice(rca);
if (status != B_OK)
return status;
return fController->execute_command(fCookie, command, argument, response);
}
status_t
MMCBus::DoIO(uint16_t rca, uint8_t command, IOOperation* operation,
bool offsetAsSectors)
{
status_t status = _ActivateDevice(rca);
if (status != B_OK)
return status;
return fController->do_io(fCookie, command, operation, offsetAsSectors);
}
void
MMCBus::SetClock(int frequency)
{
fController->set_clock(fCookie, frequency);
}
void
MMCBus::SetBusWidth(int width)
{
fController->set_bus_width(fCookie, width);
}
void
MMCBus::SetCardType(card_type type)
{
fCardType = type;
fController->set_card_type(fCookie, type);
}
status_t
MMCBus::_ActivateDevice(uint16_t rca)
{
if (fActiveDevice == rca)
return B_OK;
uint32_t response;
status_t result;
result = fController->execute_command(fCookie, SELECT_DESELECT_CARD, ((uint32)rca) << 16,
&response);
if (result == B_OK)
fActiveDevice = rca;
return result;
}
void MMCBus::_AcquireScanSemaphore()
{
ReleaseBus();
acquire_sem(fScanSemaphore);
AcquireBus();
}
void
MMCBus::_TerminateBus()
{
fController->terminate_bus(fCookie);
}
status_t
MMCBus::_WorkerThread(void* cookie)
{
MMCBus* bus = (MMCBus*)cookie;
uint32_t response;
bus->AcquireBus();
status_t result;
do {
bus->_AcquireScanSemaphore();
if (bus->fStatus == B_SHUTTING_DOWN) {
bus->ReleaseBus();
return B_OK;
}
TRACE("Reset the bus...\n");
result = bus->ExecuteCommand(0, GO_IDLE_STATE, 0, NULL);
TRACE("CMD0 result: %s\n", strerror(result));
} while (result != B_OK);
snooze(30000);
while (bus->fStatus != B_SHUTTING_DOWN) {
TRACE("Scanning the bus\n");
bus->SetClock(400);
bus->SetBusWidth(1);
enum {
HOST_27_36V = 1,
};
static const uint8 kVoltageCheckPattern = 0xAA;
uint8_t cardType = CARD_TYPE_SD;
uint32_t probe = (HOST_27_36V << 8) | kVoltageCheckPattern;
uint32_t hcs = 1 << 30;
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");
hcs = 0;
TRACE("Trying MMC CMD1 initialization...\n");
do {
status = bus->ExecuteCommand(0, MMC_SEND_OP_COND, 0xFF8000, &ocr);
if (status != B_OK) {
TRACE("MMC CMD1 failed\n");
break;
}
if ((ocr & (1 << 31)) == 0) {
TRACE("MMC card is busy\n");
snooze(100000);
}
} while ((ocr & (1 << 31)) == 0);
if (status == B_OK && (ocr & (1 << 31)) != 0) {
TRACE("Detected MMC card after CMD1\n");
if ((ocr & (1 << 30)) != 0)
cardType = CARD_TYPE_MMC_EXTENDED_CAPACITY;
else
cardType = CARD_TYPE_MMC;
}
} else if (response != probe) {
ERROR("Card does not support voltage range (expected %x, "
"reply %x)\n", probe, response);
bus->_TerminateBus();
bus->ReleaseBus();
return B_ERROR;
}
if ((cardType != CARD_TYPE_MMC) && (cardType != CARD_TYPE_MMC_EXTENDED_CAPACITY)) {
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);
if ((ocr & (1 << 31)) == 0) {
TRACE("Card is busy\n");
snooze(100000);
}
} while ((ocr & (1 << 31)) == 0);
}
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);
bus->SetCardType((card_type)cardType);
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;
if ((cardType == CARD_TYPE_MMC) || (cardType == CARD_TYPE_MMC_EXTENDED_CAPACITY)) {
if (bus->ExecuteCommand(0, ALL_SEND_CID, 0, cid) == B_OK) {
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);
if ((response & 0xFF00) != 0x500) {
TRACE("Card did not enter data state\n");
break;
}
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) {
device_attr attrs[] = {
{ B_DEVICE_BUS, B_STRING_TYPE, {.string = "mmc" }},
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "mmc device" }},
{ B_DEVICE_VENDOR_ID, B_UINT32_TYPE, {.ui32 = vendor}},
{ B_DEVICE_ID, B_STRING_TYPE, {.string = name}},
{ B_DEVICE_UNIQUE_ID, B_UINT32_TYPE, {.ui32 = serial}},
{ "mmc/revision", B_UINT16_TYPE, {.ui16 = revision}},
{ "mmc/month", B_UINT8_TYPE, {.ui8 = month}},
{ "mmc/year", B_UINT16_TYPE, {.ui16 = year}},
{ kMmcRcaAttribute, B_UINT16_TYPE, {.ui16 = rca}},
{ kMmcTypeAttribute, B_UINT8_TYPE, {.ui8 = cardType}},
{}
};
gDeviceManager->register_node(bus->fNode, MMC_BUS_MODULE_NAME,
attrs, NULL, NULL);
}
bus->SetClock(25000);
bus->_AcquireScanSemaphore();
}
bus->ReleaseBus();
TRACE("poller thread terminating");
return B_OK;
}