161 lines
3.5 KiB
C
161 lines
3.5 KiB
C
|
#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
|