Statistics
| Branch: | Revision:

root / hw / sparc32_dma.c @ d60efc6b

History | View | Annotate | Download (7.5 kB)

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

    
25
#include "hw.h"
26
#include "sparc32_dma.h"
27
#include "sun4m.h"
28
#include "sysbus.h"
29

    
30
/* debug DMA */
31
//#define DEBUG_DMA
32

    
33
/*
34
 * This is the DMA controller part of chip STP2000 (Master I/O), also
35
 * produced as NCR89C100. See
36
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
37
 * and
38
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt
39
 */
40

    
41
#ifdef DEBUG_DMA
42
#define DPRINTF(fmt, ...)                               \
43
    do { printf("DMA: " fmt , ## __VA_ARGS__); } while (0)
44
#else
45
#define DPRINTF(fmt, ...)
46
#endif
47

    
48
#define DMA_REGS 4
49
#define DMA_SIZE (4 * sizeof(uint32_t))
50
/* We need the mask, because one instance of the device is not page
51
   aligned (ledma, start address 0x0010) */
52
#define DMA_MASK (DMA_SIZE - 1)
53

    
54
#define DMA_VER 0xa0000000
55
#define DMA_INTR 1
56
#define DMA_INTREN 0x10
57
#define DMA_WRITE_MEM 0x100
58
#define DMA_LOADED 0x04000000
59
#define DMA_DRAIN_FIFO 0x40
60
#define DMA_RESET 0x80
61

    
62
typedef struct DMAState DMAState;
63

    
64
struct DMAState {
65
    SysBusDevice busdev;
66
    uint32_t dmaregs[DMA_REGS];
67
    qemu_irq irq;
68
    void *iommu;
69
    qemu_irq dev_reset;
70
};
71

    
72
/* Note: on sparc, the lance 16 bit bus is swapped */
73
void ledma_memory_read(void *opaque, target_phys_addr_t addr,
74
                       uint8_t *buf, int len, int do_bswap)
75
{
76
    DMAState *s = opaque;
77
    int i;
78

    
79
    DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n",
80
            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
81
    addr |= s->dmaregs[3];
82
    if (do_bswap) {
83
        sparc_iommu_memory_read(s->iommu, addr, buf, len);
84
    } else {
85
        addr &= ~1;
86
        len &= ~1;
87
        sparc_iommu_memory_read(s->iommu, addr, buf, len);
88
        for(i = 0; i < len; i += 2) {
89
            bswap16s((uint16_t *)(buf + i));
90
        }
91
    }
92
}
93

    
94
void ledma_memory_write(void *opaque, target_phys_addr_t addr,
95
                        uint8_t *buf, int len, int do_bswap)
96
{
97
    DMAState *s = opaque;
98
    int l, i;
99
    uint16_t tmp_buf[32];
100

    
101
    DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n",
102
            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
103
    addr |= s->dmaregs[3];
104
    if (do_bswap) {
105
        sparc_iommu_memory_write(s->iommu, addr, buf, len);
106
    } else {
107
        addr &= ~1;
108
        len &= ~1;
109
        while (len > 0) {
110
            l = len;
111
            if (l > sizeof(tmp_buf))
112
                l = sizeof(tmp_buf);
113
            for(i = 0; i < l; i += 2) {
114
                tmp_buf[i >> 1] = bswap16(*(uint16_t *)(buf + i));
115
            }
116
            sparc_iommu_memory_write(s->iommu, addr, (uint8_t *)tmp_buf, l);
117
            len -= l;
118
            buf += l;
119
            addr += l;
120
        }
121
    }
122
}
123

    
124
static void dma_set_irq(void *opaque, int irq, int level)
125
{
126
    DMAState *s = opaque;
127
    if (level) {
128
        DPRINTF("Raise IRQ\n");
129
        s->dmaregs[0] |= DMA_INTR;
130
        qemu_irq_raise(s->irq);
131
    } else {
132
        s->dmaregs[0] &= ~DMA_INTR;
133
        DPRINTF("Lower IRQ\n");
134
        qemu_irq_lower(s->irq);
135
    }
136
}
137

    
138
void espdma_memory_read(void *opaque, uint8_t *buf, int len)
139
{
140
    DMAState *s = opaque;
141

    
142
    DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n",
143
            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
144
    sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len);
145
    s->dmaregs[0] |= DMA_INTR;
146
    s->dmaregs[1] += len;
147
}
148

    
149
void espdma_memory_write(void *opaque, uint8_t *buf, int len)
150
{
151
    DMAState *s = opaque;
152

    
153
    DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n",
154
            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
155
    sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len);
156
    s->dmaregs[0] |= DMA_INTR;
157
    s->dmaregs[1] += len;
158
}
159

    
160
static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr)
161
{
162
    DMAState *s = opaque;
163
    uint32_t saddr;
164

    
165
    saddr = (addr & DMA_MASK) >> 2;
166
    DPRINTF("read dmareg " TARGET_FMT_plx ": 0x%8.8x\n", addr,
167
            s->dmaregs[saddr]);
168

    
169
    return s->dmaregs[saddr];
170
}
171

    
172
static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
173
{
174
    DMAState *s = opaque;
175
    uint32_t saddr;
176

    
177
    saddr = (addr & DMA_MASK) >> 2;
178
    DPRINTF("write dmareg " TARGET_FMT_plx ": 0x%8.8x -> 0x%8.8x\n", addr,
179
            s->dmaregs[saddr], val);
180
    switch (saddr) {
181
    case 0:
182
        if (!(val & DMA_INTREN)) {
183
            DPRINTF("Lower IRQ\n");
184
            qemu_irq_lower(s->irq);
185
        }
186
        if (val & DMA_RESET) {
187
            qemu_irq_raise(s->dev_reset);
188
            qemu_irq_lower(s->dev_reset);
189
        } else if (val & DMA_DRAIN_FIFO) {
190
            val &= ~DMA_DRAIN_FIFO;
191
        } else if (val == 0)
192
            val = DMA_DRAIN_FIFO;
193
        val &= 0x0fffffff;
194
        val |= DMA_VER;
195
        break;
196
    case 1:
197
        s->dmaregs[0] |= DMA_LOADED;
198
        break;
199
    default:
200
        break;
201
    }
202
    s->dmaregs[saddr] = val;
203
}
204

    
205
static CPUReadMemoryFunc * const dma_mem_read[3] = {
206
    NULL,
207
    NULL,
208
    dma_mem_readl,
209
};
210

    
211
static CPUWriteMemoryFunc * const dma_mem_write[3] = {
212
    NULL,
213
    NULL,
214
    dma_mem_writel,
215
};
216

    
217
static void dma_reset(void *opaque)
218
{
219
    DMAState *s = opaque;
220

    
221
    memset(s->dmaregs, 0, DMA_SIZE);
222
    s->dmaregs[0] = DMA_VER;
223
}
224

    
225
static void dma_save(QEMUFile *f, void *opaque)
226
{
227
    DMAState *s = opaque;
228
    unsigned int i;
229

    
230
    for (i = 0; i < DMA_REGS; i++)
231
        qemu_put_be32s(f, &s->dmaregs[i]);
232
}
233

    
234
static int dma_load(QEMUFile *f, void *opaque, int version_id)
235
{
236
    DMAState *s = opaque;
237
    unsigned int i;
238

    
239
    if (version_id != 2)
240
        return -EINVAL;
241
    for (i = 0; i < DMA_REGS; i++)
242
        qemu_get_be32s(f, &s->dmaregs[i]);
243

    
244
    return 0;
245
}
246

    
247
static void sparc32_dma_init1(SysBusDevice *dev)
248
{
249
    DMAState *s = FROM_SYSBUS(DMAState, dev);
250
    int dma_io_memory;
251

    
252
    sysbus_init_irq(dev, &s->irq);
253

    
254
    dma_io_memory = cpu_register_io_memory(dma_mem_read, dma_mem_write, s);
255
    sysbus_init_mmio(dev, DMA_SIZE, dma_io_memory);
256

    
257
    register_savevm("sparc32_dma", -1, 2, dma_save, dma_load, s);
258
    qemu_register_reset(dma_reset, s);
259

    
260
    qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1);
261
    qdev_init_gpio_out(&dev->qdev, &s->dev_reset, 1);
262
}
263

    
264
static SysBusDeviceInfo sparc32_dma_info = {
265
    .init = sparc32_dma_init1,
266
    .qdev.name  = "sparc32_dma",
267
    .qdev.size  = sizeof(DMAState),
268
    .qdev.props = (Property[]) {
269
        DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
270
        DEFINE_PROP_END_OF_LIST(),
271
    }
272
};
273

    
274
static void sparc32_dma_register_devices(void)
275
{
276
    sysbus_register_withprop(&sparc32_dma_info);
277
}
278

    
279
device_init(sparc32_dma_register_devices)