blob: 11d618d87a803a01c8b8ed22b8a9173af30e0a74 [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 "boards.h"
pbrook9ee6e8b2007-11-11 00:04:49 +000018
pbrookcf0dbb22007-11-18 14:36:08 +000019#define GPIO_A 0
20#define GPIO_B 1
21#define GPIO_C 2
22#define GPIO_D 3
23#define GPIO_E 4
24#define GPIO_F 5
25#define GPIO_G 6
26
27#define BP_OLED_I2C 0x01
28#define BP_OLED_SSI 0x02
29#define BP_GAMEPAD 0x04
30
pbrook9ee6e8b2007-11-11 00:04:49 +000031typedef const struct {
32 const char *name;
33 uint32_t did0;
34 uint32_t did1;
35 uint32_t dc0;
36 uint32_t dc1;
37 uint32_t dc2;
38 uint32_t dc3;
39 uint32_t dc4;
pbrookcf0dbb22007-11-18 14:36:08 +000040 uint32_t peripherals;
pbrook9ee6e8b2007-11-11 00:04:49 +000041} stellaris_board_info;
42
43/* General purpose timer module. */
44
pbrook9ee6e8b2007-11-11 00:04:49 +000045typedef struct gptm_state {
Paul Brook40905a62009-06-03 15:16:49 +010046 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +000047 uint32_t config;
48 uint32_t mode[2];
49 uint32_t control;
50 uint32_t state;
51 uint32_t mask;
52 uint32_t load[2];
53 uint32_t match[2];
54 uint32_t prescale[2];
55 uint32_t match_prescale[2];
56 uint32_t rtc;
57 int64_t tick[2];
58 struct gptm_state *opaque[2];
pbrook9ee6e8b2007-11-11 00:04:49 +000059 QEMUTimer *timer[2];
60 /* The timers have an alternate output used to trigger the ADC. */
61 qemu_irq trigger;
62 qemu_irq irq;
63} gptm_state;
64
65static void gptm_update_irq(gptm_state *s)
66{
67 int level;
68 level = (s->state & s->mask) != 0;
69 qemu_set_irq(s->irq, level);
70}
71
72static void gptm_stop(gptm_state *s, int n)
73{
74 qemu_del_timer(s->timer[n]);
75}
76
77static void gptm_reload(gptm_state *s, int n, int reset)
78{
79 int64_t tick;
80 if (reset)
Paolo Bonzini74475452011-03-11 16:47:48 +010081 tick = qemu_get_clock_ns(vm_clock);
pbrook9ee6e8b2007-11-11 00:04:49 +000082 else
83 tick = s->tick[n];
84
85 if (s->config == 0) {
86 /* 32-bit CountDown. */
87 uint32_t count;
88 count = s->load[0] | (s->load[1] << 16);
pbrooke57ec012007-11-24 03:09:07 +000089 tick += (int64_t)count * system_clock_scale;
pbrook9ee6e8b2007-11-11 00:04:49 +000090 } else if (s->config == 1) {
91 /* 32-bit RTC. 1Hz tick. */
Juan Quintela6ee093c2009-09-10 03:04:26 +020092 tick += get_ticks_per_sec();
pbrook9ee6e8b2007-11-11 00:04:49 +000093 } else if (s->mode[n] == 0xa) {
94 /* PWM mode. Not implemented. */
95 } else {
Paul Brook2ac71172009-05-08 02:35:15 +010096 hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
pbrook9ee6e8b2007-11-11 00:04:49 +000097 }
98 s->tick[n] = tick;
99 qemu_mod_timer(s->timer[n], tick);
100}
101
102static void gptm_tick(void *opaque)
103{
104 gptm_state **p = (gptm_state **)opaque;
105 gptm_state *s;
106 int n;
107
108 s = *p;
109 n = p - s->opaque;
110 if (s->config == 0) {
111 s->state |= 1;
112 if ((s->control & 0x20)) {
113 /* Output trigger. */
Paul Brook40905a62009-06-03 15:16:49 +0100114 qemu_irq_pulse(s->trigger);
pbrook9ee6e8b2007-11-11 00:04:49 +0000115 }
116 if (s->mode[0] & 1) {
117 /* One-shot. */
118 s->control &= ~1;
119 } else {
120 /* Periodic. */
121 gptm_reload(s, 0, 0);
122 }
123 } else if (s->config == 1) {
124 /* RTC. */
125 uint32_t match;
126 s->rtc++;
127 match = s->match[0] | (s->match[1] << 16);
128 if (s->rtc > match)
129 s->rtc = 0;
130 if (s->rtc == 0) {
131 s->state |= 8;
132 }
133 gptm_reload(s, 0, 0);
134 } else if (s->mode[n] == 0xa) {
135 /* PWM mode. Not implemented. */
136 } else {
Paul Brook2ac71172009-05-08 02:35:15 +0100137 hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
pbrook9ee6e8b2007-11-11 00:04:49 +0000138 }
139 gptm_update_irq(s);
140}
141
Anthony Liguoric227f092009-10-01 16:12:16 -0500142static uint32_t gptm_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000143{
144 gptm_state *s = (gptm_state *)opaque;
145
pbrook9ee6e8b2007-11-11 00:04:49 +0000146 switch (offset) {
147 case 0x00: /* CFG */
148 return s->config;
149 case 0x04: /* TAMR */
150 return s->mode[0];
151 case 0x08: /* TBMR */
152 return s->mode[1];
153 case 0x0c: /* CTL */
154 return s->control;
155 case 0x18: /* IMR */
156 return s->mask;
157 case 0x1c: /* RIS */
158 return s->state;
159 case 0x20: /* MIS */
160 return s->state & s->mask;
161 case 0x24: /* CR */
162 return 0;
163 case 0x28: /* TAILR */
164 return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0);
165 case 0x2c: /* TBILR */
166 return s->load[1];
167 case 0x30: /* TAMARCHR */
168 return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0);
169 case 0x34: /* TBMATCHR */
170 return s->match[1];
171 case 0x38: /* TAPR */
172 return s->prescale[0];
173 case 0x3c: /* TBPR */
174 return s->prescale[1];
175 case 0x40: /* TAPMR */
176 return s->match_prescale[0];
177 case 0x44: /* TBPMR */
178 return s->match_prescale[1];
179 case 0x48: /* TAR */
180 if (s->control == 1)
181 return s->rtc;
182 case 0x4c: /* TBR */
Paul Brook2ac71172009-05-08 02:35:15 +0100183 hw_error("TODO: Timer value read\n");
pbrook9ee6e8b2007-11-11 00:04:49 +0000184 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100185 hw_error("gptm_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000186 return 0;
187 }
188}
189
Anthony Liguoric227f092009-10-01 16:12:16 -0500190static void gptm_write(void *opaque, target_phys_addr_t offset, uint32_t value)
pbrook9ee6e8b2007-11-11 00:04:49 +0000191{
192 gptm_state *s = (gptm_state *)opaque;
193 uint32_t oldval;
194
pbrook9ee6e8b2007-11-11 00:04:49 +0000195 /* The timers should be disabled before changing the configuration.
196 We take advantage of this and defer everything until the timer
197 is enabled. */
198 switch (offset) {
199 case 0x00: /* CFG */
200 s->config = value;
201 break;
202 case 0x04: /* TAMR */
203 s->mode[0] = value;
204 break;
205 case 0x08: /* TBMR */
206 s->mode[1] = value;
207 break;
208 case 0x0c: /* CTL */
209 oldval = s->control;
210 s->control = value;
211 /* TODO: Implement pause. */
212 if ((oldval ^ value) & 1) {
213 if (value & 1) {
214 gptm_reload(s, 0, 1);
215 } else {
216 gptm_stop(s, 0);
217 }
218 }
219 if (((oldval ^ value) & 0x100) && s->config >= 4) {
220 if (value & 0x100) {
221 gptm_reload(s, 1, 1);
222 } else {
223 gptm_stop(s, 1);
224 }
225 }
226 break;
227 case 0x18: /* IMR */
228 s->mask = value & 0x77;
229 gptm_update_irq(s);
230 break;
231 case 0x24: /* CR */
232 s->state &= ~value;
233 break;
234 case 0x28: /* TAILR */
235 s->load[0] = value & 0xffff;
236 if (s->config < 4) {
237 s->load[1] = value >> 16;
238 }
239 break;
240 case 0x2c: /* TBILR */
241 s->load[1] = value & 0xffff;
242 break;
243 case 0x30: /* TAMARCHR */
244 s->match[0] = value & 0xffff;
245 if (s->config < 4) {
246 s->match[1] = value >> 16;
247 }
248 break;
249 case 0x34: /* TBMATCHR */
250 s->match[1] = value >> 16;
251 break;
252 case 0x38: /* TAPR */
253 s->prescale[0] = value;
254 break;
255 case 0x3c: /* TBPR */
256 s->prescale[1] = value;
257 break;
258 case 0x40: /* TAPMR */
259 s->match_prescale[0] = value;
260 break;
261 case 0x44: /* TBPMR */
262 s->match_prescale[0] = value;
263 break;
264 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100265 hw_error("gptm_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000266 }
267 gptm_update_irq(s);
268}
269
Blue Swirld60efc62009-08-25 18:29:31 +0000270static CPUReadMemoryFunc * const gptm_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000271 gptm_read,
272 gptm_read,
273 gptm_read
274};
275
Blue Swirld60efc62009-08-25 18:29:31 +0000276static CPUWriteMemoryFunc * const gptm_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000277 gptm_write,
278 gptm_write,
279 gptm_write
280};
281
pbrook23e39292008-07-02 16:48:32 +0000282static void gptm_save(QEMUFile *f, void *opaque)
283{
284 gptm_state *s = (gptm_state *)opaque;
285
286 qemu_put_be32(f, s->config);
287 qemu_put_be32(f, s->mode[0]);
288 qemu_put_be32(f, s->mode[1]);
289 qemu_put_be32(f, s->control);
290 qemu_put_be32(f, s->state);
291 qemu_put_be32(f, s->mask);
292 qemu_put_be32(f, s->mode[0]);
293 qemu_put_be32(f, s->mode[0]);
294 qemu_put_be32(f, s->load[0]);
295 qemu_put_be32(f, s->load[1]);
296 qemu_put_be32(f, s->match[0]);
297 qemu_put_be32(f, s->match[1]);
298 qemu_put_be32(f, s->prescale[0]);
299 qemu_put_be32(f, s->prescale[1]);
300 qemu_put_be32(f, s->match_prescale[0]);
301 qemu_put_be32(f, s->match_prescale[1]);
302 qemu_put_be32(f, s->rtc);
303 qemu_put_be64(f, s->tick[0]);
304 qemu_put_be64(f, s->tick[1]);
305 qemu_put_timer(f, s->timer[0]);
306 qemu_put_timer(f, s->timer[1]);
307}
308
309static int gptm_load(QEMUFile *f, void *opaque, int version_id)
310{
311 gptm_state *s = (gptm_state *)opaque;
312
313 if (version_id != 1)
314 return -EINVAL;
315
316 s->config = qemu_get_be32(f);
317 s->mode[0] = qemu_get_be32(f);
318 s->mode[1] = qemu_get_be32(f);
319 s->control = qemu_get_be32(f);
320 s->state = qemu_get_be32(f);
321 s->mask = qemu_get_be32(f);
322 s->mode[0] = qemu_get_be32(f);
323 s->mode[0] = qemu_get_be32(f);
324 s->load[0] = qemu_get_be32(f);
325 s->load[1] = qemu_get_be32(f);
326 s->match[0] = qemu_get_be32(f);
327 s->match[1] = qemu_get_be32(f);
328 s->prescale[0] = qemu_get_be32(f);
329 s->prescale[1] = qemu_get_be32(f);
330 s->match_prescale[0] = qemu_get_be32(f);
331 s->match_prescale[1] = qemu_get_be32(f);
332 s->rtc = qemu_get_be32(f);
333 s->tick[0] = qemu_get_be64(f);
334 s->tick[1] = qemu_get_be64(f);
335 qemu_get_timer(f, s->timer[0]);
336 qemu_get_timer(f, s->timer[1]);
337
338 return 0;
339}
340
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200341static int stellaris_gptm_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000342{
343 int iomemtype;
Paul Brook40905a62009-06-03 15:16:49 +0100344 gptm_state *s = FROM_SYSBUS(gptm_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +0000345
Paul Brook40905a62009-06-03 15:16:49 +0100346 sysbus_init_irq(dev, &s->irq);
347 qdev_init_gpio_out(&dev->qdev, &s->trigger, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +0000348
Avi Kivity1eed09c2009-06-14 11:38:51 +0300349 iomemtype = cpu_register_io_memory(gptm_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +0100350 gptm_writefn, s,
351 DEVICE_NATIVE_ENDIAN);
Paul Brook40905a62009-06-03 15:16:49 +0100352 sysbus_init_mmio(dev, 0x1000, iomemtype);
353
354 s->opaque[0] = s->opaque[1] = s;
Paolo Bonzini74475452011-03-11 16:47:48 +0100355 s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]);
356 s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]);
Alex Williamson0be71e32010-06-25 11:09:07 -0600357 register_savevm(&dev->qdev, "stellaris_gptm", -1, 1,
358 gptm_save, gptm_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200359 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000360}
361
362
363/* System controller. */
364
365typedef struct {
pbrook9ee6e8b2007-11-11 00:04:49 +0000366 uint32_t pborctl;
367 uint32_t ldopctl;
368 uint32_t int_status;
369 uint32_t int_mask;
370 uint32_t resc;
371 uint32_t rcc;
372 uint32_t rcgc[3];
373 uint32_t scgc[3];
374 uint32_t dcgc[3];
375 uint32_t clkvclr;
376 uint32_t ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000377 uint32_t user0;
378 uint32_t user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000379 qemu_irq irq;
380 stellaris_board_info *board;
381} ssys_state;
382
383static void ssys_update(ssys_state *s)
384{
385 qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
386}
387
388static uint32_t pllcfg_sandstorm[16] = {
389 0x31c0, /* 1 Mhz */
390 0x1ae0, /* 1.8432 Mhz */
391 0x18c0, /* 2 Mhz */
392 0xd573, /* 2.4576 Mhz */
393 0x37a6, /* 3.57954 Mhz */
394 0x1ae2, /* 3.6864 Mhz */
395 0x0c40, /* 4 Mhz */
396 0x98bc, /* 4.906 Mhz */
397 0x935b, /* 4.9152 Mhz */
398 0x09c0, /* 5 Mhz */
399 0x4dee, /* 5.12 Mhz */
400 0x0c41, /* 6 Mhz */
401 0x75db, /* 6.144 Mhz */
402 0x1ae6, /* 7.3728 Mhz */
403 0x0600, /* 8 Mhz */
404 0x585b /* 8.192 Mhz */
405};
406
407static uint32_t pllcfg_fury[16] = {
408 0x3200, /* 1 Mhz */
409 0x1b20, /* 1.8432 Mhz */
410 0x1900, /* 2 Mhz */
411 0xf42b, /* 2.4576 Mhz */
412 0x37e3, /* 3.57954 Mhz */
413 0x1b21, /* 3.6864 Mhz */
414 0x0c80, /* 4 Mhz */
415 0x98ee, /* 4.906 Mhz */
416 0xd5b4, /* 4.9152 Mhz */
417 0x0a00, /* 5 Mhz */
418 0x4e27, /* 5.12 Mhz */
419 0x1902, /* 6 Mhz */
420 0xec1c, /* 6.144 Mhz */
421 0x1b23, /* 7.3728 Mhz */
422 0x0640, /* 8 Mhz */
423 0xb11c /* 8.192 Mhz */
424};
425
Anthony Liguoric227f092009-10-01 16:12:16 -0500426static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000427{
428 ssys_state *s = (ssys_state *)opaque;
429
pbrook9ee6e8b2007-11-11 00:04:49 +0000430 switch (offset) {
431 case 0x000: /* DID0 */
432 return s->board->did0;
433 case 0x004: /* DID1 */
434 return s->board->did1;
435 case 0x008: /* DC0 */
436 return s->board->dc0;
437 case 0x010: /* DC1 */
438 return s->board->dc1;
439 case 0x014: /* DC2 */
440 return s->board->dc2;
441 case 0x018: /* DC3 */
442 return s->board->dc3;
443 case 0x01c: /* DC4 */
444 return s->board->dc4;
445 case 0x030: /* PBORCTL */
446 return s->pborctl;
447 case 0x034: /* LDOPCTL */
448 return s->ldopctl;
449 case 0x040: /* SRCR0 */
450 return 0;
451 case 0x044: /* SRCR1 */
452 return 0;
453 case 0x048: /* SRCR2 */
454 return 0;
455 case 0x050: /* RIS */
456 return s->int_status;
457 case 0x054: /* IMC */
458 return s->int_mask;
459 case 0x058: /* MISC */
460 return s->int_status & s->int_mask;
461 case 0x05c: /* RESC */
462 return s->resc;
463 case 0x060: /* RCC */
464 return s->rcc;
465 case 0x064: /* PLLCFG */
466 {
467 int xtal;
468 xtal = (s->rcc >> 6) & 0xf;
469 if (s->board->did0 & (1 << 16)) {
470 return pllcfg_fury[xtal];
471 } else {
472 return pllcfg_sandstorm[xtal];
473 }
474 }
475 case 0x100: /* RCGC0 */
476 return s->rcgc[0];
477 case 0x104: /* RCGC1 */
478 return s->rcgc[1];
479 case 0x108: /* RCGC2 */
480 return s->rcgc[2];
481 case 0x110: /* SCGC0 */
482 return s->scgc[0];
483 case 0x114: /* SCGC1 */
484 return s->scgc[1];
485 case 0x118: /* SCGC2 */
486 return s->scgc[2];
487 case 0x120: /* DCGC0 */
488 return s->dcgc[0];
489 case 0x124: /* DCGC1 */
490 return s->dcgc[1];
491 case 0x128: /* DCGC2 */
492 return s->dcgc[2];
493 case 0x150: /* CLKVCLR */
494 return s->clkvclr;
495 case 0x160: /* LDOARST */
496 return s->ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000497 case 0x1e0: /* USER0 */
498 return s->user0;
499 case 0x1e4: /* USER1 */
500 return s->user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000501 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100502 hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000503 return 0;
504 }
505}
506
pbrook23e39292008-07-02 16:48:32 +0000507static void ssys_calculate_system_clock(ssys_state *s)
508{
509 system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
510}
511
Anthony Liguoric227f092009-10-01 16:12:16 -0500512static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
pbrook9ee6e8b2007-11-11 00:04:49 +0000513{
514 ssys_state *s = (ssys_state *)opaque;
515
pbrook9ee6e8b2007-11-11 00:04:49 +0000516 switch (offset) {
517 case 0x030: /* PBORCTL */
518 s->pborctl = value & 0xffff;
519 break;
520 case 0x034: /* LDOPCTL */
521 s->ldopctl = value & 0x1f;
522 break;
523 case 0x040: /* SRCR0 */
524 case 0x044: /* SRCR1 */
525 case 0x048: /* SRCR2 */
526 fprintf(stderr, "Peripheral reset not implemented\n");
527 break;
528 case 0x054: /* IMC */
529 s->int_mask = value & 0x7f;
530 break;
531 case 0x058: /* MISC */
532 s->int_status &= ~value;
533 break;
534 case 0x05c: /* RESC */
535 s->resc = value & 0x3f;
536 break;
537 case 0x060: /* RCC */
538 if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
539 /* PLL enable. */
540 s->int_status |= (1 << 6);
541 }
542 s->rcc = value;
pbrook23e39292008-07-02 16:48:32 +0000543 ssys_calculate_system_clock(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000544 break;
545 case 0x100: /* RCGC0 */
546 s->rcgc[0] = value;
547 break;
548 case 0x104: /* RCGC1 */
549 s->rcgc[1] = value;
550 break;
551 case 0x108: /* RCGC2 */
552 s->rcgc[2] = value;
553 break;
554 case 0x110: /* SCGC0 */
555 s->scgc[0] = value;
556 break;
557 case 0x114: /* SCGC1 */
558 s->scgc[1] = value;
559 break;
560 case 0x118: /* SCGC2 */
561 s->scgc[2] = value;
562 break;
563 case 0x120: /* DCGC0 */
564 s->dcgc[0] = value;
565 break;
566 case 0x124: /* DCGC1 */
567 s->dcgc[1] = value;
568 break;
569 case 0x128: /* DCGC2 */
570 s->dcgc[2] = value;
571 break;
572 case 0x150: /* CLKVCLR */
573 s->clkvclr = value;
574 break;
575 case 0x160: /* LDOARST */
576 s->ldoarst = value;
577 break;
578 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100579 hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000580 }
581 ssys_update(s);
582}
583
Blue Swirld60efc62009-08-25 18:29:31 +0000584static CPUReadMemoryFunc * const ssys_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000585 ssys_read,
586 ssys_read,
587 ssys_read
588};
589
Blue Swirld60efc62009-08-25 18:29:31 +0000590static CPUWriteMemoryFunc * const ssys_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000591 ssys_write,
592 ssys_write,
593 ssys_write
594};
595
pbrook9596ebb2007-11-18 01:44:38 +0000596static void ssys_reset(void *opaque)
pbrook9ee6e8b2007-11-11 00:04:49 +0000597{
598 ssys_state *s = (ssys_state *)opaque;
599
600 s->pborctl = 0x7ffd;
601 s->rcc = 0x078e3ac0;
602 s->rcgc[0] = 1;
603 s->scgc[0] = 1;
604 s->dcgc[0] = 1;
605}
606
Juan Quintela293c16a2010-12-02 03:03:11 +0100607static int stellaris_sys_post_load(void *opaque, int version_id)
pbrook23e39292008-07-02 16:48:32 +0000608{
Juan Quintela293c16a2010-12-02 03:03:11 +0100609 ssys_state *s = opaque;
pbrook23e39292008-07-02 16:48:32 +0000610
pbrook23e39292008-07-02 16:48:32 +0000611 ssys_calculate_system_clock(s);
612
613 return 0;
614}
615
Juan Quintela293c16a2010-12-02 03:03:11 +0100616static const VMStateDescription vmstate_stellaris_sys = {
617 .name = "stellaris_sys",
618 .version_id = 1,
619 .minimum_version_id = 1,
620 .minimum_version_id_old = 1,
621 .post_load = stellaris_sys_post_load,
622 .fields = (VMStateField[]) {
623 VMSTATE_UINT32(pborctl, ssys_state),
624 VMSTATE_UINT32(ldopctl, ssys_state),
625 VMSTATE_UINT32(int_mask, ssys_state),
626 VMSTATE_UINT32(int_status, ssys_state),
627 VMSTATE_UINT32(resc, ssys_state),
628 VMSTATE_UINT32(rcc, ssys_state),
629 VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
630 VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
631 VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
632 VMSTATE_UINT32(clkvclr, ssys_state),
633 VMSTATE_UINT32(ldoarst, ssys_state),
634 VMSTATE_END_OF_LIST()
635 }
636};
637
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200638static int stellaris_sys_init(uint32_t base, qemu_irq irq,
639 stellaris_board_info * board,
640 uint8_t *macaddr)
pbrook9ee6e8b2007-11-11 00:04:49 +0000641{
642 int iomemtype;
643 ssys_state *s;
644
645 s = (ssys_state *)qemu_mallocz(sizeof(ssys_state));
pbrook9ee6e8b2007-11-11 00:04:49 +0000646 s->irq = irq;
647 s->board = board;
pbrookeea589c2007-11-24 03:13:04 +0000648 /* Most devices come preprogrammed with a MAC address in the user data. */
649 s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
650 s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +0000651
Avi Kivity1eed09c2009-06-14 11:38:51 +0300652 iomemtype = cpu_register_io_memory(ssys_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +0100653 ssys_writefn, s,
654 DEVICE_NATIVE_ENDIAN);
pbrook9ee6e8b2007-11-11 00:04:49 +0000655 cpu_register_physical_memory(base, 0x00001000, iomemtype);
656 ssys_reset(s);
Juan Quintela293c16a2010-12-02 03:03:11 +0100657 vmstate_register(NULL, -1, &vmstate_stellaris_sys, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200658 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000659}
660
661
662/* I2C controller. */
663
664typedef struct {
Paul Brook1de96102009-05-14 22:35:09 +0100665 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000666 i2c_bus *bus;
667 qemu_irq irq;
pbrook9ee6e8b2007-11-11 00:04:49 +0000668 uint32_t msa;
669 uint32_t mcs;
670 uint32_t mdr;
671 uint32_t mtpr;
672 uint32_t mimr;
673 uint32_t mris;
674 uint32_t mcr;
675} stellaris_i2c_state;
676
677#define STELLARIS_I2C_MCS_BUSY 0x01
678#define STELLARIS_I2C_MCS_ERROR 0x02
679#define STELLARIS_I2C_MCS_ADRACK 0x04
680#define STELLARIS_I2C_MCS_DATACK 0x08
681#define STELLARIS_I2C_MCS_ARBLST 0x10
682#define STELLARIS_I2C_MCS_IDLE 0x20
683#define STELLARIS_I2C_MCS_BUSBSY 0x40
684
Anthony Liguoric227f092009-10-01 16:12:16 -0500685static uint32_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000686{
687 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
688
pbrook9ee6e8b2007-11-11 00:04:49 +0000689 switch (offset) {
690 case 0x00: /* MSA */
691 return s->msa;
692 case 0x04: /* MCS */
693 /* We don't emulate timing, so the controller is never busy. */
694 return s->mcs | STELLARIS_I2C_MCS_IDLE;
695 case 0x08: /* MDR */
696 return s->mdr;
697 case 0x0c: /* MTPR */
698 return s->mtpr;
699 case 0x10: /* MIMR */
700 return s->mimr;
701 case 0x14: /* MRIS */
702 return s->mris;
703 case 0x18: /* MMIS */
704 return s->mris & s->mimr;
705 case 0x20: /* MCR */
706 return s->mcr;
707 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100708 hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000709 return 0;
710 }
711}
712
713static void stellaris_i2c_update(stellaris_i2c_state *s)
714{
715 int level;
716
717 level = (s->mris & s->mimr) != 0;
718 qemu_set_irq(s->irq, level);
719}
720
Anthony Liguoric227f092009-10-01 16:12:16 -0500721static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset,
pbrook9ee6e8b2007-11-11 00:04:49 +0000722 uint32_t value)
723{
724 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
725
pbrook9ee6e8b2007-11-11 00:04:49 +0000726 switch (offset) {
727 case 0x00: /* MSA */
728 s->msa = value & 0xff;
729 break;
730 case 0x04: /* MCS */
731 if ((s->mcr & 0x10) == 0) {
732 /* Disabled. Do nothing. */
733 break;
734 }
735 /* Grab the bus if this is starting a transfer. */
736 if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
737 if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
738 s->mcs |= STELLARIS_I2C_MCS_ARBLST;
739 } else {
740 s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
741 s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
742 }
743 }
744 /* If we don't have the bus then indicate an error. */
745 if (!i2c_bus_busy(s->bus)
746 || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
747 s->mcs |= STELLARIS_I2C_MCS_ERROR;
748 break;
749 }
750 s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
751 if (value & 1) {
752 /* Transfer a byte. */
753 /* TODO: Handle errors. */
754 if (s->msa & 1) {
755 /* Recv */
756 s->mdr = i2c_recv(s->bus) & 0xff;
757 } else {
758 /* Send */
759 i2c_send(s->bus, s->mdr);
760 }
761 /* Raise an interrupt. */
762 s->mris |= 1;
763 }
764 if (value & 4) {
765 /* Finish transfer. */
766 i2c_end_transfer(s->bus);
767 s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
768 }
769 break;
770 case 0x08: /* MDR */
771 s->mdr = value & 0xff;
772 break;
773 case 0x0c: /* MTPR */
774 s->mtpr = value & 0xff;
775 break;
776 case 0x10: /* MIMR */
777 s->mimr = 1;
778 break;
779 case 0x1c: /* MICR */
780 s->mris &= ~value;
781 break;
782 case 0x20: /* MCR */
783 if (value & 1)
Paul Brook2ac71172009-05-08 02:35:15 +0100784 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000785 "stellaris_i2c_write: Loopback not implemented\n");
786 if (value & 0x20)
Paul Brook2ac71172009-05-08 02:35:15 +0100787 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000788 "stellaris_i2c_write: Slave mode not implemented\n");
789 s->mcr = value & 0x31;
790 break;
791 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100792 hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +0000793 (int)offset);
794 }
795 stellaris_i2c_update(s);
796}
797
798static void stellaris_i2c_reset(stellaris_i2c_state *s)
799{
800 if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
801 i2c_end_transfer(s->bus);
802
803 s->msa = 0;
804 s->mcs = 0;
805 s->mdr = 0;
806 s->mtpr = 1;
807 s->mimr = 0;
808 s->mris = 0;
809 s->mcr = 0;
810 stellaris_i2c_update(s);
811}
812
Blue Swirld60efc62009-08-25 18:29:31 +0000813static CPUReadMemoryFunc * const stellaris_i2c_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000814 stellaris_i2c_read,
815 stellaris_i2c_read,
816 stellaris_i2c_read
817};
818
Blue Swirld60efc62009-08-25 18:29:31 +0000819static CPUWriteMemoryFunc * const stellaris_i2c_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000820 stellaris_i2c_write,
821 stellaris_i2c_write,
822 stellaris_i2c_write
823};
824
Juan Quintelaff269cd2010-12-02 02:48:43 +0100825static const VMStateDescription vmstate_stellaris_i2c = {
826 .name = "stellaris_i2c",
827 .version_id = 1,
828 .minimum_version_id = 1,
829 .minimum_version_id_old = 1,
830 .fields = (VMStateField[]) {
831 VMSTATE_UINT32(msa, stellaris_i2c_state),
832 VMSTATE_UINT32(mcs, stellaris_i2c_state),
833 VMSTATE_UINT32(mdr, stellaris_i2c_state),
834 VMSTATE_UINT32(mtpr, stellaris_i2c_state),
835 VMSTATE_UINT32(mimr, stellaris_i2c_state),
836 VMSTATE_UINT32(mris, stellaris_i2c_state),
837 VMSTATE_UINT32(mcr, stellaris_i2c_state),
838 VMSTATE_END_OF_LIST()
839 }
840};
pbrook23e39292008-07-02 16:48:32 +0000841
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200842static int stellaris_i2c_init(SysBusDevice * dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000843{
Paul Brook1de96102009-05-14 22:35:09 +0100844 stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100845 i2c_bus *bus;
pbrook9ee6e8b2007-11-11 00:04:49 +0000846 int iomemtype;
847
Paul Brook1de96102009-05-14 22:35:09 +0100848 sysbus_init_irq(dev, &s->irq);
Paul Brook02e2da42009-05-23 00:05:19 +0100849 bus = i2c_init_bus(&dev->qdev, "i2c");
pbrook9ee6e8b2007-11-11 00:04:49 +0000850 s->bus = bus;
851
Avi Kivity1eed09c2009-06-14 11:38:51 +0300852 iomemtype = cpu_register_io_memory(stellaris_i2c_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +0100853 stellaris_i2c_writefn, s,
854 DEVICE_NATIVE_ENDIAN);
Paul Brook1de96102009-05-14 22:35:09 +0100855 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +0000856 /* ??? For now we only implement the master interface. */
857 stellaris_i2c_reset(s);
Juan Quintelaff269cd2010-12-02 02:48:43 +0100858 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200859 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000860}
861
862/* Analogue to Digital Converter. This is only partially implemented,
863 enough for applications that use a combined ADC and timer tick. */
864
865#define STELLARIS_ADC_EM_CONTROLLER 0
866#define STELLARIS_ADC_EM_COMP 1
867#define STELLARIS_ADC_EM_EXTERNAL 4
868#define STELLARIS_ADC_EM_TIMER 5
869#define STELLARIS_ADC_EM_PWM0 6
870#define STELLARIS_ADC_EM_PWM1 7
871#define STELLARIS_ADC_EM_PWM2 8
872
873#define STELLARIS_ADC_FIFO_EMPTY 0x0100
874#define STELLARIS_ADC_FIFO_FULL 0x1000
875
876typedef struct
877{
Paul Brook40905a62009-06-03 15:16:49 +0100878 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000879 uint32_t actss;
880 uint32_t ris;
881 uint32_t im;
882 uint32_t emux;
883 uint32_t ostat;
884 uint32_t ustat;
885 uint32_t sspri;
886 uint32_t sac;
887 struct {
888 uint32_t state;
889 uint32_t data[16];
890 } fifo[4];
891 uint32_t ssmux[4];
892 uint32_t ssctl[4];
pbrook23e39292008-07-02 16:48:32 +0000893 uint32_t noise;
Paul Brook2c6554b2009-06-02 15:30:27 +0100894 qemu_irq irq[4];
pbrook9ee6e8b2007-11-11 00:04:49 +0000895} stellaris_adc_state;
896
897static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
898{
899 int tail;
900
901 tail = s->fifo[n].state & 0xf;
902 if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
903 s->ustat |= 1 << n;
904 } else {
905 s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
906 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
907 if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
908 s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
909 }
910 return s->fifo[n].data[tail];
911}
912
913static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
914 uint32_t value)
915{
916 int head;
917
Paul Brook2c6554b2009-06-02 15:30:27 +0100918 /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry
919 FIFO fir each sequencer. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000920 head = (s->fifo[n].state >> 4) & 0xf;
921 if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
922 s->ostat |= 1 << n;
923 return;
924 }
925 s->fifo[n].data[head] = value;
926 head = (head + 1) & 0xf;
927 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
928 s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
929 if ((s->fifo[n].state & 0xf) == head)
930 s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
931}
932
933static void stellaris_adc_update(stellaris_adc_state *s)
934{
935 int level;
Paul Brook2c6554b2009-06-02 15:30:27 +0100936 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000937
Paul Brook2c6554b2009-06-02 15:30:27 +0100938 for (n = 0; n < 4; n++) {
939 level = (s->ris & s->im & (1 << n)) != 0;
940 qemu_set_irq(s->irq[n], level);
941 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000942}
943
944static void stellaris_adc_trigger(void *opaque, int irq, int level)
945{
946 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
Paul Brook2c6554b2009-06-02 15:30:27 +0100947 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000948
Paul Brook2c6554b2009-06-02 15:30:27 +0100949 for (n = 0; n < 4; n++) {
950 if ((s->actss & (1 << n)) == 0) {
951 continue;
952 }
953
954 if (((s->emux >> (n * 4)) & 0xff) != 5) {
955 continue;
956 }
957
958 /* Some applications use the ADC as a random number source, so introduce
959 some variation into the signal. */
960 s->noise = s->noise * 314159 + 1;
961 /* ??? actual inputs not implemented. Return an arbitrary value. */
962 stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
963 s->ris |= (1 << n);
964 stellaris_adc_update(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000965 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000966}
967
968static void stellaris_adc_reset(stellaris_adc_state *s)
969{
970 int n;
971
972 for (n = 0; n < 4; n++) {
973 s->ssmux[n] = 0;
974 s->ssctl[n] = 0;
975 s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
976 }
977}
978
Anthony Liguoric227f092009-10-01 16:12:16 -0500979static uint32_t stellaris_adc_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000980{
981 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
982
983 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000984 if (offset >= 0x40 && offset < 0xc0) {
985 int n;
986 n = (offset - 0x40) >> 5;
987 switch (offset & 0x1f) {
988 case 0x00: /* SSMUX */
989 return s->ssmux[n];
990 case 0x04: /* SSCTL */
991 return s->ssctl[n];
992 case 0x08: /* SSFIFO */
993 return stellaris_adc_fifo_read(s, n);
994 case 0x0c: /* SSFSTAT */
995 return s->fifo[n].state;
996 default:
997 break;
998 }
999 }
1000 switch (offset) {
1001 case 0x00: /* ACTSS */
1002 return s->actss;
1003 case 0x04: /* RIS */
1004 return s->ris;
1005 case 0x08: /* IM */
1006 return s->im;
1007 case 0x0c: /* ISC */
1008 return s->ris & s->im;
1009 case 0x10: /* OSTAT */
1010 return s->ostat;
1011 case 0x14: /* EMUX */
1012 return s->emux;
1013 case 0x18: /* USTAT */
1014 return s->ustat;
1015 case 0x20: /* SSPRI */
1016 return s->sspri;
1017 case 0x30: /* SAC */
1018 return s->sac;
1019 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001020 hw_error("strllaris_adc_read: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001021 (int)offset);
1022 return 0;
1023 }
1024}
1025
Anthony Liguoric227f092009-10-01 16:12:16 -05001026static void stellaris_adc_write(void *opaque, target_phys_addr_t offset,
pbrook9ee6e8b2007-11-11 00:04:49 +00001027 uint32_t value)
1028{
1029 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1030
1031 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001032 if (offset >= 0x40 && offset < 0xc0) {
1033 int n;
1034 n = (offset - 0x40) >> 5;
1035 switch (offset & 0x1f) {
1036 case 0x00: /* SSMUX */
1037 s->ssmux[n] = value & 0x33333333;
1038 return;
1039 case 0x04: /* SSCTL */
1040 if (value != 6) {
Paul Brook2ac71172009-05-08 02:35:15 +01001041 hw_error("ADC: Unimplemented sequence %x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001042 value);
1043 }
1044 s->ssctl[n] = value;
1045 return;
1046 default:
1047 break;
1048 }
1049 }
1050 switch (offset) {
1051 case 0x00: /* ACTSS */
1052 s->actss = value & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00001053 break;
1054 case 0x08: /* IM */
1055 s->im = value;
1056 break;
1057 case 0x0c: /* ISC */
1058 s->ris &= ~value;
1059 break;
1060 case 0x10: /* OSTAT */
1061 s->ostat &= ~value;
1062 break;
1063 case 0x14: /* EMUX */
1064 s->emux = value;
1065 break;
1066 case 0x18: /* USTAT */
1067 s->ustat &= ~value;
1068 break;
1069 case 0x20: /* SSPRI */
1070 s->sspri = value;
1071 break;
1072 case 0x28: /* PSSI */
Paul Brook2ac71172009-05-08 02:35:15 +01001073 hw_error("Not implemented: ADC sample initiate\n");
pbrook9ee6e8b2007-11-11 00:04:49 +00001074 break;
1075 case 0x30: /* SAC */
1076 s->sac = value;
1077 break;
1078 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001079 hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00001080 }
1081 stellaris_adc_update(s);
1082}
1083
Blue Swirld60efc62009-08-25 18:29:31 +00001084static CPUReadMemoryFunc * const stellaris_adc_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +00001085 stellaris_adc_read,
1086 stellaris_adc_read,
1087 stellaris_adc_read
1088};
1089
Blue Swirld60efc62009-08-25 18:29:31 +00001090static CPUWriteMemoryFunc * const stellaris_adc_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +00001091 stellaris_adc_write,
1092 stellaris_adc_write,
1093 stellaris_adc_write
1094};
1095
pbrook23e39292008-07-02 16:48:32 +00001096static void stellaris_adc_save(QEMUFile *f, void *opaque)
1097{
1098 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1099 int i;
1100 int j;
1101
1102 qemu_put_be32(f, s->actss);
1103 qemu_put_be32(f, s->ris);
1104 qemu_put_be32(f, s->im);
1105 qemu_put_be32(f, s->emux);
1106 qemu_put_be32(f, s->ostat);
1107 qemu_put_be32(f, s->ustat);
1108 qemu_put_be32(f, s->sspri);
1109 qemu_put_be32(f, s->sac);
1110 for (i = 0; i < 4; i++) {
1111 qemu_put_be32(f, s->fifo[i].state);
1112 for (j = 0; j < 16; j++) {
1113 qemu_put_be32(f, s->fifo[i].data[j]);
1114 }
1115 qemu_put_be32(f, s->ssmux[i]);
1116 qemu_put_be32(f, s->ssctl[i]);
1117 }
1118 qemu_put_be32(f, s->noise);
1119}
1120
1121static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id)
1122{
1123 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1124 int i;
1125 int j;
1126
1127 if (version_id != 1)
1128 return -EINVAL;
1129
1130 s->actss = qemu_get_be32(f);
1131 s->ris = qemu_get_be32(f);
1132 s->im = qemu_get_be32(f);
1133 s->emux = qemu_get_be32(f);
1134 s->ostat = qemu_get_be32(f);
1135 s->ustat = qemu_get_be32(f);
1136 s->sspri = qemu_get_be32(f);
1137 s->sac = qemu_get_be32(f);
1138 for (i = 0; i < 4; i++) {
1139 s->fifo[i].state = qemu_get_be32(f);
1140 for (j = 0; j < 16; j++) {
1141 s->fifo[i].data[j] = qemu_get_be32(f);
1142 }
1143 s->ssmux[i] = qemu_get_be32(f);
1144 s->ssctl[i] = qemu_get_be32(f);
1145 }
1146 s->noise = qemu_get_be32(f);
1147
1148 return 0;
1149}
1150
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001151static int stellaris_adc_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +00001152{
Paul Brook40905a62009-06-03 15:16:49 +01001153 stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +00001154 int iomemtype;
Paul Brook2c6554b2009-06-02 15:30:27 +01001155 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +00001156
Paul Brook2c6554b2009-06-02 15:30:27 +01001157 for (n = 0; n < 4; n++) {
Paul Brook40905a62009-06-03 15:16:49 +01001158 sysbus_init_irq(dev, &s->irq[n]);
Paul Brook2c6554b2009-06-02 15:30:27 +01001159 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001160
Avi Kivity1eed09c2009-06-14 11:38:51 +03001161 iomemtype = cpu_register_io_memory(stellaris_adc_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +01001162 stellaris_adc_writefn, s,
1163 DEVICE_NATIVE_ENDIAN);
Paul Brook40905a62009-06-03 15:16:49 +01001164 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +00001165 stellaris_adc_reset(s);
Paul Brook40905a62009-06-03 15:16:49 +01001166 qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
Alex Williamson0be71e32010-06-25 11:09:07 -06001167 register_savevm(&dev->qdev, "stellaris_adc", -1, 1,
pbrook23e39292008-07-02 16:48:32 +00001168 stellaris_adc_save, stellaris_adc_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001169 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00001170}
1171
pbrook775616c2007-11-24 23:35:08 +00001172/* Some boards have both an OLED controller and SD card connected to
1173 the same SSI port, with the SD card chip select connected to a
1174 GPIO pin. Technically the OLED chip select is connected to the SSI
1175 Fss pin. We do not bother emulating that as both devices should
1176 never be selected simultaneously, and our OLED controller ignores stray
1177 0xff commands that occur when deselecting the SD card. */
1178
1179typedef struct {
Paul Brook5493e332009-05-14 22:35:09 +01001180 SSISlave ssidev;
pbrook775616c2007-11-24 23:35:08 +00001181 qemu_irq irq;
1182 int current_dev;
Paul Brook5493e332009-05-14 22:35:09 +01001183 SSIBus *bus[2];
pbrook775616c2007-11-24 23:35:08 +00001184} stellaris_ssi_bus_state;
1185
1186static void stellaris_ssi_bus_select(void *opaque, int irq, int level)
1187{
1188 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1189
1190 s->current_dev = level;
1191}
1192
Paul Brook5493e332009-05-14 22:35:09 +01001193static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
pbrook775616c2007-11-24 23:35:08 +00001194{
Paul Brook5493e332009-05-14 22:35:09 +01001195 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001196
Paul Brook5493e332009-05-14 22:35:09 +01001197 return ssi_transfer(s->bus[s->current_dev], val);
pbrook775616c2007-11-24 23:35:08 +00001198}
1199
Juan Quintelaa4dec1d2010-12-02 02:51:29 +01001200static const VMStateDescription vmstate_stellaris_ssi_bus = {
1201 .name = "stellaris_ssi_bus",
1202 .version_id = 1,
1203 .minimum_version_id = 1,
1204 .minimum_version_id_old = 1,
1205 .fields = (VMStateField[]) {
1206 VMSTATE_INT32(current_dev, stellaris_ssi_bus_state),
1207 VMSTATE_END_OF_LIST()
1208 }
1209};
pbrook23e39292008-07-02 16:48:32 +00001210
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001211static int stellaris_ssi_bus_init(SSISlave *dev)
pbrook775616c2007-11-24 23:35:08 +00001212{
Paul Brook5493e332009-05-14 22:35:09 +01001213 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001214
Paul Brook02e2da42009-05-23 00:05:19 +01001215 s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
1216 s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
Paul Brook5493e332009-05-14 22:35:09 +01001217 qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
1218
Juan Quintelaa4dec1d2010-12-02 02:51:29 +01001219 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001220 return 0;
pbrook775616c2007-11-24 23:35:08 +00001221}
1222
pbrook9ee6e8b2007-11-11 00:04:49 +00001223/* Board init. */
1224static stellaris_board_info stellaris_boards[] = {
1225 { "LM3S811EVB",
1226 0,
1227 0x0032000e,
1228 0x001f001f, /* dc0 */
1229 0x001132bf,
1230 0x01071013,
1231 0x3f0f01ff,
1232 0x0000001f,
pbrookcf0dbb22007-11-18 14:36:08 +00001233 BP_OLED_I2C
pbrook9ee6e8b2007-11-11 00:04:49 +00001234 },
1235 { "LM3S6965EVB",
1236 0x10010002,
1237 0x1073402e,
1238 0x00ff007f, /* dc0 */
1239 0x001133ff,
1240 0x030f5317,
1241 0x0f0f87ff,
1242 0x5000007f,
pbrookcf0dbb22007-11-18 14:36:08 +00001243 BP_OLED_SSI | BP_GAMEPAD
pbrook9ee6e8b2007-11-11 00:04:49 +00001244 }
1245};
1246
1247static void stellaris_init(const char *kernel_filename, const char *cpu_model,
aliguori3023f332009-01-16 19:04:14 +00001248 stellaris_board_info *board)
pbrook9ee6e8b2007-11-11 00:04:49 +00001249{
1250 static const int uart_irq[] = {5, 6, 33, 34};
1251 static const int timer_irq[] = {19, 21, 23, 35};
1252 static const uint32_t gpio_addr[7] =
1253 { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
1254 0x40024000, 0x40025000, 0x40026000};
1255 static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
1256
1257 qemu_irq *pic;
Paul Brook40905a62009-06-03 15:16:49 +01001258 DeviceState *gpio_dev[7];
1259 qemu_irq gpio_in[7][8];
1260 qemu_irq gpio_out[7][8];
pbrook9ee6e8b2007-11-11 00:04:49 +00001261 qemu_irq adc;
1262 int sram_size;
1263 int flash_size;
1264 i2c_bus *i2c;
Paul Brook40905a62009-06-03 15:16:49 +01001265 DeviceState *dev;
pbrook9ee6e8b2007-11-11 00:04:49 +00001266 int i;
Paul Brook40905a62009-06-03 15:16:49 +01001267 int j;
pbrook9ee6e8b2007-11-11 00:04:49 +00001268
1269 flash_size = ((board->dc0 & 0xffff) + 1) << 1;
1270 sram_size = (board->dc0 >> 18) + 1;
1271 pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
1272
1273 if (board->dc1 & (1 << 16)) {
Paul Brook40905a62009-06-03 15:16:49 +01001274 dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
1275 pic[14], pic[15], pic[16], pic[17], NULL);
1276 adc = qdev_get_gpio_in(dev, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00001277 } else {
1278 adc = NULL;
1279 }
1280 for (i = 0; i < 4; i++) {
1281 if (board->dc2 & (0x10000 << i)) {
Paul Brook40905a62009-06-03 15:16:49 +01001282 dev = sysbus_create_simple("stellaris-gptm",
1283 0x40030000 + i * 0x1000,
1284 pic[timer_irq[i]]);
1285 /* TODO: This is incorrect, but we get away with it because
1286 the ADC output is only ever pulsed. */
1287 qdev_connect_gpio_out(dev, 0, adc);
pbrook9ee6e8b2007-11-11 00:04:49 +00001288 }
1289 }
1290
pbrookeea589c2007-11-24 03:13:04 +00001291 stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr);
pbrook9ee6e8b2007-11-11 00:04:49 +00001292
1293 for (i = 0; i < 7; i++) {
1294 if (board->dc4 & (1 << i)) {
Peter Maydell7063f492011-02-21 20:57:51 +00001295 gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
Paul Brook40905a62009-06-03 15:16:49 +01001296 pic[gpio_irq[i]]);
1297 for (j = 0; j < 8; j++) {
1298 gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
1299 gpio_out[i][j] = NULL;
1300 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001301 }
1302 }
1303
1304 if (board->dc2 & (1 << 12)) {
Paul Brook1de96102009-05-14 22:35:09 +01001305 dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
Paul Brook02e2da42009-05-23 00:05:19 +01001306 i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
pbrookcf0dbb22007-11-18 14:36:08 +00001307 if (board->peripherals & BP_OLED_I2C) {
Paul Brookd2199002009-05-14 22:35:08 +01001308 i2c_create_slave(i2c, "ssd0303", 0x3d);
pbrook9ee6e8b2007-11-11 00:04:49 +00001309 }
1310 }
1311
1312 for (i = 0; i < 4; i++) {
1313 if (board->dc2 & (1 << i)) {
Paul Brooka7d518a2009-05-14 22:35:07 +01001314 sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
1315 pic[uart_irq[i]]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001316 }
1317 }
1318 if (board->dc2 & (1 << 4)) {
Paul Brook5493e332009-05-14 22:35:09 +01001319 dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
pbrookcf0dbb22007-11-18 14:36:08 +00001320 if (board->peripherals & BP_OLED_SSI) {
Paul Brook5493e332009-05-14 22:35:09 +01001321 DeviceState *mux;
1322 void *bus;
pbrook775616c2007-11-24 23:35:08 +00001323
Paul Brook5493e332009-05-14 22:35:09 +01001324 bus = qdev_get_child_bus(dev, "ssi");
1325 mux = ssi_create_slave(bus, "evb6965-ssi");
1326 gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
pbrook775616c2007-11-24 23:35:08 +00001327
Paul Brook5493e332009-05-14 22:35:09 +01001328 bus = qdev_get_child_bus(mux, "ssi0");
Blue Swirl22ed1d342010-04-25 19:31:06 +00001329 ssi_create_slave(bus, "ssi-sd");
pbrook775616c2007-11-24 23:35:08 +00001330
Paul Brook5493e332009-05-14 22:35:09 +01001331 bus = qdev_get_child_bus(mux, "ssi1");
1332 dev = ssi_create_slave(bus, "ssd0323");
1333 gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
1334
pbrook775616c2007-11-24 23:35:08 +00001335 /* Make sure the select pin is high. */
1336 qemu_irq_raise(gpio_out[GPIO_D][0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001337 }
1338 }
Paul Brooka5580462009-05-14 22:35:07 +01001339 if (board->dc4 & (1 << 28)) {
1340 DeviceState *enet;
1341
1342 qemu_check_nic_model(&nd_table[0], "stellaris");
1343
1344 enet = qdev_create(NULL, "stellaris_enet");
Gerd Hoffmann540f0062009-10-21 15:25:39 +02001345 qdev_set_nic_properties(enet, &nd_table[0]);
Markus Armbrustere23a1b32009-10-07 01:15:58 +02001346 qdev_init_nofail(enet);
Paul Brooka5580462009-05-14 22:35:07 +01001347 sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000);
1348 sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]);
1349 }
pbrookcf0dbb22007-11-18 14:36:08 +00001350 if (board->peripherals & BP_GAMEPAD) {
1351 qemu_irq gpad_irq[5];
1352 static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
1353
1354 gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
1355 gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
1356 gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
1357 gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
1358 gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
1359
1360 stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
1361 }
Paul Brook40905a62009-06-03 15:16:49 +01001362 for (i = 0; i < 7; i++) {
1363 if (board->dc4 & (1 << i)) {
1364 for (j = 0; j < 8; j++) {
1365 if (gpio_out[i][j]) {
1366 qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
1367 }
1368 }
1369 }
1370 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001371}
1372
1373/* FIXME: Figure out how to generate these from stellaris_boards. */
Anthony Liguoric227f092009-10-01 16:12:16 -05001374static void lm3s811evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001375 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001376 const char *kernel_filename, const char *kernel_cmdline,
1377 const char *initrd_filename, const char *cpu_model)
1378{
aliguori3023f332009-01-16 19:04:14 +00001379 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001380}
1381
Anthony Liguoric227f092009-10-01 16:12:16 -05001382static void lm3s6965evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001383 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001384 const char *kernel_filename, const char *kernel_cmdline,
1385 const char *initrd_filename, const char *cpu_model)
1386{
aliguori3023f332009-01-16 19:04:14 +00001387 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001388}
1389
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001390static QEMUMachine lm3s811evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001391 .name = "lm3s811evb",
1392 .desc = "Stellaris LM3S811EVB",
1393 .init = lm3s811evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001394};
1395
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001396static QEMUMachine lm3s6965evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001397 .name = "lm3s6965evb",
1398 .desc = "Stellaris LM3S6965EVB",
1399 .init = lm3s6965evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001400};
Paul Brook1de96102009-05-14 22:35:09 +01001401
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001402static void stellaris_machine_init(void)
1403{
1404 qemu_register_machine(&lm3s811evb_machine);
1405 qemu_register_machine(&lm3s6965evb_machine);
1406}
1407
1408machine_init(stellaris_machine_init);
1409
Paul Brook5493e332009-05-14 22:35:09 +01001410static SSISlaveInfo stellaris_ssi_bus_info = {
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +02001411 .qdev.name = "evb6965-ssi",
1412 .qdev.size = sizeof(stellaris_ssi_bus_state),
Paul Brook5493e332009-05-14 22:35:09 +01001413 .init = stellaris_ssi_bus_init,
1414 .transfer = stellaris_ssi_bus_transfer
1415};
1416
Paul Brook1de96102009-05-14 22:35:09 +01001417static void stellaris_register_devices(void)
1418{
1419 sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
1420 stellaris_i2c_init);
Paul Brook40905a62009-06-03 15:16:49 +01001421 sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
1422 stellaris_gptm_init);
1423 sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state),
1424 stellaris_adc_init);
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +02001425 ssi_register_slave(&stellaris_ssi_bus_info);
Paul Brook1de96102009-05-14 22:35:09 +01001426}
1427
1428device_init(stellaris_register_devices)