From 1ab08e6879b1fe50102fe68a1326db05891e6faa Mon Sep 17 00:00:00 2001 From: Rafaël Carré Date: Thu, 4 Dec 2008 20:48:19 +0000 Subject: Sansa AMS: updates DMA API * Adds a callback to be called on end of transfer * Add a function to disable a channel * Services the 2 channels if both are active in the isr SD driver: panics on error git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19333 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/as3525/ata_sd_as3525.c | 49 ++++++++++++++++++++++++++---- firmware/target/arm/as3525/dma-pl081.c | 29 ++++++++++++++---- firmware/target/arm/as3525/dma-target.h | 4 +-- 3 files changed, 68 insertions(+), 14 deletions(-) (limited to 'firmware') diff --git a/firmware/target/arm/as3525/ata_sd_as3525.c b/firmware/target/arm/as3525/ata_sd_as3525.c index b2d8e3c1f3..3ec1892542 100644 --- a/firmware/target/arm/as3525/ata_sd_as3525.c +++ b/firmware/target/arm/as3525/ata_sd_as3525.c @@ -129,6 +129,37 @@ static void mci_set_clock_divider(const int drive, int divider) mci_delay(); } +static void sd_panic(IF_MV2(const int drive,) const int status) +{ + char error[32]; + error[0] = '\0'; + +#ifdef HAVE_MULTIVOLUME + snprintf(error, sizeof(error), + (drive == INTERNAL_AS3525) ? "Internal storage : " : "SD Slot : " ); +#endif + + panicf("SD : %s%s%s%s%s%s%s", error, + (status & MCI_DATA_CRC_FAIL) ? "DATA CRC FAIL, " : "", + (status & MCI_DATA_TIMEOUT) ? "DATA TIMEOUT, " : "", + (status & MCI_RX_OVERRUN) ? "RX OVERRUN, " : "", + (status & MCI_TX_UNDERRUN) ? "TX UNDERRUN, " : "", + (status & MCI_RX_FIFO_FULL) ? "RXR FIFO FULL, " : "", + (status & MCI_TX_FIFO_EMPTY) ? "TX FIFO EMPTY" : ""); +} + +void INT_NAND(void) +{ + sd_panic(IF_MV2(INTERNAL_AS3525,) MCI_STATUS(INTERNAL_AS3525)); +} + +#ifdef HAVE_MULTIVOLUME +void INT_MCI0(void) +{ + sd_panic(SD_SLOT_AS3525, MCI_STATUS(SD_SLOT_AS3525)); +} +#endif + static bool send_cmd(const int drive, const int cmd, const int arg, const int flags, int *response) { @@ -362,7 +393,14 @@ static void init_pl180_controller(const int drive) MCI_COMMAND(drive) = MCI_DATA_CTRL(drive) = 0; MCI_CLEAR(drive) = 0x7ff; - MCI_MASK0(drive) = MCI_MASK1(drive) = 0; /* disable all interrupts */ + MCI_MASK0(drive) = MCI_MASK1(drive) = MCI_DATA_CRC_FAIL | MCI_DATA_TIMEOUT | + MCI_RX_OVERRUN | MCI_TX_UNDERRUN | MCI_RX_FIFO_FULL | MCI_TX_FIFO_EMPTY; + + VIC_INT_ENABLE |= INTERRUPT_NAND +#ifdef HAVE_MULTIVOLUME + | INTERRUPT_MCI0 +#endif + ; MCI_POWER(drive) = MCI_POWER_UP|(10 /*voltage*/ << 2); /* use OF voltage */ mci_delay(); @@ -378,7 +416,6 @@ static void init_pl180_controller(const int drive) /* set MCLK divider */ mci_set_clock_divider(drive, CLK_DIV(AS3525_PCLK_FREQ, AS3525_SD_IDENT_FREQ)); - } int sd_init(void) @@ -552,12 +589,12 @@ static int sd_transfer_sectors(IF_MV2(int drive,) unsigned long start, if(write) dma_enable_channel(0, buf, MCI_FIFO(drive), - (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, - DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8); + (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, + DMAC_FLOWCTRL_PERI_MEM_TO_PERI, true, false, 0, DMA_S8, NULL); else dma_enable_channel(0, MCI_FIFO(drive), buf, - (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, - DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8); + (drive == INTERNAL_AS3525) ? DMA_PERI_SD : DMA_PERI_SD_SLOT, + DMAC_FLOWCTRL_PERI_PERI_TO_MEM, false, true, 0, DMA_S8, NULL); MCI_DATA_TIMER(drive) = 0x1000000; /* FIXME: arbitrary */ MCI_DATA_LENGTH(drive) = transfer * card_info[drive].block_size; diff --git a/firmware/target/arm/as3525/dma-pl081.c b/firmware/target/arm/as3525/dma-pl081.c index fbe488ce05..3de4e73c12 100644 --- a/firmware/target/arm/as3525/dma-pl081.c +++ b/firmware/target/arm/as3525/dma-pl081.c @@ -27,6 +27,7 @@ #include "kernel.h" static struct wakeup transfer_completion_signal[2]; /* 2 channels */ +static void (*dma_callback[2])(void); /* 2 channels */ inline void dma_wait_transfer(int channel) { @@ -45,10 +46,17 @@ void dma_init(void) wakeup_init(&transfer_completion_signal[1]); } +inline void dma_disable_channel(int channel) +{ + DMAC_CH_CONFIGURATION(channel) &= ~(1<<0); +} + void dma_enable_channel(int channel, void *src, void *dst, int peri, int flow_controller, bool src_inc, bool dst_inc, - size_t size, int nwords) + size_t size, int nwords, void (*callback)(void)) { + dma_callback[channel] = callback; + int control = 0; DMAC_CH_SRC_ADDR(channel) = (int)src; @@ -92,12 +100,21 @@ void dma_enable_channel(int channel, void *src, void *dst, int peri, /* isr */ void INT_DMAC(void) { - int channel = (DMAC_INT_STATUS & (1<<0)) ? 0 : 1; + unsigned int channel; + + /* SD channel is serviced first */ + for(channel = 0; channel < 2; channel++) + if(DMAC_INT_STATUS & (1<