vxKernel/src/driver/mpu/sh/sh7305/dma/dma.c

161 lines
3.5 KiB
C
Raw Normal View History

#include <vhex/driver/mpu/sh/sh7305/dma.h>
#include <vhex/driver/mpu/sh/sh7305/intc.h>
//#include <vhex/driver/mpu/sh/sh7305/power.h>
#include <vhex/driver.h>
#include <vhex/defs/call.h>
#define DMA SH7305_DMA
//#define POWER SH7305_POWER
typedef volatile struct __sh7305_dma_channel channel_t;
//---
// Driver public API
//---
static channel_t *sh7305_dma_channel(int channel)
{
if (channel < 0 || channel >= 6)
return NULL;
return (channel_t *[6]){
&DMA.DMA0, &DMA.DMA1, &DMA.DMA2,
&DMA.DMA3, &DMA.DMA4, &DMA.DMA5,
}[channel];
}
static void sh7305_dma_spinwait(channel_t *ch)
{
(void)ch;
}
//---
// Kernel-level API
//---
/* Interrupt handler for all finished DMA transfers */
static void sh7305_dma_interrupt_transfer_ended(channel_t *ch)
{
(void)ch;
}
//---
// Declare driver
//---
//FIXME: avoid manualy sync DMAOR with header o(x_x)o
struct dma_ctx {
channel_t ch[6];
word_union(DMAOR,
uint16_t CMS :4; /* Cycle steal Mode Select */
uint16_t :2;
uint16_t PR :2; /* PRiority mode */
uint16_t :4;
uint16_t :1;
uint16_t AE :1; /* Address Error flag */
uint16_t NMIF :1; /* NMI Flag */
uint16_t DME :1; /* DMA Master Enable */
);
};
/* __dma_configure() : configure the DMA */
static void __dma_configure(struct dma_ctx *s)
{
extern void sh7305_dma_inth_te(void);
extern void sh7305_dma_inth_ae(void);
int codes[] = { 0x800, 0x820, 0x840, 0x860, 0xb80, 0xba0 };
for(int i = 0; i < 6; i++)
{
sh7305_intc_install_inth_generic(
codes[i],
VHEX_CALL(
sh7305_dma_interrupt_transfer_ended,
(void*)sh7305_dma_channel(i)
)
);
s->ch[i].SAR = 0x00000000;
s->ch[i].DAR = 0x00000000;
s->ch[i].TCR = 0x00000000;
s->ch[i].CHCR.DE = 0;
}
/* Configure the DMA operations
<> select normal cycle steal mode
<> select "normal" priority (CH0->CH1->CH2->...)
<> clear address error flags
<> clear NMIF flags
<> enable the master switch */
s->DMAOR.CMS = 0b0000;
s->DMAOR.PR = 0b00;
s->DMAOR.AE = 0;
s->DMAOR.NMIF = 0;
s->DMAOR.DME = 1;
/* Install Address Error interrupt gate */
sh7305_intc_install_inth_gate(0xbc0, sh7305_dma_inth_ae, 32);
/* Set interrupt priority to 3, except for the channels that are
used by the USB driver (channel 0) */
sh7305_intc_priority(INTC_DMA_DEI0, 9);
sh7305_intc_priority(INTC_DMA_DEI1, 3);
sh7305_intc_priority(INTC_DMA_DEI2, 3);
sh7305_intc_priority(INTC_DMA_DEI3, 3);
sh7305_intc_priority(INTC_DMA_DEI4, 3);
sh7305_intc_priority(INTC_DMA_DEI5, 3);
sh7305_intc_priority(INTC_DMA_DADERR, 3);
}
/* __rtc_hsave() : save hardware information */
static void __dma_hsave(struct dma_ctx *s)
{
for(int i = 0; i < 6; i++) {
channel_t *ch = sh7305_dma_channel(i);
sh7305_dma_spinwait(ch);
ch->SAR = s->ch[i].SAR;
ch->DAR = s->ch[i].DAR;
ch->TCR = s->ch[i].TCR;
ch->CHCR.lword = s->ch[i].CHCR.lword;
}
DMA.DMAOR.word = s->DMAOR.word;
}
/* __dma_hrestore() : restore hardware information */
static void __dma_hrestore(struct dma_ctx *s)
{
DMA.DMAOR.DME = 0;
for(int i = 0; i < 6; i++)
{
channel_t *ch = sh7305_dma_channel(i);
ch->SAR = s->ch[i].SAR;
ch->DAR = s->ch[i].DAR;
ch->TCR = s->ch[i].TCR;
ch->CHCR.lword = s->ch[i].CHCR.lword;
}
DMA.DMAOR.word = s->DMAOR.word;
}
#if 0
struct vhex_driver drv_rtc = {
.name = "DMA",
.hsave = (void*)&__dma_hsave,
.hrestore = (void*)&__dma_hrestore,
.configure = (void*)&__dma_configure,
.state_size = sizeof(struct dma_ctx),
.flags = {
.DMA = 1,
.SHARED = 0,
.UNUSED = 0,
},
};
VHEX_DECLARE_DRIVER(05, drv_dma);
#endif