125b6a6f1Skrish_iyer /* 2dedbe94eSAdrien Destugues * Copyright 2018-2020 Haiku, Inc. All rights reserved. 325b6a6f1Skrish_iyer * Distributed under the terms of the MIT License. 425b6a6f1Skrish_iyer * 525b6a6f1Skrish_iyer * Authors: 625b6a6f1Skrish_iyer * B Krishnan Iyer, krishnaniyer97@gmail.com 725b6a6f1Skrish_iyer */ 825b6a6f1Skrish_iyer #include "mmc_bus.h" 925b6a6f1Skrish_iyer 10ff76d2dfSAdrien Destugues #include <Errors.h> 11ff76d2dfSAdrien Destugues 12ff76d2dfSAdrien Destugues #include <stdint.h> 13ff76d2dfSAdrien Destugues 1425b6a6f1Skrish_iyer 1525b6a6f1Skrish_iyer MMCBus::MMCBus(device_node* node) 1625b6a6f1Skrish_iyer : 1725b6a6f1Skrish_iyer fNode(node), 1825b6a6f1Skrish_iyer fController(NULL), 1925b6a6f1Skrish_iyer fCookie(NULL), 2025b6a6f1Skrish_iyer fStatus(B_OK), 2174b60970SAnarchos fWorkerThread(-1), 2274b60970SAnarchos fActiveDevice(0) 2325b6a6f1Skrish_iyer { 2425b6a6f1Skrish_iyer CALLED(); 25ff76d2dfSAdrien Destugues 26ff76d2dfSAdrien Destugues // Get the parent info, it includes the API to send commands to the hardware 2725b6a6f1Skrish_iyer device_node* parent = gDeviceManager->get_parent_node(node); 2825b6a6f1Skrish_iyer fStatus = gDeviceManager->get_driver(parent, 2925b6a6f1Skrish_iyer (driver_module_info**)&fController, &fCookie); 3025b6a6f1Skrish_iyer gDeviceManager->put_node(parent); 3125b6a6f1Skrish_iyer 3225b6a6f1Skrish_iyer if (fStatus != B_OK) { 3325b6a6f1Skrish_iyer ERROR("Not able to establish the bus %s\n", 3425b6a6f1Skrish_iyer strerror(fStatus)); 3525b6a6f1Skrish_iyer return; 3625b6a6f1Skrish_iyer } 37ff76d2dfSAdrien Destugues 3874b60970SAnarchos fScanSemaphore = create_sem(0, "MMC bus scan"); 3974b60970SAnarchos fLockSemaphore = create_sem(1, "MMC bus lock"); 4074b60970SAnarchos fWorkerThread = spawn_kernel_thread(_WorkerThread, "SD bus controller", 41ff76d2dfSAdrien Destugues B_NORMAL_PRIORITY, this); 42ff76d2dfSAdrien Destugues resume_thread(fWorkerThread); 4324136793SAdrien Destugues 4424136793SAdrien Destugues fController->set_scan_semaphore(fCookie, fScanSemaphore); 4525b6a6f1Skrish_iyer } 4625b6a6f1Skrish_iyer 4725b6a6f1Skrish_iyer 4825b6a6f1Skrish_iyer MMCBus::~MMCBus() 4925b6a6f1Skrish_iyer { 5025b6a6f1Skrish_iyer CALLED(); 51ff76d2dfSAdrien Destugues 52a59f6b7aSAdrien Destugues // Tell the worker thread we want to stop 53ff76d2dfSAdrien Destugues fStatus = B_SHUTTING_DOWN; 54ff76d2dfSAdrien Destugues 55a59f6b7aSAdrien Destugues // Delete the semaphores (this will unlock the worker thread if it was 56a59f6b7aSAdrien Destugues // waiting on them) 57a59f6b7aSAdrien Destugues delete_sem(fScanSemaphore); 58a59f6b7aSAdrien Destugues delete_sem(fLockSemaphore); 59a59f6b7aSAdrien Destugues 60a59f6b7aSAdrien Destugues // Wait for the worker thread to terminate 61ff76d2dfSAdrien Destugues status_t result; 62ff76d2dfSAdrien Destugues if (fWorkerThread != 0) 63ff76d2dfSAdrien Destugues wait_for_thread(fWorkerThread, &result); 6474b60970SAnarchos 65a59f6b7aSAdrien Destugues // TODO power off cards, stop clock, etc if needed. 6625b6a6f1Skrish_iyer } 6725b6a6f1Skrish_iyer 6825b6a6f1Skrish_iyer 6925b6a6f1Skrish_iyer status_t 7025b6a6f1Skrish_iyer MMCBus::InitCheck() 7125b6a6f1Skrish_iyer { 7225b6a6f1Skrish_iyer return fStatus; 7325b6a6f1Skrish_iyer } 74ff76d2dfSAdrien Destugues 75ff76d2dfSAdrien Destugues 76dedbe94eSAdrien Destugues void 77dedbe94eSAdrien Destugues MMCBus::Rescan() 78dedbe94eSAdrien Destugues { 79dedbe94eSAdrien Destugues // Just wake up the thread for a scan 8074b60970SAnarchos release_sem(fScanSemaphore); 81dedbe94eSAdrien Destugues } 82dedbe94eSAdrien Destugues 83dedbe94eSAdrien Destugues 84ff76d2dfSAdrien Destugues status_t 85522c141dSAdrien Destugues MMCBus::ExecuteCommand(uint16_t rca, uint8_t command, uint32_t argument, 86522c141dSAdrien Destugues uint32_t* response) 87ff76d2dfSAdrien Destugues { 88522c141dSAdrien Destugues status_t status = _ActivateDevice(rca); 8974b60970SAnarchos if (status != B_OK) 9074b60970SAnarchos return status; 91ff76d2dfSAdrien Destugues return fController->execute_command(fCookie, command, argument, response); 92ff76d2dfSAdrien Destugues } 93ff76d2dfSAdrien Destugues 94ff76d2dfSAdrien Destugues 95ff76d2dfSAdrien Destugues status_t 96d1fee57dSAdrien Destugues MMCBus::DoIO(uint16_t rca, uint8_t command, IOOperation* operation, 97d1fee57dSAdrien Destugues bool offsetAsSectors) 9874b60970SAnarchos { 9974b60970SAnarchos status_t status = _ActivateDevice(rca); 10074b60970SAnarchos if (status != B_OK) 10174b60970SAnarchos return status; 102d1fee57dSAdrien Destugues return fController->do_io(fCookie, command, operation, offsetAsSectors); 10374b60970SAnarchos } 10474b60970SAnarchos 10574b60970SAnarchos 106522c141dSAdrien Destugues void 107522c141dSAdrien Destugues MMCBus::SetClock(int frequency) 108522c141dSAdrien Destugues { 109522c141dSAdrien Destugues fController->set_clock(fCookie, frequency); 110522c141dSAdrien Destugues } 111522c141dSAdrien Destugues 112522c141dSAdrien Destugues 11334552f8eSAdrien Destugues void 11434552f8eSAdrien Destugues MMCBus::SetBusWidth(int width) 11534552f8eSAdrien Destugues { 11634552f8eSAdrien Destugues fController->set_bus_width(fCookie, width); 11734552f8eSAdrien Destugues } 11834552f8eSAdrien Destugues 11934552f8eSAdrien Destugues 12074b60970SAnarchos status_t 12174b60970SAnarchos MMCBus::_ActivateDevice(uint16_t rca) 12274b60970SAnarchos { 12374b60970SAnarchos // Do nothing if the device is already activated 12474b60970SAnarchos if (fActiveDevice == rca) 12574b60970SAnarchos return B_OK; 12674b60970SAnarchos 12774b60970SAnarchos uint32_t response; 12874b60970SAnarchos status_t result; 12974b60970SAnarchos result = fController->execute_command(fCookie, SD_SELECT_DESELECT_CARD, 13074b60970SAnarchos ((uint32)rca) << 16, &response); 13174b60970SAnarchos 13274b60970SAnarchos if (result == B_OK) 13374b60970SAnarchos fActiveDevice = rca; 13474b60970SAnarchos 13574b60970SAnarchos return result; 13674b60970SAnarchos } 13774b60970SAnarchos 13874b60970SAnarchos 13924136793SAdrien Destugues void MMCBus::_AcquireScanSemaphore() 14024136793SAdrien Destugues { 14124136793SAdrien Destugues release_sem(fLockSemaphore); 14224136793SAdrien Destugues acquire_sem(fScanSemaphore); 14324136793SAdrien Destugues acquire_sem(fLockSemaphore); 14424136793SAdrien Destugues } 14524136793SAdrien Destugues 14624136793SAdrien Destugues 14774b60970SAnarchos status_t 14874b60970SAnarchos MMCBus::_WorkerThread(void* cookie) 149ff76d2dfSAdrien Destugues { 150ff76d2dfSAdrien Destugues MMCBus* bus = (MMCBus*)cookie; 151ff76d2dfSAdrien Destugues uint32_t response; 152ff76d2dfSAdrien Destugues 15374b60970SAnarchos acquire_sem(bus->fLockSemaphore); 15474b60970SAnarchos 155ff76d2dfSAdrien Destugues // We assume the bus defaults to 400kHz clock and has already powered on 156ff76d2dfSAdrien Destugues // cards. 157ff76d2dfSAdrien Destugues 158ff76d2dfSAdrien Destugues // Reset all cards on the bus 15924136793SAdrien Destugues // This does not work if the bus has not been powered on yet (the command 16024136793SAdrien Destugues // will timeout), in that case we wait until asked to scan again when a 16124136793SAdrien Destugues // card has been inserted and powered on. 16224136793SAdrien Destugues status_t result; 16324136793SAdrien Destugues do { 16424136793SAdrien Destugues bus->_AcquireScanSemaphore(); 16534552f8eSAdrien Destugues 166a59f6b7aSAdrien Destugues // Check if we need to exit early (possible if the parent device did 167a59f6b7aSAdrien Destugues // not manage initialize itself correctly) 168a59f6b7aSAdrien Destugues if (bus->fStatus == B_SHUTTING_DOWN) { 169a59f6b7aSAdrien Destugues release_sem(bus->fLockSemaphore); 170a59f6b7aSAdrien Destugues return B_OK; 171a59f6b7aSAdrien Destugues } 172a59f6b7aSAdrien Destugues 17324136793SAdrien Destugues TRACE("Reset the bus...\n"); 174522c141dSAdrien Destugues result = bus->ExecuteCommand(0, SD_GO_IDLE_STATE, 0, NULL); 17524136793SAdrien Destugues TRACE("CMD0 result: %s\n", strerror(result)); 17624136793SAdrien Destugues } while (result != B_OK); 17724136793SAdrien Destugues 17824136793SAdrien Destugues // Need to wait at least 8 clock cycles after CMD0 before sending the next 179522c141dSAdrien Destugues // command. With the default 400kHz clock that would be 20 microseconds, 18034552f8eSAdrien Destugues // but we need to wait at least 20ms here, otherwise the next command times 18134552f8eSAdrien Destugues // out 1825ec64c5cSAdrien Destugues snooze(30000); 183ff76d2dfSAdrien Destugues 184dedbe94eSAdrien Destugues while (bus->fStatus != B_SHUTTING_DOWN) { 185dedbe94eSAdrien Destugues TRACE("Scanning the bus\n"); 186dedbe94eSAdrien Destugues 18734552f8eSAdrien Destugues // Use the low speed clock and 1bit bus width for scanning 188522c141dSAdrien Destugues bus->SetClock(400); 18934552f8eSAdrien Destugues bus->SetBusWidth(1); 190522c141dSAdrien Destugues 191ff76d2dfSAdrien Destugues // Probe the voltage range 19274b60970SAnarchos enum { 19374b60970SAnarchos // Table 4-40 in physical layer specification v8.00 19474b60970SAnarchos // All other values are currently reserved 19574b60970SAnarchos HOST_27_36V = 1, //Host supplied voltage 2.7-3.6V 19674b60970SAnarchos }; 19774b60970SAnarchos 19874b60970SAnarchos // An arbitrary value, we just need to check that the response 19974b60970SAnarchos // containts the same. 20074b60970SAnarchos static const uint8 kVoltageCheckPattern = 0xAA; 20174b60970SAnarchos 202ff76d2dfSAdrien Destugues // FIXME MMC cards will not reply to this! They expect CMD1 instead 203ff76d2dfSAdrien Destugues // SD v1 cards will also not reply, but we can proceed to ACMD41 204ff76d2dfSAdrien Destugues // If ACMD41 also does not work, it may be an SDIO card, too 20574b60970SAnarchos uint32_t probe = (HOST_27_36V << 8) | kVoltageCheckPattern; 206518af33fSAdrien Destugues uint32_t hcs = 1 << 30; 207522c141dSAdrien Destugues if (bus->ExecuteCommand(0, SD_SEND_IF_COND, probe, &response) != B_OK) { 208518af33fSAdrien Destugues TRACE("Card does not implement CMD8, may be a V1 SD card\n"); 209518af33fSAdrien Destugues // Do not check for SDHC support in this case 210518af33fSAdrien Destugues hcs = 0; 211518af33fSAdrien Destugues } else if (response != probe) { 212dedbe94eSAdrien Destugues ERROR("Card does not support voltage range (expected %x, " 213dedbe94eSAdrien Destugues "reply %x)\n", probe, response); 21424136793SAdrien Destugues // TODO we should power off the bus in this case. 215ff76d2dfSAdrien Destugues } 216ff76d2dfSAdrien Destugues 217ff76d2dfSAdrien Destugues // Probe OCR, waiting for card to become ready 21824136793SAdrien Destugues // We keep repeating ACMD41 until the card replies that it is 21924136793SAdrien Destugues // initialized. 220ff76d2dfSAdrien Destugues uint32_t ocr; 221ff76d2dfSAdrien Destugues do { 222ff76d2dfSAdrien Destugues uint32_t cardStatus; 223522c141dSAdrien Destugues while (bus->ExecuteCommand(0, SD_APP_CMD, 0, &cardStatus) 224ff76d2dfSAdrien Destugues == B_BUSY) { 225ff76d2dfSAdrien Destugues ERROR("Card locked after CMD8...\n"); 226ff76d2dfSAdrien Destugues snooze(1000000); 227ff76d2dfSAdrien Destugues } 228ff76d2dfSAdrien Destugues if ((cardStatus & 0xFFFF8000) != 0) 229dedbe94eSAdrien Destugues ERROR("SD card reports error %x\n", cardStatus); 230ff76d2dfSAdrien Destugues if ((cardStatus & (1 << 5)) == 0) 231dedbe94eSAdrien Destugues ERROR("Card did not enter ACMD mode\n"); 232ff76d2dfSAdrien Destugues 233522c141dSAdrien Destugues bus->ExecuteCommand(0, SD_SEND_OP_COND, hcs | 0xFF8000, &ocr); 234ff76d2dfSAdrien Destugues 235ff76d2dfSAdrien Destugues if ((ocr & (1 << 31)) == 0) { 236ff76d2dfSAdrien Destugues TRACE("Card is busy\n"); 237ff76d2dfSAdrien Destugues snooze(100000); 238ff76d2dfSAdrien Destugues } 239ff76d2dfSAdrien Destugues } while (((ocr & (1 << 31)) == 0)); 240ff76d2dfSAdrien Destugues 241dedbe94eSAdrien Destugues // FIXME this should be asked to each card, when there are multiple 242dedbe94eSAdrien Destugues // ones. So ACMD41 should be moved inside the probing loop below? 243dedbe94eSAdrien Destugues uint8_t cardType = CARD_TYPE_SD; 244dedbe94eSAdrien Destugues 245eb92a834SAdrien Destugues if ((ocr & hcs) != 0) 246dedbe94eSAdrien Destugues cardType = CARD_TYPE_SDHC; 247eb92a834SAdrien Destugues if ((ocr & (1 << 29)) != 0) 248dedbe94eSAdrien Destugues cardType = CARD_TYPE_UHS2; 249eb92a834SAdrien Destugues if ((ocr & (1 << 24)) != 0) 250ff76d2dfSAdrien Destugues TRACE("Card supports 1.8v"); 251ff76d2dfSAdrien Destugues TRACE("Voltage range: %x\n", ocr & 0xFFFFFF); 252ff76d2dfSAdrien Destugues 253ff76d2dfSAdrien Destugues // TODO send CMD11 to switch to low voltage mode if card supports it? 254ff76d2dfSAdrien Destugues 25574b60970SAnarchos // We use CMD2 (ALL_SEND_CID) and CMD3 (SEND_RELATIVE_ADDR) to assign 25674b60970SAnarchos // an RCA to all cards. Initially all cards have an RCA of 0 and will 25774b60970SAnarchos // all receive CMD2. But only ne of them will reply (they do collision 25874b60970SAnarchos // detection while sending the CID in reply). We assign a new RCA to 25974b60970SAnarchos // that first card, and repeat the process with the remaining ones 26074b60970SAnarchos // until no one answers to CMD2. Then we know all cards have an RCA 26174b60970SAnarchos // (and a matching published device on our side). 262ff76d2dfSAdrien Destugues uint32_t cid[4]; 26374b60970SAnarchos 264522c141dSAdrien Destugues while (bus->ExecuteCommand(0, SD_ALL_SEND_CID, 0, cid) == B_OK) { 265522c141dSAdrien Destugues bus->ExecuteCommand(0, SD_SEND_RELATIVE_ADDR, 0, &response); 266ff76d2dfSAdrien Destugues 267ff76d2dfSAdrien Destugues TRACE("RCA: %x Status: %x\n", response >> 16, response & 0xFFFF); 268ff76d2dfSAdrien Destugues 269dedbe94eSAdrien Destugues if ((response & 0xFF00) != 0x500) { 270dedbe94eSAdrien Destugues TRACE("Card did not enter data state\n"); 271dedbe94eSAdrien Destugues // This probably means there are no more cards to scan on the 272dedbe94eSAdrien Destugues // bus, so exit the loop. 273dedbe94eSAdrien Destugues break; 274dedbe94eSAdrien Destugues } 275ff76d2dfSAdrien Destugues 276dedbe94eSAdrien Destugues // The card now has an RCA and it entered the data phase, which 277dedbe94eSAdrien Destugues // means our initializing job is over, we can pass it on to the 278dedbe94eSAdrien Destugues // mmc_disk driver. 279ff76d2dfSAdrien Destugues 280dedbe94eSAdrien Destugues uint32_t vendor = cid[3] & 0xFFFFFF; 281eb92a834SAdrien Destugues char name[6] = {(char)(cid[2] >> 24), (char)(cid[2] >> 16), 282eb92a834SAdrien Destugues (char)(cid[2] >> 8), (char)cid[2], (char)(cid[1] >> 24), 0}; 283dedbe94eSAdrien Destugues uint32_t serial = (cid[1] << 16) | (cid[0] >> 16); 284dedbe94eSAdrien Destugues uint16_t revision = (cid[1] >> 20) & 0xF; 285dedbe94eSAdrien Destugues revision *= 100; 286dedbe94eSAdrien Destugues revision += (cid[1] >> 16) & 0xF; 287dedbe94eSAdrien Destugues uint8_t month = cid[0] & 0xF; 288dedbe94eSAdrien Destugues uint16_t year = 2000 + ((cid[0] >> 4) & 0xFF); 289dedbe94eSAdrien Destugues uint16_t rca = response >> 16; 290ff76d2dfSAdrien Destugues 291dedbe94eSAdrien Destugues device_attr attrs[] = { 292*215b685fSX512 { B_DEVICE_BUS, B_STRING_TYPE, {.string = "mmc" }}, 293*215b685fSX512 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "mmc device" }}, 294*215b685fSX512 { B_DEVICE_VENDOR_ID, B_UINT32_TYPE, {.ui32 = vendor}}, 295*215b685fSX512 { B_DEVICE_ID, B_STRING_TYPE, {.string = name}}, 296*215b685fSX512 { B_DEVICE_UNIQUE_ID, B_UINT32_TYPE, {.ui32 = serial}}, 297*215b685fSX512 { "mmc/revision", B_UINT16_TYPE, {.ui16 = revision}}, 298*215b685fSX512 { "mmc/month", B_UINT8_TYPE, {.ui8 = month}}, 299*215b685fSX512 { "mmc/year", B_UINT16_TYPE, {.ui16 = year}}, 300*215b685fSX512 { kMmcRcaAttribute, B_UINT16_TYPE, {.ui16 = rca}}, 301*215b685fSX512 { kMmcTypeAttribute, B_UINT8_TYPE, {.ui8 = cardType}}, 302dedbe94eSAdrien Destugues {} 303dedbe94eSAdrien Destugues }; 304dedbe94eSAdrien Destugues 305dedbe94eSAdrien Destugues // publish child device for the card 306dedbe94eSAdrien Destugues gDeviceManager->register_node(bus->fNode, MMC_BUS_MODULE_NAME, 307dedbe94eSAdrien Destugues attrs, NULL, NULL); 308dedbe94eSAdrien Destugues } 309dedbe94eSAdrien Destugues 310522c141dSAdrien Destugues // TODO if there is a single card active, check if it supports CMD6 311522c141dSAdrien Destugues // (spec version 1.10 or later in SCR). If it does, check if CMD6 can 312522c141dSAdrien Destugues // enable high speed mode, use that to go to 50MHz instead of 25. 313522c141dSAdrien Destugues bus->SetClock(25000); 314522c141dSAdrien Destugues 315dedbe94eSAdrien Destugues // FIXME we also need to unpublish devices that are gone. Probably need 316dedbe94eSAdrien Destugues // to "ping" all RCAs somehow? Or is there an interrupt we can look for 317dedbe94eSAdrien Destugues // to detect added/removed cards? 31824136793SAdrien Destugues 31924136793SAdrien Destugues // Wait for the next scan request 32024136793SAdrien Destugues // The thread will spend most of its time waiting here 32124136793SAdrien Destugues bus->_AcquireScanSemaphore(); 322dedbe94eSAdrien Destugues } 323dedbe94eSAdrien Destugues 32474b60970SAnarchos release_sem(bus->fLockSemaphore); 32574b60970SAnarchos 326dedbe94eSAdrien Destugues TRACE("poller thread terminating"); 327dedbe94eSAdrien Destugues return B_OK; 328ff76d2dfSAdrien Destugues } 329