|
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 } |