125b6a6f1Skrish_iyer /* 225b6a6f1Skrish_iyer * Copyright 2018 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 10*ff76d2dfSAdrien Destugues #include <Errors.h> 11*ff76d2dfSAdrien Destugues 12*ff76d2dfSAdrien Destugues #include <stdint.h> 13*ff76d2dfSAdrien 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), 21*ff76d2dfSAdrien Destugues fWorkerThread(0) 2225b6a6f1Skrish_iyer { 2325b6a6f1Skrish_iyer CALLED(); 24*ff76d2dfSAdrien Destugues 25*ff76d2dfSAdrien Destugues // Get the parent info, it includes the API to send commands to the hardware 2625b6a6f1Skrish_iyer device_node* parent = gDeviceManager->get_parent_node(node); 2725b6a6f1Skrish_iyer fStatus = gDeviceManager->get_driver(parent, 2825b6a6f1Skrish_iyer (driver_module_info**)&fController, &fCookie); 2925b6a6f1Skrish_iyer gDeviceManager->put_node(parent); 3025b6a6f1Skrish_iyer 3125b6a6f1Skrish_iyer if (fStatus != B_OK) { 3225b6a6f1Skrish_iyer ERROR("Not able to establish the bus %s\n", 3325b6a6f1Skrish_iyer strerror(fStatus)); 3425b6a6f1Skrish_iyer return; 3525b6a6f1Skrish_iyer } 36*ff76d2dfSAdrien Destugues 37*ff76d2dfSAdrien Destugues // TODO enumerate the bus (in a separate thread?) 38*ff76d2dfSAdrien Destugues fWorkerThread = spawn_kernel_thread(WorkerThread, "SD bus controller", 39*ff76d2dfSAdrien Destugues B_NORMAL_PRIORITY, this); 40*ff76d2dfSAdrien Destugues resume_thread(fWorkerThread); 4125b6a6f1Skrish_iyer } 4225b6a6f1Skrish_iyer 4325b6a6f1Skrish_iyer 4425b6a6f1Skrish_iyer MMCBus::~MMCBus() 4525b6a6f1Skrish_iyer { 4625b6a6f1Skrish_iyer CALLED(); 47*ff76d2dfSAdrien Destugues 48*ff76d2dfSAdrien Destugues // stop worker thread 49*ff76d2dfSAdrien Destugues fStatus = B_SHUTTING_DOWN; 50*ff76d2dfSAdrien Destugues 51*ff76d2dfSAdrien Destugues status_t result; 52*ff76d2dfSAdrien Destugues if (fWorkerThread != 0) 53*ff76d2dfSAdrien Destugues wait_for_thread(fWorkerThread, &result); 54*ff76d2dfSAdrien Destugues // TODO power off cards, stop clock, etc if needed. 5525b6a6f1Skrish_iyer } 5625b6a6f1Skrish_iyer 5725b6a6f1Skrish_iyer 5825b6a6f1Skrish_iyer status_t 5925b6a6f1Skrish_iyer MMCBus::InitCheck() 6025b6a6f1Skrish_iyer { 6125b6a6f1Skrish_iyer return fStatus; 6225b6a6f1Skrish_iyer } 63*ff76d2dfSAdrien Destugues 64*ff76d2dfSAdrien Destugues 65*ff76d2dfSAdrien Destugues status_t 66*ff76d2dfSAdrien Destugues MMCBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) 67*ff76d2dfSAdrien Destugues { 68*ff76d2dfSAdrien Destugues return fController->execute_command(fCookie, command, argument, response); 69*ff76d2dfSAdrien Destugues } 70*ff76d2dfSAdrien Destugues 71*ff76d2dfSAdrien Destugues 72*ff76d2dfSAdrien Destugues status_t 73*ff76d2dfSAdrien Destugues MMCBus::WorkerThread(void* cookie) 74*ff76d2dfSAdrien Destugues { 75*ff76d2dfSAdrien Destugues TRACE("worker thread spawned.\n"); 76*ff76d2dfSAdrien Destugues 77*ff76d2dfSAdrien Destugues MMCBus* bus = (MMCBus*)cookie; 78*ff76d2dfSAdrien Destugues uint32_t response; 79*ff76d2dfSAdrien Destugues 80*ff76d2dfSAdrien Destugues // FIXME wait for bus to signal a card is inserted 81*ff76d2dfSAdrien Destugues // We assume the bus defaults to 400kHz clock and has already powered on 82*ff76d2dfSAdrien Destugues // cards. 83*ff76d2dfSAdrien Destugues 84*ff76d2dfSAdrien Destugues // Reset all cards on the bus 85*ff76d2dfSAdrien Destugues bus->ExecuteCommand(0, 0, NULL); 86*ff76d2dfSAdrien Destugues 87*ff76d2dfSAdrien Destugues // Probe the voltage range 88*ff76d2dfSAdrien Destugues // FIXME MMC cards will not reply to this! They expect CMD1 instead 89*ff76d2dfSAdrien Destugues // SD v1 cards will also not reply, but we can proceed to ACMD41 90*ff76d2dfSAdrien Destugues // If ACMD41 also does not work, it may be an SDIO card, too 91*ff76d2dfSAdrien Destugues uint32_t probe = (1 << 8) | 0x55; 92*ff76d2dfSAdrien Destugues bus->ExecuteCommand(8, probe, &response); 93*ff76d2dfSAdrien Destugues if (response != probe) { 94*ff76d2dfSAdrien Destugues ERROR("Card does not support voltage range (expected %x, reply %x)\n", 95*ff76d2dfSAdrien Destugues probe, response); 96*ff76d2dfSAdrien Destugues // TODO what now? 97*ff76d2dfSAdrien Destugues } 98*ff76d2dfSAdrien Destugues 99*ff76d2dfSAdrien Destugues // Probe OCR, waiting for card to become ready 100*ff76d2dfSAdrien Destugues uint32_t ocr; 101*ff76d2dfSAdrien Destugues do { 102*ff76d2dfSAdrien Destugues uint32_t cardStatus; 103*ff76d2dfSAdrien Destugues while (bus->ExecuteCommand(55, 0, &cardStatus) 104*ff76d2dfSAdrien Destugues == B_BUSY) { 105*ff76d2dfSAdrien Destugues // FIXME we shouldn't get here if we handle CMD8 failure properly 106*ff76d2dfSAdrien Destugues ERROR("Card locked after CMD8...\n"); 107*ff76d2dfSAdrien Destugues snooze(1000000); 108*ff76d2dfSAdrien Destugues } 109*ff76d2dfSAdrien Destugues if ((cardStatus & 0xFFFF8000) != 0) 110*ff76d2dfSAdrien Destugues ERROR("SD card reports error\n"); 111*ff76d2dfSAdrien Destugues if ((cardStatus & (1 << 5)) == 0) 112*ff76d2dfSAdrien Destugues ERROR("Card did not enter ACMD mode"); 113*ff76d2dfSAdrien Destugues 114*ff76d2dfSAdrien Destugues bus->ExecuteCommand(41, (1 << 30) | 0xFF8000, &ocr); 115*ff76d2dfSAdrien Destugues 116*ff76d2dfSAdrien Destugues if ((ocr & (1 << 31)) == 0) { 117*ff76d2dfSAdrien Destugues TRACE("Card is busy\n"); 118*ff76d2dfSAdrien Destugues snooze(100000); 119*ff76d2dfSAdrien Destugues } 120*ff76d2dfSAdrien Destugues } while (((ocr & (1 << 31)) == 0)); 121*ff76d2dfSAdrien Destugues 122*ff76d2dfSAdrien Destugues if (ocr & (1 << 30)) 123*ff76d2dfSAdrien Destugues TRACE("Card is SDHC"); 124*ff76d2dfSAdrien Destugues if (ocr & (1 << 29)) 125*ff76d2dfSAdrien Destugues TRACE("Card supports UHS-II"); 126*ff76d2dfSAdrien Destugues if (ocr & (1 << 24)) 127*ff76d2dfSAdrien Destugues TRACE("Card supports 1.8v"); 128*ff76d2dfSAdrien Destugues TRACE("Voltage range: %x\n", ocr & 0xFFFFFF); 129*ff76d2dfSAdrien Destugues 130*ff76d2dfSAdrien Destugues // TODO send CMD11 to switch to low voltage mode if card supports it? 131*ff76d2dfSAdrien Destugues 132*ff76d2dfSAdrien Destugues uint32_t cid[4]; 133*ff76d2dfSAdrien Destugues bus->ExecuteCommand(2, 0, cid); 134*ff76d2dfSAdrien Destugues 135*ff76d2dfSAdrien Destugues TRACE("Manufacturer: %02x%c%c\n", cid[3] >> 16, cid[3] >> 8, cid[3]); 136*ff76d2dfSAdrien Destugues TRACE("Name: %c%c%c%c%c\n", cid[2] >> 24, cid[2] >> 16, cid[2] >> 8, 137*ff76d2dfSAdrien Destugues cid[2], cid[1] >> 24); 138*ff76d2dfSAdrien Destugues TRACE("Revision: %d.%d\n", (cid[1] >> 20) & 0xF, (cid[1] >> 16) & 0xF); 139*ff76d2dfSAdrien Destugues TRACE("Serial number: %x\n", (cid[1] << 16) | (cid[0] >> 16)); 140*ff76d2dfSAdrien Destugues TRACE("Date: %d/%d\n", cid[0] & 0xF, 2000 + ((cid[0] >> 4) & 0xFF)); 141*ff76d2dfSAdrien Destugues 142*ff76d2dfSAdrien Destugues bus->ExecuteCommand(3, 0, &response); 143*ff76d2dfSAdrien Destugues 144*ff76d2dfSAdrien Destugues TRACE("RCA: %x Status: %x\n", response >> 16, response & 0xFFFF); 145*ff76d2dfSAdrien Destugues 146*ff76d2dfSAdrien Destugues if ((response & 0xFF00) != 0x5000) 147*ff76d2dfSAdrien Destugues ERROR("Card did not enter data state\n"); 148*ff76d2dfSAdrien Destugues 149*ff76d2dfSAdrien Destugues // The card now has an RCA and it entered the data phase, which means our 150*ff76d2dfSAdrien Destugues // initializing job is over, we can pass it on to the mmc_disk driver. 151*ff76d2dfSAdrien Destugues 152*ff76d2dfSAdrien Destugues // TODO publish child device for the card 153*ff76d2dfSAdrien Destugues // TODO fill it with attributes from the CID 154*ff76d2dfSAdrien Destugues 155*ff76d2dfSAdrien Destugues // TODO iterate CMD2/CMD3 to assign an RCA to all cards (and publish devices 156*ff76d2dfSAdrien Destugues // for each of them) 157*ff76d2dfSAdrien Destugues } 158