1239b9eed796cb1125af09e04682bba4bc6a95a7
[rpi-open-firmware.git] / arm_chainloader / drivers / sdhost.cc
1 /*=============================================================================
2 Copyright (C) 2016 Kristina Brooks
3 All rights reserved.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 FILE DESCRIPTION
16 SDHOST driver. This used to be known as ALTMMC.
17
18 =============================================================================*/
19
20 #include <chainloader.h>
21 #include <hardware.h>
22
23 #include "sd2.hpp"
24
25 #define SDEDM_WRITE_THRESHOLD_SHIFT 9
26 #define SDEDM_READ_THRESHOLD_SHIFT 14
27 #define SDEDM_THRESHOLD_MASK 0x1f
28
29 #define SAFE_READ_THRESHOLD 4
30 #define SAFE_WRITE_THRESHOLD 4
31
32 #define VOLTAGE_SUPPLY_RANGE 0x100
33 #define CHECK_PATTERN 0x55
34
35
36 #define SDHSTS_BUSY_IRPT 0x400
37 #define SDHSTS_BLOCK_IRPT 0x200
38 #define SDHSTS_SDIO_IRPT 0x100
39 #define SDHSTS_REW_TIME_OUT 0x80
40 #define SDHSTS_CMD_TIME_OUT 0x40
41 #define SDHSTS_CRC16_ERROR 0x20
42 #define SDHSTS_CRC7_ERROR 0x10
43 #define SDHSTS_FIFO_ERROR 0x08
44
45 #define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC7_ERROR|SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR)
46 #define SDHSTS_ERROR_MASK (SDHSTS_CMD_TIME_OUT|SDHSTS_TRANSFER_ERROR_MASK)
47
48 #define logf(fmt, ...) printf("[sdhost::%s]: " fmt, __FUNCTION__, ##__VA_ARGS__);
49
50 struct sdhost_t {
51 bool is_sdhc;
52 bool is_high_capacity;
53
54 uint32_t ocr;
55 uint32_t rca;
56
57 uint32_t cid[4];
58 uint32_t csd[4];
59
60 uint32_t r[4];
61
62 void set_power(bool on) {
63 SH_VDD = on ? SH_VDD_POWER_ON_SET : 0x0;
64 }
65
66 bool wait(uint32_t timeout = 10000) {
67 uint32_t t = timeout;
68
69 while(SH_CMD & SH_CMD_NEW_FLAG_SET) {
70 if (t == 0) {
71 logf("timed out after %dus!\n", timeout)
72 return false;
73 }
74 t--;
75 udelay(10);
76 }
77
78 return true;
79 }
80
81 bool send_raw(uint32_t command, uint32_t arg = 0) {
82 uint32_t sts;
83
84 wait();
85
86 sts = SH_HSTS;
87 if (sts & SDHSTS_ERROR_MASK)
88 SH_HSTS = sts;
89
90 SH_ARG = arg;
91 SH_CMD = command | SH_CMD_NEW_FLAG_SET;
92
93 mfence();
94
95 return true;
96 }
97
98 bool send(uint32_t command, uint32_t arg = 0) {
99 return send_raw(command & SH_CMD_COMMAND_SET, arg);
100 }
101
102 void configure_pinmux() {
103 GP_FSEL4 = 0x24000000;
104 GP_FSEL5 = 0x924;
105 GP_PUD = 2;
106
107 logf("GPIOs set!\n");
108 }
109
110 void reset() {
111 logf("resetting controller ...\n");
112 set_power(false);
113
114 SH_CMD = 0;
115 SH_ARG = 0;
116 SH_TOUT = 0xF00000;
117 SH_CDIV = 0;
118 SH_HSTS = 0x7f8;
119 SH_HCFG = 0;
120 SH_HBCT = 0;
121 SH_HBLC = 0;
122
123 uint32_t temp = SH_EDM;
124
125 temp &= ~((SDEDM_THRESHOLD_MASK<<SDEDM_READ_THRESHOLD_SHIFT) |
126 (SDEDM_THRESHOLD_MASK<<SDEDM_WRITE_THRESHOLD_SHIFT));
127 temp |= (SAFE_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT) |
128 (SAFE_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
129
130 SH_EDM = temp;
131 udelay(300);
132
133 set_power(true);
134
135 udelay(300);
136 mfence();
137 }
138
139 inline void get_response() {
140 r[0] = SH_RSP0;
141 r[1] = SH_RSP1;
142 r[2] = SH_RSP2;
143 r[3] = SH_RSP3;
144 }
145
146 bool wait_and_get_response() {
147 if (!wait())
148 return false;
149
150 get_response();
151
152 logf("HSTS: 0x%x, RSP: %08x %08x %08x %08x\n", SH_HSTS, r[0], r[1], r[2], r[3]);
153
154 return true;
155 }
156
157 bool query_voltage_and_type() {
158 uint32_t t;
159
160 /* identify */
161 send(SD_SEND_IF_COND, 0x1AA);
162 wait_and_get_response();
163
164 /* set voltage */
165 t = MMC_OCR_3_2V_3_3V;
166 if (r[0] == 0x1AA) {
167 t |= MMC_OCR_HCS;
168 is_sdhc = true;
169 }
170
171 /* query voltage and type */
172 for (;;) {
173 send(MMC_APP_CMD);
174 send(SD_APP_OP_COND, t);
175
176 if (!wait_and_get_response())
177 return false;
178
179 if (r[0] & MMC_OCR_MEM_READY)
180 break;
181
182 logf("waiting for sd card (0x%x) ...\n", r[0]);
183 udelay(100);
184 }
185
186 logf("sd card has arrived!\n", r);
187
188 is_high_capacity = (r[0] & MMC_OCR_HCS) == MMC_OCR_HCS;
189
190 if (is_high_capacity)
191 logf("this is an SDHC card!\n");
192
193 return true;
194
195 }
196
197 bool identify_card() {
198 logf("identifying card ...\n");
199
200 send_raw(SH_CMD_LONG_RESPONSE_SET | MMC_ALL_SEND_CID);
201 if (!wait_and_get_response())
202 return false;
203
204 cid[0] = r[0];
205 cid[1] = r[1];
206 cid[2] = r[2];
207 cid[3] = r[3];
208
209 send(MMC_SET_RELATIVE_ADDR);
210
211 if (!wait_and_get_response())
212 return false;
213
214 rca = SD_R6_RCA(r);
215
216 /* get card specific data */
217
218 send_raw(SH_CMD_LONG_RESPONSE_SET | MMC_SEND_CSD, MMC_ARG_RCA(rca));
219 if (!wait_and_get_response())
220 return false;
221
222 csd[0] = r[0];
223 csd[1] = r[1];
224 csd[2] = r[2];
225 csd[3] = r[3];
226
227 return true;
228 }
229
230 bool select_card() {
231 send(MMC_SELECT_CARD, MMC_ARG_RCA(rca));
232
233 if (!wait())
234 return false;
235
236 return true;
237 }
238
239 bool init_card() {
240 char pnm[8];
241
242 send(MMC_GO_IDLE_STATE);
243
244 if (!query_voltage_and_type()) {
245 logf("ERROR: Failed to query card voltage!\n");
246 return false;
247 }
248
249 if (!identify_card()) {
250 logf("ERROR: Failed to identify card!\n");
251 return false;
252 }
253
254 SD_CID_PNM_CPY(cid, pnm);
255 logf("Product : %s\n", &pnm);
256 logf("MMC Ver : %d\n", SD_CSD_MMCVER(csd));
257
258 logf("MMC Size: %d\n", MMC_CSD_C_SIZE(csd));
259 logf("MMC Cap : %d\n", MMC_CSD_CAPACITY(csd));
260
261 if (SD_CSD_CSDVER(csd) == SD_CSD_CSDVER_2_0) {
262 logf("CSD : version 2.0\n");
263 logf("Capacity: %d\n", SD_CSD_V2_CAPACITY(csd));
264 logf("Size : %d\n", SD_CSD_V2_C_SIZE(csd));
265 }
266 else if (SD_CSD_CSDVER(csd) == SD_CSD_CSDVER_1_0) {
267 logf("CSD : version 1.0\n");
268 logf("Capacity: %d\n", SD_CSD_CAPACITY(csd));
269 logf("Size : %d\n", SD_CSD_C_SIZE(csd));
270 }
271 else {
272 logf("ERROR: unknown CSD version 0x%x!\n", SD_CSD_CSDVER(csd));
273 return false;
274 }
275
276 if (!select_card()) {
277 logf("ERROR: Failed to select card!\n");
278 return false;
279 }
280
281 logf("setting block length to 512 ...\n");
282 send(MMC_SET_BLOCKLEN, 512);
283 if (!wait()) {
284 logf("ERROR: Failed to set block length!\n");
285 return false;
286 }
287
288 logf("card initialization complete!\n");
289
290 return true;
291 }
292
293 sdhost_t() {
294 is_sdhc = false;
295
296 logf("starting up ...\n");
297
298 configure_pinmux();
299 reset();
300
301 SH_HCFG = SH_HCFG_SLOW_CARD_SET | SH_HCFG_WIDE_INT_BUS_SET;
302 SH_CDIV = 0x96;
303
304 udelay(300);
305
306 logf("sdhost controller ready, initializing SD card ...\n");
307
308 if (init_card()) {
309
310 }
311 }
312 };
313
314 sdhost_t STATIC_DRIVER g_SDHostDriver {};
315
316 /*
317 * abstractions for fatfs.
318 */
319
320 #include "fatfs/diskio.h"
321
322 DSTATUS disk_initialize (BYTE pdrv) {
323 return 0;
324 }
325
326 DSTATUS disk_status (BYTE pdrv) {
327 return 0;
328 }
329
330 DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
331 return (DRESULT)0;
332 }
333
334 DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) {
335 return (DRESULT)0;
336 }
This page took 0.107863 seconds and 3 git commands to generate.