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
This commit is contained in:
Rafaël Carré 2008-12-04 20:48:19 +00:00
parent 76617c8f94
commit 1ab08e6879
3 changed files with 68 additions and 14 deletions

View file

@ -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;

View file

@ -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;
if(DMAC_INT_ERROR_STATUS & (1<<channel))
panicf("DMA error, channel %d", channel);
/* SD channel is serviced first */
for(channel = 0; channel < 2; channel++)
if(DMAC_INT_STATUS & (1<<channel))
{
if(DMAC_INT_ERROR_STATUS & (1<<channel))
panicf("DMA error, channel %d", channel);
DMAC_INT_TC_CLEAR |= (1<<channel); /* clear terminal count interrupt */
/* clear terminal count interrupt */
DMAC_INT_TC_CLEAR |= (1<<channel);
wakeup_signal(&transfer_completion_signal[channel]);
if(dma_callback[channel])
dma_callback[channel]();
wakeup_signal(&transfer_completion_signal[channel]);
}
}

View file

@ -34,6 +34,6 @@
void dma_init(void);
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));
inline void dma_disable_channel(int channel);
inline void dma_wait_transfer(int channel);