|
1 /* |
|
2 * Luminary Micro Stellaris peripherals |
|
3 * |
|
4 * Copyright (c) 2006 CodeSourcery. |
|
5 * Written by Paul Brook |
|
6 * |
|
7 * This code is licenced under the GPL. |
|
8 */ |
|
9 |
|
10 #include "hw.h" |
|
11 #include "arm-misc.h" |
|
12 #include "primecell.h" |
|
13 #include "devices.h" |
|
14 #include "qemu-timer.h" |
|
15 #include "i2c.h" |
|
16 #include "net.h" |
|
17 #include "sd.h" |
|
18 #include "sysemu.h" |
|
19 #include "boards.h" |
|
20 |
|
21 #define GPIO_A 0 |
|
22 #define GPIO_B 1 |
|
23 #define GPIO_C 2 |
|
24 #define GPIO_D 3 |
|
25 #define GPIO_E 4 |
|
26 #define GPIO_F 5 |
|
27 #define GPIO_G 6 |
|
28 |
|
29 #define BP_OLED_I2C 0x01 |
|
30 #define BP_OLED_SSI 0x02 |
|
31 #define BP_GAMEPAD 0x04 |
|
32 |
|
33 typedef const struct { |
|
34 const char *name; |
|
35 uint32_t did0; |
|
36 uint32_t did1; |
|
37 uint32_t dc0; |
|
38 uint32_t dc1; |
|
39 uint32_t dc2; |
|
40 uint32_t dc3; |
|
41 uint32_t dc4; |
|
42 uint32_t peripherals; |
|
43 } stellaris_board_info; |
|
44 |
|
45 /* General purpose timer module. */ |
|
46 |
|
47 typedef struct gptm_state { |
|
48 uint32_t config; |
|
49 uint32_t mode[2]; |
|
50 uint32_t control; |
|
51 uint32_t state; |
|
52 uint32_t mask; |
|
53 uint32_t load[2]; |
|
54 uint32_t match[2]; |
|
55 uint32_t prescale[2]; |
|
56 uint32_t match_prescale[2]; |
|
57 uint32_t rtc; |
|
58 int64_t tick[2]; |
|
59 struct gptm_state *opaque[2]; |
|
60 QEMUTimer *timer[2]; |
|
61 /* The timers have an alternate output used to trigger the ADC. */ |
|
62 qemu_irq trigger; |
|
63 qemu_irq irq; |
|
64 } gptm_state; |
|
65 |
|
66 static void gptm_update_irq(gptm_state *s) |
|
67 { |
|
68 int level; |
|
69 level = (s->state & s->mask) != 0; |
|
70 qemu_set_irq(s->irq, level); |
|
71 } |
|
72 |
|
73 static void gptm_stop(gptm_state *s, int n) |
|
74 { |
|
75 qemu_del_timer(s->timer[n]); |
|
76 } |
|
77 |
|
78 static void gptm_reload(gptm_state *s, int n, int reset) |
|
79 { |
|
80 int64_t tick; |
|
81 if (reset) |
|
82 tick = qemu_get_clock(vm_clock); |
|
83 else |
|
84 tick = s->tick[n]; |
|
85 |
|
86 if (s->config == 0) { |
|
87 /* 32-bit CountDown. */ |
|
88 uint32_t count; |
|
89 count = s->load[0] | (s->load[1] << 16); |
|
90 tick += (int64_t)count * system_clock_scale; |
|
91 } else if (s->config == 1) { |
|
92 /* 32-bit RTC. 1Hz tick. */ |
|
93 tick += ticks_per_sec; |
|
94 } else if (s->mode[n] == 0xa) { |
|
95 /* PWM mode. Not implemented. */ |
|
96 } else { |
|
97 cpu_abort(cpu_single_env, "TODO: 16-bit timer mode 0x%x\n", |
|
98 s->mode[n]); |
|
99 } |
|
100 s->tick[n] = tick; |
|
101 qemu_mod_timer(s->timer[n], tick); |
|
102 } |
|
103 |
|
104 static void gptm_tick(void *opaque) |
|
105 { |
|
106 gptm_state **p = (gptm_state **)opaque; |
|
107 gptm_state *s; |
|
108 int n; |
|
109 |
|
110 s = *p; |
|
111 n = p - s->opaque; |
|
112 if (s->config == 0) { |
|
113 s->state |= 1; |
|
114 if ((s->control & 0x20)) { |
|
115 /* Output trigger. */ |
|
116 qemu_irq_raise(s->trigger); |
|
117 qemu_irq_lower(s->trigger); |
|
118 } |
|
119 if (s->mode[0] & 1) { |
|
120 /* One-shot. */ |
|
121 s->control &= ~1; |
|
122 } else { |
|
123 /* Periodic. */ |
|
124 gptm_reload(s, 0, 0); |
|
125 } |
|
126 } else if (s->config == 1) { |
|
127 /* RTC. */ |
|
128 uint32_t match; |
|
129 s->rtc++; |
|
130 match = s->match[0] | (s->match[1] << 16); |
|
131 if (s->rtc > match) |
|
132 s->rtc = 0; |
|
133 if (s->rtc == 0) { |
|
134 s->state |= 8; |
|
135 } |
|
136 gptm_reload(s, 0, 0); |
|
137 } else if (s->mode[n] == 0xa) { |
|
138 /* PWM mode. Not implemented. */ |
|
139 } else { |
|
140 cpu_abort(cpu_single_env, "TODO: 16-bit timer mode 0x%x\n", |
|
141 s->mode[n]); |
|
142 } |
|
143 gptm_update_irq(s); |
|
144 } |
|
145 |
|
146 static uint32_t gptm_read(void *opaque, target_phys_addr_t offset) |
|
147 { |
|
148 gptm_state *s = (gptm_state *)opaque; |
|
149 |
|
150 switch (offset) { |
|
151 case 0x00: /* CFG */ |
|
152 return s->config; |
|
153 case 0x04: /* TAMR */ |
|
154 return s->mode[0]; |
|
155 case 0x08: /* TBMR */ |
|
156 return s->mode[1]; |
|
157 case 0x0c: /* CTL */ |
|
158 return s->control; |
|
159 case 0x18: /* IMR */ |
|
160 return s->mask; |
|
161 case 0x1c: /* RIS */ |
|
162 return s->state; |
|
163 case 0x20: /* MIS */ |
|
164 return s->state & s->mask; |
|
165 case 0x24: /* CR */ |
|
166 return 0; |
|
167 case 0x28: /* TAILR */ |
|
168 return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0); |
|
169 case 0x2c: /* TBILR */ |
|
170 return s->load[1]; |
|
171 case 0x30: /* TAMARCHR */ |
|
172 return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0); |
|
173 case 0x34: /* TBMATCHR */ |
|
174 return s->match[1]; |
|
175 case 0x38: /* TAPR */ |
|
176 return s->prescale[0]; |
|
177 case 0x3c: /* TBPR */ |
|
178 return s->prescale[1]; |
|
179 case 0x40: /* TAPMR */ |
|
180 return s->match_prescale[0]; |
|
181 case 0x44: /* TBPMR */ |
|
182 return s->match_prescale[1]; |
|
183 case 0x48: /* TAR */ |
|
184 if (s->control == 1) |
|
185 return s->rtc; |
|
186 case 0x4c: /* TBR */ |
|
187 cpu_abort(cpu_single_env, "TODO: Timer value read\n"); |
|
188 default: |
|
189 cpu_abort(cpu_single_env, "gptm_read: Bad offset 0x%x\n", (int)offset); |
|
190 return 0; |
|
191 } |
|
192 } |
|
193 |
|
194 static void gptm_write(void *opaque, target_phys_addr_t offset, uint32_t value) |
|
195 { |
|
196 gptm_state *s = (gptm_state *)opaque; |
|
197 uint32_t oldval; |
|
198 |
|
199 /* The timers should be disabled before changing the configuration. |
|
200 We take advantage of this and defer everything until the timer |
|
201 is enabled. */ |
|
202 switch (offset) { |
|
203 case 0x00: /* CFG */ |
|
204 s->config = value; |
|
205 break; |
|
206 case 0x04: /* TAMR */ |
|
207 s->mode[0] = value; |
|
208 break; |
|
209 case 0x08: /* TBMR */ |
|
210 s->mode[1] = value; |
|
211 break; |
|
212 case 0x0c: /* CTL */ |
|
213 oldval = s->control; |
|
214 s->control = value; |
|
215 /* TODO: Implement pause. */ |
|
216 if ((oldval ^ value) & 1) { |
|
217 if (value & 1) { |
|
218 gptm_reload(s, 0, 1); |
|
219 } else { |
|
220 gptm_stop(s, 0); |
|
221 } |
|
222 } |
|
223 if (((oldval ^ value) & 0x100) && s->config >= 4) { |
|
224 if (value & 0x100) { |
|
225 gptm_reload(s, 1, 1); |
|
226 } else { |
|
227 gptm_stop(s, 1); |
|
228 } |
|
229 } |
|
230 break; |
|
231 case 0x18: /* IMR */ |
|
232 s->mask = value & 0x77; |
|
233 gptm_update_irq(s); |
|
234 break; |
|
235 case 0x24: /* CR */ |
|
236 s->state &= ~value; |
|
237 break; |
|
238 case 0x28: /* TAILR */ |
|
239 s->load[0] = value & 0xffff; |
|
240 if (s->config < 4) { |
|
241 s->load[1] = value >> 16; |
|
242 } |
|
243 break; |
|
244 case 0x2c: /* TBILR */ |
|
245 s->load[1] = value & 0xffff; |
|
246 break; |
|
247 case 0x30: /* TAMARCHR */ |
|
248 s->match[0] = value & 0xffff; |
|
249 if (s->config < 4) { |
|
250 s->match[1] = value >> 16; |
|
251 } |
|
252 break; |
|
253 case 0x34: /* TBMATCHR */ |
|
254 s->match[1] = value >> 16; |
|
255 break; |
|
256 case 0x38: /* TAPR */ |
|
257 s->prescale[0] = value; |
|
258 break; |
|
259 case 0x3c: /* TBPR */ |
|
260 s->prescale[1] = value; |
|
261 break; |
|
262 case 0x40: /* TAPMR */ |
|
263 s->match_prescale[0] = value; |
|
264 break; |
|
265 case 0x44: /* TBPMR */ |
|
266 s->match_prescale[0] = value; |
|
267 break; |
|
268 default: |
|
269 cpu_abort(cpu_single_env, "gptm_write: Bad offset 0x%x\n", (int)offset); |
|
270 } |
|
271 gptm_update_irq(s); |
|
272 } |
|
273 |
|
274 static CPUReadMemoryFunc *gptm_readfn[] = { |
|
275 gptm_read, |
|
276 gptm_read, |
|
277 gptm_read |
|
278 }; |
|
279 |
|
280 static CPUWriteMemoryFunc *gptm_writefn[] = { |
|
281 gptm_write, |
|
282 gptm_write, |
|
283 gptm_write |
|
284 }; |
|
285 |
|
286 static void gptm_save(QEMUFile *f, void *opaque) |
|
287 { |
|
288 gptm_state *s = (gptm_state *)opaque; |
|
289 |
|
290 qemu_put_be32(f, s->config); |
|
291 qemu_put_be32(f, s->mode[0]); |
|
292 qemu_put_be32(f, s->mode[1]); |
|
293 qemu_put_be32(f, s->control); |
|
294 qemu_put_be32(f, s->state); |
|
295 qemu_put_be32(f, s->mask); |
|
296 qemu_put_be32(f, s->mode[0]); |
|
297 qemu_put_be32(f, s->mode[0]); |
|
298 qemu_put_be32(f, s->load[0]); |
|
299 qemu_put_be32(f, s->load[1]); |
|
300 qemu_put_be32(f, s->match[0]); |
|
301 qemu_put_be32(f, s->match[1]); |
|
302 qemu_put_be32(f, s->prescale[0]); |
|
303 qemu_put_be32(f, s->prescale[1]); |
|
304 qemu_put_be32(f, s->match_prescale[0]); |
|
305 qemu_put_be32(f, s->match_prescale[1]); |
|
306 qemu_put_be32(f, s->rtc); |
|
307 qemu_put_be64(f, s->tick[0]); |
|
308 qemu_put_be64(f, s->tick[1]); |
|
309 qemu_put_timer(f, s->timer[0]); |
|
310 qemu_put_timer(f, s->timer[1]); |
|
311 } |
|
312 |
|
313 static int gptm_load(QEMUFile *f, void *opaque, int version_id) |
|
314 { |
|
315 gptm_state *s = (gptm_state *)opaque; |
|
316 |
|
317 if (version_id != 1) |
|
318 return -EINVAL; |
|
319 |
|
320 s->config = qemu_get_be32(f); |
|
321 s->mode[0] = qemu_get_be32(f); |
|
322 s->mode[1] = qemu_get_be32(f); |
|
323 s->control = qemu_get_be32(f); |
|
324 s->state = qemu_get_be32(f); |
|
325 s->mask = qemu_get_be32(f); |
|
326 s->mode[0] = qemu_get_be32(f); |
|
327 s->mode[0] = qemu_get_be32(f); |
|
328 s->load[0] = qemu_get_be32(f); |
|
329 s->load[1] = qemu_get_be32(f); |
|
330 s->match[0] = qemu_get_be32(f); |
|
331 s->match[1] = qemu_get_be32(f); |
|
332 s->prescale[0] = qemu_get_be32(f); |
|
333 s->prescale[1] = qemu_get_be32(f); |
|
334 s->match_prescale[0] = qemu_get_be32(f); |
|
335 s->match_prescale[1] = qemu_get_be32(f); |
|
336 s->rtc = qemu_get_be32(f); |
|
337 s->tick[0] = qemu_get_be64(f); |
|
338 s->tick[1] = qemu_get_be64(f); |
|
339 qemu_get_timer(f, s->timer[0]); |
|
340 qemu_get_timer(f, s->timer[1]); |
|
341 |
|
342 return 0; |
|
343 } |
|
344 |
|
345 static void stellaris_gptm_init(uint32_t base, qemu_irq irq, qemu_irq trigger) |
|
346 { |
|
347 int iomemtype; |
|
348 gptm_state *s; |
|
349 |
|
350 s = (gptm_state *)qemu_mallocz(sizeof(gptm_state)); |
|
351 s->irq = irq; |
|
352 s->trigger = trigger; |
|
353 s->opaque[0] = s->opaque[1] = s; |
|
354 |
|
355 iomemtype = cpu_register_io_memory(0, gptm_readfn, |
|
356 gptm_writefn, s); |
|
357 cpu_register_physical_memory(base, 0x00001000, iomemtype); |
|
358 s->timer[0] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[0]); |
|
359 s->timer[1] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[1]); |
|
360 register_savevm("stellaris_gptm", -1, 1, gptm_save, gptm_load, s); |
|
361 } |
|
362 |
|
363 |
|
364 /* System controller. */ |
|
365 |
|
366 typedef struct { |
|
367 uint32_t pborctl; |
|
368 uint32_t ldopctl; |
|
369 uint32_t int_status; |
|
370 uint32_t int_mask; |
|
371 uint32_t resc; |
|
372 uint32_t rcc; |
|
373 uint32_t rcgc[3]; |
|
374 uint32_t scgc[3]; |
|
375 uint32_t dcgc[3]; |
|
376 uint32_t clkvclr; |
|
377 uint32_t ldoarst; |
|
378 uint32_t user0; |
|
379 uint32_t user1; |
|
380 qemu_irq irq; |
|
381 stellaris_board_info *board; |
|
382 } ssys_state; |
|
383 |
|
384 static void ssys_update(ssys_state *s) |
|
385 { |
|
386 qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0); |
|
387 } |
|
388 |
|
389 static uint32_t pllcfg_sandstorm[16] = { |
|
390 0x31c0, /* 1 Mhz */ |
|
391 0x1ae0, /* 1.8432 Mhz */ |
|
392 0x18c0, /* 2 Mhz */ |
|
393 0xd573, /* 2.4576 Mhz */ |
|
394 0x37a6, /* 3.57954 Mhz */ |
|
395 0x1ae2, /* 3.6864 Mhz */ |
|
396 0x0c40, /* 4 Mhz */ |
|
397 0x98bc, /* 4.906 Mhz */ |
|
398 0x935b, /* 4.9152 Mhz */ |
|
399 0x09c0, /* 5 Mhz */ |
|
400 0x4dee, /* 5.12 Mhz */ |
|
401 0x0c41, /* 6 Mhz */ |
|
402 0x75db, /* 6.144 Mhz */ |
|
403 0x1ae6, /* 7.3728 Mhz */ |
|
404 0x0600, /* 8 Mhz */ |
|
405 0x585b /* 8.192 Mhz */ |
|
406 }; |
|
407 |
|
408 static uint32_t pllcfg_fury[16] = { |
|
409 0x3200, /* 1 Mhz */ |
|
410 0x1b20, /* 1.8432 Mhz */ |
|
411 0x1900, /* 2 Mhz */ |
|
412 0xf42b, /* 2.4576 Mhz */ |
|
413 0x37e3, /* 3.57954 Mhz */ |
|
414 0x1b21, /* 3.6864 Mhz */ |
|
415 0x0c80, /* 4 Mhz */ |
|
416 0x98ee, /* 4.906 Mhz */ |
|
417 0xd5b4, /* 4.9152 Mhz */ |
|
418 0x0a00, /* 5 Mhz */ |
|
419 0x4e27, /* 5.12 Mhz */ |
|
420 0x1902, /* 6 Mhz */ |
|
421 0xec1c, /* 6.144 Mhz */ |
|
422 0x1b23, /* 7.3728 Mhz */ |
|
423 0x0640, /* 8 Mhz */ |
|
424 0xb11c /* 8.192 Mhz */ |
|
425 }; |
|
426 |
|
427 static uint32_t ssys_read(void *opaque, target_phys_addr_t offset) |
|
428 { |
|
429 ssys_state *s = (ssys_state *)opaque; |
|
430 |
|
431 switch (offset) { |
|
432 case 0x000: /* DID0 */ |
|
433 return s->board->did0; |
|
434 case 0x004: /* DID1 */ |
|
435 return s->board->did1; |
|
436 case 0x008: /* DC0 */ |
|
437 return s->board->dc0; |
|
438 case 0x010: /* DC1 */ |
|
439 return s->board->dc1; |
|
440 case 0x014: /* DC2 */ |
|
441 return s->board->dc2; |
|
442 case 0x018: /* DC3 */ |
|
443 return s->board->dc3; |
|
444 case 0x01c: /* DC4 */ |
|
445 return s->board->dc4; |
|
446 case 0x030: /* PBORCTL */ |
|
447 return s->pborctl; |
|
448 case 0x034: /* LDOPCTL */ |
|
449 return s->ldopctl; |
|
450 case 0x040: /* SRCR0 */ |
|
451 return 0; |
|
452 case 0x044: /* SRCR1 */ |
|
453 return 0; |
|
454 case 0x048: /* SRCR2 */ |
|
455 return 0; |
|
456 case 0x050: /* RIS */ |
|
457 return s->int_status; |
|
458 case 0x054: /* IMC */ |
|
459 return s->int_mask; |
|
460 case 0x058: /* MISC */ |
|
461 return s->int_status & s->int_mask; |
|
462 case 0x05c: /* RESC */ |
|
463 return s->resc; |
|
464 case 0x060: /* RCC */ |
|
465 return s->rcc; |
|
466 case 0x064: /* PLLCFG */ |
|
467 { |
|
468 int xtal; |
|
469 xtal = (s->rcc >> 6) & 0xf; |
|
470 if (s->board->did0 & (1 << 16)) { |
|
471 return pllcfg_fury[xtal]; |
|
472 } else { |
|
473 return pllcfg_sandstorm[xtal]; |
|
474 } |
|
475 } |
|
476 case 0x100: /* RCGC0 */ |
|
477 return s->rcgc[0]; |
|
478 case 0x104: /* RCGC1 */ |
|
479 return s->rcgc[1]; |
|
480 case 0x108: /* RCGC2 */ |
|
481 return s->rcgc[2]; |
|
482 case 0x110: /* SCGC0 */ |
|
483 return s->scgc[0]; |
|
484 case 0x114: /* SCGC1 */ |
|
485 return s->scgc[1]; |
|
486 case 0x118: /* SCGC2 */ |
|
487 return s->scgc[2]; |
|
488 case 0x120: /* DCGC0 */ |
|
489 return s->dcgc[0]; |
|
490 case 0x124: /* DCGC1 */ |
|
491 return s->dcgc[1]; |
|
492 case 0x128: /* DCGC2 */ |
|
493 return s->dcgc[2]; |
|
494 case 0x150: /* CLKVCLR */ |
|
495 return s->clkvclr; |
|
496 case 0x160: /* LDOARST */ |
|
497 return s->ldoarst; |
|
498 case 0x1e0: /* USER0 */ |
|
499 return s->user0; |
|
500 case 0x1e4: /* USER1 */ |
|
501 return s->user1; |
|
502 default: |
|
503 cpu_abort(cpu_single_env, "ssys_read: Bad offset 0x%x\n", (int)offset); |
|
504 return 0; |
|
505 } |
|
506 } |
|
507 |
|
508 static void ssys_calculate_system_clock(ssys_state *s) |
|
509 { |
|
510 system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1); |
|
511 } |
|
512 |
|
513 static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value) |
|
514 { |
|
515 ssys_state *s = (ssys_state *)opaque; |
|
516 |
|
517 switch (offset) { |
|
518 case 0x030: /* PBORCTL */ |
|
519 s->pborctl = value & 0xffff; |
|
520 break; |
|
521 case 0x034: /* LDOPCTL */ |
|
522 s->ldopctl = value & 0x1f; |
|
523 break; |
|
524 case 0x040: /* SRCR0 */ |
|
525 case 0x044: /* SRCR1 */ |
|
526 case 0x048: /* SRCR2 */ |
|
527 fprintf(stderr, "Peripheral reset not implemented\n"); |
|
528 break; |
|
529 case 0x054: /* IMC */ |
|
530 s->int_mask = value & 0x7f; |
|
531 break; |
|
532 case 0x058: /* MISC */ |
|
533 s->int_status &= ~value; |
|
534 break; |
|
535 case 0x05c: /* RESC */ |
|
536 s->resc = value & 0x3f; |
|
537 break; |
|
538 case 0x060: /* RCC */ |
|
539 if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) { |
|
540 /* PLL enable. */ |
|
541 s->int_status |= (1 << 6); |
|
542 } |
|
543 s->rcc = value; |
|
544 ssys_calculate_system_clock(s); |
|
545 break; |
|
546 case 0x100: /* RCGC0 */ |
|
547 s->rcgc[0] = value; |
|
548 break; |
|
549 case 0x104: /* RCGC1 */ |
|
550 s->rcgc[1] = value; |
|
551 break; |
|
552 case 0x108: /* RCGC2 */ |
|
553 s->rcgc[2] = value; |
|
554 break; |
|
555 case 0x110: /* SCGC0 */ |
|
556 s->scgc[0] = value; |
|
557 break; |
|
558 case 0x114: /* SCGC1 */ |
|
559 s->scgc[1] = value; |
|
560 break; |
|
561 case 0x118: /* SCGC2 */ |
|
562 s->scgc[2] = value; |
|
563 break; |
|
564 case 0x120: /* DCGC0 */ |
|
565 s->dcgc[0] = value; |
|
566 break; |
|
567 case 0x124: /* DCGC1 */ |
|
568 s->dcgc[1] = value; |
|
569 break; |
|
570 case 0x128: /* DCGC2 */ |
|
571 s->dcgc[2] = value; |
|
572 break; |
|
573 case 0x150: /* CLKVCLR */ |
|
574 s->clkvclr = value; |
|
575 break; |
|
576 case 0x160: /* LDOARST */ |
|
577 s->ldoarst = value; |
|
578 break; |
|
579 default: |
|
580 cpu_abort(cpu_single_env, "ssys_write: Bad offset 0x%x\n", (int)offset); |
|
581 } |
|
582 ssys_update(s); |
|
583 } |
|
584 |
|
585 static CPUReadMemoryFunc *ssys_readfn[] = { |
|
586 ssys_read, |
|
587 ssys_read, |
|
588 ssys_read |
|
589 }; |
|
590 |
|
591 static CPUWriteMemoryFunc *ssys_writefn[] = { |
|
592 ssys_write, |
|
593 ssys_write, |
|
594 ssys_write |
|
595 }; |
|
596 |
|
597 static void ssys_reset(void *opaque) |
|
598 { |
|
599 ssys_state *s = (ssys_state *)opaque; |
|
600 |
|
601 s->pborctl = 0x7ffd; |
|
602 s->rcc = 0x078e3ac0; |
|
603 s->rcgc[0] = 1; |
|
604 s->scgc[0] = 1; |
|
605 s->dcgc[0] = 1; |
|
606 } |
|
607 |
|
608 static void ssys_save(QEMUFile *f, void *opaque) |
|
609 { |
|
610 ssys_state *s = (ssys_state *)opaque; |
|
611 |
|
612 qemu_put_be32(f, s->pborctl); |
|
613 qemu_put_be32(f, s->ldopctl); |
|
614 qemu_put_be32(f, s->int_mask); |
|
615 qemu_put_be32(f, s->int_status); |
|
616 qemu_put_be32(f, s->resc); |
|
617 qemu_put_be32(f, s->rcc); |
|
618 qemu_put_be32(f, s->rcgc[0]); |
|
619 qemu_put_be32(f, s->rcgc[1]); |
|
620 qemu_put_be32(f, s->rcgc[2]); |
|
621 qemu_put_be32(f, s->scgc[0]); |
|
622 qemu_put_be32(f, s->scgc[1]); |
|
623 qemu_put_be32(f, s->scgc[2]); |
|
624 qemu_put_be32(f, s->dcgc[0]); |
|
625 qemu_put_be32(f, s->dcgc[1]); |
|
626 qemu_put_be32(f, s->dcgc[2]); |
|
627 qemu_put_be32(f, s->clkvclr); |
|
628 qemu_put_be32(f, s->ldoarst); |
|
629 } |
|
630 |
|
631 static int ssys_load(QEMUFile *f, void *opaque, int version_id) |
|
632 { |
|
633 ssys_state *s = (ssys_state *)opaque; |
|
634 |
|
635 if (version_id != 1) |
|
636 return -EINVAL; |
|
637 |
|
638 s->pborctl = qemu_get_be32(f); |
|
639 s->ldopctl = qemu_get_be32(f); |
|
640 s->int_mask = qemu_get_be32(f); |
|
641 s->int_status = qemu_get_be32(f); |
|
642 s->resc = qemu_get_be32(f); |
|
643 s->rcc = qemu_get_be32(f); |
|
644 s->rcgc[0] = qemu_get_be32(f); |
|
645 s->rcgc[1] = qemu_get_be32(f); |
|
646 s->rcgc[2] = qemu_get_be32(f); |
|
647 s->scgc[0] = qemu_get_be32(f); |
|
648 s->scgc[1] = qemu_get_be32(f); |
|
649 s->scgc[2] = qemu_get_be32(f); |
|
650 s->dcgc[0] = qemu_get_be32(f); |
|
651 s->dcgc[1] = qemu_get_be32(f); |
|
652 s->dcgc[2] = qemu_get_be32(f); |
|
653 s->clkvclr = qemu_get_be32(f); |
|
654 s->ldoarst = qemu_get_be32(f); |
|
655 ssys_calculate_system_clock(s); |
|
656 |
|
657 return 0; |
|
658 } |
|
659 |
|
660 static void stellaris_sys_init(uint32_t base, qemu_irq irq, |
|
661 stellaris_board_info * board, |
|
662 uint8_t *macaddr) |
|
663 { |
|
664 int iomemtype; |
|
665 ssys_state *s; |
|
666 |
|
667 s = (ssys_state *)qemu_mallocz(sizeof(ssys_state)); |
|
668 s->irq = irq; |
|
669 s->board = board; |
|
670 /* Most devices come preprogrammed with a MAC address in the user data. */ |
|
671 s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16); |
|
672 s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16); |
|
673 |
|
674 iomemtype = cpu_register_io_memory(0, ssys_readfn, |
|
675 ssys_writefn, s); |
|
676 cpu_register_physical_memory(base, 0x00001000, iomemtype); |
|
677 ssys_reset(s); |
|
678 register_savevm("stellaris_sys", -1, 1, ssys_save, ssys_load, s); |
|
679 } |
|
680 |
|
681 |
|
682 /* I2C controller. */ |
|
683 |
|
684 typedef struct { |
|
685 i2c_bus *bus; |
|
686 qemu_irq irq; |
|
687 uint32_t msa; |
|
688 uint32_t mcs; |
|
689 uint32_t mdr; |
|
690 uint32_t mtpr; |
|
691 uint32_t mimr; |
|
692 uint32_t mris; |
|
693 uint32_t mcr; |
|
694 } stellaris_i2c_state; |
|
695 |
|
696 #define STELLARIS_I2C_MCS_BUSY 0x01 |
|
697 #define STELLARIS_I2C_MCS_ERROR 0x02 |
|
698 #define STELLARIS_I2C_MCS_ADRACK 0x04 |
|
699 #define STELLARIS_I2C_MCS_DATACK 0x08 |
|
700 #define STELLARIS_I2C_MCS_ARBLST 0x10 |
|
701 #define STELLARIS_I2C_MCS_IDLE 0x20 |
|
702 #define STELLARIS_I2C_MCS_BUSBSY 0x40 |
|
703 |
|
704 static uint32_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset) |
|
705 { |
|
706 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; |
|
707 |
|
708 switch (offset) { |
|
709 case 0x00: /* MSA */ |
|
710 return s->msa; |
|
711 case 0x04: /* MCS */ |
|
712 /* We don't emulate timing, so the controller is never busy. */ |
|
713 return s->mcs | STELLARIS_I2C_MCS_IDLE; |
|
714 case 0x08: /* MDR */ |
|
715 return s->mdr; |
|
716 case 0x0c: /* MTPR */ |
|
717 return s->mtpr; |
|
718 case 0x10: /* MIMR */ |
|
719 return s->mimr; |
|
720 case 0x14: /* MRIS */ |
|
721 return s->mris; |
|
722 case 0x18: /* MMIS */ |
|
723 return s->mris & s->mimr; |
|
724 case 0x20: /* MCR */ |
|
725 return s->mcr; |
|
726 default: |
|
727 cpu_abort(cpu_single_env, "strllaris_i2c_read: Bad offset 0x%x\n", |
|
728 (int)offset); |
|
729 return 0; |
|
730 } |
|
731 } |
|
732 |
|
733 static void stellaris_i2c_update(stellaris_i2c_state *s) |
|
734 { |
|
735 int level; |
|
736 |
|
737 level = (s->mris & s->mimr) != 0; |
|
738 qemu_set_irq(s->irq, level); |
|
739 } |
|
740 |
|
741 static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset, |
|
742 uint32_t value) |
|
743 { |
|
744 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; |
|
745 |
|
746 switch (offset) { |
|
747 case 0x00: /* MSA */ |
|
748 s->msa = value & 0xff; |
|
749 break; |
|
750 case 0x04: /* MCS */ |
|
751 if ((s->mcr & 0x10) == 0) { |
|
752 /* Disabled. Do nothing. */ |
|
753 break; |
|
754 } |
|
755 /* Grab the bus if this is starting a transfer. */ |
|
756 if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { |
|
757 if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) { |
|
758 s->mcs |= STELLARIS_I2C_MCS_ARBLST; |
|
759 } else { |
|
760 s->mcs &= ~STELLARIS_I2C_MCS_ARBLST; |
|
761 s->mcs |= STELLARIS_I2C_MCS_BUSBSY; |
|
762 } |
|
763 } |
|
764 /* If we don't have the bus then indicate an error. */ |
|
765 if (!i2c_bus_busy(s->bus) |
|
766 || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) { |
|
767 s->mcs |= STELLARIS_I2C_MCS_ERROR; |
|
768 break; |
|
769 } |
|
770 s->mcs &= ~STELLARIS_I2C_MCS_ERROR; |
|
771 if (value & 1) { |
|
772 /* Transfer a byte. */ |
|
773 /* TODO: Handle errors. */ |
|
774 if (s->msa & 1) { |
|
775 /* Recv */ |
|
776 s->mdr = i2c_recv(s->bus) & 0xff; |
|
777 } else { |
|
778 /* Send */ |
|
779 i2c_send(s->bus, s->mdr); |
|
780 } |
|
781 /* Raise an interrupt. */ |
|
782 s->mris |= 1; |
|
783 } |
|
784 if (value & 4) { |
|
785 /* Finish transfer. */ |
|
786 i2c_end_transfer(s->bus); |
|
787 s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY; |
|
788 } |
|
789 break; |
|
790 case 0x08: /* MDR */ |
|
791 s->mdr = value & 0xff; |
|
792 break; |
|
793 case 0x0c: /* MTPR */ |
|
794 s->mtpr = value & 0xff; |
|
795 break; |
|
796 case 0x10: /* MIMR */ |
|
797 s->mimr = 1; |
|
798 break; |
|
799 case 0x1c: /* MICR */ |
|
800 s->mris &= ~value; |
|
801 break; |
|
802 case 0x20: /* MCR */ |
|
803 if (value & 1) |
|
804 cpu_abort(cpu_single_env, |
|
805 "stellaris_i2c_write: Loopback not implemented\n"); |
|
806 if (value & 0x20) |
|
807 cpu_abort(cpu_single_env, |
|
808 "stellaris_i2c_write: Slave mode not implemented\n"); |
|
809 s->mcr = value & 0x31; |
|
810 break; |
|
811 default: |
|
812 cpu_abort(cpu_single_env, "stellaris_i2c_write: Bad offset 0x%x\n", |
|
813 (int)offset); |
|
814 } |
|
815 stellaris_i2c_update(s); |
|
816 } |
|
817 |
|
818 static void stellaris_i2c_reset(stellaris_i2c_state *s) |
|
819 { |
|
820 if (s->mcs & STELLARIS_I2C_MCS_BUSBSY) |
|
821 i2c_end_transfer(s->bus); |
|
822 |
|
823 s->msa = 0; |
|
824 s->mcs = 0; |
|
825 s->mdr = 0; |
|
826 s->mtpr = 1; |
|
827 s->mimr = 0; |
|
828 s->mris = 0; |
|
829 s->mcr = 0; |
|
830 stellaris_i2c_update(s); |
|
831 } |
|
832 |
|
833 static CPUReadMemoryFunc *stellaris_i2c_readfn[] = { |
|
834 stellaris_i2c_read, |
|
835 stellaris_i2c_read, |
|
836 stellaris_i2c_read |
|
837 }; |
|
838 |
|
839 static CPUWriteMemoryFunc *stellaris_i2c_writefn[] = { |
|
840 stellaris_i2c_write, |
|
841 stellaris_i2c_write, |
|
842 stellaris_i2c_write |
|
843 }; |
|
844 |
|
845 static void stellaris_i2c_save(QEMUFile *f, void *opaque) |
|
846 { |
|
847 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; |
|
848 |
|
849 qemu_put_be32(f, s->msa); |
|
850 qemu_put_be32(f, s->mcs); |
|
851 qemu_put_be32(f, s->mdr); |
|
852 qemu_put_be32(f, s->mtpr); |
|
853 qemu_put_be32(f, s->mimr); |
|
854 qemu_put_be32(f, s->mris); |
|
855 qemu_put_be32(f, s->mcr); |
|
856 } |
|
857 |
|
858 static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id) |
|
859 { |
|
860 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque; |
|
861 |
|
862 if (version_id != 1) |
|
863 return -EINVAL; |
|
864 |
|
865 s->msa = qemu_get_be32(f); |
|
866 s->mcs = qemu_get_be32(f); |
|
867 s->mdr = qemu_get_be32(f); |
|
868 s->mtpr = qemu_get_be32(f); |
|
869 s->mimr = qemu_get_be32(f); |
|
870 s->mris = qemu_get_be32(f); |
|
871 s->mcr = qemu_get_be32(f); |
|
872 |
|
873 return 0; |
|
874 } |
|
875 |
|
876 static void stellaris_i2c_init(uint32_t base, qemu_irq irq, i2c_bus *bus) |
|
877 { |
|
878 stellaris_i2c_state *s; |
|
879 int iomemtype; |
|
880 |
|
881 s = (stellaris_i2c_state *)qemu_mallocz(sizeof(stellaris_i2c_state)); |
|
882 s->irq = irq; |
|
883 s->bus = bus; |
|
884 |
|
885 iomemtype = cpu_register_io_memory(0, stellaris_i2c_readfn, |
|
886 stellaris_i2c_writefn, s); |
|
887 cpu_register_physical_memory(base, 0x00001000, iomemtype); |
|
888 /* ??? For now we only implement the master interface. */ |
|
889 stellaris_i2c_reset(s); |
|
890 register_savevm("stellaris_i2c", -1, 1, |
|
891 stellaris_i2c_save, stellaris_i2c_load, s); |
|
892 } |
|
893 |
|
894 /* Analogue to Digital Converter. This is only partially implemented, |
|
895 enough for applications that use a combined ADC and timer tick. */ |
|
896 |
|
897 #define STELLARIS_ADC_EM_CONTROLLER 0 |
|
898 #define STELLARIS_ADC_EM_COMP 1 |
|
899 #define STELLARIS_ADC_EM_EXTERNAL 4 |
|
900 #define STELLARIS_ADC_EM_TIMER 5 |
|
901 #define STELLARIS_ADC_EM_PWM0 6 |
|
902 #define STELLARIS_ADC_EM_PWM1 7 |
|
903 #define STELLARIS_ADC_EM_PWM2 8 |
|
904 |
|
905 #define STELLARIS_ADC_FIFO_EMPTY 0x0100 |
|
906 #define STELLARIS_ADC_FIFO_FULL 0x1000 |
|
907 |
|
908 typedef struct |
|
909 { |
|
910 uint32_t actss; |
|
911 uint32_t ris; |
|
912 uint32_t im; |
|
913 uint32_t emux; |
|
914 uint32_t ostat; |
|
915 uint32_t ustat; |
|
916 uint32_t sspri; |
|
917 uint32_t sac; |
|
918 struct { |
|
919 uint32_t state; |
|
920 uint32_t data[16]; |
|
921 } fifo[4]; |
|
922 uint32_t ssmux[4]; |
|
923 uint32_t ssctl[4]; |
|
924 uint32_t noise; |
|
925 qemu_irq irq; |
|
926 } stellaris_adc_state; |
|
927 |
|
928 static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n) |
|
929 { |
|
930 int tail; |
|
931 |
|
932 tail = s->fifo[n].state & 0xf; |
|
933 if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) { |
|
934 s->ustat |= 1 << n; |
|
935 } else { |
|
936 s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf); |
|
937 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL; |
|
938 if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf)) |
|
939 s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY; |
|
940 } |
|
941 return s->fifo[n].data[tail]; |
|
942 } |
|
943 |
|
944 static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n, |
|
945 uint32_t value) |
|
946 { |
|
947 int head; |
|
948 |
|
949 head = (s->fifo[n].state >> 4) & 0xf; |
|
950 if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) { |
|
951 s->ostat |= 1 << n; |
|
952 return; |
|
953 } |
|
954 s->fifo[n].data[head] = value; |
|
955 head = (head + 1) & 0xf; |
|
956 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY; |
|
957 s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4); |
|
958 if ((s->fifo[n].state & 0xf) == head) |
|
959 s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL; |
|
960 } |
|
961 |
|
962 static void stellaris_adc_update(stellaris_adc_state *s) |
|
963 { |
|
964 int level; |
|
965 |
|
966 level = (s->ris & s->im) != 0; |
|
967 qemu_set_irq(s->irq, level); |
|
968 } |
|
969 |
|
970 static void stellaris_adc_trigger(void *opaque, int irq, int level) |
|
971 { |
|
972 stellaris_adc_state *s = (stellaris_adc_state *)opaque; |
|
973 |
|
974 if ((s->actss & 1) == 0) { |
|
975 return; |
|
976 } |
|
977 |
|
978 /* Some applications use the ADC as a random number source, so introduce |
|
979 some variation into the signal. */ |
|
980 s->noise = s->noise * 314159 + 1; |
|
981 /* ??? actual inputs not implemented. Return an arbitrary value. */ |
|
982 stellaris_adc_fifo_write(s, 0, 0x200 + ((s->noise >> 16) & 7)); |
|
983 s->ris |= 1; |
|
984 stellaris_adc_update(s); |
|
985 } |
|
986 |
|
987 static void stellaris_adc_reset(stellaris_adc_state *s) |
|
988 { |
|
989 int n; |
|
990 |
|
991 for (n = 0; n < 4; n++) { |
|
992 s->ssmux[n] = 0; |
|
993 s->ssctl[n] = 0; |
|
994 s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY; |
|
995 } |
|
996 } |
|
997 |
|
998 static uint32_t stellaris_adc_read(void *opaque, target_phys_addr_t offset) |
|
999 { |
|
1000 stellaris_adc_state *s = (stellaris_adc_state *)opaque; |
|
1001 |
|
1002 /* TODO: Implement this. */ |
|
1003 if (offset >= 0x40 && offset < 0xc0) { |
|
1004 int n; |
|
1005 n = (offset - 0x40) >> 5; |
|
1006 switch (offset & 0x1f) { |
|
1007 case 0x00: /* SSMUX */ |
|
1008 return s->ssmux[n]; |
|
1009 case 0x04: /* SSCTL */ |
|
1010 return s->ssctl[n]; |
|
1011 case 0x08: /* SSFIFO */ |
|
1012 return stellaris_adc_fifo_read(s, n); |
|
1013 case 0x0c: /* SSFSTAT */ |
|
1014 return s->fifo[n].state; |
|
1015 default: |
|
1016 break; |
|
1017 } |
|
1018 } |
|
1019 switch (offset) { |
|
1020 case 0x00: /* ACTSS */ |
|
1021 return s->actss; |
|
1022 case 0x04: /* RIS */ |
|
1023 return s->ris; |
|
1024 case 0x08: /* IM */ |
|
1025 return s->im; |
|
1026 case 0x0c: /* ISC */ |
|
1027 return s->ris & s->im; |
|
1028 case 0x10: /* OSTAT */ |
|
1029 return s->ostat; |
|
1030 case 0x14: /* EMUX */ |
|
1031 return s->emux; |
|
1032 case 0x18: /* USTAT */ |
|
1033 return s->ustat; |
|
1034 case 0x20: /* SSPRI */ |
|
1035 return s->sspri; |
|
1036 case 0x30: /* SAC */ |
|
1037 return s->sac; |
|
1038 default: |
|
1039 cpu_abort(cpu_single_env, "strllaris_adc_read: Bad offset 0x%x\n", |
|
1040 (int)offset); |
|
1041 return 0; |
|
1042 } |
|
1043 } |
|
1044 |
|
1045 static void stellaris_adc_write(void *opaque, target_phys_addr_t offset, |
|
1046 uint32_t value) |
|
1047 { |
|
1048 stellaris_adc_state *s = (stellaris_adc_state *)opaque; |
|
1049 |
|
1050 /* TODO: Implement this. */ |
|
1051 if (offset >= 0x40 && offset < 0xc0) { |
|
1052 int n; |
|
1053 n = (offset - 0x40) >> 5; |
|
1054 switch (offset & 0x1f) { |
|
1055 case 0x00: /* SSMUX */ |
|
1056 s->ssmux[n] = value & 0x33333333; |
|
1057 return; |
|
1058 case 0x04: /* SSCTL */ |
|
1059 if (value != 6) { |
|
1060 cpu_abort(cpu_single_env, "ADC: Unimplemented sequence %x\n", |
|
1061 value); |
|
1062 } |
|
1063 s->ssctl[n] = value; |
|
1064 return; |
|
1065 default: |
|
1066 break; |
|
1067 } |
|
1068 } |
|
1069 switch (offset) { |
|
1070 case 0x00: /* ACTSS */ |
|
1071 s->actss = value & 0xf; |
|
1072 if (value & 0xe) { |
|
1073 cpu_abort(cpu_single_env, |
|
1074 "Not implemented: ADC sequencers 1-3\n"); |
|
1075 } |
|
1076 break; |
|
1077 case 0x08: /* IM */ |
|
1078 s->im = value; |
|
1079 break; |
|
1080 case 0x0c: /* ISC */ |
|
1081 s->ris &= ~value; |
|
1082 break; |
|
1083 case 0x10: /* OSTAT */ |
|
1084 s->ostat &= ~value; |
|
1085 break; |
|
1086 case 0x14: /* EMUX */ |
|
1087 s->emux = value; |
|
1088 break; |
|
1089 case 0x18: /* USTAT */ |
|
1090 s->ustat &= ~value; |
|
1091 break; |
|
1092 case 0x20: /* SSPRI */ |
|
1093 s->sspri = value; |
|
1094 break; |
|
1095 case 0x28: /* PSSI */ |
|
1096 cpu_abort(cpu_single_env, "Not implemented: ADC sample initiate\n"); |
|
1097 break; |
|
1098 case 0x30: /* SAC */ |
|
1099 s->sac = value; |
|
1100 break; |
|
1101 default: |
|
1102 cpu_abort(cpu_single_env, "stellaris_adc_write: Bad offset 0x%x\n", |
|
1103 (int)offset); |
|
1104 } |
|
1105 stellaris_adc_update(s); |
|
1106 } |
|
1107 |
|
1108 static CPUReadMemoryFunc *stellaris_adc_readfn[] = { |
|
1109 stellaris_adc_read, |
|
1110 stellaris_adc_read, |
|
1111 stellaris_adc_read |
|
1112 }; |
|
1113 |
|
1114 static CPUWriteMemoryFunc *stellaris_adc_writefn[] = { |
|
1115 stellaris_adc_write, |
|
1116 stellaris_adc_write, |
|
1117 stellaris_adc_write |
|
1118 }; |
|
1119 |
|
1120 static void stellaris_adc_save(QEMUFile *f, void *opaque) |
|
1121 { |
|
1122 stellaris_adc_state *s = (stellaris_adc_state *)opaque; |
|
1123 int i; |
|
1124 int j; |
|
1125 |
|
1126 qemu_put_be32(f, s->actss); |
|
1127 qemu_put_be32(f, s->ris); |
|
1128 qemu_put_be32(f, s->im); |
|
1129 qemu_put_be32(f, s->emux); |
|
1130 qemu_put_be32(f, s->ostat); |
|
1131 qemu_put_be32(f, s->ustat); |
|
1132 qemu_put_be32(f, s->sspri); |
|
1133 qemu_put_be32(f, s->sac); |
|
1134 for (i = 0; i < 4; i++) { |
|
1135 qemu_put_be32(f, s->fifo[i].state); |
|
1136 for (j = 0; j < 16; j++) { |
|
1137 qemu_put_be32(f, s->fifo[i].data[j]); |
|
1138 } |
|
1139 qemu_put_be32(f, s->ssmux[i]); |
|
1140 qemu_put_be32(f, s->ssctl[i]); |
|
1141 } |
|
1142 qemu_put_be32(f, s->noise); |
|
1143 } |
|
1144 |
|
1145 static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id) |
|
1146 { |
|
1147 stellaris_adc_state *s = (stellaris_adc_state *)opaque; |
|
1148 int i; |
|
1149 int j; |
|
1150 |
|
1151 if (version_id != 1) |
|
1152 return -EINVAL; |
|
1153 |
|
1154 s->actss = qemu_get_be32(f); |
|
1155 s->ris = qemu_get_be32(f); |
|
1156 s->im = qemu_get_be32(f); |
|
1157 s->emux = qemu_get_be32(f); |
|
1158 s->ostat = qemu_get_be32(f); |
|
1159 s->ustat = qemu_get_be32(f); |
|
1160 s->sspri = qemu_get_be32(f); |
|
1161 s->sac = qemu_get_be32(f); |
|
1162 for (i = 0; i < 4; i++) { |
|
1163 s->fifo[i].state = qemu_get_be32(f); |
|
1164 for (j = 0; j < 16; j++) { |
|
1165 s->fifo[i].data[j] = qemu_get_be32(f); |
|
1166 } |
|
1167 s->ssmux[i] = qemu_get_be32(f); |
|
1168 s->ssctl[i] = qemu_get_be32(f); |
|
1169 } |
|
1170 s->noise = qemu_get_be32(f); |
|
1171 |
|
1172 return 0; |
|
1173 } |
|
1174 |
|
1175 static qemu_irq stellaris_adc_init(uint32_t base, qemu_irq irq) |
|
1176 { |
|
1177 stellaris_adc_state *s; |
|
1178 int iomemtype; |
|
1179 qemu_irq *qi; |
|
1180 |
|
1181 s = (stellaris_adc_state *)qemu_mallocz(sizeof(stellaris_adc_state)); |
|
1182 s->irq = irq; |
|
1183 |
|
1184 iomemtype = cpu_register_io_memory(0, stellaris_adc_readfn, |
|
1185 stellaris_adc_writefn, s); |
|
1186 cpu_register_physical_memory(base, 0x00001000, iomemtype); |
|
1187 stellaris_adc_reset(s); |
|
1188 qi = qemu_allocate_irqs(stellaris_adc_trigger, s, 1); |
|
1189 register_savevm("stellaris_adc", -1, 1, |
|
1190 stellaris_adc_save, stellaris_adc_load, s); |
|
1191 return qi[0]; |
|
1192 } |
|
1193 |
|
1194 /* Some boards have both an OLED controller and SD card connected to |
|
1195 the same SSI port, with the SD card chip select connected to a |
|
1196 GPIO pin. Technically the OLED chip select is connected to the SSI |
|
1197 Fss pin. We do not bother emulating that as both devices should |
|
1198 never be selected simultaneously, and our OLED controller ignores stray |
|
1199 0xff commands that occur when deselecting the SD card. */ |
|
1200 |
|
1201 typedef struct { |
|
1202 ssi_xfer_cb xfer_cb[2]; |
|
1203 void *opaque[2]; |
|
1204 qemu_irq irq; |
|
1205 int current_dev; |
|
1206 } stellaris_ssi_bus_state; |
|
1207 |
|
1208 static void stellaris_ssi_bus_select(void *opaque, int irq, int level) |
|
1209 { |
|
1210 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; |
|
1211 |
|
1212 s->current_dev = level; |
|
1213 } |
|
1214 |
|
1215 static int stellaris_ssi_bus_xfer(void *opaque, int val) |
|
1216 { |
|
1217 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; |
|
1218 |
|
1219 return s->xfer_cb[s->current_dev](s->opaque[s->current_dev], val); |
|
1220 } |
|
1221 |
|
1222 static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque) |
|
1223 { |
|
1224 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; |
|
1225 |
|
1226 qemu_put_be32(f, s->current_dev); |
|
1227 } |
|
1228 |
|
1229 static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id) |
|
1230 { |
|
1231 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque; |
|
1232 |
|
1233 if (version_id != 1) |
|
1234 return -EINVAL; |
|
1235 |
|
1236 s->current_dev = qemu_get_be32(f); |
|
1237 |
|
1238 return 0; |
|
1239 } |
|
1240 |
|
1241 static void *stellaris_ssi_bus_init(qemu_irq *irqp, |
|
1242 ssi_xfer_cb cb0, void *opaque0, |
|
1243 ssi_xfer_cb cb1, void *opaque1) |
|
1244 { |
|
1245 qemu_irq *qi; |
|
1246 stellaris_ssi_bus_state *s; |
|
1247 |
|
1248 s = (stellaris_ssi_bus_state *)qemu_mallocz(sizeof(stellaris_ssi_bus_state)); |
|
1249 s->xfer_cb[0] = cb0; |
|
1250 s->opaque[0] = opaque0; |
|
1251 s->xfer_cb[1] = cb1; |
|
1252 s->opaque[1] = opaque1; |
|
1253 qi = qemu_allocate_irqs(stellaris_ssi_bus_select, s, 1); |
|
1254 *irqp = *qi; |
|
1255 register_savevm("stellaris_ssi_bus", -1, 1, |
|
1256 stellaris_ssi_bus_save, stellaris_ssi_bus_load, s); |
|
1257 return s; |
|
1258 } |
|
1259 |
|
1260 /* Board init. */ |
|
1261 static stellaris_board_info stellaris_boards[] = { |
|
1262 { "LM3S811EVB", |
|
1263 0, |
|
1264 0x0032000e, |
|
1265 0x001f001f, /* dc0 */ |
|
1266 0x001132bf, |
|
1267 0x01071013, |
|
1268 0x3f0f01ff, |
|
1269 0x0000001f, |
|
1270 BP_OLED_I2C |
|
1271 }, |
|
1272 { "LM3S6965EVB", |
|
1273 0x10010002, |
|
1274 0x1073402e, |
|
1275 0x00ff007f, /* dc0 */ |
|
1276 0x001133ff, |
|
1277 0x030f5317, |
|
1278 0x0f0f87ff, |
|
1279 0x5000007f, |
|
1280 BP_OLED_SSI | BP_GAMEPAD |
|
1281 } |
|
1282 }; |
|
1283 |
|
1284 static void stellaris_init(const char *kernel_filename, const char *cpu_model, |
|
1285 DisplayState *ds, stellaris_board_info *board) |
|
1286 { |
|
1287 static const int uart_irq[] = {5, 6, 33, 34}; |
|
1288 static const int timer_irq[] = {19, 21, 23, 35}; |
|
1289 static const uint32_t gpio_addr[7] = |
|
1290 { 0x40004000, 0x40005000, 0x40006000, 0x40007000, |
|
1291 0x40024000, 0x40025000, 0x40026000}; |
|
1292 static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31}; |
|
1293 |
|
1294 qemu_irq *pic; |
|
1295 qemu_irq *gpio_in[7]; |
|
1296 qemu_irq *gpio_out[7]; |
|
1297 qemu_irq adc; |
|
1298 int sram_size; |
|
1299 int flash_size; |
|
1300 i2c_bus *i2c; |
|
1301 int i; |
|
1302 |
|
1303 flash_size = ((board->dc0 & 0xffff) + 1) << 1; |
|
1304 sram_size = (board->dc0 >> 18) + 1; |
|
1305 pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model); |
|
1306 |
|
1307 if (board->dc1 & (1 << 16)) { |
|
1308 adc = stellaris_adc_init(0x40038000, pic[14]); |
|
1309 } else { |
|
1310 adc = NULL; |
|
1311 } |
|
1312 for (i = 0; i < 4; i++) { |
|
1313 if (board->dc2 & (0x10000 << i)) { |
|
1314 stellaris_gptm_init(0x40030000 + i * 0x1000, |
|
1315 pic[timer_irq[i]], adc); |
|
1316 } |
|
1317 } |
|
1318 |
|
1319 stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr); |
|
1320 |
|
1321 for (i = 0; i < 7; i++) { |
|
1322 if (board->dc4 & (1 << i)) { |
|
1323 gpio_in[i] = pl061_init(gpio_addr[i], pic[gpio_irq[i]], |
|
1324 &gpio_out[i]); |
|
1325 } |
|
1326 } |
|
1327 |
|
1328 if (board->dc2 & (1 << 12)) { |
|
1329 i2c = i2c_init_bus(); |
|
1330 stellaris_i2c_init(0x40020000, pic[8], i2c); |
|
1331 if (board->peripherals & BP_OLED_I2C) { |
|
1332 ssd0303_init(ds, i2c, 0x3d); |
|
1333 } |
|
1334 } |
|
1335 |
|
1336 for (i = 0; i < 4; i++) { |
|
1337 if (board->dc2 & (1 << i)) { |
|
1338 pl011_init(0x4000c000 + i * 0x1000, pic[uart_irq[i]], |
|
1339 serial_hds[i], PL011_LUMINARY); |
|
1340 } |
|
1341 } |
|
1342 if (board->dc2 & (1 << 4)) { |
|
1343 if (board->peripherals & BP_OLED_SSI) { |
|
1344 void * oled; |
|
1345 void * sd; |
|
1346 void *ssi_bus; |
|
1347 int index; |
|
1348 |
|
1349 oled = ssd0323_init(ds, &gpio_out[GPIO_C][7]); |
|
1350 index = drive_get_index(IF_SD, 0, 0); |
|
1351 sd = ssi_sd_init(drives_table[index].bdrv); |
|
1352 |
|
1353 ssi_bus = stellaris_ssi_bus_init(&gpio_out[GPIO_D][0], |
|
1354 ssi_sd_xfer, sd, |
|
1355 ssd0323_xfer_ssi, oled); |
|
1356 |
|
1357 pl022_init(0x40008000, pic[7], stellaris_ssi_bus_xfer, ssi_bus); |
|
1358 /* Make sure the select pin is high. */ |
|
1359 qemu_irq_raise(gpio_out[GPIO_D][0]); |
|
1360 } else { |
|
1361 pl022_init(0x40008000, pic[7], NULL, NULL); |
|
1362 } |
|
1363 } |
|
1364 if (board->dc4 & (1 << 28)) { |
|
1365 /* FIXME: Obey network model. */ |
|
1366 stellaris_enet_init(&nd_table[0], 0x40048000, pic[42]); |
|
1367 } |
|
1368 if (board->peripherals & BP_GAMEPAD) { |
|
1369 qemu_irq gpad_irq[5]; |
|
1370 static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d }; |
|
1371 |
|
1372 gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */ |
|
1373 gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */ |
|
1374 gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */ |
|
1375 gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */ |
|
1376 gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */ |
|
1377 |
|
1378 stellaris_gamepad_init(5, gpad_irq, gpad_keycode); |
|
1379 } |
|
1380 } |
|
1381 |
|
1382 /* FIXME: Figure out how to generate these from stellaris_boards. */ |
|
1383 static void lm3s811evb_init(ram_addr_t ram_size, int vga_ram_size, |
|
1384 const char *boot_device, DisplayState *ds, |
|
1385 const char *kernel_filename, const char *kernel_cmdline, |
|
1386 const char *initrd_filename, const char *cpu_model) |
|
1387 { |
|
1388 stellaris_init(kernel_filename, cpu_model, ds, &stellaris_boards[0]); |
|
1389 } |
|
1390 |
|
1391 static void lm3s6965evb_init(ram_addr_t ram_size, int vga_ram_size, |
|
1392 const char *boot_device, DisplayState *ds, |
|
1393 const char *kernel_filename, const char *kernel_cmdline, |
|
1394 const char *initrd_filename, const char *cpu_model) |
|
1395 { |
|
1396 stellaris_init(kernel_filename, cpu_model, ds, &stellaris_boards[1]); |
|
1397 } |
|
1398 |
|
1399 QEMUMachine lm3s811evb_machine = { |
|
1400 .name = "lm3s811evb", |
|
1401 .desc = "Stellaris LM3S811EVB", |
|
1402 .init = lm3s811evb_init, |
|
1403 .ram_require = (64 * 1024 + 8 * 1024) | RAMSIZE_FIXED, |
|
1404 }; |
|
1405 |
|
1406 QEMUMachine lm3s6965evb_machine = { |
|
1407 .name = "lm3s6965evb", |
|
1408 .desc = "Stellaris LM3S6965EVB", |
|
1409 .init = lm3s6965evb_init, |
|
1410 .ram_require = (256 * 1024 + 64 * 1024) | RAMSIZE_FIXED, |
|
1411 }; |