Revision 502a5395 hw/versatilepb.c
b/hw/versatilepb.c | ||
---|---|---|
10 | 10 |
#include "vl.h" |
11 | 11 |
#include "arm_pic.h" |
12 | 12 |
|
13 |
#define LOCK_VALUE 0xa05f |
|
14 |
|
|
13 | 15 |
/* Primary interrupt controller. */ |
14 | 16 |
|
15 | 17 |
typedef struct vpb_sic_state |
... | ... | |
145 | 147 |
return s; |
146 | 148 |
} |
147 | 149 |
|
150 |
/* System controller. */ |
|
151 |
|
|
152 |
typedef struct { |
|
153 |
uint32_t base; |
|
154 |
uint32_t leds; |
|
155 |
uint16_t lockval; |
|
156 |
uint32_t cfgdata1; |
|
157 |
uint32_t cfgdata2; |
|
158 |
uint32_t flags; |
|
159 |
uint32_t nvflags; |
|
160 |
uint32_t resetlevel; |
|
161 |
} vpb_sys_state; |
|
162 |
|
|
163 |
static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset) |
|
164 |
{ |
|
165 |
vpb_sys_state *s = (vpb_sys_state *)opaque; |
|
166 |
|
|
167 |
offset -= s->base; |
|
168 |
switch (offset) { |
|
169 |
case 0x00: /* ID */ |
|
170 |
return 0x41007004; |
|
171 |
case 0x04: /* SW */ |
|
172 |
/* General purpose hardware switches. |
|
173 |
We don't have a useful way of exposing these to the user. */ |
|
174 |
return 0; |
|
175 |
case 0x08: /* LED */ |
|
176 |
return s->leds; |
|
177 |
case 0x20: /* LOCK */ |
|
178 |
return s->lockval; |
|
179 |
case 0x0c: /* OSC0 */ |
|
180 |
case 0x10: /* OSC1 */ |
|
181 |
case 0x14: /* OSC2 */ |
|
182 |
case 0x18: /* OSC3 */ |
|
183 |
case 0x1c: /* OSC4 */ |
|
184 |
case 0x24: /* 100HZ */ |
|
185 |
/* ??? Implement these. */ |
|
186 |
return 0; |
|
187 |
case 0x28: /* CFGDATA1 */ |
|
188 |
return s->cfgdata1; |
|
189 |
case 0x2c: /* CFGDATA2 */ |
|
190 |
return s->cfgdata2; |
|
191 |
case 0x30: /* FLAGS */ |
|
192 |
return s->flags; |
|
193 |
case 0x38: /* NVFLAGS */ |
|
194 |
return s->nvflags; |
|
195 |
case 0x40: /* RESETCTL */ |
|
196 |
return s->resetlevel; |
|
197 |
case 0x44: /* PCICTL */ |
|
198 |
return 1; |
|
199 |
case 0x48: /* MCI */ |
|
200 |
return 0; |
|
201 |
case 0x4c: /* FLASH */ |
|
202 |
return 0; |
|
203 |
case 0x50: /* CLCD */ |
|
204 |
return 0x1000; |
|
205 |
case 0x54: /* CLCDSER */ |
|
206 |
return 0; |
|
207 |
case 0x58: /* BOOTCS */ |
|
208 |
return 0; |
|
209 |
case 0x5c: /* 24MHz */ |
|
210 |
/* ??? not implemented. */ |
|
211 |
return 0; |
|
212 |
case 0x60: /* MISC */ |
|
213 |
return 0; |
|
214 |
case 0x64: /* DMAPSR0 */ |
|
215 |
case 0x68: /* DMAPSR1 */ |
|
216 |
case 0x6c: /* DMAPSR2 */ |
|
217 |
case 0x8c: /* OSCRESET0 */ |
|
218 |
case 0x90: /* OSCRESET1 */ |
|
219 |
case 0x94: /* OSCRESET2 */ |
|
220 |
case 0x98: /* OSCRESET3 */ |
|
221 |
case 0x9c: /* OSCRESET4 */ |
|
222 |
case 0xc0: /* SYS_TEST_OSC0 */ |
|
223 |
case 0xc4: /* SYS_TEST_OSC1 */ |
|
224 |
case 0xc8: /* SYS_TEST_OSC2 */ |
|
225 |
case 0xcc: /* SYS_TEST_OSC3 */ |
|
226 |
case 0xd0: /* SYS_TEST_OSC4 */ |
|
227 |
return 0; |
|
228 |
default: |
|
229 |
printf ("vpb_sys_read: Bad register offset 0x%x\n", offset); |
|
230 |
return 0; |
|
231 |
} |
|
232 |
} |
|
233 |
|
|
234 |
static void vpb_sys_write(void *opaque, target_phys_addr_t offset, |
|
235 |
uint32_t val) |
|
236 |
{ |
|
237 |
vpb_sys_state *s = (vpb_sys_state *)opaque; |
|
238 |
offset -= s->base; |
|
239 |
|
|
240 |
switch (offset) { |
|
241 |
case 0x08: /* LED */ |
|
242 |
s->leds = val; |
|
243 |
case 0x0c: /* OSC0 */ |
|
244 |
case 0x10: /* OSC1 */ |
|
245 |
case 0x14: /* OSC2 */ |
|
246 |
case 0x18: /* OSC3 */ |
|
247 |
case 0x1c: /* OSC4 */ |
|
248 |
/* ??? */ |
|
249 |
break; |
|
250 |
case 0x20: /* LOCK */ |
|
251 |
if (val == LOCK_VALUE) |
|
252 |
s->lockval = val; |
|
253 |
else |
|
254 |
s->lockval = val & 0x7fff; |
|
255 |
break; |
|
256 |
case 0x28: /* CFGDATA1 */ |
|
257 |
/* ??? Need to implement this. */ |
|
258 |
s->cfgdata1 = val; |
|
259 |
break; |
|
260 |
case 0x2c: /* CFGDATA2 */ |
|
261 |
/* ??? Need to implement this. */ |
|
262 |
s->cfgdata2 = val; |
|
263 |
break; |
|
264 |
case 0x30: /* FLAGSSET */ |
|
265 |
s->flags |= val; |
|
266 |
break; |
|
267 |
case 0x34: /* FLAGSCLR */ |
|
268 |
s->flags &= ~val; |
|
269 |
break; |
|
270 |
case 0x38: /* NVFLAGSSET */ |
|
271 |
s->nvflags |= val; |
|
272 |
break; |
|
273 |
case 0x3c: /* NVFLAGSCLR */ |
|
274 |
s->nvflags &= ~val; |
|
275 |
break; |
|
276 |
case 0x40: /* RESETCTL */ |
|
277 |
if (s->lockval == LOCK_VALUE) { |
|
278 |
s->resetlevel = val; |
|
279 |
if (val & 0x100) |
|
280 |
cpu_abort(cpu_single_env, "Board reset\n"); |
|
281 |
} |
|
282 |
break; |
|
283 |
case 0x44: /* PCICTL */ |
|
284 |
/* nothing to do. */ |
|
285 |
break; |
|
286 |
case 0x4c: /* FLASH */ |
|
287 |
case 0x50: /* CLCD */ |
|
288 |
case 0x54: /* CLCDSER */ |
|
289 |
case 0x64: /* DMAPSR0 */ |
|
290 |
case 0x68: /* DMAPSR1 */ |
|
291 |
case 0x6c: /* DMAPSR2 */ |
|
292 |
case 0x8c: /* OSCRESET0 */ |
|
293 |
case 0x90: /* OSCRESET1 */ |
|
294 |
case 0x94: /* OSCRESET2 */ |
|
295 |
case 0x98: /* OSCRESET3 */ |
|
296 |
case 0x9c: /* OSCRESET4 */ |
|
297 |
break; |
|
298 |
default: |
|
299 |
printf ("vpb_sys_write: Bad register offset 0x%x\n", offset); |
|
300 |
return; |
|
301 |
} |
|
302 |
} |
|
303 |
|
|
304 |
static CPUReadMemoryFunc *vpb_sys_readfn[] = { |
|
305 |
vpb_sys_read, |
|
306 |
vpb_sys_read, |
|
307 |
vpb_sys_read |
|
308 |
}; |
|
309 |
|
|
310 |
static CPUWriteMemoryFunc *vpb_sys_writefn[] = { |
|
311 |
vpb_sys_write, |
|
312 |
vpb_sys_write, |
|
313 |
vpb_sys_write |
|
314 |
}; |
|
315 |
|
|
316 |
static vpb_sys_state *vpb_sys_init(uint32_t base) |
|
317 |
{ |
|
318 |
vpb_sys_state *s; |
|
319 |
int iomemtype; |
|
320 |
|
|
321 |
s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state)); |
|
322 |
if (!s) |
|
323 |
return NULL; |
|
324 |
s->base = base; |
|
325 |
iomemtype = cpu_register_io_memory(0, vpb_sys_readfn, |
|
326 |
vpb_sys_writefn, s); |
|
327 |
cpu_register_physical_memory(base, 0x00000fff, iomemtype); |
|
328 |
/* ??? Save/restore. */ |
|
329 |
return s; |
|
330 |
} |
|
331 |
|
|
148 | 332 |
/* Board init. */ |
149 | 333 |
|
150 | 334 |
/* The AB and PB boards both use the same core, just with different |
... | ... | |
159 | 343 |
CPUState *env; |
160 | 344 |
void *pic; |
161 | 345 |
void *sic; |
346 |
PCIBus *pci_bus; |
|
347 |
NICInfo *nd; |
|
348 |
int n; |
|
349 |
int done_smc = 0; |
|
162 | 350 |
|
163 | 351 |
env = cpu_init(); |
164 | 352 |
cpu_arm_set_model(env, ARM_CPUID_ARM926); |
... | ... | |
166 | 354 |
/* SDRAM at address zero. */ |
167 | 355 |
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); |
168 | 356 |
|
357 |
vpb_sys_init(0x10000000); |
|
169 | 358 |
pic = arm_pic_init_cpu(env); |
170 | 359 |
pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); |
171 | 360 |
sic = vpb_sic_init(0x10003000, pic, 31); |
172 | 361 |
pl050_init(0x10006000, sic, 3, 0); |
173 | 362 |
pl050_init(0x10007000, sic, 4, 1); |
174 | 363 |
|
175 |
/* TODO: Init PCI NICs. */ |
|
176 |
if (nd_table[0].vlan) { |
|
177 |
if (nd_table[0].model == NULL |
|
178 |
|| strcmp(nd_table[0].model, "smc91c111") == 0) { |
|
179 |
smc91c111_init(&nd_table[0], 0x10010000, sic, 25); |
|
364 |
pci_bus = pci_vpb_init(sic); |
|
365 |
/* The Versatile PCI bridge does not provide access to PCI IO space, |
|
366 |
so many of the qemu PCI devices are not useable. */ |
|
367 |
for(n = 0; n < nb_nics; n++) { |
|
368 |
nd = &nd_table[n]; |
|
369 |
if (!nd->model) |
|
370 |
nd->model = done_smc ? "rtl8139" : "smc91c111"; |
|
371 |
if (strcmp(nd->model, "smc91c111") == 0) { |
|
372 |
smc91c111_init(nd, 0x10010000, sic, 25); |
|
180 | 373 |
} else { |
181 |
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); |
|
182 |
exit (1); |
|
374 |
pci_nic_init(pci_bus, nd); |
|
183 | 375 |
} |
184 | 376 |
} |
185 | 377 |
|
Also available in: Unified diff