 187337f8b0
			
		
	
	
		187337f8b0
		
	
	
	
	
		
			
			git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2931 c046a42c-6fe2-441c-8c8c-71466251a162
		
			
				
	
	
		
			554 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			554 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Intel XScale PXA255/270 DMA controller.
 | |
|  *
 | |
|  * Copyright (c) 2006 Openedhand Ltd.
 | |
|  * Copyright (c) 2006 Thorsten Zitterell
 | |
|  * Written by Andrzej Zaborowski <balrog@zabor.org>
 | |
|  *
 | |
|  * This code is licenced under the GPL.
 | |
|  */
 | |
| 
 | |
| #include "vl.h"
 | |
| 
 | |
| struct pxa2xx_dma_channel_s {
 | |
|     target_phys_addr_t descr;
 | |
|     target_phys_addr_t src;
 | |
|     target_phys_addr_t dest;
 | |
|     uint32_t cmd;
 | |
|     uint32_t state;
 | |
|     int request;
 | |
| };
 | |
| 
 | |
| /* Allow the DMA to be used as a PIC.  */
 | |
| typedef void (*pxa2xx_dma_handler_t)(void *opaque, int irq, int level);
 | |
| 
 | |
| struct pxa2xx_dma_state_s {
 | |
|     pxa2xx_dma_handler_t handler;
 | |
|     target_phys_addr_t base;
 | |
|     qemu_irq irq;
 | |
| 
 | |
|     uint32_t stopintr;
 | |
|     uint32_t eorintr;
 | |
|     uint32_t rasintr;
 | |
|     uint32_t startintr;
 | |
|     uint32_t endintr;
 | |
| 
 | |
|     uint32_t align;
 | |
|     uint32_t pio;
 | |
| 
 | |
|     int channels;
 | |
|     struct pxa2xx_dma_channel_s *chan;
 | |
| 
 | |
|     uint8_t *req;
 | |
| 
 | |
|     /* Flag to avoid recursive DMA invocations.  */
 | |
|     int running;
 | |
| };
 | |
| 
 | |
| #define PXA255_DMA_NUM_CHANNELS	16
 | |
| #define PXA27X_DMA_NUM_CHANNELS	32
 | |
| 
 | |
| #define PXA2XX_DMA_NUM_REQUESTS	75
 | |
| 
 | |
| #define DCSR0	0x0000	/* DMA Control / Status register for Channel 0 */
 | |
| #define DCSR31	0x007c	/* DMA Control / Status register for Channel 31 */
 | |
| #define DALGN	0x00a0	/* DMA Alignment register */
 | |
| #define DPCSR	0x00a4	/* DMA Programmed I/O Control Status register */
 | |
| #define DRQSR0	0x00e0	/* DMA DREQ<0> Status register */
 | |
| #define DRQSR1	0x00e4	/* DMA DREQ<1> Status register */
 | |
| #define DRQSR2	0x00e8	/* DMA DREQ<2> Status register */
 | |
| #define DINT	0x00f0	/* DMA Interrupt register */
 | |
| #define DRCMR0	0x0100	/* Request to Channel Map register 0 */
 | |
| #define DRCMR63	0x01fc	/* Request to Channel Map register 63 */
 | |
| #define D_CH0	0x0200	/* Channel 0 Descriptor start */
 | |
| #define DRCMR64	0x1100	/* Request to Channel Map register 64 */
 | |
| #define DRCMR74	0x1128	/* Request to Channel Map register 74 */
 | |
| 
 | |
| /* Per-channel register */
 | |
| #define DDADR	0x00
 | |
| #define DSADR	0x01
 | |
| #define DTADR	0x02
 | |
| #define DCMD	0x03
 | |
| 
 | |
| /* Bit-field masks */
 | |
| #define DRCMR_CHLNUM		0x1f
 | |
| #define DRCMR_MAPVLD		(1 << 7)
 | |
| #define DDADR_STOP		(1 << 0)
 | |
| #define DDADR_BREN		(1 << 1)
 | |
| #define DCMD_LEN		0x1fff
 | |
| #define DCMD_WIDTH(x)		(1 << ((((x) >> 14) & 3) - 1))
 | |
| #define DCMD_SIZE(x)		(4 << (((x) >> 16) & 3))
 | |
| #define DCMD_FLYBYT		(1 << 19)
 | |
| #define DCMD_FLYBYS		(1 << 20)
 | |
| #define DCMD_ENDIRQEN		(1 << 21)
 | |
| #define DCMD_STARTIRQEN		(1 << 22)
 | |
| #define DCMD_CMPEN		(1 << 25)
 | |
| #define DCMD_FLOWTRG		(1 << 28)
 | |
| #define DCMD_FLOWSRC		(1 << 29)
 | |
| #define DCMD_INCTRGADDR		(1 << 30)
 | |
| #define DCMD_INCSRCADDR		(1 << 31)
 | |
| #define DCSR_BUSERRINTR		(1 << 0)
 | |
| #define DCSR_STARTINTR		(1 << 1)
 | |
| #define DCSR_ENDINTR		(1 << 2)
 | |
| #define DCSR_STOPINTR		(1 << 3)
 | |
| #define DCSR_RASINTR		(1 << 4)
 | |
| #define DCSR_REQPEND		(1 << 8)
 | |
| #define DCSR_EORINT		(1 << 9)
 | |
| #define DCSR_CMPST		(1 << 10)
 | |
| #define DCSR_MASKRUN		(1 << 22)
 | |
| #define DCSR_RASIRQEN		(1 << 23)
 | |
| #define DCSR_CLRCMPST		(1 << 24)
 | |
| #define DCSR_SETCMPST		(1 << 25)
 | |
| #define DCSR_EORSTOPEN		(1 << 26)
 | |
| #define DCSR_EORJMPEN		(1 << 27)
 | |
| #define DCSR_EORIRQEN		(1 << 28)
 | |
| #define DCSR_STOPIRQEN		(1 << 29)
 | |
| #define DCSR_NODESCFETCH	(1 << 30)
 | |
| #define DCSR_RUN		(1 << 31)
 | |
| 
 | |
| static inline void pxa2xx_dma_update(struct pxa2xx_dma_state_s *s, int ch)
 | |
| {
 | |
|     if (ch >= 0) {
 | |
|         if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
 | |
|                 (s->chan[ch].state & DCSR_STOPINTR))
 | |
|             s->stopintr |= 1 << ch;
 | |
|         else
 | |
|             s->stopintr &= ~(1 << ch);
 | |
| 
 | |
|         if ((s->chan[ch].state & DCSR_EORIRQEN) &&
 | |
|                 (s->chan[ch].state & DCSR_EORINT))
 | |
|             s->eorintr |= 1 << ch;
 | |
|         else
 | |
|             s->eorintr &= ~(1 << ch);
 | |
| 
 | |
|         if ((s->chan[ch].state & DCSR_RASIRQEN) &&
 | |
|                 (s->chan[ch].state & DCSR_RASINTR))
 | |
|             s->rasintr |= 1 << ch;
 | |
|         else
 | |
|             s->rasintr &= ~(1 << ch);
 | |
| 
 | |
|         if (s->chan[ch].state & DCSR_STARTINTR)
 | |
|             s->startintr |= 1 << ch;
 | |
|         else
 | |
|             s->startintr &= ~(1 << ch);
 | |
| 
 | |
|         if (s->chan[ch].state & DCSR_ENDINTR)
 | |
|             s->endintr |= 1 << ch;
 | |
|         else
 | |
|             s->endintr &= ~(1 << ch);
 | |
|     }
 | |
| 
 | |
|     if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
 | |
|         qemu_irq_raise(s->irq);
 | |
|     else
 | |
|         qemu_irq_lower(s->irq);
 | |
| }
 | |
| 
 | |
| static inline void pxa2xx_dma_descriptor_fetch(
 | |
|                 struct pxa2xx_dma_state_s *s, int ch)
 | |
| {
 | |
|     uint32_t desc[4];
 | |
|     target_phys_addr_t daddr = s->chan[ch].descr & ~0xf;
 | |
|     if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
 | |
|         daddr += 32;
 | |
| 
 | |
|     cpu_physical_memory_read(daddr, (uint8_t *) desc, 16);
 | |
|     s->chan[ch].descr = desc[DDADR];
 | |
|     s->chan[ch].src = desc[DSADR];
 | |
|     s->chan[ch].dest = desc[DTADR];
 | |
|     s->chan[ch].cmd = desc[DCMD];
 | |
| 
 | |
|     if (s->chan[ch].cmd & DCMD_FLOWSRC)
 | |
|         s->chan[ch].src &= ~3;
 | |
|     if (s->chan[ch].cmd & DCMD_FLOWTRG)
 | |
|         s->chan[ch].dest &= ~3;
 | |
| 
 | |
|     if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
 | |
|         printf("%s: unsupported mode in channel %i\n", __FUNCTION__, ch);
 | |
| 
 | |
|     if (s->chan[ch].cmd & DCMD_STARTIRQEN)
 | |
|         s->chan[ch].state |= DCSR_STARTINTR;
 | |
| }
 | |
| 
 | |
| static void pxa2xx_dma_run(struct pxa2xx_dma_state_s *s)
 | |
| {
 | |
|     int c, srcinc, destinc;
 | |
|     uint32_t n, size;
 | |
|     uint32_t width;
 | |
|     uint32_t length;
 | |
|     char buffer[32];
 | |
|     struct pxa2xx_dma_channel_s *ch;
 | |
| 
 | |
|     if (s->running ++)
 | |
|         return;
 | |
| 
 | |
|     while (s->running) {
 | |
|         s->running = 1;
 | |
|         for (c = 0; c < s->channels; c ++) {
 | |
|             ch = &s->chan[c];
 | |
| 
 | |
|             while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
 | |
|                 /* Test for pending requests */
 | |
|                 if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
 | |
|                     break;
 | |
| 
 | |
|                 length = ch->cmd & DCMD_LEN;
 | |
|                 size = DCMD_SIZE(ch->cmd);
 | |
|                 width = DCMD_WIDTH(ch->cmd);
 | |
| 
 | |
|                 srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
 | |
|                 destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
 | |
| 
 | |
|                 while (length) {
 | |
|                     size = MIN(length, size);
 | |
| 
 | |
|                     for (n = 0; n < size; n += width) {
 | |
|                         cpu_physical_memory_read(ch->src, buffer + n, width);
 | |
|                         ch->src += srcinc;
 | |
|                     }
 | |
| 
 | |
|                     for (n = 0; n < size; n += width) {
 | |
|                         cpu_physical_memory_write(ch->dest, buffer + n, width);
 | |
|                         ch->dest += destinc;
 | |
|                     }
 | |
| 
 | |
|                     length -= size;
 | |
| 
 | |
|                     if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
 | |
|                             !ch->request) {
 | |
|                         ch->state |= DCSR_EORINT;
 | |
|                         if (ch->state & DCSR_EORSTOPEN)
 | |
|                             ch->state |= DCSR_STOPINTR;
 | |
|                         if ((ch->state & DCSR_EORJMPEN) &&
 | |
|                                         !(ch->state & DCSR_NODESCFETCH))
 | |
|                             pxa2xx_dma_descriptor_fetch(s, c);
 | |
|                         break;
 | |
| 		    }
 | |
|                 }
 | |
| 
 | |
|                 ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
 | |
| 
 | |
|                 /* Is the transfer complete now? */
 | |
|                 if (!length) {
 | |
|                     if (ch->cmd & DCMD_ENDIRQEN)
 | |
|                         ch->state |= DCSR_ENDINTR;
 | |
| 
 | |
|                     if ((ch->state & DCSR_NODESCFETCH) ||
 | |
|                                 (ch->descr & DDADR_STOP) ||
 | |
|                                 (ch->state & DCSR_EORSTOPEN)) {
 | |
|                         ch->state |= DCSR_STOPINTR;
 | |
|                         ch->state &= ~DCSR_RUN;
 | |
| 
 | |
|                         break;
 | |
|                     }
 | |
| 
 | |
|                     ch->state |= DCSR_STOPINTR;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         s->running --;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static uint32_t pxa2xx_dma_read(void *opaque, target_phys_addr_t offset)
 | |
| {
 | |
|     struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
 | |
|     unsigned int channel;
 | |
|     offset -= s->base;
 | |
| 
 | |
|     switch (offset) {
 | |
|     case DRCMR64 ... DRCMR74:
 | |
|         offset -= DRCMR64 - DRCMR0 - (64 << 2);
 | |
|         /* Fall through */
 | |
|     case DRCMR0 ... DRCMR63:
 | |
|         channel = (offset - DRCMR0) >> 2;
 | |
|         return s->req[channel];
 | |
| 
 | |
|     case DRQSR0:
 | |
|     case DRQSR1:
 | |
|     case DRQSR2:
 | |
|         return 0;
 | |
| 
 | |
|     case DCSR0 ... DCSR31:
 | |
|         channel = offset >> 2;
 | |
| 	if (s->chan[channel].request)
 | |
|             return s->chan[channel].state | DCSR_REQPEND;
 | |
|         return s->chan[channel].state;
 | |
| 
 | |
|     case DINT:
 | |
|         return s->stopintr | s->eorintr | s->rasintr |
 | |
|                 s->startintr | s->endintr;
 | |
| 
 | |
|     case DALGN:
 | |
|         return s->align;
 | |
| 
 | |
|     case DPCSR:
 | |
|         return s->pio;
 | |
|     }
 | |
| 
 | |
|     if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
 | |
|         channel = (offset - D_CH0) >> 4;
 | |
|         switch ((offset & 0x0f) >> 2) {
 | |
|         case DDADR:
 | |
|             return s->chan[channel].descr;
 | |
|         case DSADR:
 | |
|             return s->chan[channel].src;
 | |
|         case DTADR:
 | |
|             return s->chan[channel].dest;
 | |
|         case DCMD:
 | |
|             return s->chan[channel].cmd;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     cpu_abort(cpu_single_env,
 | |
|                     "%s: Bad offset 0x%04lx\n", __FUNCTION__, offset);
 | |
|     return 7;
 | |
| }
 | |
| 
 | |
| static void pxa2xx_dma_write(void *opaque,
 | |
|                  target_phys_addr_t offset, uint32_t value)
 | |
| {
 | |
|     struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
 | |
|     unsigned int channel;
 | |
|     offset -= s->base;
 | |
| 
 | |
|     switch (offset) {
 | |
|     case DRCMR64 ... DRCMR74:
 | |
|         offset -= DRCMR64 - DRCMR0 - (64 << 2);
 | |
|         /* Fall through */
 | |
|     case DRCMR0 ... DRCMR63:
 | |
|         channel = (offset - DRCMR0) >> 2;
 | |
| 
 | |
|         if (value & DRCMR_MAPVLD)
 | |
|             if ((value & DRCMR_CHLNUM) > s->channels)
 | |
|                 cpu_abort(cpu_single_env, "%s: Bad DMA channel %i\n",
 | |
|                         __FUNCTION__, value & DRCMR_CHLNUM);
 | |
| 
 | |
|         s->req[channel] = value;
 | |
|         break;
 | |
| 
 | |
|     case DRQSR0:
 | |
|     case DRQSR1:
 | |
|     case DRQSR2:
 | |
|         /* Nothing to do */
 | |
|         break;
 | |
| 
 | |
|     case DCSR0 ... DCSR31:
 | |
|         channel = offset >> 2;
 | |
|         s->chan[channel].state &= 0x0000071f & ~(value &
 | |
|                         (DCSR_EORINT | DCSR_ENDINTR |
 | |
|                          DCSR_STARTINTR | DCSR_BUSERRINTR));
 | |
|         s->chan[channel].state |= value & 0xfc800000;
 | |
| 
 | |
|         if (s->chan[channel].state & DCSR_STOPIRQEN)
 | |
|             s->chan[channel].state &= ~DCSR_STOPINTR;
 | |
| 
 | |
|         if (value & DCSR_NODESCFETCH) {
 | |
|             /* No-descriptor-fetch mode */
 | |
|             if (value & DCSR_RUN)
 | |
|                 pxa2xx_dma_run(s);
 | |
|         } else {
 | |
|             /* Descriptor-fetch mode */
 | |
|             if (value & DCSR_RUN) {
 | |
|                 s->chan[channel].state &= ~DCSR_STOPINTR;
 | |
|                 pxa2xx_dma_descriptor_fetch(s, channel);
 | |
|                 pxa2xx_dma_run(s);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /* Shouldn't matter as our DMA is synchronous.  */
 | |
|         if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
 | |
|             s->chan[channel].state |= DCSR_STOPINTR;
 | |
| 
 | |
|         if (value & DCSR_CLRCMPST)
 | |
|             s->chan[channel].state &= ~DCSR_CMPST;
 | |
|         if (value & DCSR_SETCMPST)
 | |
|             s->chan[channel].state |= DCSR_CMPST;
 | |
| 
 | |
|         pxa2xx_dma_update(s, channel);
 | |
|         break;
 | |
| 
 | |
|     case DALGN:
 | |
|         s->align = value;
 | |
|         break;
 | |
| 
 | |
|     case DPCSR:
 | |
|         s->pio = value & 0x80000001;
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|         if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
 | |
|             channel = (offset - D_CH0) >> 4;
 | |
|             switch ((offset & 0x0f) >> 2) {
 | |
|             case DDADR:
 | |
|                 s->chan[channel].descr = value;
 | |
|                 break;
 | |
|             case DSADR:
 | |
|                 s->chan[channel].src = value;
 | |
|                 break;
 | |
|             case DTADR:
 | |
|                 s->chan[channel].dest = value;
 | |
|                 break;
 | |
|             case DCMD:
 | |
|                 s->chan[channel].cmd = value;
 | |
|                 break;
 | |
|             default:
 | |
|                 goto fail;
 | |
|             }
 | |
| 
 | |
|             break;
 | |
|         }
 | |
|     fail:
 | |
|         cpu_abort(cpu_single_env, "%s: Bad offset 0x%04lx\n",
 | |
|                 __FUNCTION__, offset);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static uint32_t pxa2xx_dma_readbad(void *opaque, target_phys_addr_t offset)
 | |
| {
 | |
|     cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__);
 | |
|     return 5;
 | |
| }
 | |
| 
 | |
| static void pxa2xx_dma_writebad(void *opaque,
 | |
|                  target_phys_addr_t offset, uint32_t value)
 | |
| {
 | |
|     cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__);
 | |
| }
 | |
| 
 | |
| static CPUReadMemoryFunc *pxa2xx_dma_readfn[] = {
 | |
|     pxa2xx_dma_readbad,
 | |
|     pxa2xx_dma_readbad,
 | |
|     pxa2xx_dma_read
 | |
| };
 | |
| 
 | |
| static CPUWriteMemoryFunc *pxa2xx_dma_writefn[] = {
 | |
|     pxa2xx_dma_writebad,
 | |
|     pxa2xx_dma_writebad,
 | |
|     pxa2xx_dma_write
 | |
| };
 | |
| 
 | |
| static void pxa2xx_dma_save(QEMUFile *f, void *opaque)
 | |
| {
 | |
|     struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
 | |
|     int i;
 | |
| 
 | |
|     qemu_put_be32(f, s->channels);
 | |
| 
 | |
|     qemu_put_be32s(f, &s->stopintr);
 | |
|     qemu_put_be32s(f, &s->eorintr);
 | |
|     qemu_put_be32s(f, &s->rasintr);
 | |
|     qemu_put_be32s(f, &s->startintr);
 | |
|     qemu_put_be32s(f, &s->endintr);
 | |
|     qemu_put_be32s(f, &s->align);
 | |
|     qemu_put_be32s(f, &s->pio);
 | |
| 
 | |
|     qemu_put_buffer(f, s->req, PXA2XX_DMA_NUM_REQUESTS);
 | |
|     for (i = 0; i < s->channels; i ++) {
 | |
|         qemu_put_betl(f, s->chan[i].descr);
 | |
|         qemu_put_betl(f, s->chan[i].src);
 | |
|         qemu_put_betl(f, s->chan[i].dest);
 | |
|         qemu_put_be32s(f, &s->chan[i].cmd);
 | |
|         qemu_put_be32s(f, &s->chan[i].state);
 | |
|         qemu_put_be32(f, s->chan[i].request);
 | |
|     };
 | |
| }
 | |
| 
 | |
| static int pxa2xx_dma_load(QEMUFile *f, void *opaque, int version_id)
 | |
| {
 | |
|     struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
 | |
|     int i;
 | |
| 
 | |
|     if (qemu_get_be32(f) != s->channels)
 | |
|         return -EINVAL;
 | |
| 
 | |
|     qemu_get_be32s(f, &s->stopintr);
 | |
|     qemu_get_be32s(f, &s->eorintr);
 | |
|     qemu_get_be32s(f, &s->rasintr);
 | |
|     qemu_get_be32s(f, &s->startintr);
 | |
|     qemu_get_be32s(f, &s->endintr);
 | |
|     qemu_get_be32s(f, &s->align);
 | |
|     qemu_get_be32s(f, &s->pio);
 | |
| 
 | |
|     qemu_get_buffer(f, s->req, PXA2XX_DMA_NUM_REQUESTS);
 | |
|     for (i = 0; i < s->channels; i ++) {
 | |
|         s->chan[i].descr = qemu_get_betl(f);
 | |
|         s->chan[i].src = qemu_get_betl(f);
 | |
|         s->chan[i].dest = qemu_get_betl(f);
 | |
|         qemu_get_be32s(f, &s->chan[i].cmd);
 | |
|         qemu_get_be32s(f, &s->chan[i].state);
 | |
|         s->chan[i].request = qemu_get_be32(f);
 | |
|     };
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base,
 | |
|                 qemu_irq irq, int channels)
 | |
| {
 | |
|     int i, iomemtype;
 | |
|     struct pxa2xx_dma_state_s *s;
 | |
|     s = (struct pxa2xx_dma_state_s *)
 | |
|             qemu_mallocz(sizeof(struct pxa2xx_dma_state_s));
 | |
| 
 | |
|     s->channels = channels;
 | |
|     s->chan = qemu_mallocz(sizeof(struct pxa2xx_dma_channel_s) * s->channels);
 | |
|     s->base = base;
 | |
|     s->irq = irq;
 | |
|     s->handler = (pxa2xx_dma_handler_t) pxa2xx_dma_request;
 | |
|     s->req = qemu_mallocz(sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
 | |
| 
 | |
|     memset(s->chan, 0, sizeof(struct pxa2xx_dma_channel_s) * s->channels);
 | |
|     for (i = 0; i < s->channels; i ++)
 | |
|         s->chan[i].state = DCSR_STOPINTR;
 | |
| 
 | |
|     memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
 | |
| 
 | |
|     iomemtype = cpu_register_io_memory(0, pxa2xx_dma_readfn,
 | |
|                     pxa2xx_dma_writefn, s);
 | |
|     cpu_register_physical_memory(base, 0x00010000, iomemtype);
 | |
| 
 | |
|     register_savevm("pxa2xx_dma", 0, 0, pxa2xx_dma_save, pxa2xx_dma_load, s);
 | |
| 
 | |
|     return s;
 | |
| }
 | |
| 
 | |
| struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
 | |
|                 qemu_irq irq)
 | |
| {
 | |
|     return pxa2xx_dma_init(base, irq, PXA27X_DMA_NUM_CHANNELS);
 | |
| }
 | |
| 
 | |
| struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
 | |
|                 qemu_irq irq)
 | |
| {
 | |
|     return pxa2xx_dma_init(base, irq, PXA255_DMA_NUM_CHANNELS);
 | |
| }
 | |
| 
 | |
| void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on)
 | |
| {
 | |
|     int ch;
 | |
|     if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
 | |
|         cpu_abort(cpu_single_env,
 | |
|               "%s: Bad DMA request %i\n", __FUNCTION__, req_num);
 | |
| 
 | |
|     if (!(s->req[req_num] & DRCMR_MAPVLD))
 | |
|         return;
 | |
|     ch = s->req[req_num] & DRCMR_CHLNUM;
 | |
| 
 | |
|     if (!s->chan[ch].request && on)
 | |
|         s->chan[ch].state |= DCSR_RASINTR;
 | |
|     else
 | |
|         s->chan[ch].state &= ~DCSR_RASINTR;
 | |
|     if (s->chan[ch].request && !on)
 | |
|         s->chan[ch].state |= DCSR_EORINT;
 | |
| 
 | |
|     s->chan[ch].request = on;
 | |
|     if (on) {
 | |
|         pxa2xx_dma_run(s);
 | |
|         pxa2xx_dma_update(s, ch);
 | |
|     }
 | |
| }
 |