blob: bcde0a2977565ad14e9f18088f09f589f1bcc266 [file] [log] [blame]
pbrook9ee6e8b2007-11-11 00:04:49 +00001/*
aurel321654b2d2008-04-11 04:55:07 +00002 * Luminary Micro Stellaris peripherals
pbrook9ee6e8b2007-11-11 00:04:49 +00003 *
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
6 *
7 * This code is licenced under the GPL.
8 */
9
Paul Brooka7d518a2009-05-14 22:35:07 +010010#include "sysbus.h"
Paul Brook5493e332009-05-14 22:35:09 +010011#include "ssi.h"
pbrook87ecb682007-11-17 17:14:51 +000012#include "arm-misc.h"
pbrook87ecb682007-11-17 17:14:51 +000013#include "devices.h"
14#include "qemu-timer.h"
15#include "i2c.h"
pbrookeea589c2007-11-24 03:13:04 +000016#include "net.h"
pbrook87ecb682007-11-17 17:14:51 +000017#include "sysemu.h"
18#include "boards.h"
pbrook9ee6e8b2007-11-11 00:04:49 +000019
pbrookcf0dbb22007-11-18 14:36:08 +000020#define GPIO_A 0
21#define GPIO_B 1
22#define GPIO_C 2
23#define GPIO_D 3
24#define GPIO_E 4
25#define GPIO_F 5
26#define GPIO_G 6
27
28#define BP_OLED_I2C 0x01
29#define BP_OLED_SSI 0x02
30#define BP_GAMEPAD 0x04
31
pbrook9ee6e8b2007-11-11 00:04:49 +000032typedef const struct {
33 const char *name;
34 uint32_t did0;
35 uint32_t did1;
36 uint32_t dc0;
37 uint32_t dc1;
38 uint32_t dc2;
39 uint32_t dc3;
40 uint32_t dc4;
pbrookcf0dbb22007-11-18 14:36:08 +000041 uint32_t peripherals;
pbrook9ee6e8b2007-11-11 00:04:49 +000042} stellaris_board_info;
43
44/* General purpose timer module. */
45
pbrook9ee6e8b2007-11-11 00:04:49 +000046typedef struct gptm_state {
Paul Brook40905a62009-06-03 15:16:49 +010047 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +000048 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];
pbrook9ee6e8b2007-11-11 00:04:49 +000060 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
66static 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
73static void gptm_stop(gptm_state *s, int n)
74{
75 qemu_del_timer(s->timer[n]);
76}
77
78static 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);
pbrooke57ec012007-11-24 03:09:07 +000090 tick += (int64_t)count * system_clock_scale;
pbrook9ee6e8b2007-11-11 00:04:49 +000091 } else if (s->config == 1) {
92 /* 32-bit RTC. 1Hz tick. */
Juan Quintela6ee093c2009-09-10 03:04:26 +020093 tick += get_ticks_per_sec();
pbrook9ee6e8b2007-11-11 00:04:49 +000094 } else if (s->mode[n] == 0xa) {
95 /* PWM mode. Not implemented. */
96 } else {
Paul Brook2ac71172009-05-08 02:35:15 +010097 hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
pbrook9ee6e8b2007-11-11 00:04:49 +000098 }
99 s->tick[n] = tick;
100 qemu_mod_timer(s->timer[n], tick);
101}
102
103static void gptm_tick(void *opaque)
104{
105 gptm_state **p = (gptm_state **)opaque;
106 gptm_state *s;
107 int n;
108
109 s = *p;
110 n = p - s->opaque;
111 if (s->config == 0) {
112 s->state |= 1;
113 if ((s->control & 0x20)) {
114 /* Output trigger. */
Paul Brook40905a62009-06-03 15:16:49 +0100115 qemu_irq_pulse(s->trigger);
pbrook9ee6e8b2007-11-11 00:04:49 +0000116 }
117 if (s->mode[0] & 1) {
118 /* One-shot. */
119 s->control &= ~1;
120 } else {
121 /* Periodic. */
122 gptm_reload(s, 0, 0);
123 }
124 } else if (s->config == 1) {
125 /* RTC. */
126 uint32_t match;
127 s->rtc++;
128 match = s->match[0] | (s->match[1] << 16);
129 if (s->rtc > match)
130 s->rtc = 0;
131 if (s->rtc == 0) {
132 s->state |= 8;
133 }
134 gptm_reload(s, 0, 0);
135 } else if (s->mode[n] == 0xa) {
136 /* PWM mode. Not implemented. */
137 } else {
Paul Brook2ac71172009-05-08 02:35:15 +0100138 hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
pbrook9ee6e8b2007-11-11 00:04:49 +0000139 }
140 gptm_update_irq(s);
141}
142
Anthony Liguoric227f092009-10-01 16:12:16 -0500143static uint32_t gptm_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000144{
145 gptm_state *s = (gptm_state *)opaque;
146
pbrook9ee6e8b2007-11-11 00:04:49 +0000147 switch (offset) {
148 case 0x00: /* CFG */
149 return s->config;
150 case 0x04: /* TAMR */
151 return s->mode[0];
152 case 0x08: /* TBMR */
153 return s->mode[1];
154 case 0x0c: /* CTL */
155 return s->control;
156 case 0x18: /* IMR */
157 return s->mask;
158 case 0x1c: /* RIS */
159 return s->state;
160 case 0x20: /* MIS */
161 return s->state & s->mask;
162 case 0x24: /* CR */
163 return 0;
164 case 0x28: /* TAILR */
165 return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0);
166 case 0x2c: /* TBILR */
167 return s->load[1];
168 case 0x30: /* TAMARCHR */
169 return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0);
170 case 0x34: /* TBMATCHR */
171 return s->match[1];
172 case 0x38: /* TAPR */
173 return s->prescale[0];
174 case 0x3c: /* TBPR */
175 return s->prescale[1];
176 case 0x40: /* TAPMR */
177 return s->match_prescale[0];
178 case 0x44: /* TBPMR */
179 return s->match_prescale[1];
180 case 0x48: /* TAR */
181 if (s->control == 1)
182 return s->rtc;
183 case 0x4c: /* TBR */
Paul Brook2ac71172009-05-08 02:35:15 +0100184 hw_error("TODO: Timer value read\n");
pbrook9ee6e8b2007-11-11 00:04:49 +0000185 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100186 hw_error("gptm_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000187 return 0;
188 }
189}
190
Anthony Liguoric227f092009-10-01 16:12:16 -0500191static void gptm_write(void *opaque, target_phys_addr_t offset, uint32_t value)
pbrook9ee6e8b2007-11-11 00:04:49 +0000192{
193 gptm_state *s = (gptm_state *)opaque;
194 uint32_t oldval;
195
pbrook9ee6e8b2007-11-11 00:04:49 +0000196 /* The timers should be disabled before changing the configuration.
197 We take advantage of this and defer everything until the timer
198 is enabled. */
199 switch (offset) {
200 case 0x00: /* CFG */
201 s->config = value;
202 break;
203 case 0x04: /* TAMR */
204 s->mode[0] = value;
205 break;
206 case 0x08: /* TBMR */
207 s->mode[1] = value;
208 break;
209 case 0x0c: /* CTL */
210 oldval = s->control;
211 s->control = value;
212 /* TODO: Implement pause. */
213 if ((oldval ^ value) & 1) {
214 if (value & 1) {
215 gptm_reload(s, 0, 1);
216 } else {
217 gptm_stop(s, 0);
218 }
219 }
220 if (((oldval ^ value) & 0x100) && s->config >= 4) {
221 if (value & 0x100) {
222 gptm_reload(s, 1, 1);
223 } else {
224 gptm_stop(s, 1);
225 }
226 }
227 break;
228 case 0x18: /* IMR */
229 s->mask = value & 0x77;
230 gptm_update_irq(s);
231 break;
232 case 0x24: /* CR */
233 s->state &= ~value;
234 break;
235 case 0x28: /* TAILR */
236 s->load[0] = value & 0xffff;
237 if (s->config < 4) {
238 s->load[1] = value >> 16;
239 }
240 break;
241 case 0x2c: /* TBILR */
242 s->load[1] = value & 0xffff;
243 break;
244 case 0x30: /* TAMARCHR */
245 s->match[0] = value & 0xffff;
246 if (s->config < 4) {
247 s->match[1] = value >> 16;
248 }
249 break;
250 case 0x34: /* TBMATCHR */
251 s->match[1] = value >> 16;
252 break;
253 case 0x38: /* TAPR */
254 s->prescale[0] = value;
255 break;
256 case 0x3c: /* TBPR */
257 s->prescale[1] = value;
258 break;
259 case 0x40: /* TAPMR */
260 s->match_prescale[0] = value;
261 break;
262 case 0x44: /* TBPMR */
263 s->match_prescale[0] = value;
264 break;
265 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100266 hw_error("gptm_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000267 }
268 gptm_update_irq(s);
269}
270
Blue Swirld60efc62009-08-25 18:29:31 +0000271static CPUReadMemoryFunc * const gptm_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000272 gptm_read,
273 gptm_read,
274 gptm_read
275};
276
Blue Swirld60efc62009-08-25 18:29:31 +0000277static CPUWriteMemoryFunc * const gptm_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000278 gptm_write,
279 gptm_write,
280 gptm_write
281};
282
pbrook23e39292008-07-02 16:48:32 +0000283static void gptm_save(QEMUFile *f, void *opaque)
284{
285 gptm_state *s = (gptm_state *)opaque;
286
287 qemu_put_be32(f, s->config);
288 qemu_put_be32(f, s->mode[0]);
289 qemu_put_be32(f, s->mode[1]);
290 qemu_put_be32(f, s->control);
291 qemu_put_be32(f, s->state);
292 qemu_put_be32(f, s->mask);
293 qemu_put_be32(f, s->mode[0]);
294 qemu_put_be32(f, s->mode[0]);
295 qemu_put_be32(f, s->load[0]);
296 qemu_put_be32(f, s->load[1]);
297 qemu_put_be32(f, s->match[0]);
298 qemu_put_be32(f, s->match[1]);
299 qemu_put_be32(f, s->prescale[0]);
300 qemu_put_be32(f, s->prescale[1]);
301 qemu_put_be32(f, s->match_prescale[0]);
302 qemu_put_be32(f, s->match_prescale[1]);
303 qemu_put_be32(f, s->rtc);
304 qemu_put_be64(f, s->tick[0]);
305 qemu_put_be64(f, s->tick[1]);
306 qemu_put_timer(f, s->timer[0]);
307 qemu_put_timer(f, s->timer[1]);
308}
309
310static int gptm_load(QEMUFile *f, void *opaque, int version_id)
311{
312 gptm_state *s = (gptm_state *)opaque;
313
314 if (version_id != 1)
315 return -EINVAL;
316
317 s->config = qemu_get_be32(f);
318 s->mode[0] = qemu_get_be32(f);
319 s->mode[1] = qemu_get_be32(f);
320 s->control = qemu_get_be32(f);
321 s->state = qemu_get_be32(f);
322 s->mask = qemu_get_be32(f);
323 s->mode[0] = qemu_get_be32(f);
324 s->mode[0] = qemu_get_be32(f);
325 s->load[0] = qemu_get_be32(f);
326 s->load[1] = qemu_get_be32(f);
327 s->match[0] = qemu_get_be32(f);
328 s->match[1] = qemu_get_be32(f);
329 s->prescale[0] = qemu_get_be32(f);
330 s->prescale[1] = qemu_get_be32(f);
331 s->match_prescale[0] = qemu_get_be32(f);
332 s->match_prescale[1] = qemu_get_be32(f);
333 s->rtc = qemu_get_be32(f);
334 s->tick[0] = qemu_get_be64(f);
335 s->tick[1] = qemu_get_be64(f);
336 qemu_get_timer(f, s->timer[0]);
337 qemu_get_timer(f, s->timer[1]);
338
339 return 0;
340}
341
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200342static int stellaris_gptm_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000343{
344 int iomemtype;
Paul Brook40905a62009-06-03 15:16:49 +0100345 gptm_state *s = FROM_SYSBUS(gptm_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +0000346
Paul Brook40905a62009-06-03 15:16:49 +0100347 sysbus_init_irq(dev, &s->irq);
348 qdev_init_gpio_out(&dev->qdev, &s->trigger, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +0000349
Avi Kivity1eed09c2009-06-14 11:38:51 +0300350 iomemtype = cpu_register_io_memory(gptm_readfn,
pbrook9ee6e8b2007-11-11 00:04:49 +0000351 gptm_writefn, s);
Paul Brook40905a62009-06-03 15:16:49 +0100352 sysbus_init_mmio(dev, 0x1000, iomemtype);
353
354 s->opaque[0] = s->opaque[1] = s;
pbrook9ee6e8b2007-11-11 00:04:49 +0000355 s->timer[0] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[0]);
356 s->timer[1] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[1]);
pbrook23e39292008-07-02 16:48:32 +0000357 register_savevm("stellaris_gptm", -1, 1, gptm_save, gptm_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200358 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000359}
360
361
362/* System controller. */
363
364typedef struct {
pbrook9ee6e8b2007-11-11 00:04:49 +0000365 uint32_t pborctl;
366 uint32_t ldopctl;
367 uint32_t int_status;
368 uint32_t int_mask;
369 uint32_t resc;
370 uint32_t rcc;
371 uint32_t rcgc[3];
372 uint32_t scgc[3];
373 uint32_t dcgc[3];
374 uint32_t clkvclr;
375 uint32_t ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000376 uint32_t user0;
377 uint32_t user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000378 qemu_irq irq;
379 stellaris_board_info *board;
380} ssys_state;
381
382static void ssys_update(ssys_state *s)
383{
384 qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
385}
386
387static uint32_t pllcfg_sandstorm[16] = {
388 0x31c0, /* 1 Mhz */
389 0x1ae0, /* 1.8432 Mhz */
390 0x18c0, /* 2 Mhz */
391 0xd573, /* 2.4576 Mhz */
392 0x37a6, /* 3.57954 Mhz */
393 0x1ae2, /* 3.6864 Mhz */
394 0x0c40, /* 4 Mhz */
395 0x98bc, /* 4.906 Mhz */
396 0x935b, /* 4.9152 Mhz */
397 0x09c0, /* 5 Mhz */
398 0x4dee, /* 5.12 Mhz */
399 0x0c41, /* 6 Mhz */
400 0x75db, /* 6.144 Mhz */
401 0x1ae6, /* 7.3728 Mhz */
402 0x0600, /* 8 Mhz */
403 0x585b /* 8.192 Mhz */
404};
405
406static uint32_t pllcfg_fury[16] = {
407 0x3200, /* 1 Mhz */
408 0x1b20, /* 1.8432 Mhz */
409 0x1900, /* 2 Mhz */
410 0xf42b, /* 2.4576 Mhz */
411 0x37e3, /* 3.57954 Mhz */
412 0x1b21, /* 3.6864 Mhz */
413 0x0c80, /* 4 Mhz */
414 0x98ee, /* 4.906 Mhz */
415 0xd5b4, /* 4.9152 Mhz */
416 0x0a00, /* 5 Mhz */
417 0x4e27, /* 5.12 Mhz */
418 0x1902, /* 6 Mhz */
419 0xec1c, /* 6.144 Mhz */
420 0x1b23, /* 7.3728 Mhz */
421 0x0640, /* 8 Mhz */
422 0xb11c /* 8.192 Mhz */
423};
424
Anthony Liguoric227f092009-10-01 16:12:16 -0500425static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000426{
427 ssys_state *s = (ssys_state *)opaque;
428
pbrook9ee6e8b2007-11-11 00:04:49 +0000429 switch (offset) {
430 case 0x000: /* DID0 */
431 return s->board->did0;
432 case 0x004: /* DID1 */
433 return s->board->did1;
434 case 0x008: /* DC0 */
435 return s->board->dc0;
436 case 0x010: /* DC1 */
437 return s->board->dc1;
438 case 0x014: /* DC2 */
439 return s->board->dc2;
440 case 0x018: /* DC3 */
441 return s->board->dc3;
442 case 0x01c: /* DC4 */
443 return s->board->dc4;
444 case 0x030: /* PBORCTL */
445 return s->pborctl;
446 case 0x034: /* LDOPCTL */
447 return s->ldopctl;
448 case 0x040: /* SRCR0 */
449 return 0;
450 case 0x044: /* SRCR1 */
451 return 0;
452 case 0x048: /* SRCR2 */
453 return 0;
454 case 0x050: /* RIS */
455 return s->int_status;
456 case 0x054: /* IMC */
457 return s->int_mask;
458 case 0x058: /* MISC */
459 return s->int_status & s->int_mask;
460 case 0x05c: /* RESC */
461 return s->resc;
462 case 0x060: /* RCC */
463 return s->rcc;
464 case 0x064: /* PLLCFG */
465 {
466 int xtal;
467 xtal = (s->rcc >> 6) & 0xf;
468 if (s->board->did0 & (1 << 16)) {
469 return pllcfg_fury[xtal];
470 } else {
471 return pllcfg_sandstorm[xtal];
472 }
473 }
474 case 0x100: /* RCGC0 */
475 return s->rcgc[0];
476 case 0x104: /* RCGC1 */
477 return s->rcgc[1];
478 case 0x108: /* RCGC2 */
479 return s->rcgc[2];
480 case 0x110: /* SCGC0 */
481 return s->scgc[0];
482 case 0x114: /* SCGC1 */
483 return s->scgc[1];
484 case 0x118: /* SCGC2 */
485 return s->scgc[2];
486 case 0x120: /* DCGC0 */
487 return s->dcgc[0];
488 case 0x124: /* DCGC1 */
489 return s->dcgc[1];
490 case 0x128: /* DCGC2 */
491 return s->dcgc[2];
492 case 0x150: /* CLKVCLR */
493 return s->clkvclr;
494 case 0x160: /* LDOARST */
495 return s->ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000496 case 0x1e0: /* USER0 */
497 return s->user0;
498 case 0x1e4: /* USER1 */
499 return s->user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000500 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100501 hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000502 return 0;
503 }
504}
505
pbrook23e39292008-07-02 16:48:32 +0000506static void ssys_calculate_system_clock(ssys_state *s)
507{
508 system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
509}
510
Anthony Liguoric227f092009-10-01 16:12:16 -0500511static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
pbrook9ee6e8b2007-11-11 00:04:49 +0000512{
513 ssys_state *s = (ssys_state *)opaque;
514
pbrook9ee6e8b2007-11-11 00:04:49 +0000515 switch (offset) {
516 case 0x030: /* PBORCTL */
517 s->pborctl = value & 0xffff;
518 break;
519 case 0x034: /* LDOPCTL */
520 s->ldopctl = value & 0x1f;
521 break;
522 case 0x040: /* SRCR0 */
523 case 0x044: /* SRCR1 */
524 case 0x048: /* SRCR2 */
525 fprintf(stderr, "Peripheral reset not implemented\n");
526 break;
527 case 0x054: /* IMC */
528 s->int_mask = value & 0x7f;
529 break;
530 case 0x058: /* MISC */
531 s->int_status &= ~value;
532 break;
533 case 0x05c: /* RESC */
534 s->resc = value & 0x3f;
535 break;
536 case 0x060: /* RCC */
537 if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
538 /* PLL enable. */
539 s->int_status |= (1 << 6);
540 }
541 s->rcc = value;
pbrook23e39292008-07-02 16:48:32 +0000542 ssys_calculate_system_clock(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000543 break;
544 case 0x100: /* RCGC0 */
545 s->rcgc[0] = value;
546 break;
547 case 0x104: /* RCGC1 */
548 s->rcgc[1] = value;
549 break;
550 case 0x108: /* RCGC2 */
551 s->rcgc[2] = value;
552 break;
553 case 0x110: /* SCGC0 */
554 s->scgc[0] = value;
555 break;
556 case 0x114: /* SCGC1 */
557 s->scgc[1] = value;
558 break;
559 case 0x118: /* SCGC2 */
560 s->scgc[2] = value;
561 break;
562 case 0x120: /* DCGC0 */
563 s->dcgc[0] = value;
564 break;
565 case 0x124: /* DCGC1 */
566 s->dcgc[1] = value;
567 break;
568 case 0x128: /* DCGC2 */
569 s->dcgc[2] = value;
570 break;
571 case 0x150: /* CLKVCLR */
572 s->clkvclr = value;
573 break;
574 case 0x160: /* LDOARST */
575 s->ldoarst = value;
576 break;
577 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100578 hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000579 }
580 ssys_update(s);
581}
582
Blue Swirld60efc62009-08-25 18:29:31 +0000583static CPUReadMemoryFunc * const ssys_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000584 ssys_read,
585 ssys_read,
586 ssys_read
587};
588
Blue Swirld60efc62009-08-25 18:29:31 +0000589static CPUWriteMemoryFunc * const ssys_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000590 ssys_write,
591 ssys_write,
592 ssys_write
593};
594
pbrook9596ebb2007-11-18 01:44:38 +0000595static void ssys_reset(void *opaque)
pbrook9ee6e8b2007-11-11 00:04:49 +0000596{
597 ssys_state *s = (ssys_state *)opaque;
598
599 s->pborctl = 0x7ffd;
600 s->rcc = 0x078e3ac0;
601 s->rcgc[0] = 1;
602 s->scgc[0] = 1;
603 s->dcgc[0] = 1;
604}
605
pbrook23e39292008-07-02 16:48:32 +0000606static void ssys_save(QEMUFile *f, void *opaque)
607{
608 ssys_state *s = (ssys_state *)opaque;
609
610 qemu_put_be32(f, s->pborctl);
611 qemu_put_be32(f, s->ldopctl);
612 qemu_put_be32(f, s->int_mask);
613 qemu_put_be32(f, s->int_status);
614 qemu_put_be32(f, s->resc);
615 qemu_put_be32(f, s->rcc);
616 qemu_put_be32(f, s->rcgc[0]);
617 qemu_put_be32(f, s->rcgc[1]);
618 qemu_put_be32(f, s->rcgc[2]);
619 qemu_put_be32(f, s->scgc[0]);
620 qemu_put_be32(f, s->scgc[1]);
621 qemu_put_be32(f, s->scgc[2]);
622 qemu_put_be32(f, s->dcgc[0]);
623 qemu_put_be32(f, s->dcgc[1]);
624 qemu_put_be32(f, s->dcgc[2]);
625 qemu_put_be32(f, s->clkvclr);
626 qemu_put_be32(f, s->ldoarst);
627}
628
629static int ssys_load(QEMUFile *f, void *opaque, int version_id)
630{
631 ssys_state *s = (ssys_state *)opaque;
632
633 if (version_id != 1)
634 return -EINVAL;
635
636 s->pborctl = qemu_get_be32(f);
637 s->ldopctl = qemu_get_be32(f);
638 s->int_mask = qemu_get_be32(f);
639 s->int_status = qemu_get_be32(f);
640 s->resc = qemu_get_be32(f);
641 s->rcc = qemu_get_be32(f);
642 s->rcgc[0] = qemu_get_be32(f);
643 s->rcgc[1] = qemu_get_be32(f);
644 s->rcgc[2] = qemu_get_be32(f);
645 s->scgc[0] = qemu_get_be32(f);
646 s->scgc[1] = qemu_get_be32(f);
647 s->scgc[2] = qemu_get_be32(f);
648 s->dcgc[0] = qemu_get_be32(f);
649 s->dcgc[1] = qemu_get_be32(f);
650 s->dcgc[2] = qemu_get_be32(f);
651 s->clkvclr = qemu_get_be32(f);
652 s->ldoarst = qemu_get_be32(f);
653 ssys_calculate_system_clock(s);
654
655 return 0;
656}
657
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200658static int stellaris_sys_init(uint32_t base, qemu_irq irq,
659 stellaris_board_info * board,
660 uint8_t *macaddr)
pbrook9ee6e8b2007-11-11 00:04:49 +0000661{
662 int iomemtype;
663 ssys_state *s;
664
665 s = (ssys_state *)qemu_mallocz(sizeof(ssys_state));
pbrook9ee6e8b2007-11-11 00:04:49 +0000666 s->irq = irq;
667 s->board = board;
pbrookeea589c2007-11-24 03:13:04 +0000668 /* Most devices come preprogrammed with a MAC address in the user data. */
669 s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
670 s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +0000671
Avi Kivity1eed09c2009-06-14 11:38:51 +0300672 iomemtype = cpu_register_io_memory(ssys_readfn,
pbrook9ee6e8b2007-11-11 00:04:49 +0000673 ssys_writefn, s);
674 cpu_register_physical_memory(base, 0x00001000, iomemtype);
675 ssys_reset(s);
pbrook23e39292008-07-02 16:48:32 +0000676 register_savevm("stellaris_sys", -1, 1, ssys_save, ssys_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200677 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000678}
679
680
681/* I2C controller. */
682
683typedef struct {
Paul Brook1de96102009-05-14 22:35:09 +0100684 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000685 i2c_bus *bus;
686 qemu_irq irq;
pbrook9ee6e8b2007-11-11 00:04:49 +0000687 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
Anthony Liguoric227f092009-10-01 16:12:16 -0500704static uint32_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000705{
706 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
707
pbrook9ee6e8b2007-11-11 00:04:49 +0000708 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:
Paul Brook2ac71172009-05-08 02:35:15 +0100727 hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000728 return 0;
729 }
730}
731
732static void stellaris_i2c_update(stellaris_i2c_state *s)
733{
734 int level;
735
736 level = (s->mris & s->mimr) != 0;
737 qemu_set_irq(s->irq, level);
738}
739
Anthony Liguoric227f092009-10-01 16:12:16 -0500740static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset,
pbrook9ee6e8b2007-11-11 00:04:49 +0000741 uint32_t value)
742{
743 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
744
pbrook9ee6e8b2007-11-11 00:04:49 +0000745 switch (offset) {
746 case 0x00: /* MSA */
747 s->msa = value & 0xff;
748 break;
749 case 0x04: /* MCS */
750 if ((s->mcr & 0x10) == 0) {
751 /* Disabled. Do nothing. */
752 break;
753 }
754 /* Grab the bus if this is starting a transfer. */
755 if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
756 if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
757 s->mcs |= STELLARIS_I2C_MCS_ARBLST;
758 } else {
759 s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
760 s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
761 }
762 }
763 /* If we don't have the bus then indicate an error. */
764 if (!i2c_bus_busy(s->bus)
765 || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
766 s->mcs |= STELLARIS_I2C_MCS_ERROR;
767 break;
768 }
769 s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
770 if (value & 1) {
771 /* Transfer a byte. */
772 /* TODO: Handle errors. */
773 if (s->msa & 1) {
774 /* Recv */
775 s->mdr = i2c_recv(s->bus) & 0xff;
776 } else {
777 /* Send */
778 i2c_send(s->bus, s->mdr);
779 }
780 /* Raise an interrupt. */
781 s->mris |= 1;
782 }
783 if (value & 4) {
784 /* Finish transfer. */
785 i2c_end_transfer(s->bus);
786 s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
787 }
788 break;
789 case 0x08: /* MDR */
790 s->mdr = value & 0xff;
791 break;
792 case 0x0c: /* MTPR */
793 s->mtpr = value & 0xff;
794 break;
795 case 0x10: /* MIMR */
796 s->mimr = 1;
797 break;
798 case 0x1c: /* MICR */
799 s->mris &= ~value;
800 break;
801 case 0x20: /* MCR */
802 if (value & 1)
Paul Brook2ac71172009-05-08 02:35:15 +0100803 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000804 "stellaris_i2c_write: Loopback not implemented\n");
805 if (value & 0x20)
Paul Brook2ac71172009-05-08 02:35:15 +0100806 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000807 "stellaris_i2c_write: Slave mode not implemented\n");
808 s->mcr = value & 0x31;
809 break;
810 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100811 hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +0000812 (int)offset);
813 }
814 stellaris_i2c_update(s);
815}
816
817static void stellaris_i2c_reset(stellaris_i2c_state *s)
818{
819 if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
820 i2c_end_transfer(s->bus);
821
822 s->msa = 0;
823 s->mcs = 0;
824 s->mdr = 0;
825 s->mtpr = 1;
826 s->mimr = 0;
827 s->mris = 0;
828 s->mcr = 0;
829 stellaris_i2c_update(s);
830}
831
Blue Swirld60efc62009-08-25 18:29:31 +0000832static CPUReadMemoryFunc * const stellaris_i2c_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000833 stellaris_i2c_read,
834 stellaris_i2c_read,
835 stellaris_i2c_read
836};
837
Blue Swirld60efc62009-08-25 18:29:31 +0000838static CPUWriteMemoryFunc * const stellaris_i2c_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000839 stellaris_i2c_write,
840 stellaris_i2c_write,
841 stellaris_i2c_write
842};
843
pbrook23e39292008-07-02 16:48:32 +0000844static void stellaris_i2c_save(QEMUFile *f, void *opaque)
845{
846 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
847
848 qemu_put_be32(f, s->msa);
849 qemu_put_be32(f, s->mcs);
850 qemu_put_be32(f, s->mdr);
851 qemu_put_be32(f, s->mtpr);
852 qemu_put_be32(f, s->mimr);
853 qemu_put_be32(f, s->mris);
854 qemu_put_be32(f, s->mcr);
855}
856
857static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id)
858{
859 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
860
861 if (version_id != 1)
862 return -EINVAL;
863
864 s->msa = qemu_get_be32(f);
865 s->mcs = qemu_get_be32(f);
866 s->mdr = qemu_get_be32(f);
867 s->mtpr = qemu_get_be32(f);
868 s->mimr = qemu_get_be32(f);
869 s->mris = qemu_get_be32(f);
870 s->mcr = qemu_get_be32(f);
871
872 return 0;
873}
874
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200875static int stellaris_i2c_init(SysBusDevice * dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000876{
Paul Brook1de96102009-05-14 22:35:09 +0100877 stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100878 i2c_bus *bus;
pbrook9ee6e8b2007-11-11 00:04:49 +0000879 int iomemtype;
880
Paul Brook1de96102009-05-14 22:35:09 +0100881 sysbus_init_irq(dev, &s->irq);
Paul Brook02e2da42009-05-23 00:05:19 +0100882 bus = i2c_init_bus(&dev->qdev, "i2c");
pbrook9ee6e8b2007-11-11 00:04:49 +0000883 s->bus = bus;
884
Avi Kivity1eed09c2009-06-14 11:38:51 +0300885 iomemtype = cpu_register_io_memory(stellaris_i2c_readfn,
pbrook9ee6e8b2007-11-11 00:04:49 +0000886 stellaris_i2c_writefn, s);
Paul Brook1de96102009-05-14 22:35:09 +0100887 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +0000888 /* ??? For now we only implement the master interface. */
889 stellaris_i2c_reset(s);
pbrook23e39292008-07-02 16:48:32 +0000890 register_savevm("stellaris_i2c", -1, 1,
891 stellaris_i2c_save, stellaris_i2c_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200892 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000893}
894
895/* Analogue to Digital Converter. This is only partially implemented,
896 enough for applications that use a combined ADC and timer tick. */
897
898#define STELLARIS_ADC_EM_CONTROLLER 0
899#define STELLARIS_ADC_EM_COMP 1
900#define STELLARIS_ADC_EM_EXTERNAL 4
901#define STELLARIS_ADC_EM_TIMER 5
902#define STELLARIS_ADC_EM_PWM0 6
903#define STELLARIS_ADC_EM_PWM1 7
904#define STELLARIS_ADC_EM_PWM2 8
905
906#define STELLARIS_ADC_FIFO_EMPTY 0x0100
907#define STELLARIS_ADC_FIFO_FULL 0x1000
908
909typedef struct
910{
Paul Brook40905a62009-06-03 15:16:49 +0100911 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000912 uint32_t actss;
913 uint32_t ris;
914 uint32_t im;
915 uint32_t emux;
916 uint32_t ostat;
917 uint32_t ustat;
918 uint32_t sspri;
919 uint32_t sac;
920 struct {
921 uint32_t state;
922 uint32_t data[16];
923 } fifo[4];
924 uint32_t ssmux[4];
925 uint32_t ssctl[4];
pbrook23e39292008-07-02 16:48:32 +0000926 uint32_t noise;
Paul Brook2c6554b2009-06-02 15:30:27 +0100927 qemu_irq irq[4];
pbrook9ee6e8b2007-11-11 00:04:49 +0000928} stellaris_adc_state;
929
930static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
931{
932 int tail;
933
934 tail = s->fifo[n].state & 0xf;
935 if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
936 s->ustat |= 1 << n;
937 } else {
938 s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
939 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
940 if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
941 s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
942 }
943 return s->fifo[n].data[tail];
944}
945
946static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
947 uint32_t value)
948{
949 int head;
950
Paul Brook2c6554b2009-06-02 15:30:27 +0100951 /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry
952 FIFO fir each sequencer. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000953 head = (s->fifo[n].state >> 4) & 0xf;
954 if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
955 s->ostat |= 1 << n;
956 return;
957 }
958 s->fifo[n].data[head] = value;
959 head = (head + 1) & 0xf;
960 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
961 s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
962 if ((s->fifo[n].state & 0xf) == head)
963 s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
964}
965
966static void stellaris_adc_update(stellaris_adc_state *s)
967{
968 int level;
Paul Brook2c6554b2009-06-02 15:30:27 +0100969 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000970
Paul Brook2c6554b2009-06-02 15:30:27 +0100971 for (n = 0; n < 4; n++) {
972 level = (s->ris & s->im & (1 << n)) != 0;
973 qemu_set_irq(s->irq[n], level);
974 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000975}
976
977static void stellaris_adc_trigger(void *opaque, int irq, int level)
978{
979 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
Paul Brook2c6554b2009-06-02 15:30:27 +0100980 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000981
Paul Brook2c6554b2009-06-02 15:30:27 +0100982 for (n = 0; n < 4; n++) {
983 if ((s->actss & (1 << n)) == 0) {
984 continue;
985 }
986
987 if (((s->emux >> (n * 4)) & 0xff) != 5) {
988 continue;
989 }
990
991 /* Some applications use the ADC as a random number source, so introduce
992 some variation into the signal. */
993 s->noise = s->noise * 314159 + 1;
994 /* ??? actual inputs not implemented. Return an arbitrary value. */
995 stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
996 s->ris |= (1 << n);
997 stellaris_adc_update(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000998 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000999}
1000
1001static void stellaris_adc_reset(stellaris_adc_state *s)
1002{
1003 int n;
1004
1005 for (n = 0; n < 4; n++) {
1006 s->ssmux[n] = 0;
1007 s->ssctl[n] = 0;
1008 s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
1009 }
1010}
1011
Anthony Liguoric227f092009-10-01 16:12:16 -05001012static uint32_t stellaris_adc_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +00001013{
1014 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1015
1016 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001017 if (offset >= 0x40 && offset < 0xc0) {
1018 int n;
1019 n = (offset - 0x40) >> 5;
1020 switch (offset & 0x1f) {
1021 case 0x00: /* SSMUX */
1022 return s->ssmux[n];
1023 case 0x04: /* SSCTL */
1024 return s->ssctl[n];
1025 case 0x08: /* SSFIFO */
1026 return stellaris_adc_fifo_read(s, n);
1027 case 0x0c: /* SSFSTAT */
1028 return s->fifo[n].state;
1029 default:
1030 break;
1031 }
1032 }
1033 switch (offset) {
1034 case 0x00: /* ACTSS */
1035 return s->actss;
1036 case 0x04: /* RIS */
1037 return s->ris;
1038 case 0x08: /* IM */
1039 return s->im;
1040 case 0x0c: /* ISC */
1041 return s->ris & s->im;
1042 case 0x10: /* OSTAT */
1043 return s->ostat;
1044 case 0x14: /* EMUX */
1045 return s->emux;
1046 case 0x18: /* USTAT */
1047 return s->ustat;
1048 case 0x20: /* SSPRI */
1049 return s->sspri;
1050 case 0x30: /* SAC */
1051 return s->sac;
1052 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001053 hw_error("strllaris_adc_read: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001054 (int)offset);
1055 return 0;
1056 }
1057}
1058
Anthony Liguoric227f092009-10-01 16:12:16 -05001059static void stellaris_adc_write(void *opaque, target_phys_addr_t offset,
pbrook9ee6e8b2007-11-11 00:04:49 +00001060 uint32_t value)
1061{
1062 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1063
1064 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001065 if (offset >= 0x40 && offset < 0xc0) {
1066 int n;
1067 n = (offset - 0x40) >> 5;
1068 switch (offset & 0x1f) {
1069 case 0x00: /* SSMUX */
1070 s->ssmux[n] = value & 0x33333333;
1071 return;
1072 case 0x04: /* SSCTL */
1073 if (value != 6) {
Paul Brook2ac71172009-05-08 02:35:15 +01001074 hw_error("ADC: Unimplemented sequence %x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001075 value);
1076 }
1077 s->ssctl[n] = value;
1078 return;
1079 default:
1080 break;
1081 }
1082 }
1083 switch (offset) {
1084 case 0x00: /* ACTSS */
1085 s->actss = value & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00001086 break;
1087 case 0x08: /* IM */
1088 s->im = value;
1089 break;
1090 case 0x0c: /* ISC */
1091 s->ris &= ~value;
1092 break;
1093 case 0x10: /* OSTAT */
1094 s->ostat &= ~value;
1095 break;
1096 case 0x14: /* EMUX */
1097 s->emux = value;
1098 break;
1099 case 0x18: /* USTAT */
1100 s->ustat &= ~value;
1101 break;
1102 case 0x20: /* SSPRI */
1103 s->sspri = value;
1104 break;
1105 case 0x28: /* PSSI */
Paul Brook2ac71172009-05-08 02:35:15 +01001106 hw_error("Not implemented: ADC sample initiate\n");
pbrook9ee6e8b2007-11-11 00:04:49 +00001107 break;
1108 case 0x30: /* SAC */
1109 s->sac = value;
1110 break;
1111 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001112 hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00001113 }
1114 stellaris_adc_update(s);
1115}
1116
Blue Swirld60efc62009-08-25 18:29:31 +00001117static CPUReadMemoryFunc * const stellaris_adc_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +00001118 stellaris_adc_read,
1119 stellaris_adc_read,
1120 stellaris_adc_read
1121};
1122
Blue Swirld60efc62009-08-25 18:29:31 +00001123static CPUWriteMemoryFunc * const stellaris_adc_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +00001124 stellaris_adc_write,
1125 stellaris_adc_write,
1126 stellaris_adc_write
1127};
1128
pbrook23e39292008-07-02 16:48:32 +00001129static void stellaris_adc_save(QEMUFile *f, void *opaque)
1130{
1131 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1132 int i;
1133 int j;
1134
1135 qemu_put_be32(f, s->actss);
1136 qemu_put_be32(f, s->ris);
1137 qemu_put_be32(f, s->im);
1138 qemu_put_be32(f, s->emux);
1139 qemu_put_be32(f, s->ostat);
1140 qemu_put_be32(f, s->ustat);
1141 qemu_put_be32(f, s->sspri);
1142 qemu_put_be32(f, s->sac);
1143 for (i = 0; i < 4; i++) {
1144 qemu_put_be32(f, s->fifo[i].state);
1145 for (j = 0; j < 16; j++) {
1146 qemu_put_be32(f, s->fifo[i].data[j]);
1147 }
1148 qemu_put_be32(f, s->ssmux[i]);
1149 qemu_put_be32(f, s->ssctl[i]);
1150 }
1151 qemu_put_be32(f, s->noise);
1152}
1153
1154static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id)
1155{
1156 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1157 int i;
1158 int j;
1159
1160 if (version_id != 1)
1161 return -EINVAL;
1162
1163 s->actss = qemu_get_be32(f);
1164 s->ris = qemu_get_be32(f);
1165 s->im = qemu_get_be32(f);
1166 s->emux = qemu_get_be32(f);
1167 s->ostat = qemu_get_be32(f);
1168 s->ustat = qemu_get_be32(f);
1169 s->sspri = qemu_get_be32(f);
1170 s->sac = qemu_get_be32(f);
1171 for (i = 0; i < 4; i++) {
1172 s->fifo[i].state = qemu_get_be32(f);
1173 for (j = 0; j < 16; j++) {
1174 s->fifo[i].data[j] = qemu_get_be32(f);
1175 }
1176 s->ssmux[i] = qemu_get_be32(f);
1177 s->ssctl[i] = qemu_get_be32(f);
1178 }
1179 s->noise = qemu_get_be32(f);
1180
1181 return 0;
1182}
1183
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001184static int stellaris_adc_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +00001185{
Paul Brook40905a62009-06-03 15:16:49 +01001186 stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +00001187 int iomemtype;
Paul Brook2c6554b2009-06-02 15:30:27 +01001188 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +00001189
Paul Brook2c6554b2009-06-02 15:30:27 +01001190 for (n = 0; n < 4; n++) {
Paul Brook40905a62009-06-03 15:16:49 +01001191 sysbus_init_irq(dev, &s->irq[n]);
Paul Brook2c6554b2009-06-02 15:30:27 +01001192 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001193
Avi Kivity1eed09c2009-06-14 11:38:51 +03001194 iomemtype = cpu_register_io_memory(stellaris_adc_readfn,
pbrook9ee6e8b2007-11-11 00:04:49 +00001195 stellaris_adc_writefn, s);
Paul Brook40905a62009-06-03 15:16:49 +01001196 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +00001197 stellaris_adc_reset(s);
Paul Brook40905a62009-06-03 15:16:49 +01001198 qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
pbrook23e39292008-07-02 16:48:32 +00001199 register_savevm("stellaris_adc", -1, 1,
1200 stellaris_adc_save, stellaris_adc_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001201 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00001202}
1203
pbrook775616c2007-11-24 23:35:08 +00001204/* Some boards have both an OLED controller and SD card connected to
1205 the same SSI port, with the SD card chip select connected to a
1206 GPIO pin. Technically the OLED chip select is connected to the SSI
1207 Fss pin. We do not bother emulating that as both devices should
1208 never be selected simultaneously, and our OLED controller ignores stray
1209 0xff commands that occur when deselecting the SD card. */
1210
1211typedef struct {
Paul Brook5493e332009-05-14 22:35:09 +01001212 SSISlave ssidev;
pbrook775616c2007-11-24 23:35:08 +00001213 qemu_irq irq;
1214 int current_dev;
Paul Brook5493e332009-05-14 22:35:09 +01001215 SSIBus *bus[2];
pbrook775616c2007-11-24 23:35:08 +00001216} stellaris_ssi_bus_state;
1217
1218static void stellaris_ssi_bus_select(void *opaque, int irq, int level)
1219{
1220 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1221
1222 s->current_dev = level;
1223}
1224
Paul Brook5493e332009-05-14 22:35:09 +01001225static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
pbrook775616c2007-11-24 23:35:08 +00001226{
Paul Brook5493e332009-05-14 22:35:09 +01001227 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001228
Paul Brook5493e332009-05-14 22:35:09 +01001229 return ssi_transfer(s->bus[s->current_dev], val);
pbrook775616c2007-11-24 23:35:08 +00001230}
1231
pbrook23e39292008-07-02 16:48:32 +00001232static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque)
1233{
1234 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1235
1236 qemu_put_be32(f, s->current_dev);
1237}
1238
1239static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id)
1240{
1241 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1242
1243 if (version_id != 1)
1244 return -EINVAL;
1245
1246 s->current_dev = qemu_get_be32(f);
1247
1248 return 0;
1249}
1250
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001251static int stellaris_ssi_bus_init(SSISlave *dev)
pbrook775616c2007-11-24 23:35:08 +00001252{
Paul Brook5493e332009-05-14 22:35:09 +01001253 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001254
Paul Brook02e2da42009-05-23 00:05:19 +01001255 s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
1256 s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
Paul Brook5493e332009-05-14 22:35:09 +01001257 qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
1258
pbrook23e39292008-07-02 16:48:32 +00001259 register_savevm("stellaris_ssi_bus", -1, 1,
1260 stellaris_ssi_bus_save, stellaris_ssi_bus_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001261 return 0;
pbrook775616c2007-11-24 23:35:08 +00001262}
1263
pbrook9ee6e8b2007-11-11 00:04:49 +00001264/* Board init. */
1265static stellaris_board_info stellaris_boards[] = {
1266 { "LM3S811EVB",
1267 0,
1268 0x0032000e,
1269 0x001f001f, /* dc0 */
1270 0x001132bf,
1271 0x01071013,
1272 0x3f0f01ff,
1273 0x0000001f,
pbrookcf0dbb22007-11-18 14:36:08 +00001274 BP_OLED_I2C
pbrook9ee6e8b2007-11-11 00:04:49 +00001275 },
1276 { "LM3S6965EVB",
1277 0x10010002,
1278 0x1073402e,
1279 0x00ff007f, /* dc0 */
1280 0x001133ff,
1281 0x030f5317,
1282 0x0f0f87ff,
1283 0x5000007f,
pbrookcf0dbb22007-11-18 14:36:08 +00001284 BP_OLED_SSI | BP_GAMEPAD
pbrook9ee6e8b2007-11-11 00:04:49 +00001285 }
1286};
1287
1288static void stellaris_init(const char *kernel_filename, const char *cpu_model,
aliguori3023f332009-01-16 19:04:14 +00001289 stellaris_board_info *board)
pbrook9ee6e8b2007-11-11 00:04:49 +00001290{
1291 static const int uart_irq[] = {5, 6, 33, 34};
1292 static const int timer_irq[] = {19, 21, 23, 35};
1293 static const uint32_t gpio_addr[7] =
1294 { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
1295 0x40024000, 0x40025000, 0x40026000};
1296 static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
1297
1298 qemu_irq *pic;
Paul Brook40905a62009-06-03 15:16:49 +01001299 DeviceState *gpio_dev[7];
1300 qemu_irq gpio_in[7][8];
1301 qemu_irq gpio_out[7][8];
pbrook9ee6e8b2007-11-11 00:04:49 +00001302 qemu_irq adc;
1303 int sram_size;
1304 int flash_size;
1305 i2c_bus *i2c;
Paul Brook40905a62009-06-03 15:16:49 +01001306 DeviceState *dev;
pbrook9ee6e8b2007-11-11 00:04:49 +00001307 int i;
Paul Brook40905a62009-06-03 15:16:49 +01001308 int j;
pbrook9ee6e8b2007-11-11 00:04:49 +00001309
1310 flash_size = ((board->dc0 & 0xffff) + 1) << 1;
1311 sram_size = (board->dc0 >> 18) + 1;
1312 pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
1313
1314 if (board->dc1 & (1 << 16)) {
Paul Brook40905a62009-06-03 15:16:49 +01001315 dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
1316 pic[14], pic[15], pic[16], pic[17], NULL);
1317 adc = qdev_get_gpio_in(dev, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00001318 } else {
1319 adc = NULL;
1320 }
1321 for (i = 0; i < 4; i++) {
1322 if (board->dc2 & (0x10000 << i)) {
Paul Brook40905a62009-06-03 15:16:49 +01001323 dev = sysbus_create_simple("stellaris-gptm",
1324 0x40030000 + i * 0x1000,
1325 pic[timer_irq[i]]);
1326 /* TODO: This is incorrect, but we get away with it because
1327 the ADC output is only ever pulsed. */
1328 qdev_connect_gpio_out(dev, 0, adc);
pbrook9ee6e8b2007-11-11 00:04:49 +00001329 }
1330 }
1331
pbrookeea589c2007-11-24 03:13:04 +00001332 stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr);
pbrook9ee6e8b2007-11-11 00:04:49 +00001333
1334 for (i = 0; i < 7; i++) {
1335 if (board->dc4 & (1 << i)) {
Paul Brook40905a62009-06-03 15:16:49 +01001336 gpio_dev[i] = sysbus_create_simple("pl061", gpio_addr[i],
1337 pic[gpio_irq[i]]);
1338 for (j = 0; j < 8; j++) {
1339 gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
1340 gpio_out[i][j] = NULL;
1341 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001342 }
1343 }
1344
1345 if (board->dc2 & (1 << 12)) {
Paul Brook1de96102009-05-14 22:35:09 +01001346 dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
Paul Brook02e2da42009-05-23 00:05:19 +01001347 i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
pbrookcf0dbb22007-11-18 14:36:08 +00001348 if (board->peripherals & BP_OLED_I2C) {
Paul Brookd2199002009-05-14 22:35:08 +01001349 i2c_create_slave(i2c, "ssd0303", 0x3d);
pbrook9ee6e8b2007-11-11 00:04:49 +00001350 }
1351 }
1352
1353 for (i = 0; i < 4; i++) {
1354 if (board->dc2 & (1 << i)) {
Paul Brooka7d518a2009-05-14 22:35:07 +01001355 sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
1356 pic[uart_irq[i]]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001357 }
1358 }
1359 if (board->dc2 & (1 << 4)) {
Paul Brook5493e332009-05-14 22:35:09 +01001360 dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
pbrookcf0dbb22007-11-18 14:36:08 +00001361 if (board->peripherals & BP_OLED_SSI) {
Paul Brook5493e332009-05-14 22:35:09 +01001362 DeviceState *mux;
1363 void *bus;
pbrook775616c2007-11-24 23:35:08 +00001364
Paul Brook5493e332009-05-14 22:35:09 +01001365 bus = qdev_get_child_bus(dev, "ssi");
1366 mux = ssi_create_slave(bus, "evb6965-ssi");
1367 gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
pbrook775616c2007-11-24 23:35:08 +00001368
Paul Brook5493e332009-05-14 22:35:09 +01001369 bus = qdev_get_child_bus(mux, "ssi0");
1370 dev = ssi_create_slave(bus, "ssi-sd");
pbrook775616c2007-11-24 23:35:08 +00001371
Paul Brook5493e332009-05-14 22:35:09 +01001372 bus = qdev_get_child_bus(mux, "ssi1");
1373 dev = ssi_create_slave(bus, "ssd0323");
1374 gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
1375
pbrook775616c2007-11-24 23:35:08 +00001376 /* Make sure the select pin is high. */
1377 qemu_irq_raise(gpio_out[GPIO_D][0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001378 }
1379 }
Paul Brooka5580462009-05-14 22:35:07 +01001380 if (board->dc4 & (1 << 28)) {
1381 DeviceState *enet;
1382
1383 qemu_check_nic_model(&nd_table[0], "stellaris");
1384
1385 enet = qdev_create(NULL, "stellaris_enet");
Gerd Hoffmannee6847d2009-07-15 13:43:31 +02001386 enet->nd = &nd_table[0];
Paul Brooka5580462009-05-14 22:35:07 +01001387 qdev_init(enet);
1388 sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000);
1389 sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]);
1390 }
pbrookcf0dbb22007-11-18 14:36:08 +00001391 if (board->peripherals & BP_GAMEPAD) {
1392 qemu_irq gpad_irq[5];
1393 static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
1394
1395 gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
1396 gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
1397 gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
1398 gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
1399 gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
1400
1401 stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
1402 }
Paul Brook40905a62009-06-03 15:16:49 +01001403 for (i = 0; i < 7; i++) {
1404 if (board->dc4 & (1 << i)) {
1405 for (j = 0; j < 8; j++) {
1406 if (gpio_out[i][j]) {
1407 qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
1408 }
1409 }
1410 }
1411 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001412}
1413
1414/* FIXME: Figure out how to generate these from stellaris_boards. */
Anthony Liguoric227f092009-10-01 16:12:16 -05001415static void lm3s811evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001416 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001417 const char *kernel_filename, const char *kernel_cmdline,
1418 const char *initrd_filename, const char *cpu_model)
1419{
aliguori3023f332009-01-16 19:04:14 +00001420 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001421}
1422
Anthony Liguoric227f092009-10-01 16:12:16 -05001423static void lm3s6965evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001424 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001425 const char *kernel_filename, const char *kernel_cmdline,
1426 const char *initrd_filename, const char *cpu_model)
1427{
aliguori3023f332009-01-16 19:04:14 +00001428 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001429}
1430
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001431static QEMUMachine lm3s811evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001432 .name = "lm3s811evb",
1433 .desc = "Stellaris LM3S811EVB",
1434 .init = lm3s811evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001435};
1436
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001437static QEMUMachine lm3s6965evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001438 .name = "lm3s6965evb",
1439 .desc = "Stellaris LM3S6965EVB",
1440 .init = lm3s6965evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001441};
Paul Brook1de96102009-05-14 22:35:09 +01001442
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001443static void stellaris_machine_init(void)
1444{
1445 qemu_register_machine(&lm3s811evb_machine);
1446 qemu_register_machine(&lm3s6965evb_machine);
1447}
1448
1449machine_init(stellaris_machine_init);
1450
Paul Brook5493e332009-05-14 22:35:09 +01001451static SSISlaveInfo stellaris_ssi_bus_info = {
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +02001452 .qdev.name = "evb6965-ssi",
1453 .qdev.size = sizeof(stellaris_ssi_bus_state),
Paul Brook5493e332009-05-14 22:35:09 +01001454 .init = stellaris_ssi_bus_init,
1455 .transfer = stellaris_ssi_bus_transfer
1456};
1457
Paul Brook1de96102009-05-14 22:35:09 +01001458static void stellaris_register_devices(void)
1459{
1460 sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
1461 stellaris_i2c_init);
Paul Brook40905a62009-06-03 15:16:49 +01001462 sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
1463 stellaris_gptm_init);
1464 sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state),
1465 stellaris_adc_init);
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +02001466 ssi_register_slave(&stellaris_ssi_bus_info);
Paul Brook1de96102009-05-14 22:35:09 +01001467}
1468
1469device_init(stellaris_register_devices)