diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/target/arm/as3525/ata_sd_as3525.c | 29 |
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 | ||
649 | static int32_t aligned_buffer[UNALIGNED_NUM_SECTORS* (SECTOR_SIZE / 4)]; | ||
650 | |||
648 | static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start, | 651 | static 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; |