source: trunk/modules/sdmmc/caba/source/src/sdmmc.cpp@ 1052

Last change on this file since 1052 was 1052, checked in by alain, 9 years ago

few bugs

File size: 18.9 KB
Line 
1/*
2 -*- c++ -*-
3 *
4 * SOCLIB_LGPL_HEADER_BEGIN
5 *
6 * This file is part of SoCLib, GNU LGPLv2.1.
7 *
8 * SoCLib is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation; version 2.1 of the License.
11 *
12 * SoCLib is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with SoCLib; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 * SOCLIB_LGPL_HEADER_END
23 *
24 * Copyright (c) UPMC, Lip6, SoC
25 * manuel.bouyer@lip6.fr october 2013
26 *
27 * Maintainers: bouyer
28 */
29
30#include <stdint.h>
31#include <errno.h>
32#include <cstring>
33#include <iostream>
34#include <fcntl.h>
35#include <cassert>
36#include "sdmmc.h"
37
38namespace soclib { namespace caba {
39
40using namespace soclib::caba;
41
42////////////////////////
43void SdMMC::genMealy()
44{
45 if(p_resetn.read() == false)
46 {
47 spi_fsm = S_IDLE;
48 m_acmd = false;
49 m_sdstate = SD_IDLE;
50 return;
51 }
52
53 if (p_spi_ss.read())
54 {
55 if (spi_fsm != S_IDLE)
56 {
57 std::cerr << name() << " deselect but not idle, state "
58 << std::dec << spi_fsm << " last cmd " << (int)command
59 << " args " << std::hex << args << std::dec
60 << " bitcount " << (int)spi_bitcount
61 << " idx " << m_data_idx << " len_snd " << m_datalen_snd
62 << " len_rcv " << m_datalen_rcv << std::endl;
63 }
64 spi_fsm = S_IDLE;
65 spi_clk = p_spi_clk;
66 spi_mosi_previous = p_spi_mosi;
67 return;
68 }
69
70 switch(spi_fsm)
71 {
72 case S_IDLE:
73 if (p_spi_clk.read() == 1 && spi_clk == 0) // rising edge
74 {
75 command = (command << 1) | spi_mosi_previous;
76 spi_bitcount = 6;
77 spi_fsm = S_RECEIVE_CMD;
78 }
79 break;
80 case S_RECEIVE_CMD:
81 if (p_spi_clk.read() == 1 && spi_clk == 0) // rising edge
82 {
83 command = (command << 1) | spi_mosi_previous;
84 if (spi_bitcount == 0)
85 {
86 if ((command & 0x80) == 0)
87 {
88 spi_fsm = S_RECEIVE_ARGS_START;
89 }
90 else
91 {
92#ifdef SOCLIB_MODULE_DEBUG0
93 std::cout << name() << " S_RECEIVE_CMD " << std::hex << (int)command << std::endl;
94#endif
95 spi_fsm = S_IDLE;
96 }
97 }
98 else
99 {
100 spi_bitcount = spi_bitcount - 1;
101 }
102 }
103 break;
104 case S_RECEIVE_ARGS_START:
105 if (p_spi_clk.read() == 1 && spi_clk == 0) // rising edge
106 {
107 args = (args << 1) | spi_mosi_previous;
108 spi_bitcount = 30;
109 spi_fsm = S_RECEIVE_ARGS;
110 }
111 break;
112 case S_RECEIVE_ARGS:
113 if (p_spi_clk.read() == 1 && spi_clk == 0) // rising edge
114 {
115 args = (args << 1) | spi_mosi_previous;
116 if (spi_bitcount == 0)
117 {
118 spi_bitcount = 7;
119 spi_fsm = S_RECEIVE_CRC;
120 }
121 else
122 {
123 spi_bitcount = spi_bitcount - 1;
124 }
125 }
126 break;
127 case S_RECEIVE_CRC:
128 if (p_spi_clk.read() == 1 && spi_clk == 0) // rising edge
129 {
130 cmdcrc = (cmdcrc << 1) | spi_mosi_previous;
131 if (spi_bitcount == 0)
132 {
133 handle_sdmmc_cmd(command, args);
134 spi_bitcount = 0; // SEND_DATA will reset it
135 spi_fsm = S_SEND_DATA;
136 m_data_idx = 0;
137 }
138 else
139 {
140 spi_bitcount = spi_bitcount - 1;
141 }
142 }
143 break;
144
145 case S_SEND_DATA:
146 if (p_spi_clk.read() == 0 && spi_clk == 1) // falling edge
147 {
148 if (spi_bitcount == 0)
149 {
150 if (m_data_idx != m_datalen_snd)
151 {
152 spi_shiftreg = m_databuf[m_data_idx];
153 spi_bitcount = 7;
154 spi_fsm = S_SEND_DATA;
155 m_data_idx++;
156#ifdef SOCLIB_MODULE_DEBUG0
157 std::cout << name() << " S_SEND_DATA " << std::dec << m_datalen_snd << " idx " << m_data_idx << " " << std::hex << (uint32_t)m_databuf[m_data_idx] << std::endl;
158#endif
159 }
160 else if (m_datalen_rcv != 0)
161 {
162 spi_fsm = S_RECEIVE_DATA_WAIT;
163 spi_bitcount = 7;
164 m_data_idx = 0;
165 }
166 else
167 {
168 spi_fsm = S_IDLE;
169 }
170 }
171 else
172 {
173 spi_bitcount = spi_bitcount - 1;
174 spi_shiftreg = spi_shiftreg << 1;
175 }
176 }
177 break;
178 /////////////////////////
179 case S_RECEIVE_DATA_WAIT:
180 if (p_spi_clk.read() == 1 && spi_clk == 0) // rising edge
181 {
182 uint8_t s_data;
183 s_data = (m_databuf[0] << 1) | spi_mosi_previous;
184 m_databuf[0] = s_data;
185 if (spi_bitcount == 0)
186 {
187#ifdef SOCLIB_MODULE_DEBUG
188std::cout << name() << " S_RECEIVE_DATA_WAIT " << std::dec << (int)s_data << std::endl;
189#endif
190 spi_bitcount = 7;
191 if (s_data == 0xfe) // data start token
192 {
193 spi_fsm = S_RECEIVE_DATA;
194 m_data_idx = 1;
195 }
196 else
197 {
198#ifdef SOCLIB_MODULE_DEBUG
199std::cout << name() << " S_RECEIVE_DATA_WAIT " << std::hex << (int)s_data << std::endl;
200#endif
201 spi_fsm = S_RECEIVE_DATA_WAIT;
202 }
203 }
204 else
205 {
206 spi_bitcount = spi_bitcount - 1;
207 }
208 }
209 break;
210 ////////////////////
211 case S_RECEIVE_DATA:
212 if (p_spi_clk.read() == 1 && spi_clk == 0) // rising edge
213 {
214 m_databuf[m_data_idx] = (m_databuf[m_data_idx] << 1) | spi_mosi_previous;
215 if (spi_bitcount == 0)
216 {
217 m_data_idx++;
218 if (m_data_idx != m_datalen_rcv)
219 {
220 spi_fsm = S_RECEIVE_DATA;
221 spi_bitcount = 7;
222 }
223 else
224 {
225 handle_sdmmc_write(command, args);
226 if (m_datalen_snd > 0)
227 {
228 spi_bitcount = 0; // SEND_DATA will reset it
229 spi_fsm = S_SEND_DATA;
230 m_data_idx = 0;
231 }
232 else
233 {
234 spi_fsm = S_IDLE;
235 }
236 }
237 }
238 else
239 {
240 spi_bitcount = spi_bitcount - 1;
241 }
242 }
243 break;
244 } // end switch spi_fsm
245
246 //// now generate output signal
247
248 switch(spi_fsm)
249 {
250 case S_IDLE:
251 p_spi_miso = !p_spi_ss.read();
252 break;
253
254 case S_SEND_DATA:
255 p_spi_miso = (spi_shiftreg & 0x80) != 0;
256 break;
257
258 default:
259 p_spi_miso = !p_spi_ss.read();
260 break;
261 }
262
263 //// sample inputs
264 spi_clk = p_spi_clk.read();
265 spi_mosi_previous = p_spi_mosi;
266
267} // end GenMealy()
268
269
270////////////////////////////////////////////////////////
271void SdMMC::handle_sdmmc_cmd(uint8_t cmd, uint32_t data)
272{
273 m_datalen_rcv = 0;
274 m_databuf[0] = 0x04; // default value : illegal command
275 m_datalen_snd = 1; // default value : 1 byte
276
277 if (m_sdstate == SD_IDLE)
278 m_databuf[0] |= 0x01; // idle
279
280 if ((cmd & 0x40) == 0)
281 {
282 //illegal command
283 return;
284 }
285 cmd &= 0x3f;
286
287 if (m_acmd)
288 {
289#ifdef SOCLIB_MODULE_DEBUG0
290std::cout << name() << " new acmd " << std::dec << (int)cmd << " args " << std::hex << data << " crc " << (int)cmdcrc << std::endl;
291#endif
292 m_acmd = false;
293 switch (cmd)
294 {
295 case 41: // ACD41 : Send OP_COND
296 m_databuf[0] = 0x0; // card ready
297 m_datalen_snd = 1;
298 m_sdstate = SD_READY;
299 break;
300 case 51: // send SCR
301 m_databuf[ 0] = (m_sdstate == SD_IDLE) ? 0x1 : 0x0; // R1
302 m_databuf[ 1] = 0xfe; // data token
303 m_databuf[ 2] = 0x00; // SCR_STRUCTURE / SD_SPEC
304 m_databuf[ 3] = 0x05; // DATA_STAT_AFTER_ERASE, SD_SECURITY, SD_BUS_WIDTHS
305 m_databuf[ 4] = 0; // SD_SPEC3, EX_SECURITY, SD_SPEC4
306 m_databuf[ 5] = 0; // CMD_SUPPORT
307 m_databuf[ 6] = 0; // vendor specific
308 m_databuf[ 7] = 0; // vendor specific
309 m_databuf[ 8] = 0; // vendor specific
310 m_databuf[ 9] = 0; // vendor specific
311 m_databuf[10] = 0x0; // CRC16
312 m_databuf[11] = 0x0; // CRC16
313 m_datalen_snd = 12;
314 break;
315 default:
316 std::cout << name() << " unknown acmd " << std::dec
317 << (int)cmd << std::endl;
318 break; // return illegal command
319 }
320 }
321 else
322 {
323#ifdef SOCLIB_MODULE_DEBUG0
324std::cout << name() << " new cmd " << std::dec << (int)cmd << " args " << std::hex << data << " crc " << (int)cmdcrc << std::endl;
325#endif
326 switch (cmd)
327 {
328 ///////
329 case 0: // CMD0
330 m_databuf[0] = 0x1;
331 m_datalen_snd = 1;
332 m_sdstate = SD_IDLE;
333 break;
334 ///////
335 case 8: // CMD8
336 // reply with illegal command for now
337 break;
338 ///////
339 case 9: // CMD9 : send CSD
340 {
341 // we use a block len of 1024
342 uint32_t csize = ((m_device_size + (512 * 1024) - 1) / (512 * 1024)) - 1;
343 m_databuf[ 0] = (m_sdstate == SD_IDLE) ? 0x1 : 0x0; // R1
344 m_databuf[ 1] = 0xfe; // data token
345 m_databuf[ 2] = 0x00; // CSD_STRUCTURE
346 m_databuf[ 3] = 0xe; // TAAC
347 m_databuf[ 4] = 0; // NSAC
348 m_databuf[ 5] = 0x32; // TRAN_SPEED
349 m_databuf[ 6] = 0x5b; // CCC_H
350 m_databuf[ 7] = 0x5a; // CCC_L + READ_BL_LEN
351 m_databuf[ 8] = 0x80; // READ_BL_PARTIAL, R/W_BLK_MISALIGN, DSR_IMP
352 m_databuf[ 8] |= (csize >> 10) & 0x03; // CSIZE[12-11]
353 m_databuf[ 9] = (csize >> 2) & 0xff; // CSIZE[10-2]
354 m_databuf[10] = (csize << 6) & 0xc0; // CSIZE[1-0]
355 m_databuf[10] |= 0; // R_CURR_MIN, R_CURR_MAX
356 m_databuf[11] = 0x3; // W_CURR_MIN, W_CURR_MAX, CSIZE_MULT[2-1];
357 m_databuf[12] = 0xff; // CSIZE_MULT[1], ERASE_BLK_EN, ERASE_SECTOR_SIZE[6-1]
358 m_databuf[13] = 0x80; // ERASE_SECTOR_SIZE[0]. WP_GRP_SIZE
359 m_databuf[14] = 0x0a; // WP_GRP_ENABLE, R2W_FACTOR, WRITE_BL_LEN[2-3]
360 m_databuf[15] = 0x40; // WRITE_BL_LEN[0-1], WR_BL_PARTIAL
361 m_databuf[16] = 0; // FILE_FORMAT
362 m_databuf[17] = 0x1; // CRC7
363 m_databuf[18] = 0x0; // CRC16
364 m_databuf[19] = 0x0; // CRC16
365 m_datalen_snd = 20;
366 }
367 break;
368 ////////
369 case 10: // CMD10 : send CID
370 m_databuf[ 0] = (m_sdstate == SD_IDLE) ? 0x1 : 0x0; // R1
371 m_databuf[ 1] = 0xfe; // data token
372 m_databuf[ 2] = 0xda; // MID
373 m_databuf[ 3] = 'P'; // OID
374 m_databuf[ 4] = '6'; // OID
375 m_databuf[ 5] = 's'; // PNM
376 m_databuf[ 6] = 'o'; // PNM
377 m_databuf[ 7] = 'c'; // PNM
378 m_databuf[ 8] = 's'; // PNM
379 m_databuf[ 9] = 'd'; // PNM
380 m_databuf[10] = 0x01; // PRV
381 m_databuf[11] = 0xde; // PSN
382 m_databuf[12] = 0xad; // PSN
383 m_databuf[13] = 0xbe; // PSN
384 m_databuf[14] = 0xef; // PSN
385 m_databuf[15] = 10; // MDT
386 m_databuf[16] = 13; // MDT
387 m_databuf[17] = 0x1; // CRC7
388 m_databuf[18] = 0x0; // CRC16
389 m_databuf[19] = 0x0; // CRC16
390 m_datalen_snd = 20;
391 break;
392 ////////
393 case 16: // CMD16 : set block size
394 if (m_sdstate != SD_IDLE && data == 512)
395 {
396 m_databuf[0] = 0x00;
397 m_datalen_snd = 1;
398 } // else illegal command
399 break;
400 ////////
401 case 17: // CMD17 : read data block
402 {
403 int ret;
404 if (m_sdstate == SD_IDLE) // return illegal command
405 {
406 return;
407 }
408 if (data >= m_device_size) // return "out of range"
409 {
410 std::cerr << name() << " read: request " << data
411 << " past end of file " << m_device_size << std::endl;
412 m_databuf[0] = 0x00; // R1 OK
413 m_databuf[1] = 0x08; // error tocken "out of range"
414 m_datalen_snd = 2;
415 return;
416 }
417 do
418 {
419 if (lseek(m_fd, data, SEEK_SET) < 0)
420 {
421 std::cerr << name() << " lseek: " <<
422 strerror(errno) << std::endl;
423 m_databuf[0] = 0x00; // R1 OK
424 m_databuf[1] = 0x02; // error tocken "CC err"
425 m_datalen_snd = 2;
426 return;
427 }
428 ret = read(m_fd, &m_databuf[2], 512);
429 } while (ret < 0 && errno == EINTR);
430 if (ret < 0)
431 {
432 std::cerr << name() << " read: " << strerror(errno) << std::endl;
433 m_databuf[0] = 0x00; // R1 OK
434 m_databuf[1] = 0x04; // error tocken "card ECC failed"
435 m_datalen_snd = 2;
436 return;
437 }
438 m_databuf[514] = m_databuf[515] = 0; // XXX CRC
439 m_databuf[0] = 0x0; // R1
440 m_databuf[1] = 0xfe; // start block tocken
441 m_datalen_snd = 516;
442 }
443 break;
444 ////////
445 case 24: // CMD 24 : write data block
446 {
447 if (m_sdstate == SD_IDLE) // return illegal command
448 {
449 return;
450 }
451#ifdef SOCLIB_MODULE_DEBUG
452 std::cout << name() << " new cmd write " << std::dec << (int)cmd << " args " << std::hex << data << std::endl;
453#endif
454 m_databuf[0] = 0x0; // R1
455 m_datalen_snd = 1;
456 m_datalen_rcv = 512 + 2 + 1; // data + tocken + CRC
457 }
458 break;
459 ////////
460 case 55: // CMD55 : app-specific command follow
461 m_acmd = true;
462 m_databuf[0] = (m_sdstate == SD_IDLE) ? 0x1 : 0x0;
463 m_datalen_snd = 1;
464 break;
465 ////////
466 case 58: // CMD 58 : send OCR
467 m_databuf[4] = (m_sdstate == SD_IDLE) ? 0x1 : 0x0; // R1
468 m_databuf[3] = 0x80; // power up complete, SDSC
469 m_databuf[2] = 0xff; // all voltages supported
470 m_databuf[1] = 0x00;
471 m_databuf[0] = 0x00;
472 m_datalen_snd = 5;
473 break;
474 ////////
475 default: // return illegal command
476 std::cout << name() << " unknown cmd " << std::dec << (int)cmd << std::endl;
477 break;
478 }
479 }
480} // end handle_sdmmc_cmd()
481
482///////////////////////////////////////////////////////////
483void SdMMC::handle_sdmmc_write(uint8_t cmd, uint32_t data)
484{
485 m_datalen_rcv = 0;
486 cmd &= 0x3f;
487#ifdef SOCLIB_MODULE_DEBUG
488 std::cout << name() << " cmd write " << std::dec << (int)cmd << " args " << std::hex << data << std::endl;
489#endif
490 switch(cmd)
491 {
492 case 24: // CMD24 : write data block
493 {
494 int ret;
495 assert(m_sdstate != SD_IDLE && "can't write in idle state");
496 if (data >= m_device_size)
497 {
498 std::cerr << name() << " write: request " << data
499 << " past end of file " << m_device_size << std::endl;
500 m_databuf[0] = 0xd; // write error
501 m_datalen_snd = 1;
502 return;
503 }
504 do
505 {
506 if (lseek(m_fd, data, SEEK_SET) < 0)
507 {
508 std::cerr << name() << " lseek: " << strerror(errno) << std::endl;
509 m_databuf[0] = 0xd; // write error
510 m_datalen_snd = 1;
511 return;
512 }
513 ret = write(m_fd, &m_databuf[1], 512);
514 }
515 while (ret < 0 && errno == EINTR);
516 if (ret < 0)
517 {
518 std::cerr << name() << " write: " << strerror(errno) << std::endl;
519 m_databuf[0] = 0xd; // write error
520 m_datalen_snd = 1;
521 return;
522 }
523 m_databuf[0] = 0x5; // write complete
524 m_databuf[1] = 0x0; // busy
525 m_datalen_snd = 2;
526 }
527 break;
528 default:
529 {
530 std::cerr << name() << " unkown write cmd " << std::dec << (int)cmd << std::endl;
531 m_databuf[0] = 0xd; // write error;
532 m_datalen_snd = 1;
533 }
534 }
535 return;
536}
537
538//////////////////////////////////////////////////////////////
539SdMMC::SdMMC( sc_core::sc_module_name name,
540 const std::string &filename,
541 const uint32_t latency)
542
543: caba::BaseModule(name),
544 m_latency(latency),
545 p_clk("p_clk"),
546 p_resetn("p_resetn"),
547 p_spi_ss("p_spi_ss"),
548 p_spi_clk("p_spi_clk"),
549 p_spi_mosi("p_spi_mosi"),
550 p_spi_miso("p_spi_miso")
551{
552 std::cout << " - Building SdMMC " << name << std::endl;
553
554 SC_METHOD(genMealy);
555 dont_initialize();
556 sensitive << p_clk.neg();
557 sensitive << p_resetn;
558 sensitive << p_spi_ss;
559 sensitive << p_spi_clk;
560
561 m_fd = ::open(filename.c_str(), O_RDWR);
562 if ( m_fd < 0 )
563 {
564 std::cout << "Error in component SdMMC : " << name
565 << " Unable to open file " << filename << std::endl;
566 exit(1);
567 }
568 m_device_size = lseek(m_fd, 0, SEEK_END);
569
570} // end constructor
571
572SdMMC::~SdMMC()
573{
574}
575
576
577//////////////////////////
578void SdMMC::print_trace()
579{
580 const char* spi_str[] =
581 {
582 "S_IDLE",
583 "S_RECEIVE_CMD",
584 "S_RECEIVE_ARGS_START",
585 "S_RECEIVE_ARGS",
586 "S_RECEIVE_CRC",
587 "S_RECEIVE_DATA_START",
588 "S_RECEIVE_DATA",
589 "S_SEND_DATA",
590 "S_NOP",
591 };
592 if (spi_clk != p_spi_clk.read()) {
593 std::cout << name() << " SPI_FSM : " << spi_str[spi_fsm]
594 << std::dec
595 << " clk " << spi_clk << "->" << p_spi_clk << " ss " << p_spi_ss
596 << " mosi " << p_spi_mosi << " miso " << p_spi_miso
597 << std::endl;
598 std::cout << " spi_shiftreg: " << std::hex << (int)spi_shiftreg
599 << " spi_bitcount: " << (int)spi_bitcount
600 << std::endl;
601 }
602}
603}} // end namespace
604
605// Local Variables:
606// tab-width: 4
607// c-basic-offset: 4
608// c-file-offsets:((innamespace . 0)(inline-open . 0))
609// indent-tabs-mode: nil
610// End:
611
612// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
613
Note: See TracBrowser for help on using the repository browser.