xref: /haiku/src/add-ons/kernel/bus_managers/mmc/mmc_bus.cpp (revision 8c78892580f132d10e624aef96f835df8d94bf19)
1 /*
2  * Copyright 2018-2020 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 	fSemaphore = create_sem(0, "MMC bus scan");
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 void
66 MMCBus::Rescan()
67 {
68 	// Just wake up the thread for a scan
69 	release_sem(fSemaphore);
70 }
71 
72 
73 status_t
74 MMCBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
75 {
76 	return fController->execute_command(fCookie, command, argument, response);
77 }
78 
79 
80 status_t
81 MMCBus::WorkerThread(void* cookie)
82 {
83 	MMCBus* bus = (MMCBus*)cookie;
84 	uint32_t response;
85 
86 	// We assume the bus defaults to 400kHz clock and has already powered on
87 	// cards.
88 
89 	// Reset all cards on the bus
90 	bus->ExecuteCommand(0, 0, NULL);
91 
92 	while (bus->fStatus != B_SHUTTING_DOWN) {
93 		// wait for bus to signal a card is inserted
94 		acquire_sem(bus->fSemaphore);
95 		TRACE("Scanning the bus\n");
96 
97 		// Probe the voltage range
98 		// FIXME MMC cards will not reply to this! They expect CMD1 instead
99 		// SD v1 cards will also not reply, but we can proceed to ACMD41
100 		// If ACMD41 also does not work, it may be an SDIO card, too
101 		uint32_t probe = (1 << 8) | 0xAA;
102 		uint32_t hcs = 1 << 30;
103 		if (bus->ExecuteCommand(8, probe, &response) != B_OK) {
104 			TRACE("Card does not implement CMD8, may be a V1 SD card\n");
105 			// Do not check for SDHC support in this case
106 			hcs = 0;
107 		} else if (response != probe) {
108 			ERROR("Card does not support voltage range (expected %x, "
109 				"reply %x)\n", probe, response);
110 			// TODO what now?
111 		}
112 
113 		// Probe OCR, waiting for card to become ready
114 		uint32_t ocr;
115 		do {
116 			uint32_t cardStatus;
117 			while (bus->ExecuteCommand(55, 0, &cardStatus)
118 					== B_BUSY) {
119 				ERROR("Card locked after CMD8...\n");
120 				snooze(1000000);
121 			}
122 			if ((cardStatus & 0xFFFF8000) != 0)
123 				ERROR("SD card reports error %x\n", cardStatus);
124 			if ((cardStatus & (1 << 5)) == 0)
125 				ERROR("Card did not enter ACMD mode\n");
126 
127 			bus->ExecuteCommand(41, hcs | 0xFF8000, &ocr);
128 
129 			if ((ocr & (1 << 31)) == 0) {
130 				TRACE("Card is busy\n");
131 				snooze(100000);
132 			}
133 		} while (((ocr & (1 << 31)) == 0));
134 
135 		// FIXME this should be asked to each card, when there are multiple
136 		// ones. So ACMD41 should be moved inside the probing loop below?
137 		uint8_t cardType = CARD_TYPE_SD;
138 
139 		if (ocr & hcs != 0)
140 			cardType = CARD_TYPE_SDHC;
141 		if (ocr & (1 << 29) != 0)
142 			cardType = CARD_TYPE_UHS2;
143 		if (ocr & (1 << 24) != 0)
144 			TRACE("Card supports 1.8v");
145 		TRACE("Voltage range: %x\n", ocr & 0xFFFFFF);
146 
147 		// TODO send CMD11 to switch to low voltage mode if card supports it?
148 
149 		// iterate CMD2/CMD3 to assign an RCA to all cards and publish devices
150 		// for each of them
151 		uint32_t cid[4];
152 		while (bus->ExecuteCommand(2, 0, cid) == B_OK) {
153 			bus->ExecuteCommand(3, 0, &response);
154 
155 			TRACE("RCA: %x Status: %x\n", response >> 16, response & 0xFFFF);
156 
157 			if ((response & 0xFF00) != 0x500) {
158 				TRACE("Card did not enter data state\n");
159 				// This probably means there are no more cards to scan on the
160 				// bus, so exit the loop.
161 				break;
162 			}
163 
164 			// The card now has an RCA and it entered the data phase, which
165 			// means our initializing job is over, we can pass it on to the
166 			// mmc_disk driver.
167 
168 			uint32_t vendor = cid[3] & 0xFFFFFF;
169 			char name[6] = {cid[2] >> 24, cid[2] >> 16, cid[2] >> 8, cid[2],
170 				cid[1] >> 24, 0};
171 			uint32_t serial = (cid[1] << 16) | (cid[0] >> 16);
172 			uint16_t revision = (cid[1] >> 20) & 0xF;
173 			revision *= 100;
174 			revision += (cid[1] >> 16) & 0xF;
175 			uint8_t month = cid[0] & 0xF;
176 			uint16_t year = 2000 + ((cid[0] >> 4) & 0xFF);
177 			uint16_t rca = response >> 16;
178 
179 			device_attr attrs[] = {
180 				{ B_DEVICE_BUS, B_STRING_TYPE, {string: "mmc" }},
181 				{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "mmc device" }},
182 				{ B_DEVICE_VENDOR_ID, B_UINT32_TYPE, {ui32: vendor}},
183 				{ B_DEVICE_ID, B_STRING_TYPE, {string: name}},
184 				{ B_DEVICE_UNIQUE_ID, B_UINT32_TYPE, {ui32: serial}},
185 				{ "mmc/revision", B_UINT16_TYPE, {ui16: revision}},
186 				{ "mmc/month", B_UINT8_TYPE, {ui8: month}},
187 				{ "mmc/year", B_UINT16_TYPE, {ui16: year}},
188 				{ "mmc/rca", B_UINT16_TYPE, {ui16: rca}},
189 				{ "mmc/type", B_UINT8_TYPE, {ui8: cardType}},
190 				{}
191 			};
192 
193 			// publish child device for the card
194 			gDeviceManager->register_node(bus->fNode, MMC_BUS_MODULE_NAME,
195 				attrs, NULL, NULL);
196 		}
197 
198 		// FIXME we also need to unpublish devices that are gone. Probably need
199 		// to "ping" all RCAs somehow? Or is there an interrupt we can look for
200 		// to detect added/removed cards?
201 	}
202 
203 	TRACE("poller thread terminating");
204 	return B_OK;
205 }
206