blob: 38b9830e27a1188fe8e01122821d4b08a2d724f7 [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. */
93 tick += ticks_per_sec;
94 } 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
143static uint32_t gptm_read(void *opaque, target_phys_addr_t offset)
144{
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
191static void gptm_write(void *opaque, target_phys_addr_t offset, uint32_t value)
192{
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
271static CPUReadMemoryFunc *gptm_readfn[] = {
272 gptm_read,
273 gptm_read,
274 gptm_read
275};
276
277static CPUWriteMemoryFunc *gptm_writefn[] = {
278 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
Paul Brook40905a62009-06-03 15:16:49 +0100342static void 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
350 iomemtype = cpu_register_io_memory(0, gptm_readfn,
351 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);
pbrook9ee6e8b2007-11-11 00:04:49 +0000358}
359
360
361/* System controller. */
362
363typedef struct {
pbrook9ee6e8b2007-11-11 00:04:49 +0000364 uint32_t pborctl;
365 uint32_t ldopctl;
366 uint32_t int_status;
367 uint32_t int_mask;
368 uint32_t resc;
369 uint32_t rcc;
370 uint32_t rcgc[3];
371 uint32_t scgc[3];
372 uint32_t dcgc[3];
373 uint32_t clkvclr;
374 uint32_t ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000375 uint32_t user0;
376 uint32_t user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000377 qemu_irq irq;
378 stellaris_board_info *board;
379} ssys_state;
380
381static void ssys_update(ssys_state *s)
382{
383 qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
384}
385
386static uint32_t pllcfg_sandstorm[16] = {
387 0x31c0, /* 1 Mhz */
388 0x1ae0, /* 1.8432 Mhz */
389 0x18c0, /* 2 Mhz */
390 0xd573, /* 2.4576 Mhz */
391 0x37a6, /* 3.57954 Mhz */
392 0x1ae2, /* 3.6864 Mhz */
393 0x0c40, /* 4 Mhz */
394 0x98bc, /* 4.906 Mhz */
395 0x935b, /* 4.9152 Mhz */
396 0x09c0, /* 5 Mhz */
397 0x4dee, /* 5.12 Mhz */
398 0x0c41, /* 6 Mhz */
399 0x75db, /* 6.144 Mhz */
400 0x1ae6, /* 7.3728 Mhz */
401 0x0600, /* 8 Mhz */
402 0x585b /* 8.192 Mhz */
403};
404
405static uint32_t pllcfg_fury[16] = {
406 0x3200, /* 1 Mhz */
407 0x1b20, /* 1.8432 Mhz */
408 0x1900, /* 2 Mhz */
409 0xf42b, /* 2.4576 Mhz */
410 0x37e3, /* 3.57954 Mhz */
411 0x1b21, /* 3.6864 Mhz */
412 0x0c80, /* 4 Mhz */
413 0x98ee, /* 4.906 Mhz */
414 0xd5b4, /* 4.9152 Mhz */
415 0x0a00, /* 5 Mhz */
416 0x4e27, /* 5.12 Mhz */
417 0x1902, /* 6 Mhz */
418 0xec1c, /* 6.144 Mhz */
419 0x1b23, /* 7.3728 Mhz */
420 0x0640, /* 8 Mhz */
421 0xb11c /* 8.192 Mhz */
422};
423
424static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
425{
426 ssys_state *s = (ssys_state *)opaque;
427
pbrook9ee6e8b2007-11-11 00:04:49 +0000428 switch (offset) {
429 case 0x000: /* DID0 */
430 return s->board->did0;
431 case 0x004: /* DID1 */
432 return s->board->did1;
433 case 0x008: /* DC0 */
434 return s->board->dc0;
435 case 0x010: /* DC1 */
436 return s->board->dc1;
437 case 0x014: /* DC2 */
438 return s->board->dc2;
439 case 0x018: /* DC3 */
440 return s->board->dc3;
441 case 0x01c: /* DC4 */
442 return s->board->dc4;
443 case 0x030: /* PBORCTL */
444 return s->pborctl;
445 case 0x034: /* LDOPCTL */
446 return s->ldopctl;
447 case 0x040: /* SRCR0 */
448 return 0;
449 case 0x044: /* SRCR1 */
450 return 0;
451 case 0x048: /* SRCR2 */
452 return 0;
453 case 0x050: /* RIS */
454 return s->int_status;
455 case 0x054: /* IMC */
456 return s->int_mask;
457 case 0x058: /* MISC */
458 return s->int_status & s->int_mask;
459 case 0x05c: /* RESC */
460 return s->resc;
461 case 0x060: /* RCC */
462 return s->rcc;
463 case 0x064: /* PLLCFG */
464 {
465 int xtal;
466 xtal = (s->rcc >> 6) & 0xf;
467 if (s->board->did0 & (1 << 16)) {
468 return pllcfg_fury[xtal];
469 } else {
470 return pllcfg_sandstorm[xtal];
471 }
472 }
473 case 0x100: /* RCGC0 */
474 return s->rcgc[0];
475 case 0x104: /* RCGC1 */
476 return s->rcgc[1];
477 case 0x108: /* RCGC2 */
478 return s->rcgc[2];
479 case 0x110: /* SCGC0 */
480 return s->scgc[0];
481 case 0x114: /* SCGC1 */
482 return s->scgc[1];
483 case 0x118: /* SCGC2 */
484 return s->scgc[2];
485 case 0x120: /* DCGC0 */
486 return s->dcgc[0];
487 case 0x124: /* DCGC1 */
488 return s->dcgc[1];
489 case 0x128: /* DCGC2 */
490 return s->dcgc[2];
491 case 0x150: /* CLKVCLR */
492 return s->clkvclr;
493 case 0x160: /* LDOARST */
494 return s->ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000495 case 0x1e0: /* USER0 */
496 return s->user0;
497 case 0x1e4: /* USER1 */
498 return s->user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000499 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100500 hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000501 return 0;
502 }
503}
504
pbrook23e39292008-07-02 16:48:32 +0000505static void ssys_calculate_system_clock(ssys_state *s)
506{
507 system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
508}
509
pbrook9ee6e8b2007-11-11 00:04:49 +0000510static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
511{
512 ssys_state *s = (ssys_state *)opaque;
513
pbrook9ee6e8b2007-11-11 00:04:49 +0000514 switch (offset) {
515 case 0x030: /* PBORCTL */
516 s->pborctl = value & 0xffff;
517 break;
518 case 0x034: /* LDOPCTL */
519 s->ldopctl = value & 0x1f;
520 break;
521 case 0x040: /* SRCR0 */
522 case 0x044: /* SRCR1 */
523 case 0x048: /* SRCR2 */
524 fprintf(stderr, "Peripheral reset not implemented\n");
525 break;
526 case 0x054: /* IMC */
527 s->int_mask = value & 0x7f;
528 break;
529 case 0x058: /* MISC */
530 s->int_status &= ~value;
531 break;
532 case 0x05c: /* RESC */
533 s->resc = value & 0x3f;
534 break;
535 case 0x060: /* RCC */
536 if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
537 /* PLL enable. */
538 s->int_status |= (1 << 6);
539 }
540 s->rcc = value;
pbrook23e39292008-07-02 16:48:32 +0000541 ssys_calculate_system_clock(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000542 break;
543 case 0x100: /* RCGC0 */
544 s->rcgc[0] = value;
545 break;
546 case 0x104: /* RCGC1 */
547 s->rcgc[1] = value;
548 break;
549 case 0x108: /* RCGC2 */
550 s->rcgc[2] = value;
551 break;
552 case 0x110: /* SCGC0 */
553 s->scgc[0] = value;
554 break;
555 case 0x114: /* SCGC1 */
556 s->scgc[1] = value;
557 break;
558 case 0x118: /* SCGC2 */
559 s->scgc[2] = value;
560 break;
561 case 0x120: /* DCGC0 */
562 s->dcgc[0] = value;
563 break;
564 case 0x124: /* DCGC1 */
565 s->dcgc[1] = value;
566 break;
567 case 0x128: /* DCGC2 */
568 s->dcgc[2] = value;
569 break;
570 case 0x150: /* CLKVCLR */
571 s->clkvclr = value;
572 break;
573 case 0x160: /* LDOARST */
574 s->ldoarst = value;
575 break;
576 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100577 hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000578 }
579 ssys_update(s);
580}
581
582static CPUReadMemoryFunc *ssys_readfn[] = {
583 ssys_read,
584 ssys_read,
585 ssys_read
586};
587
588static CPUWriteMemoryFunc *ssys_writefn[] = {
589 ssys_write,
590 ssys_write,
591 ssys_write
592};
593
pbrook9596ebb2007-11-18 01:44:38 +0000594static void ssys_reset(void *opaque)
pbrook9ee6e8b2007-11-11 00:04:49 +0000595{
596 ssys_state *s = (ssys_state *)opaque;
597
598 s->pborctl = 0x7ffd;
599 s->rcc = 0x078e3ac0;
600 s->rcgc[0] = 1;
601 s->scgc[0] = 1;
602 s->dcgc[0] = 1;
603}
604
pbrook23e39292008-07-02 16:48:32 +0000605static void ssys_save(QEMUFile *f, void *opaque)
606{
607 ssys_state *s = (ssys_state *)opaque;
608
609 qemu_put_be32(f, s->pborctl);
610 qemu_put_be32(f, s->ldopctl);
611 qemu_put_be32(f, s->int_mask);
612 qemu_put_be32(f, s->int_status);
613 qemu_put_be32(f, s->resc);
614 qemu_put_be32(f, s->rcc);
615 qemu_put_be32(f, s->rcgc[0]);
616 qemu_put_be32(f, s->rcgc[1]);
617 qemu_put_be32(f, s->rcgc[2]);
618 qemu_put_be32(f, s->scgc[0]);
619 qemu_put_be32(f, s->scgc[1]);
620 qemu_put_be32(f, s->scgc[2]);
621 qemu_put_be32(f, s->dcgc[0]);
622 qemu_put_be32(f, s->dcgc[1]);
623 qemu_put_be32(f, s->dcgc[2]);
624 qemu_put_be32(f, s->clkvclr);
625 qemu_put_be32(f, s->ldoarst);
626}
627
628static int ssys_load(QEMUFile *f, void *opaque, int version_id)
629{
630 ssys_state *s = (ssys_state *)opaque;
631
632 if (version_id != 1)
633 return -EINVAL;
634
635 s->pborctl = qemu_get_be32(f);
636 s->ldopctl = qemu_get_be32(f);
637 s->int_mask = qemu_get_be32(f);
638 s->int_status = qemu_get_be32(f);
639 s->resc = qemu_get_be32(f);
640 s->rcc = qemu_get_be32(f);
641 s->rcgc[0] = qemu_get_be32(f);
642 s->rcgc[1] = qemu_get_be32(f);
643 s->rcgc[2] = qemu_get_be32(f);
644 s->scgc[0] = qemu_get_be32(f);
645 s->scgc[1] = qemu_get_be32(f);
646 s->scgc[2] = qemu_get_be32(f);
647 s->dcgc[0] = qemu_get_be32(f);
648 s->dcgc[1] = qemu_get_be32(f);
649 s->dcgc[2] = qemu_get_be32(f);
650 s->clkvclr = qemu_get_be32(f);
651 s->ldoarst = qemu_get_be32(f);
652 ssys_calculate_system_clock(s);
653
654 return 0;
655}
656
pbrook9ee6e8b2007-11-11 00:04:49 +0000657static void stellaris_sys_init(uint32_t base, qemu_irq irq,
pbrookeea589c2007-11-24 03:13:04 +0000658 stellaris_board_info * board,
659 uint8_t *macaddr)
pbrook9ee6e8b2007-11-11 00:04:49 +0000660{
661 int iomemtype;
662 ssys_state *s;
663
664 s = (ssys_state *)qemu_mallocz(sizeof(ssys_state));
pbrook9ee6e8b2007-11-11 00:04:49 +0000665 s->irq = irq;
666 s->board = board;
pbrookeea589c2007-11-24 03:13:04 +0000667 /* Most devices come preprogrammed with a MAC address in the user data. */
668 s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
669 s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +0000670
671 iomemtype = cpu_register_io_memory(0, ssys_readfn,
672 ssys_writefn, s);
673 cpu_register_physical_memory(base, 0x00001000, iomemtype);
674 ssys_reset(s);
pbrook23e39292008-07-02 16:48:32 +0000675 register_savevm("stellaris_sys", -1, 1, ssys_save, ssys_load, s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000676}
677
678
679/* I2C controller. */
680
681typedef struct {
Paul Brook1de96102009-05-14 22:35:09 +0100682 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000683 i2c_bus *bus;
684 qemu_irq irq;
pbrook9ee6e8b2007-11-11 00:04:49 +0000685 uint32_t msa;
686 uint32_t mcs;
687 uint32_t mdr;
688 uint32_t mtpr;
689 uint32_t mimr;
690 uint32_t mris;
691 uint32_t mcr;
692} stellaris_i2c_state;
693
694#define STELLARIS_I2C_MCS_BUSY 0x01
695#define STELLARIS_I2C_MCS_ERROR 0x02
696#define STELLARIS_I2C_MCS_ADRACK 0x04
697#define STELLARIS_I2C_MCS_DATACK 0x08
698#define STELLARIS_I2C_MCS_ARBLST 0x10
699#define STELLARIS_I2C_MCS_IDLE 0x20
700#define STELLARIS_I2C_MCS_BUSBSY 0x40
701
702static uint32_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset)
703{
704 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
705
pbrook9ee6e8b2007-11-11 00:04:49 +0000706 switch (offset) {
707 case 0x00: /* MSA */
708 return s->msa;
709 case 0x04: /* MCS */
710 /* We don't emulate timing, so the controller is never busy. */
711 return s->mcs | STELLARIS_I2C_MCS_IDLE;
712 case 0x08: /* MDR */
713 return s->mdr;
714 case 0x0c: /* MTPR */
715 return s->mtpr;
716 case 0x10: /* MIMR */
717 return s->mimr;
718 case 0x14: /* MRIS */
719 return s->mris;
720 case 0x18: /* MMIS */
721 return s->mris & s->mimr;
722 case 0x20: /* MCR */
723 return s->mcr;
724 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100725 hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000726 return 0;
727 }
728}
729
730static void stellaris_i2c_update(stellaris_i2c_state *s)
731{
732 int level;
733
734 level = (s->mris & s->mimr) != 0;
735 qemu_set_irq(s->irq, level);
736}
737
738static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset,
739 uint32_t value)
740{
741 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
742
pbrook9ee6e8b2007-11-11 00:04:49 +0000743 switch (offset) {
744 case 0x00: /* MSA */
745 s->msa = value & 0xff;
746 break;
747 case 0x04: /* MCS */
748 if ((s->mcr & 0x10) == 0) {
749 /* Disabled. Do nothing. */
750 break;
751 }
752 /* Grab the bus if this is starting a transfer. */
753 if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
754 if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
755 s->mcs |= STELLARIS_I2C_MCS_ARBLST;
756 } else {
757 s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
758 s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
759 }
760 }
761 /* If we don't have the bus then indicate an error. */
762 if (!i2c_bus_busy(s->bus)
763 || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
764 s->mcs |= STELLARIS_I2C_MCS_ERROR;
765 break;
766 }
767 s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
768 if (value & 1) {
769 /* Transfer a byte. */
770 /* TODO: Handle errors. */
771 if (s->msa & 1) {
772 /* Recv */
773 s->mdr = i2c_recv(s->bus) & 0xff;
774 } else {
775 /* Send */
776 i2c_send(s->bus, s->mdr);
777 }
778 /* Raise an interrupt. */
779 s->mris |= 1;
780 }
781 if (value & 4) {
782 /* Finish transfer. */
783 i2c_end_transfer(s->bus);
784 s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
785 }
786 break;
787 case 0x08: /* MDR */
788 s->mdr = value & 0xff;
789 break;
790 case 0x0c: /* MTPR */
791 s->mtpr = value & 0xff;
792 break;
793 case 0x10: /* MIMR */
794 s->mimr = 1;
795 break;
796 case 0x1c: /* MICR */
797 s->mris &= ~value;
798 break;
799 case 0x20: /* MCR */
800 if (value & 1)
Paul Brook2ac71172009-05-08 02:35:15 +0100801 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000802 "stellaris_i2c_write: Loopback not implemented\n");
803 if (value & 0x20)
Paul Brook2ac71172009-05-08 02:35:15 +0100804 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000805 "stellaris_i2c_write: Slave mode not implemented\n");
806 s->mcr = value & 0x31;
807 break;
808 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100809 hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +0000810 (int)offset);
811 }
812 stellaris_i2c_update(s);
813}
814
815static void stellaris_i2c_reset(stellaris_i2c_state *s)
816{
817 if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
818 i2c_end_transfer(s->bus);
819
820 s->msa = 0;
821 s->mcs = 0;
822 s->mdr = 0;
823 s->mtpr = 1;
824 s->mimr = 0;
825 s->mris = 0;
826 s->mcr = 0;
827 stellaris_i2c_update(s);
828}
829
830static CPUReadMemoryFunc *stellaris_i2c_readfn[] = {
831 stellaris_i2c_read,
832 stellaris_i2c_read,
833 stellaris_i2c_read
834};
835
836static CPUWriteMemoryFunc *stellaris_i2c_writefn[] = {
837 stellaris_i2c_write,
838 stellaris_i2c_write,
839 stellaris_i2c_write
840};
841
pbrook23e39292008-07-02 16:48:32 +0000842static void stellaris_i2c_save(QEMUFile *f, void *opaque)
843{
844 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
845
846 qemu_put_be32(f, s->msa);
847 qemu_put_be32(f, s->mcs);
848 qemu_put_be32(f, s->mdr);
849 qemu_put_be32(f, s->mtpr);
850 qemu_put_be32(f, s->mimr);
851 qemu_put_be32(f, s->mris);
852 qemu_put_be32(f, s->mcr);
853}
854
855static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id)
856{
857 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
858
859 if (version_id != 1)
860 return -EINVAL;
861
862 s->msa = qemu_get_be32(f);
863 s->mcs = qemu_get_be32(f);
864 s->mdr = qemu_get_be32(f);
865 s->mtpr = qemu_get_be32(f);
866 s->mimr = qemu_get_be32(f);
867 s->mris = qemu_get_be32(f);
868 s->mcr = qemu_get_be32(f);
869
870 return 0;
871}
872
Paul Brook1de96102009-05-14 22:35:09 +0100873static void stellaris_i2c_init(SysBusDevice * dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000874{
Paul Brook1de96102009-05-14 22:35:09 +0100875 stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100876 i2c_bus *bus;
pbrook9ee6e8b2007-11-11 00:04:49 +0000877 int iomemtype;
878
Paul Brook1de96102009-05-14 22:35:09 +0100879 sysbus_init_irq(dev, &s->irq);
Paul Brook02e2da42009-05-23 00:05:19 +0100880 bus = i2c_init_bus(&dev->qdev, "i2c");
pbrook9ee6e8b2007-11-11 00:04:49 +0000881 s->bus = bus;
882
883 iomemtype = cpu_register_io_memory(0, stellaris_i2c_readfn,
884 stellaris_i2c_writefn, s);
Paul Brook1de96102009-05-14 22:35:09 +0100885 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +0000886 /* ??? For now we only implement the master interface. */
887 stellaris_i2c_reset(s);
pbrook23e39292008-07-02 16:48:32 +0000888 register_savevm("stellaris_i2c", -1, 1,
889 stellaris_i2c_save, stellaris_i2c_load, s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000890}
891
892/* Analogue to Digital Converter. This is only partially implemented,
893 enough for applications that use a combined ADC and timer tick. */
894
895#define STELLARIS_ADC_EM_CONTROLLER 0
896#define STELLARIS_ADC_EM_COMP 1
897#define STELLARIS_ADC_EM_EXTERNAL 4
898#define STELLARIS_ADC_EM_TIMER 5
899#define STELLARIS_ADC_EM_PWM0 6
900#define STELLARIS_ADC_EM_PWM1 7
901#define STELLARIS_ADC_EM_PWM2 8
902
903#define STELLARIS_ADC_FIFO_EMPTY 0x0100
904#define STELLARIS_ADC_FIFO_FULL 0x1000
905
906typedef struct
907{
Paul Brook40905a62009-06-03 15:16:49 +0100908 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000909 uint32_t actss;
910 uint32_t ris;
911 uint32_t im;
912 uint32_t emux;
913 uint32_t ostat;
914 uint32_t ustat;
915 uint32_t sspri;
916 uint32_t sac;
917 struct {
918 uint32_t state;
919 uint32_t data[16];
920 } fifo[4];
921 uint32_t ssmux[4];
922 uint32_t ssctl[4];
pbrook23e39292008-07-02 16:48:32 +0000923 uint32_t noise;
Paul Brook2c6554b2009-06-02 15:30:27 +0100924 qemu_irq irq[4];
pbrook9ee6e8b2007-11-11 00:04:49 +0000925} stellaris_adc_state;
926
927static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
928{
929 int tail;
930
931 tail = s->fifo[n].state & 0xf;
932 if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
933 s->ustat |= 1 << n;
934 } else {
935 s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
936 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
937 if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
938 s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
939 }
940 return s->fifo[n].data[tail];
941}
942
943static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
944 uint32_t value)
945{
946 int head;
947
Paul Brook2c6554b2009-06-02 15:30:27 +0100948 /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry
949 FIFO fir each sequencer. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000950 head = (s->fifo[n].state >> 4) & 0xf;
951 if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
952 s->ostat |= 1 << n;
953 return;
954 }
955 s->fifo[n].data[head] = value;
956 head = (head + 1) & 0xf;
957 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
958 s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
959 if ((s->fifo[n].state & 0xf) == head)
960 s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
961}
962
963static void stellaris_adc_update(stellaris_adc_state *s)
964{
965 int level;
Paul Brook2c6554b2009-06-02 15:30:27 +0100966 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000967
Paul Brook2c6554b2009-06-02 15:30:27 +0100968 for (n = 0; n < 4; n++) {
969 level = (s->ris & s->im & (1 << n)) != 0;
970 qemu_set_irq(s->irq[n], level);
971 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000972}
973
974static void stellaris_adc_trigger(void *opaque, int irq, int level)
975{
976 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
Paul Brook2c6554b2009-06-02 15:30:27 +0100977 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000978
Paul Brook2c6554b2009-06-02 15:30:27 +0100979 for (n = 0; n < 4; n++) {
980 if ((s->actss & (1 << n)) == 0) {
981 continue;
982 }
983
984 if (((s->emux >> (n * 4)) & 0xff) != 5) {
985 continue;
986 }
987
988 /* Some applications use the ADC as a random number source, so introduce
989 some variation into the signal. */
990 s->noise = s->noise * 314159 + 1;
991 /* ??? actual inputs not implemented. Return an arbitrary value. */
992 stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
993 s->ris |= (1 << n);
994 stellaris_adc_update(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000995 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000996}
997
998static void stellaris_adc_reset(stellaris_adc_state *s)
999{
1000 int n;
1001
1002 for (n = 0; n < 4; n++) {
1003 s->ssmux[n] = 0;
1004 s->ssctl[n] = 0;
1005 s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
1006 }
1007}
1008
1009static uint32_t stellaris_adc_read(void *opaque, target_phys_addr_t offset)
1010{
1011 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1012
1013 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001014 if (offset >= 0x40 && offset < 0xc0) {
1015 int n;
1016 n = (offset - 0x40) >> 5;
1017 switch (offset & 0x1f) {
1018 case 0x00: /* SSMUX */
1019 return s->ssmux[n];
1020 case 0x04: /* SSCTL */
1021 return s->ssctl[n];
1022 case 0x08: /* SSFIFO */
1023 return stellaris_adc_fifo_read(s, n);
1024 case 0x0c: /* SSFSTAT */
1025 return s->fifo[n].state;
1026 default:
1027 break;
1028 }
1029 }
1030 switch (offset) {
1031 case 0x00: /* ACTSS */
1032 return s->actss;
1033 case 0x04: /* RIS */
1034 return s->ris;
1035 case 0x08: /* IM */
1036 return s->im;
1037 case 0x0c: /* ISC */
1038 return s->ris & s->im;
1039 case 0x10: /* OSTAT */
1040 return s->ostat;
1041 case 0x14: /* EMUX */
1042 return s->emux;
1043 case 0x18: /* USTAT */
1044 return s->ustat;
1045 case 0x20: /* SSPRI */
1046 return s->sspri;
1047 case 0x30: /* SAC */
1048 return s->sac;
1049 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001050 hw_error("strllaris_adc_read: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001051 (int)offset);
1052 return 0;
1053 }
1054}
1055
1056static void stellaris_adc_write(void *opaque, target_phys_addr_t offset,
1057 uint32_t value)
1058{
1059 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1060
1061 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001062 if (offset >= 0x40 && offset < 0xc0) {
1063 int n;
1064 n = (offset - 0x40) >> 5;
1065 switch (offset & 0x1f) {
1066 case 0x00: /* SSMUX */
1067 s->ssmux[n] = value & 0x33333333;
1068 return;
1069 case 0x04: /* SSCTL */
1070 if (value != 6) {
Paul Brook2ac71172009-05-08 02:35:15 +01001071 hw_error("ADC: Unimplemented sequence %x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001072 value);
1073 }
1074 s->ssctl[n] = value;
1075 return;
1076 default:
1077 break;
1078 }
1079 }
1080 switch (offset) {
1081 case 0x00: /* ACTSS */
1082 s->actss = value & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00001083 break;
1084 case 0x08: /* IM */
1085 s->im = value;
1086 break;
1087 case 0x0c: /* ISC */
1088 s->ris &= ~value;
1089 break;
1090 case 0x10: /* OSTAT */
1091 s->ostat &= ~value;
1092 break;
1093 case 0x14: /* EMUX */
1094 s->emux = value;
1095 break;
1096 case 0x18: /* USTAT */
1097 s->ustat &= ~value;
1098 break;
1099 case 0x20: /* SSPRI */
1100 s->sspri = value;
1101 break;
1102 case 0x28: /* PSSI */
Paul Brook2ac71172009-05-08 02:35:15 +01001103 hw_error("Not implemented: ADC sample initiate\n");
pbrook9ee6e8b2007-11-11 00:04:49 +00001104 break;
1105 case 0x30: /* SAC */
1106 s->sac = value;
1107 break;
1108 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001109 hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00001110 }
1111 stellaris_adc_update(s);
1112}
1113
1114static CPUReadMemoryFunc *stellaris_adc_readfn[] = {
1115 stellaris_adc_read,
1116 stellaris_adc_read,
1117 stellaris_adc_read
1118};
1119
1120static CPUWriteMemoryFunc *stellaris_adc_writefn[] = {
1121 stellaris_adc_write,
1122 stellaris_adc_write,
1123 stellaris_adc_write
1124};
1125
pbrook23e39292008-07-02 16:48:32 +00001126static void stellaris_adc_save(QEMUFile *f, void *opaque)
1127{
1128 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1129 int i;
1130 int j;
1131
1132 qemu_put_be32(f, s->actss);
1133 qemu_put_be32(f, s->ris);
1134 qemu_put_be32(f, s->im);
1135 qemu_put_be32(f, s->emux);
1136 qemu_put_be32(f, s->ostat);
1137 qemu_put_be32(f, s->ustat);
1138 qemu_put_be32(f, s->sspri);
1139 qemu_put_be32(f, s->sac);
1140 for (i = 0; i < 4; i++) {
1141 qemu_put_be32(f, s->fifo[i].state);
1142 for (j = 0; j < 16; j++) {
1143 qemu_put_be32(f, s->fifo[i].data[j]);
1144 }
1145 qemu_put_be32(f, s->ssmux[i]);
1146 qemu_put_be32(f, s->ssctl[i]);
1147 }
1148 qemu_put_be32(f, s->noise);
1149}
1150
1151static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id)
1152{
1153 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1154 int i;
1155 int j;
1156
1157 if (version_id != 1)
1158 return -EINVAL;
1159
1160 s->actss = qemu_get_be32(f);
1161 s->ris = qemu_get_be32(f);
1162 s->im = qemu_get_be32(f);
1163 s->emux = qemu_get_be32(f);
1164 s->ostat = qemu_get_be32(f);
1165 s->ustat = qemu_get_be32(f);
1166 s->sspri = qemu_get_be32(f);
1167 s->sac = qemu_get_be32(f);
1168 for (i = 0; i < 4; i++) {
1169 s->fifo[i].state = qemu_get_be32(f);
1170 for (j = 0; j < 16; j++) {
1171 s->fifo[i].data[j] = qemu_get_be32(f);
1172 }
1173 s->ssmux[i] = qemu_get_be32(f);
1174 s->ssctl[i] = qemu_get_be32(f);
1175 }
1176 s->noise = qemu_get_be32(f);
1177
1178 return 0;
1179}
1180
Paul Brook40905a62009-06-03 15:16:49 +01001181static void stellaris_adc_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +00001182{
Paul Brook40905a62009-06-03 15:16:49 +01001183 stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +00001184 int iomemtype;
Paul Brook2c6554b2009-06-02 15:30:27 +01001185 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +00001186
Paul Brook2c6554b2009-06-02 15:30:27 +01001187 for (n = 0; n < 4; n++) {
Paul Brook40905a62009-06-03 15:16:49 +01001188 sysbus_init_irq(dev, &s->irq[n]);
Paul Brook2c6554b2009-06-02 15:30:27 +01001189 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001190
1191 iomemtype = cpu_register_io_memory(0, stellaris_adc_readfn,
1192 stellaris_adc_writefn, s);
Paul Brook40905a62009-06-03 15:16:49 +01001193 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +00001194 stellaris_adc_reset(s);
Paul Brook40905a62009-06-03 15:16:49 +01001195 qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
pbrook23e39292008-07-02 16:48:32 +00001196 register_savevm("stellaris_adc", -1, 1,
1197 stellaris_adc_save, stellaris_adc_load, s);
pbrook9ee6e8b2007-11-11 00:04:49 +00001198}
1199
pbrook775616c2007-11-24 23:35:08 +00001200/* Some boards have both an OLED controller and SD card connected to
1201 the same SSI port, with the SD card chip select connected to a
1202 GPIO pin. Technically the OLED chip select is connected to the SSI
1203 Fss pin. We do not bother emulating that as both devices should
1204 never be selected simultaneously, and our OLED controller ignores stray
1205 0xff commands that occur when deselecting the SD card. */
1206
1207typedef struct {
Paul Brook5493e332009-05-14 22:35:09 +01001208 SSISlave ssidev;
pbrook775616c2007-11-24 23:35:08 +00001209 qemu_irq irq;
1210 int current_dev;
Paul Brook5493e332009-05-14 22:35:09 +01001211 SSIBus *bus[2];
pbrook775616c2007-11-24 23:35:08 +00001212} stellaris_ssi_bus_state;
1213
1214static void stellaris_ssi_bus_select(void *opaque, int irq, int level)
1215{
1216 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1217
1218 s->current_dev = level;
1219}
1220
Paul Brook5493e332009-05-14 22:35:09 +01001221static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
pbrook775616c2007-11-24 23:35:08 +00001222{
Paul Brook5493e332009-05-14 22:35:09 +01001223 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001224
Paul Brook5493e332009-05-14 22:35:09 +01001225 return ssi_transfer(s->bus[s->current_dev], val);
pbrook775616c2007-11-24 23:35:08 +00001226}
1227
pbrook23e39292008-07-02 16:48:32 +00001228static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque)
1229{
1230 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1231
1232 qemu_put_be32(f, s->current_dev);
1233}
1234
1235static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id)
1236{
1237 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1238
1239 if (version_id != 1)
1240 return -EINVAL;
1241
1242 s->current_dev = qemu_get_be32(f);
1243
1244 return 0;
1245}
1246
Paul Brook5493e332009-05-14 22:35:09 +01001247static void stellaris_ssi_bus_init(SSISlave *dev)
pbrook775616c2007-11-24 23:35:08 +00001248{
Paul Brook5493e332009-05-14 22:35:09 +01001249 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001250
Paul Brook02e2da42009-05-23 00:05:19 +01001251 s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
1252 s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
Paul Brook5493e332009-05-14 22:35:09 +01001253 qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
1254
pbrook23e39292008-07-02 16:48:32 +00001255 register_savevm("stellaris_ssi_bus", -1, 1,
1256 stellaris_ssi_bus_save, stellaris_ssi_bus_load, s);
pbrook775616c2007-11-24 23:35:08 +00001257}
1258
pbrook9ee6e8b2007-11-11 00:04:49 +00001259/* Board init. */
1260static stellaris_board_info stellaris_boards[] = {
1261 { "LM3S811EVB",
1262 0,
1263 0x0032000e,
1264 0x001f001f, /* dc0 */
1265 0x001132bf,
1266 0x01071013,
1267 0x3f0f01ff,
1268 0x0000001f,
pbrookcf0dbb22007-11-18 14:36:08 +00001269 BP_OLED_I2C
pbrook9ee6e8b2007-11-11 00:04:49 +00001270 },
1271 { "LM3S6965EVB",
1272 0x10010002,
1273 0x1073402e,
1274 0x00ff007f, /* dc0 */
1275 0x001133ff,
1276 0x030f5317,
1277 0x0f0f87ff,
1278 0x5000007f,
pbrookcf0dbb22007-11-18 14:36:08 +00001279 BP_OLED_SSI | BP_GAMEPAD
pbrook9ee6e8b2007-11-11 00:04:49 +00001280 }
1281};
1282
1283static void stellaris_init(const char *kernel_filename, const char *cpu_model,
aliguori3023f332009-01-16 19:04:14 +00001284 stellaris_board_info *board)
pbrook9ee6e8b2007-11-11 00:04:49 +00001285{
1286 static const int uart_irq[] = {5, 6, 33, 34};
1287 static const int timer_irq[] = {19, 21, 23, 35};
1288 static const uint32_t gpio_addr[7] =
1289 { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
1290 0x40024000, 0x40025000, 0x40026000};
1291 static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
1292
1293 qemu_irq *pic;
Paul Brook40905a62009-06-03 15:16:49 +01001294 DeviceState *gpio_dev[7];
1295 qemu_irq gpio_in[7][8];
1296 qemu_irq gpio_out[7][8];
pbrook9ee6e8b2007-11-11 00:04:49 +00001297 qemu_irq adc;
1298 int sram_size;
1299 int flash_size;
1300 i2c_bus *i2c;
Paul Brook40905a62009-06-03 15:16:49 +01001301 DeviceState *dev;
pbrook9ee6e8b2007-11-11 00:04:49 +00001302 int i;
Paul Brook40905a62009-06-03 15:16:49 +01001303 int j;
pbrook9ee6e8b2007-11-11 00:04:49 +00001304
1305 flash_size = ((board->dc0 & 0xffff) + 1) << 1;
1306 sram_size = (board->dc0 >> 18) + 1;
1307 pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
1308
1309 if (board->dc1 & (1 << 16)) {
Paul Brook40905a62009-06-03 15:16:49 +01001310 dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
1311 pic[14], pic[15], pic[16], pic[17], NULL);
1312 adc = qdev_get_gpio_in(dev, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00001313 } else {
1314 adc = NULL;
1315 }
1316 for (i = 0; i < 4; i++) {
1317 if (board->dc2 & (0x10000 << i)) {
Paul Brook40905a62009-06-03 15:16:49 +01001318 dev = sysbus_create_simple("stellaris-gptm",
1319 0x40030000 + i * 0x1000,
1320 pic[timer_irq[i]]);
1321 /* TODO: This is incorrect, but we get away with it because
1322 the ADC output is only ever pulsed. */
1323 qdev_connect_gpio_out(dev, 0, adc);
pbrook9ee6e8b2007-11-11 00:04:49 +00001324 }
1325 }
1326
pbrookeea589c2007-11-24 03:13:04 +00001327 stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr);
pbrook9ee6e8b2007-11-11 00:04:49 +00001328
1329 for (i = 0; i < 7; i++) {
1330 if (board->dc4 & (1 << i)) {
Paul Brook40905a62009-06-03 15:16:49 +01001331 gpio_dev[i] = sysbus_create_simple("pl061", gpio_addr[i],
1332 pic[gpio_irq[i]]);
1333 for (j = 0; j < 8; j++) {
1334 gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
1335 gpio_out[i][j] = NULL;
1336 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001337 }
1338 }
1339
1340 if (board->dc2 & (1 << 12)) {
Paul Brook1de96102009-05-14 22:35:09 +01001341 dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
Paul Brook02e2da42009-05-23 00:05:19 +01001342 i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
pbrookcf0dbb22007-11-18 14:36:08 +00001343 if (board->peripherals & BP_OLED_I2C) {
Paul Brookd2199002009-05-14 22:35:08 +01001344 i2c_create_slave(i2c, "ssd0303", 0x3d);
pbrook9ee6e8b2007-11-11 00:04:49 +00001345 }
1346 }
1347
1348 for (i = 0; i < 4; i++) {
1349 if (board->dc2 & (1 << i)) {
Paul Brooka7d518a2009-05-14 22:35:07 +01001350 sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
1351 pic[uart_irq[i]]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001352 }
1353 }
1354 if (board->dc2 & (1 << 4)) {
Paul Brook5493e332009-05-14 22:35:09 +01001355 dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
pbrookcf0dbb22007-11-18 14:36:08 +00001356 if (board->peripherals & BP_OLED_SSI) {
Paul Brook5493e332009-05-14 22:35:09 +01001357 DeviceState *mux;
1358 void *bus;
pbrook775616c2007-11-24 23:35:08 +00001359
Paul Brook5493e332009-05-14 22:35:09 +01001360 bus = qdev_get_child_bus(dev, "ssi");
1361 mux = ssi_create_slave(bus, "evb6965-ssi");
1362 gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
pbrook775616c2007-11-24 23:35:08 +00001363
Paul Brook5493e332009-05-14 22:35:09 +01001364 bus = qdev_get_child_bus(mux, "ssi0");
1365 dev = ssi_create_slave(bus, "ssi-sd");
pbrook775616c2007-11-24 23:35:08 +00001366
Paul Brook5493e332009-05-14 22:35:09 +01001367 bus = qdev_get_child_bus(mux, "ssi1");
1368 dev = ssi_create_slave(bus, "ssd0323");
1369 gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
1370
pbrook775616c2007-11-24 23:35:08 +00001371 /* Make sure the select pin is high. */
1372 qemu_irq_raise(gpio_out[GPIO_D][0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001373 }
1374 }
Paul Brooka5580462009-05-14 22:35:07 +01001375 if (board->dc4 & (1 << 28)) {
1376 DeviceState *enet;
1377
1378 qemu_check_nic_model(&nd_table[0], "stellaris");
1379
1380 enet = qdev_create(NULL, "stellaris_enet");
1381 qdev_set_netdev(enet, &nd_table[0]);
1382 qdev_init(enet);
1383 sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000);
1384 sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]);
1385 }
pbrookcf0dbb22007-11-18 14:36:08 +00001386 if (board->peripherals & BP_GAMEPAD) {
1387 qemu_irq gpad_irq[5];
1388 static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
1389
1390 gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
1391 gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
1392 gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
1393 gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
1394 gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
1395
1396 stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
1397 }
Paul Brook40905a62009-06-03 15:16:49 +01001398 for (i = 0; i < 7; i++) {
1399 if (board->dc4 & (1 << i)) {
1400 for (j = 0; j < 8; j++) {
1401 if (gpio_out[i][j]) {
1402 qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
1403 }
1404 }
1405 }
1406 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001407}
1408
1409/* FIXME: Figure out how to generate these from stellaris_boards. */
Paul Brookfbe1b592009-05-13 17:56:25 +01001410static void lm3s811evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001411 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001412 const char *kernel_filename, const char *kernel_cmdline,
1413 const char *initrd_filename, const char *cpu_model)
1414{
aliguori3023f332009-01-16 19:04:14 +00001415 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001416}
1417
Paul Brookfbe1b592009-05-13 17:56:25 +01001418static void lm3s6965evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001419 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001420 const char *kernel_filename, const char *kernel_cmdline,
1421 const char *initrd_filename, const char *cpu_model)
1422{
aliguori3023f332009-01-16 19:04:14 +00001423 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001424}
1425
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001426static QEMUMachine lm3s811evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001427 .name = "lm3s811evb",
1428 .desc = "Stellaris LM3S811EVB",
1429 .init = lm3s811evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001430};
1431
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001432static QEMUMachine lm3s6965evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001433 .name = "lm3s6965evb",
1434 .desc = "Stellaris LM3S6965EVB",
1435 .init = lm3s6965evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001436};
Paul Brook1de96102009-05-14 22:35:09 +01001437
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001438static void stellaris_machine_init(void)
1439{
1440 qemu_register_machine(&lm3s811evb_machine);
1441 qemu_register_machine(&lm3s6965evb_machine);
1442}
1443
1444machine_init(stellaris_machine_init);
1445
Paul Brook5493e332009-05-14 22:35:09 +01001446static SSISlaveInfo stellaris_ssi_bus_info = {
1447 .init = stellaris_ssi_bus_init,
1448 .transfer = stellaris_ssi_bus_transfer
1449};
1450
Paul Brook1de96102009-05-14 22:35:09 +01001451static void stellaris_register_devices(void)
1452{
1453 sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
1454 stellaris_i2c_init);
Paul Brook40905a62009-06-03 15:16:49 +01001455 sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
1456 stellaris_gptm_init);
1457 sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state),
1458 stellaris_adc_init);
Paul Brook5493e332009-05-14 22:35:09 +01001459 ssi_register_slave("evb6965-ssi", sizeof(stellaris_ssi_bus_state),
1460 &stellaris_ssi_bus_info);
Paul Brook1de96102009-05-14 22:35:09 +01001461}
1462
1463device_init(stellaris_register_devices)