0c15156301ea1e41d6598a5c00f238d3647aad08
[bertos.git] / bertos / drv / sd.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2007 Develer S.r.l. (http://www.develer.com/)
30  * -->
31  *
32  * \brief Function library for secure digital memory.
33  *
34  * \version $Id$
35  * \author Francesco Sacchi <batt@develer.com>
36  */
37
38
39 #include "sd.h"
40 #include "hw/hw_sd.h"
41 #include <kern/kfile.h>
42 #include <drv/timer.h>
43
44 #include <fs/fat.h>
45
46 #include <cfg/log.h>
47 #include <cpu/power.h>
48
49 #include <string.h> /* memset */
50
51 /**
52  * Card Specific Data
53  * read directly from the card.
54  */
55 typedef struct CardCSD
56 {
57         uint16_t block_len;  ///< Length of a block
58         uint32_t block_num;  ///< Number of block on the card
59         uint16_t capacity;   ///< Card capacity in MB
60 } CardCSD;
61
62 #define SD_IN_IDLE    0x01
63 #define SD_STARTTOKEN 0xFE
64
65 #define TIMEOUT_NAC   256
66
67 #define SD_DEFAULT_BLOCKLEN 512
68
69 /**
70  * SPI communication channel.
71  */
72 static KFile *fd;
73
74 /**
75  * Current SD status.
76  */
77 static bool sd_status;
78
79 #define SD_BUSY_TIMEOUT ms_to_ticks(200)
80
81 static bool sd_select(bool state)
82 {
83         if (state)
84         {
85                 ticks_t start = timer_clock();
86                 do
87                 {
88                         SD_CS_ON();
89                         if (kfile_getc(fd) == 0xff)
90                                 return true;
91                         SD_CS_OFF();
92                         kfile_putc(0xff, fd);
93                         kfile_flush(fd);
94                         cpu_relax();
95                 }
96                 while (timer_clock() - start < SD_BUSY_TIMEOUT);
97
98                 LOG_ERR("sd_select timeout\n");
99                 return false;
100         }
101         else
102         {
103                 kfile_putc(0xff, fd);
104                 kfile_flush(fd);
105                 SD_CS_OFF();
106                 return true;
107         }
108 }
109
110 static int16_t sd_waitR1(void)
111 {
112         uint8_t datain;
113
114         for (int i = 0; i < TIMEOUT_NAC; i++)
115         {
116           datain = kfile_getc(fd);
117           if (datain != 0xff)
118                 return (int16_t)datain;
119         }
120         LOG_ERR("Timeout waiting R1\n");
121         return EOF;
122 }
123
124 static int16_t sd_sendCommand(uint8_t cmd, uint32_t param, uint8_t crc)
125 {
126         /* The 7th bit of command must be a 1 */
127         kfile_putc(cmd | 0x40, fd);
128
129         /* send parameter */
130         kfile_putc((param >> 24) & 0xFF, fd);
131         kfile_putc((param >> 16) & 0xFF, fd);
132         kfile_putc((param >> 8) & 0xFF, fd);
133         kfile_putc((param) & 0xFF, fd);
134
135         kfile_putc(crc, fd);
136
137         return sd_waitR1();
138 }
139
140
141 static bool sd_getBlock(void *buf, size_t len)
142 {
143         uint8_t token;
144         uint16_t crc;
145
146         for (int i = 0; i < TIMEOUT_NAC; i++)
147         {
148                 token = kfile_getc(fd);
149                 if (token != 0xff)
150                 {
151                         if (token == SD_STARTTOKEN)
152                         {
153                                 if (kfile_read(fd, buf, len) == len)
154                                 {
155                                         if (kfile_read(fd, &crc, sizeof(crc)) == sizeof(crc))
156                                                 /* check CRC here if needed */
157                                                 return true;
158                                         else
159                                                 LOG_ERR("get_block error getting crc\n");
160                                 }
161                                 else
162                                         LOG_ERR("get_block len error: %d\n", (int)len);
163                         }
164                         else
165                                 LOG_ERR("get_block token error: %02X\n", token);
166
167                         return false;
168                 }
169         }
170
171         LOG_ERR("get_block timeout waiting token\n");
172         return false;
173 }
174
175 #define SD_SELECT() \
176 do \
177 { \
178         if (!sd_select(true)) \
179         { \
180                 LOG_ERR("%s failed, card busy\n", __func__); \
181                 return EOF; \
182         } \
183 } \
184 while (0)
185
186 #define SD_SETBLOCKLEN 0x50
187
188 static int16_t sd_setBlockLen(uint32_t newlen)
189 {
190         SD_SELECT();
191
192         int16_t r1 = sd_sendCommand(SD_SETBLOCKLEN, newlen, 0);
193
194         sd_select(false);
195         return r1;
196 }
197
198 #define SD_SEND_CSD 0x49
199
200 static int16_t sd_getCSD(CardCSD *csd)
201 {
202         SD_SELECT();
203
204         int16_t r1 = sd_sendCommand(SD_SEND_CSD, 0, 0);
205
206         if (r1)
207         {
208                 LOG_ERR("send_csd failed: %04X\n", r1);
209                 sd_select(false);
210                 return r1;
211         }
212
213         uint8_t buf[16];
214         bool res = sd_getBlock(buf, sizeof(buf));
215         sd_select(false);
216
217         if (res)
218         {
219                 uint16_t mult = (1L << ((((buf[9] & 0x03) << 1) | ((buf[10] & 0x80) >> 7)) + 2));
220                 uint16_t c_size = (((uint16_t)(buf[6] & 0x03)) << 10) | (((uint16_t)buf[7]) << 2) |
221                                   (((uint16_t)(buf[8] & 0xC0)) >> 6);
222
223                 csd->block_len = (1L << (buf[5] & 0x0F));
224                 csd->block_num = (c_size + 1) * mult;
225                 csd->capacity = (csd->block_len * csd->block_num) >> 20; // in MB
226
227                 LOG_INFO("block_len %d bytes, block_num %ld, total capacity %dMB\n", csd->block_len, csd->block_num, csd->capacity);
228                 return 0;
229         }
230         else
231                 return EOF;
232 }
233
234
235 #define SD_READ_SINGLEBLOCK 0x51
236
237 static int16_t sd_readBlock(void *buf, uint32_t addr)
238 {
239         SD_SELECT();
240
241         int16_t r1 = sd_sendCommand(SD_READ_SINGLEBLOCK, addr, 0);
242
243         if (r1)
244         {
245                 LOG_ERR("read single block failed: %04X\n", r1);
246                 sd_select(false);
247                 return r1;
248         }
249
250         bool res = sd_getBlock(buf, SD_DEFAULT_BLOCKLEN);
251         sd_select(false);
252         if (!res)
253         {
254                 LOG_ERR("read single block failed reading data\n");
255                 return EOF;
256         }
257         else
258                 return 0;
259 }
260
261 #define SD_WRITE_SINGLEBLOCK 0x58
262 #define SD_DATA_ACCEPTED     0x05
263
264 static int16_t sd_writeBlock(const void *buf, uint32_t addr)
265 {
266         SD_SELECT();
267
268         int16_t r1 = sd_sendCommand(SD_WRITE_SINGLEBLOCK, addr, 0);
269
270         if (r1)
271         {
272                 LOG_ERR("write single block failed: %04X\n", r1);
273                 sd_select(false);
274                 return r1;
275         }
276
277         kfile_putc(SD_STARTTOKEN, fd);
278         kfile_write(fd, buf, SD_DEFAULT_BLOCKLEN);
279         /* send fake crc */
280         kfile_putc(0, fd);
281         kfile_putc(0, fd);
282         uint8_t dataresp = (kfile_getc(fd) & 0x1F);
283         sd_select(false);
284
285         // FIXME: sometimes dataresp is 0, find out why.
286         if (dataresp != SD_DATA_ACCEPTED)
287         {
288                 LOG_ERR("write single block failed: %02X\n", dataresp);
289                 return EOF;
290         }
291         else
292                 return 0;
293 }
294
295
296 bool sd_test(void)
297 {
298         CardCSD csd;
299         sd_getCSD(&csd);
300
301         uint8_t buf[SD_DEFAULT_BLOCKLEN];
302
303         if (sd_readBlock(buf, 0) != 0)
304                 return false;
305
306         kputchar('\n');
307         for (int i = 0; i < SD_DEFAULT_BLOCKLEN; i++)
308         {
309                 kprintf("%02X ", buf[i]);
310                 buf[i] = i;
311                 if (!((i+1) % 16))
312                         kputchar('\n');
313         }
314
315         if (sd_writeBlock(buf, 0) != 0)
316                 return false;
317
318         memset(buf, 0, sizeof(buf));
319         if (sd_readBlock(buf, 0) != 0)
320                 return false;
321
322         kputchar('\n');
323         for (int i = 0; i < SD_DEFAULT_BLOCKLEN; i++)
324         {
325                 kprintf("%02X ", buf[i]);
326                 buf[i] = i;
327                 if (!((i+1) % 16))
328                         kputchar('\n');
329         }
330
331         return true;
332 }
333
334 #define SD_GO_IDLE_STATE     0x40
335 #define SD_GO_IDLE_STATE_CRC 0x95
336 #define SD_SEND_OP_COND      0x41
337 #define SD_SEND_OP_COND_CRC  0xF9
338
339 #define SD_START_DELAY  ms_to_ticks(10)
340 #define SD_INIT_TIMEOUT ms_to_ticks(1000)
341 #define SD_IDLE_RETRIES 4
342
343 bool sd_init(KFile *_fd)
344 {
345         uint16_t r1;
346
347         ASSERT(_fd);
348         fd = _fd;
349
350         SD_CS_INIT();
351         SD_CS_OFF();
352
353         /* Wait a few moments for supply voltage to stabilize */
354         timer_delay(SD_START_DELAY);
355
356         /* Give 80 clk pulses to wake up the card */
357         for (int i = 0; i < 10; i++)
358                 kfile_putc(0xff, fd);
359         kfile_flush(fd);
360
361         for (int i = 0; i < SD_IDLE_RETRIES; i++)
362         {
363                 SD_SELECT();
364                 r1 = sd_sendCommand(SD_GO_IDLE_STATE, 0, SD_GO_IDLE_STATE_CRC);
365                 sd_select(false);
366
367                 if (r1 == SD_IN_IDLE)
368                         break;
369         }
370
371         if (r1 != SD_IN_IDLE)
372         {
373                 LOG_ERR("go_idle_state failed: %04X\n", r1);
374                 return false;
375         }
376
377         ticks_t start = timer_clock();
378
379         /* Wait for card to start */
380         do
381         {
382                 SD_SELECT();
383                 r1 = sd_sendCommand(SD_SEND_OP_COND, 0, SD_SEND_OP_COND_CRC);
384                 sd_select(false);
385                 cpu_relax();
386         }
387         while (r1 != 0 && timer_clock() - start < SD_INIT_TIMEOUT);
388
389         if (r1)
390         {
391                 LOG_ERR("send_op_cond failed: %04X\n", r1);
392                 return false;
393         }
394
395         r1 = sd_setBlockLen(SD_DEFAULT_BLOCKLEN);
396
397         if (r1)
398         {
399                 LOG_ERR("setBlockLen failed: %04X\n", r1);
400                 return false;
401         }
402
403         sd_status = !r1;
404         return sd_status;
405 }
406
407 DSTATUS sd_disk_initialize(BYTE drv)
408 {
409         return sd_disk_status(drv);
410 }
411
412 DSTATUS sd_disk_status(BYTE drv)
413 {
414         ASSERT(!drv);
415
416         if (sd_status)
417                 return RES_OK;
418         else
419                 return STA_NOINIT;
420 }
421
422 DRESULT sd_disk_read(BYTE drv, BYTE* buf, DWORD sector, BYTE count)
423 {
424         ASSERT(!drv);
425
426         if (!sd_status)
427                 return RES_NOTRDY;
428
429         while (count--)
430         {
431                 if (sd_readBlock(buf, sector * SD_DEFAULT_BLOCKLEN))
432                         return RES_ERROR;
433                 buf += SD_DEFAULT_BLOCKLEN;
434                 sector++;
435         }
436         return RES_OK;
437 }
438
439 DRESULT sd_disk_write(BYTE drv, const BYTE* buf, DWORD sector, BYTE count)
440 {
441         ASSERT(!drv);
442
443         if (!sd_status)
444                 return RES_NOTRDY;
445
446         while (count--)
447         {
448                 if (sd_writeBlock(buf, sector * SD_DEFAULT_BLOCKLEN))
449                         return RES_ERROR;
450                 buf += SD_DEFAULT_BLOCKLEN;
451                 sector++;
452         }
453         return RES_OK;
454 }
455
456 DRESULT sd_disk_ioctl(BYTE drv, BYTE cmd, void* buf)
457 {
458         ASSERT(!drv);
459
460         if (!sd_status)
461                 return RES_NOTRDY;
462
463         switch (cmd)
464         {
465                 case CTRL_SYNC:
466                         return RES_OK;
467
468                 case GET_SECTOR_SIZE:
469                         *(WORD *)buf = SD_DEFAULT_BLOCKLEN;
470                         return RES_OK;
471
472                 case GET_SECTOR_COUNT:
473                 {
474                         CardCSD csd;
475                         if (sd_getCSD(&csd))
476                                 return RES_ERROR;
477                         else
478                         {
479                                 *(DWORD *)buf = csd.block_num;
480                                 return RES_OK;
481                         }
482
483                 }
484
485                 case GET_BLOCK_SIZE:
486                         *(DWORD *)buf = 1;
487                         return RES_OK;
488
489                 default:
490                         LOG_ERR("unknown command: [%d]\n", cmd);
491                         return RES_PARERR;
492         }
493 }
494
495 DWORD get_fattime(void)
496 {
497         return 0;
498 }