summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/ata_sd_as3525.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/as3525/ata_sd_as3525.c')
-rw-r--r--firmware/target/arm/as3525/ata_sd_as3525.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/firmware/target/arm/as3525/ata_sd_as3525.c b/firmware/target/arm/as3525/ata_sd_as3525.c
index 042af3b5a1..7e5bc126af 100644
--- a/firmware/target/arm/as3525/ata_sd_as3525.c
+++ b/firmware/target/arm/as3525/ata_sd_as3525.c
@@ -645,14 +645,18 @@ static int sd_select_bank(signed char bank)
645 return 0; 645 return 0;
646} 646}
647 647
648#define UNALIGNED_NUM_SECTORS 10
649static int32_t aligned_buffer[UNALIGNED_NUM_SECTORS* (SECTOR_SIZE / 4)];
650
648static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start, 651static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
649 int count, void* buf, bool write) 652 int count, void* buf, const bool write)
650{ 653{
651#ifndef HAVE_MULTIVOLUME 654#ifndef HAVE_MULTIVOLUME
652 const int drive = 0; 655 const int drive = 0;
653#endif 656#endif
654 int ret = 0; 657 int ret = 0;
655 int bank; 658 int bank;
659 bool unaligned_transfer = (int)buf & 3;
656 660
657 /* skip SanDisk OF */ 661 /* skip SanDisk OF */
658 if (drive == INTERNAL_AS3525) 662 if (drive == INTERNAL_AS3525)
@@ -706,17 +710,30 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
706 710
707 while(count) 711 while(count)
708 { 712 {
709 /* Interrupt handler might set this to true during transfer */
710 retry = false;
711 /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH 713 /* 128 * 512 = 2^16, and doesn't fit in the 16 bits of DATA_LENGTH
712 * register, so we have to transfer maximum 127 sectors at a time. */ 714 * register, so we have to transfer maximum 127 sectors at a time. */
713 unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */ 715 unsigned int transfer = (count >= 128) ? 127 : count; /* sectors */
716 void *dma_buf;
714 const int cmd = 717 const int cmd =
715 write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK; 718 write ? SD_WRITE_MULTIPLE_BLOCK : SD_READ_MULTIPLE_BLOCK;
716 int arg = start; 719 int arg = start;
717 if(!(card_info[drive].ocr & (1<<30))) /* not SDHC */ 720 if(!(card_info[drive].ocr & (1<<30))) /* not SDHC */
718 arg *= BLOCK_SIZE; 721 arg *= BLOCK_SIZE;
719 722
723 /* Interrupt handler might set this to true during transfer */
724 retry = false;
725
726 if(unaligned_transfer)
727 {
728 dma_buf = aligned_buffer;
729 if(transfer > UNALIGNED_NUM_SECTORS)
730 transfer = UNALIGNED_NUM_SECTORS;
731 if(write)
732 memcpy(aligned_buffer, buf, transfer * SECTOR_SIZE);
733 }
734 else
735 dma_buf = buf;
736
720 if(!send_cmd(drive, cmd, arg, MCI_ARG, NULL)) 737 if(!send_cmd(drive, cmd, arg, MCI_ARG, NULL))
721 { 738 {
722 ret -= 3*20; 739 ret -= 3*20;
@@ -724,11 +741,11 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
724 } 741 }
725 742
726 if(write) 743 if(write)
727 dma_enable_channel(0, buf, MCI_FIFO(drive), 744 dma_enable_channel(0, dma_buf, MCI_FIFO(drive),
728 (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, 745 (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT,
729 DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL); 746 DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL);
730 else 747 else
731 dma_enable_channel(0, MCI_FIFO(drive), buf, 748 dma_enable_channel(0, MCI_FIFO(drive), dma_buf,
732 (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, 749 (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT,
733 DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL); 750 DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL);
734 751
@@ -743,6 +760,8 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start,
743 wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK); 760 wakeup_wait(&transfer_completion_signal, TIMEOUT_BLOCK);
744 if(!retry) 761 if(!retry)
745 { 762 {
763 if(unaligned_transfer && !write)
764 memcpy(buf, aligned_buffer, transfer * SECTOR_SIZE);
746 buf += transfer * SECTOR_SIZE; 765 buf += transfer * SECTOR_SIZE;
747 start += transfer; 766 start += transfer;
748 count -= transfer; 767 count -= transfer;