symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/sparc32_dma.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU Sparc32 DMA controller emulation
       
     3  *
       
     4  * Copyright (c) 2006 Fabrice Bellard
       
     5  *
       
     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     7  * of this software and associated documentation files (the "Software"), to deal
       
     8  * in the Software without restriction, including without limitation the rights
       
     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    10  * copies of the Software, and to permit persons to whom the Software is
       
    11  * furnished to do so, subject to the following conditions:
       
    12  *
       
    13  * The above copyright notice and this permission notice shall be included in
       
    14  * all copies or substantial portions of the Software.
       
    15  *
       
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    22  * THE SOFTWARE.
       
    23  */
       
    24 #include "hw.h"
       
    25 #include "sparc32_dma.h"
       
    26 #include "sun4m.h"
       
    27 
       
    28 /* debug DMA */
       
    29 //#define DEBUG_DMA
       
    30 
       
    31 /*
       
    32  * This is the DMA controller part of chip STP2000 (Master I/O), also
       
    33  * produced as NCR89C100. See
       
    34  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
       
    35  * and
       
    36  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt
       
    37  */
       
    38 
       
    39 #ifdef DEBUG_DMA
       
    40 #define DPRINTF(fmt, args...) \
       
    41 do { printf("DMA: " fmt , ##args); } while (0)
       
    42 #else
       
    43 #define DPRINTF(fmt, args...)
       
    44 #endif
       
    45 
       
    46 #define DMA_REGS 4
       
    47 #define DMA_SIZE (4 * sizeof(uint32_t))
       
    48 /* We need the mask, because one instance of the device is not page
       
    49    aligned (ledma, start address 0x0010) */
       
    50 #define DMA_MASK (DMA_SIZE - 1)
       
    51 
       
    52 #define DMA_VER 0xa0000000
       
    53 #define DMA_INTR 1
       
    54 #define DMA_INTREN 0x10
       
    55 #define DMA_WRITE_MEM 0x100
       
    56 #define DMA_LOADED 0x04000000
       
    57 #define DMA_DRAIN_FIFO 0x40
       
    58 #define DMA_RESET 0x80
       
    59 
       
    60 typedef struct DMAState DMAState;
       
    61 
       
    62 struct DMAState {
       
    63     uint32_t dmaregs[DMA_REGS];
       
    64     qemu_irq irq;
       
    65     void *iommu;
       
    66     qemu_irq dev_reset;
       
    67 };
       
    68 
       
    69 /* Note: on sparc, the lance 16 bit bus is swapped */
       
    70 void ledma_memory_read(void *opaque, target_phys_addr_t addr,
       
    71                        uint8_t *buf, int len, int do_bswap)
       
    72 {
       
    73     DMAState *s = opaque;
       
    74     int i;
       
    75 
       
    76     DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n",
       
    77             s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
       
    78     addr |= s->dmaregs[3];
       
    79     if (do_bswap) {
       
    80         sparc_iommu_memory_read(s->iommu, addr, buf, len);
       
    81     } else {
       
    82         addr &= ~1;
       
    83         len &= ~1;
       
    84         sparc_iommu_memory_read(s->iommu, addr, buf, len);
       
    85         for(i = 0; i < len; i += 2) {
       
    86             bswap16s((uint16_t *)(buf + i));
       
    87         }
       
    88     }
       
    89 }
       
    90 
       
    91 void ledma_memory_write(void *opaque, target_phys_addr_t addr,
       
    92                         uint8_t *buf, int len, int do_bswap)
       
    93 {
       
    94     DMAState *s = opaque;
       
    95     int l, i;
       
    96     uint16_t tmp_buf[32];
       
    97 
       
    98     DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n",
       
    99             s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
       
   100     addr |= s->dmaregs[3];
       
   101     if (do_bswap) {
       
   102         sparc_iommu_memory_write(s->iommu, addr, buf, len);
       
   103     } else {
       
   104         addr &= ~1;
       
   105         len &= ~1;
       
   106         while (len > 0) {
       
   107             l = len;
       
   108             if (l > sizeof(tmp_buf))
       
   109                 l = sizeof(tmp_buf);
       
   110             for(i = 0; i < l; i += 2) {
       
   111                 tmp_buf[i >> 1] = bswap16(*(uint16_t *)(buf + i));
       
   112             }
       
   113             sparc_iommu_memory_write(s->iommu, addr, (uint8_t *)tmp_buf, l);
       
   114             len -= l;
       
   115             buf += l;
       
   116             addr += l;
       
   117         }
       
   118     }
       
   119 }
       
   120 
       
   121 static void dma_set_irq(void *opaque, int irq, int level)
       
   122 {
       
   123     DMAState *s = opaque;
       
   124     if (level) {
       
   125         DPRINTF("Raise IRQ\n");
       
   126         s->dmaregs[0] |= DMA_INTR;
       
   127         qemu_irq_raise(s->irq);
       
   128     } else {
       
   129         s->dmaregs[0] &= ~DMA_INTR;
       
   130         DPRINTF("Lower IRQ\n");
       
   131         qemu_irq_lower(s->irq);
       
   132     }
       
   133 }
       
   134 
       
   135 void espdma_memory_read(void *opaque, uint8_t *buf, int len)
       
   136 {
       
   137     DMAState *s = opaque;
       
   138 
       
   139     DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n",
       
   140             s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
       
   141     sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len);
       
   142     s->dmaregs[0] |= DMA_INTR;
       
   143     s->dmaregs[1] += len;
       
   144 }
       
   145 
       
   146 void espdma_memory_write(void *opaque, uint8_t *buf, int len)
       
   147 {
       
   148     DMAState *s = opaque;
       
   149 
       
   150     DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n",
       
   151             s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
       
   152     sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len);
       
   153     s->dmaregs[0] |= DMA_INTR;
       
   154     s->dmaregs[1] += len;
       
   155 }
       
   156 
       
   157 static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr)
       
   158 {
       
   159     DMAState *s = opaque;
       
   160     uint32_t saddr;
       
   161 
       
   162     saddr = (addr & DMA_MASK) >> 2;
       
   163     DPRINTF("read dmareg " TARGET_FMT_plx ": 0x%8.8x\n", addr,
       
   164             s->dmaregs[saddr]);
       
   165 
       
   166     return s->dmaregs[saddr];
       
   167 }
       
   168 
       
   169 static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
       
   170 {
       
   171     DMAState *s = opaque;
       
   172     uint32_t saddr;
       
   173 
       
   174     saddr = (addr & DMA_MASK) >> 2;
       
   175     DPRINTF("write dmareg " TARGET_FMT_plx ": 0x%8.8x -> 0x%8.8x\n", addr,
       
   176             s->dmaregs[saddr], val);
       
   177     switch (saddr) {
       
   178     case 0:
       
   179         if (!(val & DMA_INTREN)) {
       
   180             DPRINTF("Lower IRQ\n");
       
   181             qemu_irq_lower(s->irq);
       
   182         }
       
   183         if (val & DMA_RESET) {
       
   184             qemu_irq_raise(s->dev_reset);
       
   185             qemu_irq_lower(s->dev_reset);
       
   186         } else if (val & DMA_DRAIN_FIFO) {
       
   187             val &= ~DMA_DRAIN_FIFO;
       
   188         } else if (val == 0)
       
   189             val = DMA_DRAIN_FIFO;
       
   190         val &= 0x0fffffff;
       
   191         val |= DMA_VER;
       
   192         break;
       
   193     case 1:
       
   194         s->dmaregs[0] |= DMA_LOADED;
       
   195         break;
       
   196     default:
       
   197         break;
       
   198     }
       
   199     s->dmaregs[saddr] = val;
       
   200 }
       
   201 
       
   202 static CPUReadMemoryFunc *dma_mem_read[3] = {
       
   203     NULL,
       
   204     NULL,
       
   205     dma_mem_readl,
       
   206 };
       
   207 
       
   208 static CPUWriteMemoryFunc *dma_mem_write[3] = {
       
   209     NULL,
       
   210     NULL,
       
   211     dma_mem_writel,
       
   212 };
       
   213 
       
   214 static void dma_reset(void *opaque)
       
   215 {
       
   216     DMAState *s = opaque;
       
   217 
       
   218     memset(s->dmaregs, 0, DMA_SIZE);
       
   219     s->dmaregs[0] = DMA_VER;
       
   220 }
       
   221 
       
   222 static void dma_save(QEMUFile *f, void *opaque)
       
   223 {
       
   224     DMAState *s = opaque;
       
   225     unsigned int i;
       
   226 
       
   227     for (i = 0; i < DMA_REGS; i++)
       
   228         qemu_put_be32s(f, &s->dmaregs[i]);
       
   229 }
       
   230 
       
   231 static int dma_load(QEMUFile *f, void *opaque, int version_id)
       
   232 {
       
   233     DMAState *s = opaque;
       
   234     unsigned int i;
       
   235 
       
   236     if (version_id != 2)
       
   237         return -EINVAL;
       
   238     for (i = 0; i < DMA_REGS; i++)
       
   239         qemu_get_be32s(f, &s->dmaregs[i]);
       
   240 
       
   241     return 0;
       
   242 }
       
   243 
       
   244 void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq,
       
   245                        void *iommu, qemu_irq **dev_irq, qemu_irq **reset)
       
   246 {
       
   247     DMAState *s;
       
   248     int dma_io_memory;
       
   249 
       
   250     s = qemu_mallocz(sizeof(DMAState));
       
   251     if (!s)
       
   252         return NULL;
       
   253 
       
   254     s->irq = parent_irq;
       
   255     s->iommu = iommu;
       
   256 
       
   257     dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s);
       
   258     cpu_register_physical_memory(daddr, DMA_SIZE, dma_io_memory);
       
   259 
       
   260     register_savevm("sparc32_dma", daddr, 2, dma_save, dma_load, s);
       
   261     qemu_register_reset(dma_reset, s);
       
   262     *dev_irq = qemu_allocate_irqs(dma_set_irq, s, 1);
       
   263 
       
   264     *reset = &s->dev_reset;
       
   265 
       
   266     return s;
       
   267 }