summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/ata_mmc.c260
1 files changed, 192 insertions, 68 deletions
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c
index ea7c5f1737..54cb275a0d 100644
--- a/firmware/drivers/ata_mmc.c
+++ b/firmware/drivers/ata_mmc.c
@@ -79,9 +79,6 @@
79#define DT_START_WRITE_MULTIPLE 0xfc 79#define DT_START_WRITE_MULTIPLE 0xfc
80#define DT_STOP_TRAN 0xfd 80#define DT_STOP_TRAN 0xfd
81 81
82// DEBUG
83#include "../../apps/screens.h"
84
85/* for compatibility */ 82/* for compatibility */
86bool old_recorder = false; /* FIXME: get rid of this cross-dependency */ 83bool old_recorder = false; /* FIXME: get rid of this cross-dependency */
87int ata_spinup_time = 0; 84int ata_spinup_time = 0;
@@ -101,19 +98,30 @@ static bool delayed_write = false;
101static unsigned char delayed_sector[SECTOR_SIZE]; 98static unsigned char delayed_sector[SECTOR_SIZE];
102static int delayed_sector_num; 99static int delayed_sector_num;
103 100
104static int current_card = 0; 101static enum {
102 SER_POLL_WRITE,
103 SER_POLL_READ,
104 SER_DISABLED
105} serial_mode;
105 106
106static const unsigned char dummy[] = { 107static const unsigned char dummy[] = {
107 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 108 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
108}; 109};
109 110
111/* 2 buffers for writing, include start token and dummy crc and an extra
112 * byte to keep word alignment */
113static unsigned char sector_buffer[2][(SECTOR_SIZE+4)];
114static int current_buffer = 0;
115
110static tCardInfo card_info[2]; 116static tCardInfo card_info[2];
117static int current_card = 0;
111 118
112/* private function declarations */ 119/* private function declarations */
113 120
114static int select_card(int card_no); 121static int select_card(int card_no);
115static void deselect_card(void); 122static void deselect_card(void);
116static void setup_sci1(int bitrate_register); 123static void setup_sci1(int bitrate_register);
124static void set_sci1_poll_read(void);
117static void write_transfer(const unsigned char *buf, int len) 125static void write_transfer(const unsigned char *buf, int len)
118 __attribute__ ((section(".icode"))); 126 __attribute__ ((section(".icode")));
119static void read_transfer(unsigned char *buf, int len) 127static void read_transfer(unsigned char *buf, int len)
@@ -121,10 +129,13 @@ static void read_transfer(unsigned char *buf, int len)
121static unsigned char poll_byte(int timeout); 129static unsigned char poll_byte(int timeout);
122static unsigned char poll_busy(int timeout); 130static unsigned char poll_busy(int timeout);
123static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); 131static int send_cmd(int cmd, unsigned long parameter, unsigned char *response);
124static int receive_data(unsigned char *buf, int len, int timeout); 132static int receive_cxd(unsigned char *buf);
125static int send_data(char start_token, const unsigned char *buf, int len,
126 int timeout);
127static int initialize_card(int card_no); 133static int initialize_card(int card_no);
134static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf,
135 int timeout);
136static void swapcopy_sector(const unsigned char *buf);
137static int send_sector(const unsigned char *nextbuf, int timeout);
138static int send_single_sector(const unsigned char *buf, int timeout);
128 139
129/* implementation */ 140/* implementation */
130 141
@@ -170,19 +181,25 @@ static void deselect_card(void)
170 181
171static void setup_sci1(int bitrate_register) 182static void setup_sci1(int bitrate_register)
172{ 183{
173 int i;
174
175 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ 184 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
176 185
177 SCR1 = 0; /* disable serial port */ 186 SCR1 = 0; /* disable serial port */
178 SMR1 = SYNC_MODE; /* no prescale */ 187 SMR1 = SYNC_MODE; /* no prescale */
179 BRR1 = bitrate_register; 188 BRR1 = bitrate_register;
180 SCR1 = SCI_CKE0;
181 SSR1 = 0; 189 SSR1 = 0;
182 190
183 for (i = 0; i <= bitrate_register; i++); /* wait at least one bit time */ 191 SCR1 = SCI_TE; /* enable transmitter */
184 192 serial_mode = SER_POLL_WRITE;
185 or_b((SCI_TE|SCI_RE), &SCR1); /* enable transmitter & receiver */ 193}
194
195static void set_sci1_poll_read(void)
196{
197 while(!(SSR1 & SCI_TEND)); /* wait for end of transfer */
198 SCR1 = 0; /* disable transmitter (& receiver) */
199 SCR1 = (SCI_TE|SCI_RE); /* re-enable transmitter & receiver */
200 while(!(SSR1 & SCI_TEND)); /* wait for SCI init completion (!) */
201 serial_mode = SER_POLL_READ;
202 TDR1 = 0xFF; /* send do-nothing while reading */
186} 203}
187 204
188static void write_transfer(const unsigned char *buf, int len) 205static void write_transfer(const unsigned char *buf, int len)
@@ -190,12 +207,19 @@ static void write_transfer(const unsigned char *buf, int len)
190 const unsigned char *buf_end = buf + len; 207 const unsigned char *buf_end = buf + len;
191 register unsigned char data; 208 register unsigned char data;
192 209
193 /* TODO: DMA */ 210 if (serial_mode != SER_POLL_WRITE)
194 211 {
212 while(!(SSR1 & SCI_TEND)); /* wait for end of transfer */
213 SCR1 = 0; /* disable transmitter & receiver */
214 SSR1 = 0; /* clear all flags */
215 SCR1 = SCI_TE; /* enable transmitter only */
216 serial_mode = SER_POLL_WRITE;
217 }
218
195 while (buf < buf_end) 219 while (buf < buf_end)
196 { 220 {
197 data = fliptable[(signed char)(*buf++)]; /* bitswap */ 221 data = fliptable[(signed char)(*buf++)]; /* bitswap */
198 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ 222 while (!(SSR1 & SCI_TDRE)); /* wait for end of transfer */
199 TDR1 = data; /* write byte */ 223 TDR1 = data; /* write byte */
200 SSR1 = 0; /* start transmitting */ 224 SSR1 = 0; /* start transmitting */
201 } 225 }
@@ -207,11 +231,9 @@ static void read_transfer(unsigned char *buf, int len)
207 unsigned char *buf_end = buf + len - 1; 231 unsigned char *buf_end = buf + len - 1;
208 register signed char data; 232 register signed char data;
209 233
210 /* TODO: DMA */ 234 if (serial_mode != SER_POLL_READ)
235 set_sci1_poll_read();
211 236
212 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
213 TDR1 = 0xFF; /* send do-nothing data in parallel */
214
215 SSR1 = 0; /* start receiving first byte */ 237 SSR1 = 0; /* start receiving first byte */
216 while (buf < buf_end) 238 while (buf < buf_end)
217 { 239 {
@@ -229,8 +251,8 @@ static unsigned char poll_byte(int timeout) /* timeout is in bytes */
229 int i; 251 int i;
230 unsigned char data = 0; /* stop the compiler complaining */ 252 unsigned char data = 0; /* stop the compiler complaining */
231 253
232 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */ 254 if (serial_mode != SER_POLL_READ)
233 TDR1 = 0xFF; /* send do-nothing data in parallel */ 255 set_sci1_poll_read();
234 256
235 i = 0; 257 i = 0;
236 do { 258 do {
@@ -247,8 +269,8 @@ static unsigned char poll_busy(int timeout) /* timeout is in bytes */
247 int i; 269 int i;
248 unsigned char data, dummy; 270 unsigned char data, dummy;
249 271
250 while (!(SSR1 &SCI_TEND)); /* wait for end of transfer */ 272 if (serial_mode != SER_POLL_READ)
251 TDR1 = 0xFF; /* send do-nothing data in parallel */ 273 set_sci1_poll_read();
252 274
253 /* get data response */ 275 /* get data response */
254 SSR1 = 0; /* start receiving */ 276 SSR1 = 0; /* start receiving */
@@ -266,6 +288,7 @@ static unsigned char poll_busy(int timeout) /* timeout is in bytes */
266 return data; 288 return data;
267} 289}
268 290
291/* Send MMC command and get response */
269static int send_cmd(int cmd, unsigned long parameter, unsigned char *response) 292static int send_cmd(int cmd, unsigned long parameter, unsigned char *response)
270{ 293{
271 unsigned char command[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF}; 294 unsigned char command[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF};
@@ -283,7 +306,7 @@ static int send_cmd(int cmd, unsigned long parameter, unsigned char *response)
283 write_transfer(command, 7); 306 write_transfer(command, 7);
284 307
285 response[0] = poll_byte(20); 308 response[0] = poll_byte(20);
286 309
287 if (response[0] != 0x00) 310 if (response[0] != 0x00)
288 { 311 {
289 write_transfer(dummy, 1); 312 write_transfer(dummy, 1);
@@ -316,38 +339,18 @@ static int send_cmd(int cmd, unsigned long parameter, unsigned char *response)
316 return 0; 339 return 0;
317} 340}
318 341
319static int receive_data(unsigned char *buf, int len, int timeout) 342/* Receive CID/ CSD data (16 bytes) */
343static int receive_cxd(unsigned char *buf)
320{ 344{
321 unsigned char crc[2]; /* unused */ 345 if (poll_byte(20) != DT_START_BLOCK)
322
323 if (poll_byte(timeout) != DT_START_BLOCK)
324 { 346 {
325 write_transfer(dummy, 1); 347 write_transfer(dummy, 1);
326 return -1; /* not start of data */ 348 return -1; /* not start of data */
327 } 349 }
328
329 read_transfer(buf, len);
330 read_transfer(crc, 2); /* throw away */
331 write_transfer(dummy, 1);
332
333 return 0;
334}
335
336static int send_data(char start_token, const unsigned char *buf, int len,
337 int timeout)
338{
339 int ret = 0;
340
341 write_transfer(&start_token, 1);
342 write_transfer(buf, len);
343 write_transfer(dummy, 2); /* crc - dontcare */
344
345 if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */
346 ret = -1;
347
348 write_transfer(dummy, 1);
349 350
350 return ret; 351 read_transfer(buf, 16);
352 write_transfer(dummy, 3); /* 2 bytes dontcare crc + 1 byte trailer */
353 return 0;
351} 354}
352 355
353/* helper function to extract n (<=32) bits from an arbitrary position. 356/* helper function to extract n (<=32) bits from an arbitrary position.
@@ -423,7 +426,7 @@ static int initialize_card(int card_no)
423 /* get CSD register */ 426 /* get CSD register */
424 if (send_cmd(CMD_SEND_CSD, 0, response)) 427 if (send_cmd(CMD_SEND_CSD, 0, response))
425 return -5; 428 return -5;
426 if (receive_data((unsigned char*)card->csd, 16, 20)) 429 if (receive_cxd((unsigned char*)card->csd))
427 return -6; 430 return -6;
428 431
429 /* check block size */ 432 /* check block size */
@@ -459,7 +462,7 @@ static int initialize_card(int card_no)
459 /* get CID register */ 462 /* get CID register */
460 if (send_cmd(CMD_SEND_CID, 0, response)) 463 if (send_cmd(CMD_SEND_CID, 0, response))
461 return -8; 464 return -8;
462 if (receive_data((unsigned char*)card->cid, 16, 20)) 465 if (receive_cxd((unsigned char*)card->cid))
463 return -9; 466 return -9;
464 467
465 card->initialized = true; 468 card->initialized = true;
@@ -478,6 +481,119 @@ tCardInfo *mmc_card_info(int card_no)
478 return card; 481 return card;
479} 482}
480 483
484/* Receive one sector with dma, possibly swapping the previously received
485 * sector in the background */
486static int receive_sector(unsigned char *inbuf, unsigned char *swapbuf,
487 int timeout)
488{
489 if (poll_byte(timeout) != DT_START_BLOCK)
490 {
491 write_transfer(dummy, 1);
492 return -1; /* not start of data */
493 }
494
495 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
496
497 SCR1 = 0; /* disable serial */
498 SSR1 = 0; /* clear all flags */
499
500 /* setup DMA channel 2 */
501 CHCR2 = 0; /* disable */
502 SAR2 = RDR1_ADDR;
503 DAR2 = (unsigned long) inbuf;
504 DTCR2 = SECTOR_SIZE;
505 CHCR2 = 0x4601; /* fixed source address, RXI1, enable */
506 DMAOR = 0x0001;
507 SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */
508
509 /* dma receives 2 bytes more than DTCR2, but the last 2 bytes are not
510 * stored. The first extra byte is available from RDR1 after the DMA ends,
511 * the second one is lost because of the SCI overrun. However, this
512 * behaviour conveniently discards the crc. */
513
514 if (swapbuf != NULL) /* bitswap previous sector */
515 bitswap(swapbuf, SECTOR_SIZE);
516 yield(); /* be nice */
517
518 while (!(CHCR2 & 0x0002)); /* wait for end of DMA */
519 while (!(SSR1 & SCI_ORER)); /* wait for the trailing bytes */
520 SCR1 = 0;
521 serial_mode = SER_DISABLED;
522
523 write_transfer(dummy, 1); /* send trailer */
524 return 0;
525}
526
527/* copies one sector into the next-current write buffer, then bitswaps */
528static void swapcopy_sector(const unsigned char *buf)
529{
530 unsigned char *curbuf;
531
532 current_buffer ^= 1; /* toggles between 0 and 1 */
533
534 curbuf = sector_buffer[current_buffer];
535 curbuf[1] = DT_START_WRITE_MULTIPLE;
536 curbuf[(SECTOR_SIZE+2)] = curbuf[(SECTOR_SIZE+3)] = 0xFF; /* dummy crc */
537 memcpy(curbuf + 2, buf, SECTOR_SIZE);
538 bitswap(curbuf + 1, (SECTOR_SIZE+1));
539}
540
541/* Send one sector with dma from the current sector buffer, possibly preparing
542 * the next sector within the other sector buffer in the background. Use
543 * for multisector transfer only */
544static int send_sector(const unsigned char *nextbuf, int timeout)
545{
546 int ret = 0;
547
548 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
549
550 SCR1 = 0; /* disable serial */
551 SSR1 = 0; /* clear all flags */
552
553 /* setup DMA channel 2 */
554 CHCR2 = 0; /* disable */
555 SAR2 = (unsigned long)(sector_buffer[current_buffer] + 1);
556 DAR2 = TDR1_ADDR;
557 DTCR2 = (SECTOR_SIZE+3);
558 CHCR2 = 0x1701; /* fixed dest. address, TXI1, enable */
559 DMAOR = 0x0001;
560 SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */
561
562 if (nextbuf != NULL) /* prepare next sector */
563 swapcopy_sector(nextbuf);
564 yield(); /* be nice */
565
566 while (!(CHCR2 & 0x0002)); /* wait for end of DMA */
567 while (!(SSR1 & SCI_TEND)); /* wait for end of transfer */
568 SCR1 = 0;
569 serial_mode = SER_DISABLED;
570
571 if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */
572 ret = -1;
573
574 write_transfer(dummy, 1);
575
576 return ret;
577}
578
579/* Send one sector with polled i/o. Use for single sector transfers only. */
580static int send_single_sector(const unsigned char *buf, int timeout)
581{
582 int ret = 0;
583 unsigned char start_token = DT_START_BLOCK;
584
585 write_transfer(&start_token, 1);
586 write_transfer(buf, SECTOR_SIZE);
587 write_transfer(dummy, 2); /* crc - dontcare */
588
589 if ((poll_busy(timeout) & 0x1F) != 0x05) /* something went wrong */
590 ret = -1;
591
592 write_transfer(dummy, 1);
593
594 return ret;
595}
596
481int ata_read_sectors(unsigned long start, 597int ata_read_sectors(unsigned long start,
482 int incount, 598 int incount,
483 void* inbuf) 599 void* inbuf)
@@ -486,8 +602,9 @@ int ata_read_sectors(unsigned long start,
486 int i; 602 int i;
487 unsigned long addr; 603 unsigned long addr;
488 unsigned char response; 604 unsigned char response;
605 void *inbuf_prev = NULL;
489 tCardInfo *card = &card_info[current_card]; 606 tCardInfo *card = &card_info[current_card];
490 607
491 addr = start * SECTOR_SIZE; 608 addr = start * SECTOR_SIZE;
492 609
493 mutex_lock(&mmc_mutex); 610 mutex_lock(&mmc_mutex);
@@ -499,21 +616,27 @@ int ata_read_sectors(unsigned long start,
499 { 616 {
500 ret = send_cmd(CMD_READ_SINGLE_BLOCK, addr, &response); 617 ret = send_cmd(CMD_READ_SINGLE_BLOCK, addr, &response);
501 if (ret == 0) 618 if (ret == 0)
502 ret = receive_data(inbuf, SECTOR_SIZE, card->read_timeout); 619 {
620 ret = receive_sector(inbuf, inbuf_prev, card->read_timeout);
621 inbuf_prev = inbuf;
503 last_disk_activity = current_tick; 622 last_disk_activity = current_tick;
623 }
504 } 624 }
505 else 625 else
506 { 626 {
507 ret = send_cmd(CMD_READ_MULTIPLE_BLOCK, addr, &response); 627 ret = send_cmd(CMD_READ_MULTIPLE_BLOCK, addr, &response);
508 for (i = 0; (i < incount) && (ret == 0); i++) 628 for (i = 0; (i < incount) && (ret == 0); i++)
509 { 629 {
510 ret = receive_data(inbuf, SECTOR_SIZE, card->read_timeout); 630 ret = receive_sector(inbuf, inbuf_prev, card->read_timeout);
631 inbuf_prev = inbuf;
511 inbuf += SECTOR_SIZE; 632 inbuf += SECTOR_SIZE;
512 last_disk_activity = current_tick; 633 last_disk_activity = current_tick;
513 } 634 }
514 if (ret == 0) 635 if (ret == 0)
515 ret = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); 636 ret = send_cmd(CMD_STOP_TRANSMISSION, 0, &response);
516 } 637 }
638 if (ret == 0)
639 bitswap(inbuf_prev, SECTOR_SIZE);
517 } 640 }
518 641
519 deselect_card(); 642 deselect_card();
@@ -550,25 +673,28 @@ int ata_write_sectors(unsigned long start,
550 { 673 {
551 ret = send_cmd(CMD_WRITE_BLOCK, addr, &response); 674 ret = send_cmd(CMD_WRITE_BLOCK, addr, &response);
552 if (ret == 0) 675 if (ret == 0)
553 ret = send_data(DT_START_BLOCK, buf, SECTOR_SIZE, 676 ret = send_single_sector(buf, card->write_timeout);
554 card->write_timeout);
555 last_disk_activity = current_tick; 677 last_disk_activity = current_tick;
556 } 678 }
557 else 679 else
558 { 680 {
681 swapcopy_sector(buf); /* prepare first sector */
559 ret = send_cmd(CMD_WRITE_MULTIPLE_BLOCK, addr, &response); 682 ret = send_cmd(CMD_WRITE_MULTIPLE_BLOCK, addr, &response);
560 for (i = 0; (i < count) && (ret == 0); i++) 683 for (i = 1; (i < count) && (ret == 0); i++)
561 { 684 {
562 ret = send_data(DT_START_WRITE_MULTIPLE, buf, SECTOR_SIZE,
563 card->write_timeout);
564 buf += SECTOR_SIZE; 685 buf += SECTOR_SIZE;
686 ret = send_sector(buf, card->write_timeout);
565 last_disk_activity = current_tick; 687 last_disk_activity = current_tick;
566 } 688 }
567 if (ret == 0) 689 if (ret == 0)
568 { 690 {
569 response = DT_STOP_TRAN; 691 ret = send_sector(NULL, card->write_timeout);
570 write_transfer(&response, 1); 692 if (ret == 0)
571 poll_busy(card->write_timeout); 693 {
694 response = DT_STOP_TRAN;
695 write_transfer(&response, 1);
696 poll_busy(card->write_timeout);
697 }
572 last_disk_activity = current_tick; 698 last_disk_activity = current_tick;
573 } 699 }
574 } 700 }
@@ -656,9 +782,7 @@ static void mmc_thread(void)
656 782
657int ata_soft_reset(void) 783int ata_soft_reset(void)
658{ 784{
659 int ret = 0; 785 return 0;
660
661 return ret;
662} 786}
663 787
664void ata_enable(bool on) 788void ata_enable(bool on)
@@ -706,7 +830,7 @@ int ata_init(void)
706 } 830 }
707 831
708 ata_enable(true); 832 ata_enable(true);
709 833
710 if ( !initialized ) { 834 if ( !initialized ) {
711 835
712 queue_init(&mmc_queue); 836 queue_init(&mmc_queue);