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