xref: /haiku/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp (revision 5629675a326ecf2ff3fd23f154beb525c171048d)
1 /*
2  * Copyright 2018 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		B Krishnan Iyer, krishnaniyer97@gmail.com
7  */
8 #include "mmc_bus.h"
9 
10 #include <Errors.h>
11 
12 #include <stdint.h>
13 
14 
15 MMCBus::MMCBus(device_node* node)
16 	:
17 	fNode(node),
18 	fController(NULL),
19 	fCookie(NULL),
20 	fStatus(B_OK),
21 	fWorkerThread(0)
22 {
23 	CALLED();
24 
25 	// Get the parent info, it includes the API to send commands to the hardware
26 	device_node* parent = gDeviceManager->get_parent_node(node);
27 	fStatus = gDeviceManager->get_driver(parent,
28 		(driver_module_info**)&fController, &fCookie);
29 	gDeviceManager->put_node(parent);
30 
31 	if (fStatus != B_OK) {
32 		ERROR("Not able to establish the bus %s\n",
33 			strerror(fStatus));
34 		return;
35 	}
36 
37 	// TODO enumerate the bus (in a separate thread?)
38 	fWorkerThread = spawn_kernel_thread(WorkerThread, "SD bus controller",
39 		B_NORMAL_PRIORITY, this);
40 	resume_thread(fWorkerThread);
41 }
42 
43 
44 MMCBus::~MMCBus()
45 {
46 	CALLED();
47 
48 	// stop worker thread
49 	fStatus = B_SHUTTING_DOWN;
50 
51 	status_t result;
52 	if (fWorkerThread != 0)
53 		wait_for_thread(fWorkerThread, &result);
54 	// TODO power off cards, stop clock, etc if needed.
55 }
56 
57 
58 status_t
59 MMCBus::InitCheck()
60 {
61 	return fStatus;
62 }
63 
64 
65 status_t
66 MMCBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
67 {
68 	return fController->execute_command(fCookie, command, argument, response);
69 }
70 
71 
72 status_t
73 MMCBus::WorkerThread(void* cookie)
74 {
75 	TRACE("worker thread spawned.\n");
76 
77 	MMCBus* bus = (MMCBus*)cookie;
78 	uint32_t response;
79 
80 	// FIXME wait for bus to signal a card is inserted
81 	// We assume the bus defaults to 400kHz clock and has already powered on
82 	// cards.
83 
84 	// Reset all cards on the bus
85 	bus->ExecuteCommand(0, 0, NULL);
86 
87 	// Probe the voltage range
88 	// FIXME MMC cards will not reply to this! They expect CMD1 instead
89 	// SD v1 cards will also not reply, but we can proceed to ACMD41
90 	// If ACMD41 also does not work, it may be an SDIO card, too
91 	uint32_t probe = (1 << 8) | 0x55;
92 	uint32_t hcs = 1 << 30;
93 	if (bus->ExecuteCommand(8, probe, &response) != B_OK) {
94 		TRACE("Card does not implement CMD8, may be a V1 SD card\n");
95 		// Do not check for SDHC support in this case
96 		hcs = 0;
97 	} else if (response != probe) {
98 		ERROR("Card does not support voltage range (expected %x, reply %x)\n",
99 			probe, response);
100 		// TODO what now?
101 	}
102 
103 	// Probe OCR, waiting for card to become ready
104 	uint32_t ocr;
105 	do {
106 		uint32_t cardStatus;
107 		while (bus->ExecuteCommand(55, 0, &cardStatus)
108 			== B_BUSY) {
109 			// FIXME we shouldn't get here if we handle CMD8 failure properly
110 			ERROR("Card locked after CMD8...\n");
111 			snooze(1000000);
112 		}
113 		if ((cardStatus & 0xFFFF8000) != 0)
114 			ERROR("SD card reports error\n");
115 		if ((cardStatus & (1 << 5)) == 0)
116 			ERROR("Card did not enter ACMD mode");
117 
118 		bus->ExecuteCommand(41, hcs | 0xFF8000, &ocr);
119 
120 		if ((ocr & (1 << 31)) == 0) {
121 			TRACE("Card is busy\n");
122 			snooze(100000);
123 		}
124 	} while (((ocr & (1 << 31)) == 0));
125 
126 	if (ocr & hcs != 0)
127 		TRACE("Card is SDHC");
128 	if (ocr & (1 << 29) != 0)
129 		TRACE("Card supports UHS-II");
130 	if (ocr & (1 << 24) != 0)
131 		TRACE("Card supports 1.8v");
132 	TRACE("Voltage range: %x\n", ocr & 0xFFFFFF);
133 
134 	// TODO send CMD11 to switch to low voltage mode if card supports it?
135 
136 	uint32_t cid[4];
137 	bus->ExecuteCommand(2, 0, cid);
138 
139 	TRACE("Manufacturer: %02x%c%c\n", cid[3] >> 16, cid[3] >> 8, cid[3]);
140 	TRACE("Name: %c%c%c%c%c\n", cid[2] >> 24, cid[2] >> 16, cid[2] >> 8,
141 		cid[2], cid[1] >> 24);
142 	TRACE("Revision: %d.%d\n", (cid[1] >> 20) & 0xF, (cid[1] >> 16) & 0xF);
143 	TRACE("Serial number: %x\n", (cid[1] << 16) | (cid[0] >> 16));
144 	TRACE("Date: %d/%d\n", cid[0] & 0xF, 2000 + ((cid[0] >> 4) & 0xFF));
145 
146 	bus->ExecuteCommand(3, 0, &response);
147 
148 	TRACE("RCA: %x Status: %x\n", response >> 16, response & 0xFFFF);
149 
150 	if ((response & 0xFF00) != 0x5000)
151 		ERROR("Card did not enter data state\n");
152 
153 	// The card now has an RCA and it entered the data phase, which means our
154 	// initializing job is over, we can pass it on to the mmc_disk driver.
155 
156 	// TODO publish child device for the card
157 	// TODO fill it with attributes from the CID
158 
159 	// TODO iterate CMD2/CMD3 to assign an RCA to all cards (and publish devices
160 	// for each of them)
161 }
162