summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2008-09-14 23:38:31 +0000
committerJens Arnold <amiconn@rockbox.org>2008-09-14 23:38:31 +0000
commit36e311f68b3c332738187affad155a2851cf6934 (patch)
tree09c45718f7deeb709d83b063ef4aacd30a2b5a1d /firmware/drivers
parentb1a584a1b6fbc3d16d7dbbd8f2fac857a1332f60 (diff)
downloadrockbox-36e311f68b3c332738187affad155a2851cf6934.tar.gz
rockbox-36e311f68b3c332738187affad155a2851cf6934.zip
Implement chasing bitswap for reading. Speeds up reading single 512-byte blocks by 15..20%. * Restructure the write buffer handling a bit, making it more readable and a bit smaller. Also fixes an old corner case bug: writing data from address 0x0 (archos boot ROM dump) would have written wrong data.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18516 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/ata_mmc.c111
1 files changed, 54 insertions, 57 deletions
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c
index da9f0d69fe..6c3f1f6775 100644
--- a/firmware/drivers/ata_mmc.c
+++ b/firmware/drivers/ata_mmc.c
@@ -120,13 +120,9 @@ static const unsigned char dummy[] = {
120 120
121/* 2 buffers used alternatively for writing, including start token, 121/* 2 buffers used alternatively for writing, including start token,
122 * dummy CRC and an extra byte to keep word alignment. */ 122 * dummy CRC and an extra byte to keep word alignment. */
123static unsigned char block_buffer[2][BLOCK_SIZE+4]; 123static unsigned char write_buffer[2][BLOCK_SIZE+4];
124static int current_buffer = 0; 124static int current_buffer = 0;
125 125static const unsigned char *send_block_addr = NULL;
126/* globals for background copy and swap */
127static const unsigned char *bcs_src = NULL;
128static unsigned char *bcs_dest = NULL;
129static unsigned long bcs_len = 0;
130 126
131static tCardInfo card_info[2]; 127static tCardInfo card_info[2];
132#ifndef HAVE_MULTIVOLUME 128#ifndef HAVE_MULTIVOLUME
@@ -152,9 +148,10 @@ static unsigned char poll_busy(long timeout);
152static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); 148static int send_cmd(int cmd, unsigned long parameter, unsigned char *response);
153static int receive_cxd(unsigned char *buf); 149static int receive_cxd(unsigned char *buf);
154static int initialize_card(int card_no); 150static int initialize_card(int card_no);
155static void bg_copy_swap(void);
156static int receive_block(unsigned char *inbuf, long timeout); 151static int receive_block(unsigned char *inbuf, long timeout);
157static int send_block(unsigned char start_token, long timeout); 152static void send_block_prepare(void);
153static int send_block_send(unsigned char start_token, long timeout,
154 bool prepare_next);
158static void mmc_tick(void); 155static void mmc_tick(void);
159 156
160/* implementation */ 157/* implementation */
@@ -504,32 +501,11 @@ tCardInfo *mmc_card_info(int card_no)
504 return card; 501 return card;
505} 502}
506 503
507/* Copy and swap in the background 504/* Receive one block with DMA and bitswap it (chasing bitswap). */
508 * If destination is NULL, use the next block buffer */
509static void bg_copy_swap(void)
510{
511 if (!bcs_len)
512 return;
513
514 if (!bcs_dest)
515 {
516 current_buffer ^= 1; /* toggle buffer */
517 bcs_dest = block_buffer[current_buffer] + 2;
518 }
519 if (bcs_src)
520 {
521 memcpy(bcs_dest, bcs_src, bcs_len);
522 bcs_src += bcs_len;
523 }
524 bitswap(bcs_dest, bcs_len);
525 bcs_dest += bcs_len;
526 bcs_len = 0;
527}
528
529/* Receive one block with dma, possibly swapping the previously received
530 * block in the background */
531static int receive_block(unsigned char *inbuf, long timeout) 505static int receive_block(unsigned char *inbuf, long timeout)
532{ 506{
507 unsigned long buf_end;
508
533 if (poll_byte(timeout) != DT_START_BLOCK) 509 if (poll_byte(timeout) != DT_START_BLOCK)
534 { 510 {
535 write_transfer(dummy, 1); 511 write_transfer(dummy, 1);
@@ -549,14 +525,28 @@ static int receive_block(unsigned char *inbuf, long timeout)
549 CHCR0 = 0x4601; /* fixed source address, RXI1, enable */ 525 CHCR0 = 0x4601; /* fixed source address, RXI1, enable */
550 DMAOR = 0x0001; 526 DMAOR = 0x0001;
551 SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */ 527 SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */
552 528
553 /* dma receives 2 bytes more than DTCR2, but the last 2 bytes are not 529 /* DMA receives 2 bytes more than DTCR2, but the last 2 bytes are not
554 * stored. The first extra byte is available from RDR1 after the DMA ends, 530 * stored. The first extra byte is available from RDR1 after the DMA ends,
555 * the second one is lost because of the SCI overrun. However, this 531 * the second one is lost because of the SCI overrun. However, this
556 * behaviour conveniently discards the crc. */ 532 * behaviour conveniently discards the crc. */
557 533
558 bg_copy_swap();
559 yield(); /* be nice */ 534 yield(); /* be nice */
535
536 /* Bitswap received data, chasing the DMA pointer */
537 buf_end = (unsigned long)inbuf + BLOCK_SIZE;
538 do
539 {
540 /* Call bitswap whenever (a multiple of) 8 bytes are
541 * available (value optimised by experimentation). */
542 int swap_now = (DAR0 - (unsigned long)inbuf) & ~0x00000007;
543 if (swap_now)
544 {
545 bitswap(inbuf, swap_now);
546 inbuf += swap_now;
547 }
548 }
549 while ((unsigned long)inbuf < buf_end);
560 550
561 while (!(CHCR0 & 0x0002)); /* wait for end of DMA */ 551 while (!(CHCR0 & 0x0002)); /* wait for end of DMA */
562 while (!(SSR1 & SCI_ORER)); /* wait for the trailing bytes */ 552 while (!(SSR1 & SCI_ORER)); /* wait for the trailing bytes */
@@ -568,13 +558,29 @@ static int receive_block(unsigned char *inbuf, long timeout)
568 return 0; 558 return 0;
569} 559}
570 560
571/* Send one block with dma from the current block buffer, possibly preparing 561/* Prepare a block for sending by copying it to the next write buffer
572 * the next block within the next block buffer in the background. */ 562 * and bitswapping it. */
573static int send_block(unsigned char start_token, long timeout) 563static void send_block_prepare(void)
564{
565 unsigned char *dest;
566
567 current_buffer ^= 1; /* toggle buffer */
568 dest = write_buffer[current_buffer] + 2;
569
570 memcpy(dest, send_block_addr, BLOCK_SIZE);
571 bitswap(dest, BLOCK_SIZE);
572
573 send_block_addr += BLOCK_SIZE;
574}
575
576/* Send one block with DMA from the current write buffer, possibly preparing
577 * the next block within the next write buffer in the background. */
578static int send_block_send(unsigned char start_token, long timeout,
579 bool prepare_next)
574{ 580{
575 int rc = 0; 581 int rc = 0;
576 unsigned char *curbuf = block_buffer[current_buffer]; 582 unsigned char *curbuf = write_buffer[current_buffer];
577 583
578 curbuf[1] = fliptable[(signed char)start_token]; 584 curbuf[1] = fliptable[(signed char)start_token];
579 *(unsigned short *)(curbuf + BLOCK_SIZE + 2) = 0xFFFF; 585 *(unsigned short *)(curbuf + BLOCK_SIZE + 2) = 0xFFFF;
580 586
@@ -592,7 +598,8 @@ static int send_block(unsigned char start_token, long timeout)
592 DMAOR = 0x0001; 598 DMAOR = 0x0001;
593 SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ 599 SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */
594 600
595 bg_copy_swap(); 601 if (prepare_next)
602 send_block_prepare();
596 yield(); /* be nice */ 603 yield(); /* be nice */
597 604
598 while (!(CHCR0 & 0x0002)); /* wait for end of DMA */ 605 while (!(CHCR0 & 0x0002)); /* wait for end of DMA */
@@ -644,9 +651,6 @@ int ata_read_sectors(IF_MV2(int drive,)
644 if (end_block == card->numblocks) 651 if (end_block == card->numblocks)
645 lastblock = 1; 652 lastblock = 1;
646 653
647 bcs_src = NULL;
648 bcs_dest = inbuf;
649
650 if (incount > 1) 654 if (incount > 1)
651 { 655 {
652 rc = send_cmd(CMD_READ_MULTIPLE_BLOCK, start * BLOCK_SIZE, &response); 656 rc = send_cmd(CMD_READ_MULTIPLE_BLOCK, start * BLOCK_SIZE, &response);
@@ -664,9 +668,8 @@ int ata_read_sectors(IF_MV2(int drive,)
664 rc = rc * 10 - 4; 668 rc = rc * 10 - 4;
665 goto error; 669 goto error;
666 } 670 }
667 bcs_len = BLOCK_SIZE;
668 inbuf += BLOCK_SIZE; 671 inbuf += BLOCK_SIZE;
669 start++; 672 start++;
670 /* ^^ necessary for the abovementioned last block special case */ 673 /* ^^ necessary for the abovementioned last block special case */
671 } 674 }
672 rc = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); 675 rc = send_cmd(CMD_STOP_TRANSMISSION, 0, &response);
@@ -691,9 +694,7 @@ int ata_read_sectors(IF_MV2(int drive,)
691 rc = rc * 10 - 7; 694 rc = rc * 10 - 7;
692 goto error; 695 goto error;
693 } 696 }
694 bcs_len = BLOCK_SIZE;
695 } 697 }
696 bg_copy_swap();
697 698
698 error: 699 error:
699 700
@@ -727,10 +728,8 @@ int ata_write_sectors(IF_MV2(int drive,)
727 if (start + count > card->numblocks) 728 if (start + count > card->numblocks)
728 panicf("Writing past end of card"); 729 panicf("Writing past end of card");
729 730
730 bcs_src = buf; 731 send_block_addr = buf;
731 bcs_dest = NULL; /* next block buffer */ 732 send_block_prepare();
732 bcs_len = BLOCK_SIZE;
733 bg_copy_swap();
734 733
735 if (count > 1) 734 if (count > 1)
736 { 735 {
@@ -752,16 +751,14 @@ int ata_write_sectors(IF_MV2(int drive,)
752 751
753 while (--count > 0) 752 while (--count > 0)
754 { 753 {
755 bcs_dest = NULL; /* next block cache */ 754 rc = send_block_send(start_token, card->write_timeout, true);
756 bcs_len = BLOCK_SIZE;
757 rc = send_block(start_token, card->write_timeout);
758 if (rc) 755 if (rc)
759 { 756 {
760 rc = rc * 10 - 3; 757 rc = rc * 10 - 3;
761 goto error; 758 goto error;
762 } 759 }
763 } 760 }
764 rc = send_block(start_token, card->write_timeout); 761 rc = send_block_send(start_token, card->write_timeout, false);
765 if (rc) 762 if (rc)
766 { 763 {
767 rc = rc * 10 - 4; 764 rc = rc * 10 - 4;