Fix to install pppoecd (in router/Makefile)
[tomato.git] / release / src / router / mmc / spi.c
blobeb15360b700274beee9cf91aef8b1ebb1cba277f
1 /*==============================================================================
2 * spi.c - routines that communicate with the card using spi
3 *
4 * Methods in this file perform all I/O with the media card.
6 * This file is broken into 2 sections:
8 * 1) Unoptimized methods
9 *
10 * -Methods that have not been optimized for maximum performance.
12 * -Honour the maximum frequency setting (if set).
14 * -There's little payback trying to optimize these, as they are only used
15 * during card initialization.
17 * 2) Optimized methods
19 * -Methods that have been optimized for maximum performance.
21 * -Don't honour the maximum frequency setting and are coded to run as fast
22 * as possible - don't call any from code that does card initialization
23 * (max 400khz frequency).
25 * -There are different variants of methods to help optimize throughput.
26 * For example, there is rarely a need to both send and receive data at
27 * the same time, so instead of using just spi_io, 3 variants can be
28 * created that have better performance.
30 * r = spi_io(0xab) - send argument, return data out bits.
31 * spi_io_v_o(0xab) - send argument, ignore data out bits.
32 * r = spi_io_ff_o() - send 0xff, return data out bits.
33 * spi_io_ff_v_o() - send 0xff, ignore data out bits.
35 * -Efficiency was tuned by having the compiler dump the generated MIPS
36 * assembler instructions, then adjusting the C source to minimize the
37 * number of MIPS instructions generated (wherever possible).
39 * -Looping is avoided or reduced where possible to improve efficiency. This
40 * does increase module size.
42 * -The compiler, with optimization on, winds up inlining the vast majority
43 * of the code, so even though we have more methods, code size is not
44 * greatly impacted.
46 * Conventions:
48 * -All methods begin with "spi_".
49 * -Optimized methods are suffixed with "_o" to make them easy to identify.
50 * -Variants of methods that return no (void) value are suffixed with "_v".
51 * -Only variables used exclusively by methods in this module are defined here.
52 * All begin with "spi_".
53 *============================================================================*/
55 // Handy to turn off inlining globally when analyzing generated MIPS assembler code
56 #define INLINE inline
58 // Function prototypes - non optimized functions
59 static int spi_init(void);
60 static int spi_freq_max(int);
61 static void spi_freq_wait(cycles_t);
62 static void spi_cs_ass(void);
63 static void spi_cs_dea(void);
64 static unsigned char spi_io(unsigned char);
65 static unsigned char spi_mmc_cmd_r(unsigned char, unsigned int, unsigned char, unsigned char *, int);
66 static unsigned char spi_mmc_read_blk(unsigned char, unsigned int, unsigned char, unsigned char *, int);
68 // Function prototypes - optimized functions
69 static inline void spi_cs_ass_o(void);
70 static inline void spi_cs_dea_o(void);
71 static inline void spi_io_ff_v_o(void);
72 static inline void spi_io_2ff_v_o(void);
73 static inline void spi_io_6ff_v_o(void);
74 static inline unsigned char spi_io_ff_o(void);
75 static inline void spi_io_v_o(unsigned char);
76 static inline unsigned char spi_mmc_write_multi_o(unsigned int, unsigned char *, int, unsigned char, unsigned char);
77 static inline unsigned char spi_mmc_read_multi_o(unsigned int, unsigned char *, int, unsigned char, unsigned char);
79 // Variables used to set GPIO port state (cs low = asserted)
80 static unsigned char spi_ps_d0_c1; // data low, clock hi, cs low
81 static unsigned char spi_ps_d0_c0; // data low, clock low, cs low
82 static unsigned char spi_ps_d1_c1; // data hi, clock hi, cs low
83 static unsigned char spi_ps_d1_c0; // data hi, clock low, cs low
85 // Masks and bit numbers - spi->GPIO mappings
86 static unsigned char spi_di_mask;
87 static unsigned char spi_do_mask;
88 static unsigned char spi_do_pin;
89 static unsigned char spi_cl_mask;
90 static unsigned char spi_cs_mask;
92 // Vars that are used to control the max clock frequency
93 static cycles_t spi_clk_delay = 0; // set max clock frequency (khz)
94 static cycles_t spi_clk_last = 0; // time of last clock transition
97 //======================= UNOPTIMIZED METHODS ==================================
100 /*------------------------------------------------------------------------------
101 * spi_init
103 * Initialize spi hardware - specify which IO pins used for SPI communications
105 * Set the required state, IO mode, and control mode for SPI.
107 *----------------------------------------------------------------------------*/
108 static int spi_init() {
110 // Convert gpio pin nums to bit mask used to set/clear appropriate GPIO bit.
111 spi_di_mask = (1 << din);
112 spi_do_mask = (1 << dout);
113 spi_cl_mask = (1 << clk);
114 spi_cs_mask = (1 << cs);
115 spi_do_pin = dout;
117 // Disable weak pullups on all GPIO pins used by this module
118 *gpio_control &= ~( spi_di_mask | spi_cl_mask | spi_cs_mask | spi_do_mask);
120 // Set din, clk and cs GPIO pins to outputs, dout GPIO pin to input
121 *gpio_enable = (*gpio_enable | spi_di_mask | spi_cl_mask | spi_cs_mask) & ~spi_do_mask;
123 // Initial setup of port state variables
124 spi_ps_d1_c0 = ((*gpio_output | spi_di_mask) & ~spi_cl_mask) & ~spi_cs_mask; // din hi, clock low
125 spi_ps_d1_c1 = spi_ps_d1_c0 | spi_cl_mask; // din hi, clock hi
126 spi_ps_d0_c1 = spi_ps_d1_c1 & ~spi_di_mask; // din low, clock hi
127 spi_ps_d0_c0 = spi_ps_d0_c1 & ~spi_cl_mask; // din low, clock hi
129 // Initial state - data hi, clock low, cs hi - restores output state of unused pins
130 *gpio_output = spi_ps_d1_c0 | spi_cs_mask;
132 return 0;
136 /*------------------------------------------------------------------------------
137 * SPI Freq
139 * Set the maximum frequency (in KHz) the spi clock may run at.
140 * A value of zero means no maximum frequency - as fast as possible.
142 * Notes: Complete
143 *----------------------------------------------------------------------------*/
144 static int spi_freq_max(int freq) {
146 /* calculate and save the period of the specified frequency */
147 if ( freq > 0 ) {
148 spi_clk_delay = (loops_per_jiffy*(HZ<<1)) / (freq*1000*2);
149 } else {
150 spi_clk_delay = 0;
153 return 0;
157 /*------------------------------------------------------------------------------
158 * SPI Freq Wait
160 * Used to ensure enough time has elapsed between clock transitions so clock
161 * frequency remains below the set maximum.
163 * Notes:
165 * -spi_clk_last is global. It is also set in the spi_cs_ass method...
166 *----------------------------------------------------------------------------*/
167 static void spi_freq_wait(cycles_t wait) {
168 cycles_t now, delta, future;
170 // Calculate how many cycles have elapsed since clock last toggled
171 now = get_cycles();
172 delta = (now > spi_clk_last) ? (now - spi_clk_last) : (spi_clk_last - now); // abs(now - last)
174 if (delta < wait) {
176 // Less than requested wait - calc future time we must wait until
177 future = now + (wait - delta); /* can overflow and wrap arround */
179 // Now wait until that future time - handle overflow...
180 if (future < now) {
181 // Value overflowed - wait till now <= future
182 while (get_cycles() > future) ;
184 while (get_cycles() < future) ;
188 // Save current cycles value so we know when next transition allowed.
189 spi_clk_last = get_cycles();
193 /*------------------------------------------------------------------------------
194 * spi_cs_ass
196 * Assert CS signal. Unoptimized version that supports max frequency setting.
198 * Notes: Complete
199 *----------------------------------------------------------------------------*/
200 static INLINE void spi_cs_ass(void) {
201 spi_clk_last = get_cycles(); // assume clock just transitioned
202 spi_ps_d1_c0 = ((*gpio_output | spi_di_mask) & ~spi_cl_mask) & ~spi_cs_mask; // din hi, clock low
203 spi_ps_d1_c1 = spi_ps_d1_c0 | spi_cl_mask; // din hi, clock hi
204 spi_ps_d0_c1 = spi_ps_d1_c1 & ~spi_di_mask; // din low, clock hi
205 spi_ps_d0_c0 = spi_ps_d0_c1 & ~spi_cl_mask; // din low, clock hi
206 *gpio_output = spi_ps_d1_c0; // assert cs
210 /*------------------------------------------------------------------------------
211 * spi_cs_dea
213 * Deassert CS signal - send 8 clocks to release DO
215 * Notes: Complete
216 *----------------------------------------------------------------------------*/
217 static INLINE void spi_cs_dea(void) {
218 *gpio_output = spi_ps_d1_c0 | spi_cs_mask; // deassert cs (cs line hi) and clock low
219 spi_io(0xff); // 8 clocks
223 /*------------------------------------------------------------------------------
224 * spi_io
226 * Send/Receive 8 bits of data at same time.
228 * Notes: Complete
229 *----------------------------------------------------------------------------*/
230 static unsigned char spi_io(unsigned char data_out) {
231 volatile unsigned char * out = gpio_output;
232 volatile unsigned char * in = gpio_input;
233 unsigned char r = 0;
234 int i;
236 for (i = 7; i >= 0; i--) {
238 // Set data bit appropriately and toggle clock hi
239 if (data_out & (1 << i)) {
240 *out |= spi_di_mask;
241 } else {
242 *out &= ~spi_di_mask;
244 *out |= spi_cl_mask;
246 // read data from card...
247 r <<= 1;
248 r |= ((*in & spi_do_mask) ? 1 : 0);
250 // toggle clock low
251 if (spi_clk_delay) spi_freq_wait(spi_clk_delay);
252 *out &= ~spi_cl_mask;
256 return r;
260 /*------------------------------------------------------------------------------
261 * spi_mmc_cmd_r
263 * Send a command and retrieve the command response
265 * Supports commands that return r1, r3 and r7 response formats.
267 * The first byte of the response (the r1 data) is the subroutine return value.
268 * If executing commands that return additional bytes in the response (r3 and r7 formats),
269 * pass a buffer and the additional number of bytes to read in the buf and len values.
271 * Notes: Complete
272 *----------------------------------------------------------------------------*/
273 static unsigned char spi_mmc_cmd_r(unsigned char cmd, unsigned int param, unsigned char crc7, unsigned char *buf, int len) {
274 int i;
275 unsigned char r = 0;
277 // Assert CS
278 spi_cs_ass();
280 // send command, arguments, crc
281 spi_io(0x40 | cmd);
282 spi_io(param>>24);
283 spi_io(param>>16);
284 spi_io(param>>8);
285 spi_io(param);
286 spi_io(crc7);
288 // wait up to 8 bytes for command r1 response
289 for (i = 0; i < 8; i++) {
290 r = spi_io(0xff);
291 if (r != 0xff) break;
294 // return additional response bytes in buffer if requested
295 for (i = 0; i < len; i++) buf[i] = spi_io(0xff);
297 spi_cs_dea();
299 return r;
303 /*------------------------------------------------------------------------------
304 * spi_mmc_read_blk
306 * Send an mmc command that returns a single block of data
307 *----------------------------------------------------------------------------*/
308 static unsigned char spi_mmc_read_blk(unsigned char cmd, unsigned int param, unsigned char crc7, unsigned char *buf, int len) {
309 int i;
310 unsigned char r = 0;
312 // Assert CS
313 spi_cs_ass();
315 // send command, arguments, crc
316 spi_io(0x40 | cmd);
317 spi_io(param>>24);
318 spi_io(param>>16);
319 spi_io(param>>8);
320 spi_io(param);
321 spi_io(crc7);
323 // wait up to 8 bytes for command response
324 for (i = 0; i < 8; i++) {
325 r = spi_io(0xff);
326 if (r == 0x00) break;
328 if (r != 0x00) goto err1;
330 // wait for start of data token
331 for (i = 0; i < 1000000; i++) {
332 r = spi_io(0xff);
333 if (r == 0xfe) break;
335 if (r != 0xfe) goto err1;
337 // Read in data
338 for (i = 0; i < len; i++) buf[i] = spi_io(0xff);
340 // Read and discard the data packet crc bytes
341 spi_io(0xff);
342 spi_io(0xff);
344 // Deassert CS - send 8 bits to release DO
345 spi_cs_dea();
347 return 0;
349 err1:
350 spi_cs_dea();
351 return r;
355 //======================== OPTIMIZED METHODS ===================================
358 /*------------------------------------------------------------------------------
359 * spi_cs_ass_o
361 * Assert CS signal - don't care about max frequency setting
363 * Notes:
365 * -Re-read port to pick up any changes to wlan/power values.
366 * -Precalculate port states - allows bit changes via assignement (1 cycle)
367 * vs by bit operations (3 cycles)
368 *----------------------------------------------------------------------------*/
369 static INLINE void spi_cs_ass_o(void) {
370 spi_ps_d1_c0 = ((*gpio_output | spi_di_mask) & ~spi_cl_mask) & ~spi_cs_mask; // din hi, clock low
371 spi_ps_d1_c1 = spi_ps_d1_c0 | spi_cl_mask; // din hi, clock hi
372 spi_ps_d0_c1 = spi_ps_d1_c1 & ~spi_di_mask; // din low, clock hi
373 spi_ps_d0_c0 = spi_ps_d0_c1 & ~spi_cl_mask; // din low, clock hi
374 *gpio_output = spi_ps_d1_c0; // assert cs
378 /*------------------------------------------------------------------------------
379 * spi_cs_dea_o
381 * Deassert CS signal. Send 8 clocks to release DO.
383 * Notes:
384 * - Local vars out, clk_hi, clk_low improve efficiency of generated code
385 *----------------------------------------------------------------------------*/
386 static INLINE void spi_cs_dea_o(void) {
387 volatile unsigned char * out = gpio_output;
388 const unsigned char clk_hi = spi_ps_d1_c1 | spi_cs_mask;
389 const unsigned char clk_low = spi_ps_d1_c0 | spi_cs_mask;
391 *out = clk_low; // deassert cs (cs line hi) and clock low
392 *out = clk_hi; *out = clk_low;
393 *out = clk_hi; *out = clk_low;
394 *out = clk_hi; *out = clk_low;
395 *out = clk_hi; *out = clk_low;
396 *out = clk_hi; *out = clk_low;
397 *out = clk_hi; *out = clk_low;
398 *out = clk_hi; *out = clk_low;
399 *out = clk_hi; *out = clk_low;
403 /*------------------------------------------------------------------------------
404 * spi_io_ff_v_o
406 * Send 0xff - don't worry about reading response
408 * Notes:
410 * - One asm instruction per clock toggle!
411 * - Could this possibly exceed 25MHz max for clock?
412 * - Local vars out, clk_hi, clk_low improve efficiency of generated code
413 *----------------------------------------------------------------------------*/
414 static INLINE void spi_io_ff_v_o(void) {
415 volatile unsigned char * out = gpio_output;
416 const unsigned char clk_hi = spi_ps_d1_c1;
417 const unsigned char clk_low = spi_ps_d1_c0;
419 *out = clk_low; *out = clk_hi;
420 *out = clk_low; *out = clk_hi;
421 *out = clk_low; *out = clk_hi;
422 *out = clk_low; *out = clk_hi;
423 *out = clk_low; *out = clk_hi;
424 *out = clk_low; *out = clk_hi;
425 *out = clk_low; *out = clk_hi;
426 *out = clk_low; *out = clk_hi;
430 /*------------------------------------------------------------------------------
431 * spi_io_2ff_v_o
433 * Send 0xff 2 times - don't worry about reading response
435 * Notes:
437 * - Ever so slightly more efficient than calling spi_io_ff_v_o 2 times
438 *----------------------------------------------------------------------------*/
439 static INLINE void spi_io_2ff_v_o(void) {
440 volatile unsigned char * out = gpio_output;
441 const unsigned char clk_hi = spi_ps_d1_c1;
442 const unsigned char clk_low = spi_ps_d1_c0;
444 *out = clk_low; *out = clk_hi;
445 *out = clk_low; *out = clk_hi;
446 *out = clk_low; *out = clk_hi;
447 *out = clk_low; *out = clk_hi;
448 *out = clk_low; *out = clk_hi;
449 *out = clk_low; *out = clk_hi;
450 *out = clk_low; *out = clk_hi;
451 *out = clk_low; *out = clk_hi;
452 *out = clk_low; *out = clk_hi;
453 *out = clk_low; *out = clk_hi;
454 *out = clk_low; *out = clk_hi;
455 *out = clk_low; *out = clk_hi;
456 *out = clk_low; *out = clk_hi;
457 *out = clk_low; *out = clk_hi;
458 *out = clk_low; *out = clk_hi;
459 *out = clk_low; *out = clk_hi;
463 /*------------------------------------------------------------------------------
464 * spi_io_6ff_v_o
466 * Send 0xff 6 times - don't worry about reading response
468 * Notes:
470 * - Ever so slightly more efficient than calling spi_io_ff_v_o 6 times
471 *----------------------------------------------------------------------------*/
472 static INLINE void spi_io_6ff_v_o(void) {
473 volatile unsigned char * out = gpio_output;
474 const unsigned char clk_hi = spi_ps_d1_c1;
475 const unsigned char clk_low = spi_ps_d1_c0;
477 *out = clk_low; *out = clk_hi;
478 *out = clk_low; *out = clk_hi;
479 *out = clk_low; *out = clk_hi;
480 *out = clk_low; *out = clk_hi;
481 *out = clk_low; *out = clk_hi;
482 *out = clk_low; *out = clk_hi;
483 *out = clk_low; *out = clk_hi;
484 *out = clk_low; *out = clk_hi;
485 *out = clk_low; *out = clk_hi;
486 *out = clk_low; *out = clk_hi;
487 *out = clk_low; *out = clk_hi;
488 *out = clk_low; *out = clk_hi;
489 *out = clk_low; *out = clk_hi;
490 *out = clk_low; *out = clk_hi;
491 *out = clk_low; *out = clk_hi;
492 *out = clk_low; *out = clk_hi;
493 *out = clk_low; *out = clk_hi;
494 *out = clk_low; *out = clk_hi;
495 *out = clk_low; *out = clk_hi;
496 *out = clk_low; *out = clk_hi;
497 *out = clk_low; *out = clk_hi;
498 *out = clk_low; *out = clk_hi;
499 *out = clk_low; *out = clk_hi;
500 *out = clk_low; *out = clk_hi;
501 *out = clk_low; *out = clk_hi;
502 *out = clk_low; *out = clk_hi;
503 *out = clk_low; *out = clk_hi;
504 *out = clk_low; *out = clk_hi;
505 *out = clk_low; *out = clk_hi;
506 *out = clk_low; *out = clk_hi;
507 *out = clk_low; *out = clk_hi;
508 *out = clk_low; *out = clk_hi;
509 *out = clk_low; *out = clk_hi;
510 *out = clk_low; *out = clk_hi;
511 *out = clk_low; *out = clk_hi;
512 *out = clk_low; *out = clk_hi;
513 *out = clk_low; *out = clk_hi;
514 *out = clk_low; *out = clk_hi;
515 *out = clk_low; *out = clk_hi;
516 *out = clk_low; *out = clk_hi;
517 *out = clk_low; *out = clk_hi;
518 *out = clk_low; *out = clk_hi;
519 *out = clk_low; *out = clk_hi;
520 *out = clk_low; *out = clk_hi;
521 *out = clk_low; *out = clk_hi;
522 *out = clk_low; *out = clk_hi;
523 *out = clk_low; *out = clk_hi;
524 *out = clk_low; *out = clk_hi;
528 /*------------------------------------------------------------------------------
529 * spi_io_ff_o
531 * Send 0xff - read and return response.
533 * Notes:
535 * - Local vars improve efficiency of generated code
536 * - 'r' must be an int (because of the way shifting is done). Approach
537 * allows efficient read with gpio assignment via module parm. Added
538 * bonus: switch to int saves one instruction per read (5 to 4).
539 * - Final shift fixes up return value.
540 *----------------------------------------------------------------------------*/
541 static INLINE unsigned char spi_io_ff_o(void) {
542 volatile unsigned char *out = gpio_output;
543 volatile unsigned char *in = gpio_input;
544 const unsigned char clk_hi = spi_ps_d1_c1;
545 const unsigned char clk_low = spi_ps_d1_c0;
546 const unsigned char do_mask = spi_do_mask;
547 unsigned int r = 0;
549 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
550 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
551 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
552 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
553 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
554 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
555 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
556 *out = clk_low; *out=clk_hi; r |= (*in & do_mask);
558 // Fixup result - shift right based on gpio pin dout assigned to...
559 r >>= spi_do_pin;
561 return r;
564 /*------------------------------------------------------------------------------
565 * spi_io_4ff_o
567 * Send 0xffffff - read and return 32 bit response (word).
569 * Notes:
571 * - Local vars improve efficiency of generated code
572 * - Slightly more efficient than 4 calls to spi_io_ff_o
573 * - The MIPS architecture is little endian, so bytes have to be reversed in
574 * the register before the word is written to memory
575 * byte order while reading, so when bytes are reversed when the word is written
576 * to memory, they are stored correctly!
578 * e.g. Card sends the characters "abcd" as 4 bytes.
579 * Algorithm reads it into the 32 bit register as "dcba" (bytes reversed).
580 * Memory write reverses the bytes - storing "abcd" in ascending locations.
581 *----------------------------------------------------------------------------*/
582 static INLINE unsigned int spi_io_4ff_o(void) {
583 volatile unsigned char *out = gpio_output;
584 volatile unsigned char *in = gpio_input;
585 const unsigned char clk_hi = spi_ps_d1_c1;
586 const unsigned char clk_low = spi_ps_d1_c0;
587 const unsigned char do_mask = spi_do_mask;
588 const unsigned char do_pin = spi_do_pin;
589 unsigned int r = 0;
590 unsigned int w = 0;
592 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
593 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
594 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
595 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
596 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
597 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
598 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
599 *out = clk_low; *out=clk_hi; r |= (*in & do_mask);
600 r >>= do_pin; w |= r; r = 0;
601 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
602 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
603 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
604 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
605 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
606 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
607 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
608 *out = clk_low; *out=clk_hi; r |= (*in & do_mask);
609 r >>= do_pin; r <<= 8; w |= r; r = 0;
610 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
611 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
612 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
613 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
614 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
615 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
616 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
617 *out = clk_low; *out=clk_hi; r |= (*in & do_mask);
618 r >>= do_pin; r <<= 16; w |= r; r = 0;
619 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
620 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
621 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
622 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
623 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
624 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
625 *out = clk_low; *out=clk_hi; r |= (*in & do_mask); r <<= 1;
626 *out = clk_low; *out=clk_hi; r |= (*in & do_mask);
627 r >>= do_pin; r <<= 24; w |= r;
629 return w;
633 /*------------------------------------------------------------------------------
634 * spi_io_v_o
636 * Send 8 bits of data - don't worry about reading response.
638 * Notes:
640 * - Local vars improve efficiency of generated code
641 * - if structures - larger code size, but less instructions per bit written
642 * than attempting to use bit shift/and/or instructions...
643 *----------------------------------------------------------------------------*/
644 static INLINE void spi_io_v_o(unsigned char data_out) {
645 volatile unsigned char * out = gpio_output;
646 const unsigned int d1_c0 = spi_ps_d1_c0;
647 const unsigned int d1_c1 = spi_ps_d1_c1;
648 const unsigned int d0_c0 = spi_ps_d0_c0;
649 const unsigned int d0_c1 = spi_ps_d0_c1;
651 if (data_out & (1 << 7)) { *out = d1_c0; *out = d1_c1; } else { *out = d0_c0; *out = d0_c1; }
652 if (data_out & (1 << 6)) { *out = d1_c0; *out = d1_c1; } else { *out = d0_c0; *out = d0_c1; }
653 if (data_out & (1 << 5)) { *out = d1_c0; *out = d1_c1; } else { *out = d0_c0; *out = d0_c1; }
654 if (data_out & (1 << 4)) { *out = d1_c0; *out = d1_c1; } else { *out = d0_c0; *out = d0_c1; }
655 if (data_out & (1 << 3)) { *out = d1_c0; *out = d1_c1; } else { *out = d0_c0; *out = d0_c1; }
656 if (data_out & (1 << 2)) { *out = d1_c0; *out = d1_c1; } else { *out = d0_c0; *out = d0_c1; }
657 if (data_out & (1 << 1)) { *out = d1_c0; *out = d1_c1; } else { *out = d0_c0; *out = d0_c1; }
658 if (data_out & (1 << 0)) { *out = d1_c0; *out = d1_c1; } else { *out = d0_c0; *out = d0_c1; }
662 /*------------------------------------------------------------------------------
663 * spi_mmc_write_multi_o
665 * Write multiple 512 byte blocks from buffer with the multi block write CMD25
667 * Return Codes:
669 * 0 - Successful write
670 * 1 - Busy wait timeout
671 * 2 - CMD25 (multi block write) error
672 * 3 - Data response token not received
673 * 4 - Data response token - busy error
674 * 11 - Data rejected due to crc error
675 * 14 - Data rejected due to write error
677 * Notes:
679 * - Local vars improve efficiency of generated code
680 * - Possible improvements - unsigned int array - send 32 bits at a time
681 * - Try pre-erase command and analyze effect
682 *----------------------------------------------------------------------------*/
683 static INLINE unsigned char spi_mmc_write_multi_o(unsigned int addr, unsigned char *buf, int blocks, unsigned char first, unsigned char last) {
684 volatile unsigned char *in = gpio_input;
685 volatile unsigned char *out = gpio_output;
686 const unsigned char clk_hi = spi_ps_d1_c1;
687 const unsigned char clk_low = spi_ps_d1_c0;
688 const unsigned int do_mask = spi_do_mask;
689 unsigned char *p = buf;
690 int err = 0;
691 int r = 0;
692 int i,j;
694 // Only send the multi block write if first first buffer in a request
695 // Otherwise it's a continuation of an already running request
696 if (first) {
698 // send multi block write command, address, crc
699 spi_cs_ass_o();
700 spi_io_v_o(0x40 | 25);
701 spi_io_v_o(addr>>24);
702 spi_io_v_o(addr>>16);
703 spi_io_v_o(addr>>8);
704 spi_io_v_o(addr);
705 spi_io_ff_v_o();
707 // wait up to 8 bytes for command response
708 for (i = 0; i < 8; i++) {
709 r = spi_io_ff_o();
710 if (r == 0x00) break;
712 if (r != 0x00) return 2;
715 // process each block in a loop
716 for (j=0; j < blocks; j++) {
718 // write start of data token
719 spi_io_v_o(0xfc);
721 // write data block
722 for (i = 0; i < 512; i++) {
723 spi_io_v_o(*p);
724 *p++;
727 // write dummy crc (2 bytes)
728 spi_io_2ff_v_o();
730 // wait up to 9 bytes for data response token
731 for (i = 0; i < 29; i++) {
732 r = spi_io_ff_o();
733 if (r != 0xff) break;
735 if ((r & 0x0f) != 0x05) {
736 if (r == 0xff)
737 err = 3;
738 else if (r == 0x00)
739 err = 4;
740 else
741 err = r & 0x0f;
742 break;
745 // Busy state follows data response token (dout pulled low).
746 // Keep the clock running until it's done..
747 *out = clk_low;
748 for (i = 1; i < 1000000; i++) {
749 *out = clk_low; *out = clk_hi;
750 *out = clk_low; *out = clk_hi;
751 *out = clk_low; *out = clk_hi;
752 *out = clk_low; *out = clk_hi;
753 *out = clk_low; *out = clk_hi;
754 *out = clk_low; *out = clk_hi;
755 *out = clk_low; *out = clk_hi;
756 *out = clk_low; *out = clk_hi;
757 if (*in & do_mask) break;
758 yield();
760 LOG_DEBUG(DBG_BUSY, "Write_multi: Data response busy: %d clock cycles\n",i * 8);
763 // Only send the stop transmission if last buffer, otherwise we'll be called again
764 // with the next buffer.
765 if (last) {
767 // send stop transmission token + 1 byte till busy flag appears
768 spi_io_v_o(0xfd);
769 spi_io_ff_v_o();
771 // Busy state follows stop transmission token (dout pulled low).
772 // Keep the clock running until it's done..
773 for (i = 1; i < 1000000; i++) {
774 *out = clk_low; *out = clk_hi;
775 *out = clk_low; *out = clk_hi;
776 *out = clk_low; *out = clk_hi;
777 *out = clk_low; *out = clk_hi;
778 *out = clk_low; *out = clk_hi;
779 *out = clk_low; *out = clk_hi;
780 *out = clk_low; *out = clk_hi;
781 *out = clk_low; *out = clk_hi;
782 if (*in & do_mask) break;
783 yield();
785 LOG_DEBUG(DBG_BUSY, "Write_multi: Stop tran busy: %d clock cycles\n",i * 8);
787 spi_cs_dea_o();
790 return err;
794 /*------------------------------------------------------------------------------
795 * spi_mmc_read_multi_o
797 * Read multiple 512 byte blocks into a buffer with the multi block read CMD18
799 * Return Codes:
801 * 0 - Successful write
802 * 1 - Busy wait timeout
803 * 2 - CMD18 (multi block read) error
804 * 3 - Start of data packet not received
805 * 11 - Data rejected due to crc error
806 * 14 - Data rejected due to write error
808 * Notes:
810 * - Local vars improve efficiency of generated code
811 * - Possible improvements - unsigned int array - send 32 bits at a time
812 * read 32 bits at at time...
813 *----------------------------------------------------------------------------*/
814 static INLINE unsigned char spi_mmc_read_multi_o(unsigned int addr, unsigned char *buf, int blocks, unsigned char first, unsigned char last) {
815 volatile unsigned char *in = gpio_input;
816 volatile unsigned char *out = gpio_output;
817 const unsigned char clk_hi = spi_ps_d1_c1;
818 const unsigned char clk_low = spi_ps_d1_c0;
819 const unsigned int do_mask = spi_do_mask;
820 unsigned int *p;
821 int r = 0;
822 int err = 0;
823 int i,j;
825 p = (unsigned int *) buf; // Cast to an int pointer for 32bit io...
827 // Only send the multi block write if first first buffer in a request
828 // Otherwise it's a continuation of an already running request
829 if (first) {
831 // send multi block read command, address, crc
832 spi_cs_ass_o();
833 spi_io_v_o(0x40 | 18);
834 spi_io_v_o(addr>>24);
835 spi_io_v_o(addr>>16);
836 spi_io_v_o(addr>>8);
837 spi_io_v_o(addr);
838 spi_io_ff_v_o();
840 // wait up to 8 bytes for command response
841 for (i = 0; i < 8; i++) {
842 r = spi_io_ff_o();
843 if (r == 0x00) break;
845 if (r != 0x00) goto err2;
848 // process each block in a loop
849 for (j=0; j < blocks; j++) {
851 // wait for start of data token
852 for (i = 1; i < 1000000; i++) {
853 r = spi_io_ff_o();
854 if (r != 0xff) break;
856 if (r != 0xfe) {
857 err = 3;
858 break;
860 LOG_DEBUG(DBG_BUSY, "Read_multi: Data token busy: %d clock cycles\n",i * 8);
862 // Read in data block a word at a time. Reduce looping overhead by doing
863 // multiple reads per an iteration of the loop.
864 for (i = 0; i < 512/4/4; i++) {
865 *p = spi_io_4ff_o(); p++;
866 *p = spi_io_4ff_o(); p++;
867 *p = spi_io_4ff_o(); p++;
868 *p = spi_io_4ff_o(); p++;
871 // Read and discard the data packet crc bytes
872 spi_io_2ff_v_o();
875 // Only send the stop transmission if last buffer, otherwise we'll be called again
876 // with the next buffer.
877 if (last) {
879 // send stop transmission command, parm, crc and skip following stuff byte.
880 spi_io_v_o(0x40 | 12);
881 spi_io_6ff_v_o(); // parm (4) - crc (1) - stuff byte (1)
883 // wait up to 8 bytes for command response
884 for (i = 0; i < 8; i++) {
885 r = spi_io_ff_o();
886 if (r == 0x00) break;
888 if (r != 0x00) err=4;
890 // Busy state can follow CMD12
891 *out = clk_low;
892 for (i = 1; i < 1000000; i++) {
893 *out = clk_low; *out = clk_hi;
894 *out = clk_low; *out = clk_hi;
895 *out = clk_low; *out = clk_hi;
896 *out = clk_low; *out = clk_hi;
897 *out = clk_low; *out = clk_hi;
898 *out = clk_low; *out = clk_hi;
899 *out = clk_low; *out = clk_hi;
900 *out = clk_low; *out = clk_hi;
901 if (*in & do_mask) break;
902 yield();
904 LOG_DEBUG(DBG_BUSY, "Read_multi: Stop tran busy: %d clock cycles\n",i * 8);
905 if ((*in & do_mask) == 0) goto err1;
907 spi_cs_dea_o();
910 return err;
912 err2:
913 err++;
914 err1:
915 err++;
916 spi_cs_dea_o();
917 return err;