blob: 5d8bd5568d50876d2340e9152f839f288ecd36df [file] [log] [blame]
pbrook9ee6e8b2007-11-11 00:04:49 +00001/*
aurel321654b2d2008-04-11 04:55:07 +00002 * Luminary Micro Stellaris peripherals
pbrook9ee6e8b2007-11-11 00:04:49 +00003 *
4 * Copyright (c) 2006 CodeSourcery.
5 * Written by Paul Brook
6 *
7 * This code is licenced under the GPL.
8 */
9
Paul Brooka7d518a2009-05-14 22:35:07 +010010#include "sysbus.h"
Paul Brook5493e332009-05-14 22:35:09 +010011#include "ssi.h"
pbrook87ecb682007-11-17 17:14:51 +000012#include "arm-misc.h"
pbrook87ecb682007-11-17 17:14:51 +000013#include "devices.h"
14#include "qemu-timer.h"
15#include "i2c.h"
pbrookeea589c2007-11-24 03:13:04 +000016#include "net.h"
pbrook87ecb682007-11-17 17:14:51 +000017#include "sysemu.h"
18#include "boards.h"
pbrook9ee6e8b2007-11-11 00:04:49 +000019
pbrookcf0dbb22007-11-18 14:36:08 +000020#define GPIO_A 0
21#define GPIO_B 1
22#define GPIO_C 2
23#define GPIO_D 3
24#define GPIO_E 4
25#define GPIO_F 5
26#define GPIO_G 6
27
28#define BP_OLED_I2C 0x01
29#define BP_OLED_SSI 0x02
30#define BP_GAMEPAD 0x04
31
pbrook9ee6e8b2007-11-11 00:04:49 +000032typedef const struct {
33 const char *name;
34 uint32_t did0;
35 uint32_t did1;
36 uint32_t dc0;
37 uint32_t dc1;
38 uint32_t dc2;
39 uint32_t dc3;
40 uint32_t dc4;
pbrookcf0dbb22007-11-18 14:36:08 +000041 uint32_t peripherals;
pbrook9ee6e8b2007-11-11 00:04:49 +000042} stellaris_board_info;
43
44/* General purpose timer module. */
45
pbrook9ee6e8b2007-11-11 00:04:49 +000046typedef struct gptm_state {
Paul Brook40905a62009-06-03 15:16:49 +010047 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +000048 uint32_t config;
49 uint32_t mode[2];
50 uint32_t control;
51 uint32_t state;
52 uint32_t mask;
53 uint32_t load[2];
54 uint32_t match[2];
55 uint32_t prescale[2];
56 uint32_t match_prescale[2];
57 uint32_t rtc;
58 int64_t tick[2];
59 struct gptm_state *opaque[2];
pbrook9ee6e8b2007-11-11 00:04:49 +000060 QEMUTimer *timer[2];
61 /* The timers have an alternate output used to trigger the ADC. */
62 qemu_irq trigger;
63 qemu_irq irq;
64} gptm_state;
65
66static void gptm_update_irq(gptm_state *s)
67{
68 int level;
69 level = (s->state & s->mask) != 0;
70 qemu_set_irq(s->irq, level);
71}
72
73static void gptm_stop(gptm_state *s, int n)
74{
75 qemu_del_timer(s->timer[n]);
76}
77
78static void gptm_reload(gptm_state *s, int n, int reset)
79{
80 int64_t tick;
81 if (reset)
82 tick = qemu_get_clock(vm_clock);
83 else
84 tick = s->tick[n];
85
86 if (s->config == 0) {
87 /* 32-bit CountDown. */
88 uint32_t count;
89 count = s->load[0] | (s->load[1] << 16);
pbrooke57ec012007-11-24 03:09:07 +000090 tick += (int64_t)count * system_clock_scale;
pbrook9ee6e8b2007-11-11 00:04:49 +000091 } else if (s->config == 1) {
92 /* 32-bit RTC. 1Hz tick. */
Juan Quintela6ee093c2009-09-10 03:04:26 +020093 tick += get_ticks_per_sec();
pbrook9ee6e8b2007-11-11 00:04:49 +000094 } else if (s->mode[n] == 0xa) {
95 /* PWM mode. Not implemented. */
96 } else {
Paul Brook2ac71172009-05-08 02:35:15 +010097 hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
pbrook9ee6e8b2007-11-11 00:04:49 +000098 }
99 s->tick[n] = tick;
100 qemu_mod_timer(s->timer[n], tick);
101}
102
103static void gptm_tick(void *opaque)
104{
105 gptm_state **p = (gptm_state **)opaque;
106 gptm_state *s;
107 int n;
108
109 s = *p;
110 n = p - s->opaque;
111 if (s->config == 0) {
112 s->state |= 1;
113 if ((s->control & 0x20)) {
114 /* Output trigger. */
Paul Brook40905a62009-06-03 15:16:49 +0100115 qemu_irq_pulse(s->trigger);
pbrook9ee6e8b2007-11-11 00:04:49 +0000116 }
117 if (s->mode[0] & 1) {
118 /* One-shot. */
119 s->control &= ~1;
120 } else {
121 /* Periodic. */
122 gptm_reload(s, 0, 0);
123 }
124 } else if (s->config == 1) {
125 /* RTC. */
126 uint32_t match;
127 s->rtc++;
128 match = s->match[0] | (s->match[1] << 16);
129 if (s->rtc > match)
130 s->rtc = 0;
131 if (s->rtc == 0) {
132 s->state |= 8;
133 }
134 gptm_reload(s, 0, 0);
135 } else if (s->mode[n] == 0xa) {
136 /* PWM mode. Not implemented. */
137 } else {
Paul Brook2ac71172009-05-08 02:35:15 +0100138 hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
pbrook9ee6e8b2007-11-11 00:04:49 +0000139 }
140 gptm_update_irq(s);
141}
142
Anthony Liguoric227f092009-10-01 16:12:16 -0500143static uint32_t gptm_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000144{
145 gptm_state *s = (gptm_state *)opaque;
146
pbrook9ee6e8b2007-11-11 00:04:49 +0000147 switch (offset) {
148 case 0x00: /* CFG */
149 return s->config;
150 case 0x04: /* TAMR */
151 return s->mode[0];
152 case 0x08: /* TBMR */
153 return s->mode[1];
154 case 0x0c: /* CTL */
155 return s->control;
156 case 0x18: /* IMR */
157 return s->mask;
158 case 0x1c: /* RIS */
159 return s->state;
160 case 0x20: /* MIS */
161 return s->state & s->mask;
162 case 0x24: /* CR */
163 return 0;
164 case 0x28: /* TAILR */
165 return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0);
166 case 0x2c: /* TBILR */
167 return s->load[1];
168 case 0x30: /* TAMARCHR */
169 return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0);
170 case 0x34: /* TBMATCHR */
171 return s->match[1];
172 case 0x38: /* TAPR */
173 return s->prescale[0];
174 case 0x3c: /* TBPR */
175 return s->prescale[1];
176 case 0x40: /* TAPMR */
177 return s->match_prescale[0];
178 case 0x44: /* TBPMR */
179 return s->match_prescale[1];
180 case 0x48: /* TAR */
181 if (s->control == 1)
182 return s->rtc;
183 case 0x4c: /* TBR */
Paul Brook2ac71172009-05-08 02:35:15 +0100184 hw_error("TODO: Timer value read\n");
pbrook9ee6e8b2007-11-11 00:04:49 +0000185 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100186 hw_error("gptm_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000187 return 0;
188 }
189}
190
Anthony Liguoric227f092009-10-01 16:12:16 -0500191static void gptm_write(void *opaque, target_phys_addr_t offset, uint32_t value)
pbrook9ee6e8b2007-11-11 00:04:49 +0000192{
193 gptm_state *s = (gptm_state *)opaque;
194 uint32_t oldval;
195
pbrook9ee6e8b2007-11-11 00:04:49 +0000196 /* The timers should be disabled before changing the configuration.
197 We take advantage of this and defer everything until the timer
198 is enabled. */
199 switch (offset) {
200 case 0x00: /* CFG */
201 s->config = value;
202 break;
203 case 0x04: /* TAMR */
204 s->mode[0] = value;
205 break;
206 case 0x08: /* TBMR */
207 s->mode[1] = value;
208 break;
209 case 0x0c: /* CTL */
210 oldval = s->control;
211 s->control = value;
212 /* TODO: Implement pause. */
213 if ((oldval ^ value) & 1) {
214 if (value & 1) {
215 gptm_reload(s, 0, 1);
216 } else {
217 gptm_stop(s, 0);
218 }
219 }
220 if (((oldval ^ value) & 0x100) && s->config >= 4) {
221 if (value & 0x100) {
222 gptm_reload(s, 1, 1);
223 } else {
224 gptm_stop(s, 1);
225 }
226 }
227 break;
228 case 0x18: /* IMR */
229 s->mask = value & 0x77;
230 gptm_update_irq(s);
231 break;
232 case 0x24: /* CR */
233 s->state &= ~value;
234 break;
235 case 0x28: /* TAILR */
236 s->load[0] = value & 0xffff;
237 if (s->config < 4) {
238 s->load[1] = value >> 16;
239 }
240 break;
241 case 0x2c: /* TBILR */
242 s->load[1] = value & 0xffff;
243 break;
244 case 0x30: /* TAMARCHR */
245 s->match[0] = value & 0xffff;
246 if (s->config < 4) {
247 s->match[1] = value >> 16;
248 }
249 break;
250 case 0x34: /* TBMATCHR */
251 s->match[1] = value >> 16;
252 break;
253 case 0x38: /* TAPR */
254 s->prescale[0] = value;
255 break;
256 case 0x3c: /* TBPR */
257 s->prescale[1] = value;
258 break;
259 case 0x40: /* TAPMR */
260 s->match_prescale[0] = value;
261 break;
262 case 0x44: /* TBPMR */
263 s->match_prescale[0] = value;
264 break;
265 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100266 hw_error("gptm_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000267 }
268 gptm_update_irq(s);
269}
270
Blue Swirld60efc62009-08-25 18:29:31 +0000271static CPUReadMemoryFunc * const gptm_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000272 gptm_read,
273 gptm_read,
274 gptm_read
275};
276
Blue Swirld60efc62009-08-25 18:29:31 +0000277static CPUWriteMemoryFunc * const gptm_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000278 gptm_write,
279 gptm_write,
280 gptm_write
281};
282
pbrook23e39292008-07-02 16:48:32 +0000283static void gptm_save(QEMUFile *f, void *opaque)
284{
285 gptm_state *s = (gptm_state *)opaque;
286
287 qemu_put_be32(f, s->config);
288 qemu_put_be32(f, s->mode[0]);
289 qemu_put_be32(f, s->mode[1]);
290 qemu_put_be32(f, s->control);
291 qemu_put_be32(f, s->state);
292 qemu_put_be32(f, s->mask);
293 qemu_put_be32(f, s->mode[0]);
294 qemu_put_be32(f, s->mode[0]);
295 qemu_put_be32(f, s->load[0]);
296 qemu_put_be32(f, s->load[1]);
297 qemu_put_be32(f, s->match[0]);
298 qemu_put_be32(f, s->match[1]);
299 qemu_put_be32(f, s->prescale[0]);
300 qemu_put_be32(f, s->prescale[1]);
301 qemu_put_be32(f, s->match_prescale[0]);
302 qemu_put_be32(f, s->match_prescale[1]);
303 qemu_put_be32(f, s->rtc);
304 qemu_put_be64(f, s->tick[0]);
305 qemu_put_be64(f, s->tick[1]);
306 qemu_put_timer(f, s->timer[0]);
307 qemu_put_timer(f, s->timer[1]);
308}
309
310static int gptm_load(QEMUFile *f, void *opaque, int version_id)
311{
312 gptm_state *s = (gptm_state *)opaque;
313
314 if (version_id != 1)
315 return -EINVAL;
316
317 s->config = qemu_get_be32(f);
318 s->mode[0] = qemu_get_be32(f);
319 s->mode[1] = qemu_get_be32(f);
320 s->control = qemu_get_be32(f);
321 s->state = qemu_get_be32(f);
322 s->mask = qemu_get_be32(f);
323 s->mode[0] = qemu_get_be32(f);
324 s->mode[0] = qemu_get_be32(f);
325 s->load[0] = qemu_get_be32(f);
326 s->load[1] = qemu_get_be32(f);
327 s->match[0] = qemu_get_be32(f);
328 s->match[1] = qemu_get_be32(f);
329 s->prescale[0] = qemu_get_be32(f);
330 s->prescale[1] = qemu_get_be32(f);
331 s->match_prescale[0] = qemu_get_be32(f);
332 s->match_prescale[1] = qemu_get_be32(f);
333 s->rtc = qemu_get_be32(f);
334 s->tick[0] = qemu_get_be64(f);
335 s->tick[1] = qemu_get_be64(f);
336 qemu_get_timer(f, s->timer[0]);
337 qemu_get_timer(f, s->timer[1]);
338
339 return 0;
340}
341
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200342static int stellaris_gptm_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000343{
344 int iomemtype;
Paul Brook40905a62009-06-03 15:16:49 +0100345 gptm_state *s = FROM_SYSBUS(gptm_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +0000346
Paul Brook40905a62009-06-03 15:16:49 +0100347 sysbus_init_irq(dev, &s->irq);
348 qdev_init_gpio_out(&dev->qdev, &s->trigger, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +0000349
Avi Kivity1eed09c2009-06-14 11:38:51 +0300350 iomemtype = cpu_register_io_memory(gptm_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +0100351 gptm_writefn, s,
352 DEVICE_NATIVE_ENDIAN);
Paul Brook40905a62009-06-03 15:16:49 +0100353 sysbus_init_mmio(dev, 0x1000, iomemtype);
354
355 s->opaque[0] = s->opaque[1] = s;
pbrook9ee6e8b2007-11-11 00:04:49 +0000356 s->timer[0] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[0]);
357 s->timer[1] = qemu_new_timer(vm_clock, gptm_tick, &s->opaque[1]);
Alex Williamson0be71e32010-06-25 11:09:07 -0600358 register_savevm(&dev->qdev, "stellaris_gptm", -1, 1,
359 gptm_save, gptm_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200360 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000361}
362
363
364/* System controller. */
365
366typedef struct {
pbrook9ee6e8b2007-11-11 00:04:49 +0000367 uint32_t pborctl;
368 uint32_t ldopctl;
369 uint32_t int_status;
370 uint32_t int_mask;
371 uint32_t resc;
372 uint32_t rcc;
373 uint32_t rcgc[3];
374 uint32_t scgc[3];
375 uint32_t dcgc[3];
376 uint32_t clkvclr;
377 uint32_t ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000378 uint32_t user0;
379 uint32_t user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000380 qemu_irq irq;
381 stellaris_board_info *board;
382} ssys_state;
383
384static void ssys_update(ssys_state *s)
385{
386 qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
387}
388
389static uint32_t pllcfg_sandstorm[16] = {
390 0x31c0, /* 1 Mhz */
391 0x1ae0, /* 1.8432 Mhz */
392 0x18c0, /* 2 Mhz */
393 0xd573, /* 2.4576 Mhz */
394 0x37a6, /* 3.57954 Mhz */
395 0x1ae2, /* 3.6864 Mhz */
396 0x0c40, /* 4 Mhz */
397 0x98bc, /* 4.906 Mhz */
398 0x935b, /* 4.9152 Mhz */
399 0x09c0, /* 5 Mhz */
400 0x4dee, /* 5.12 Mhz */
401 0x0c41, /* 6 Mhz */
402 0x75db, /* 6.144 Mhz */
403 0x1ae6, /* 7.3728 Mhz */
404 0x0600, /* 8 Mhz */
405 0x585b /* 8.192 Mhz */
406};
407
408static uint32_t pllcfg_fury[16] = {
409 0x3200, /* 1 Mhz */
410 0x1b20, /* 1.8432 Mhz */
411 0x1900, /* 2 Mhz */
412 0xf42b, /* 2.4576 Mhz */
413 0x37e3, /* 3.57954 Mhz */
414 0x1b21, /* 3.6864 Mhz */
415 0x0c80, /* 4 Mhz */
416 0x98ee, /* 4.906 Mhz */
417 0xd5b4, /* 4.9152 Mhz */
418 0x0a00, /* 5 Mhz */
419 0x4e27, /* 5.12 Mhz */
420 0x1902, /* 6 Mhz */
421 0xec1c, /* 6.144 Mhz */
422 0x1b23, /* 7.3728 Mhz */
423 0x0640, /* 8 Mhz */
424 0xb11c /* 8.192 Mhz */
425};
426
Anthony Liguoric227f092009-10-01 16:12:16 -0500427static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000428{
429 ssys_state *s = (ssys_state *)opaque;
430
pbrook9ee6e8b2007-11-11 00:04:49 +0000431 switch (offset) {
432 case 0x000: /* DID0 */
433 return s->board->did0;
434 case 0x004: /* DID1 */
435 return s->board->did1;
436 case 0x008: /* DC0 */
437 return s->board->dc0;
438 case 0x010: /* DC1 */
439 return s->board->dc1;
440 case 0x014: /* DC2 */
441 return s->board->dc2;
442 case 0x018: /* DC3 */
443 return s->board->dc3;
444 case 0x01c: /* DC4 */
445 return s->board->dc4;
446 case 0x030: /* PBORCTL */
447 return s->pborctl;
448 case 0x034: /* LDOPCTL */
449 return s->ldopctl;
450 case 0x040: /* SRCR0 */
451 return 0;
452 case 0x044: /* SRCR1 */
453 return 0;
454 case 0x048: /* SRCR2 */
455 return 0;
456 case 0x050: /* RIS */
457 return s->int_status;
458 case 0x054: /* IMC */
459 return s->int_mask;
460 case 0x058: /* MISC */
461 return s->int_status & s->int_mask;
462 case 0x05c: /* RESC */
463 return s->resc;
464 case 0x060: /* RCC */
465 return s->rcc;
466 case 0x064: /* PLLCFG */
467 {
468 int xtal;
469 xtal = (s->rcc >> 6) & 0xf;
470 if (s->board->did0 & (1 << 16)) {
471 return pllcfg_fury[xtal];
472 } else {
473 return pllcfg_sandstorm[xtal];
474 }
475 }
476 case 0x100: /* RCGC0 */
477 return s->rcgc[0];
478 case 0x104: /* RCGC1 */
479 return s->rcgc[1];
480 case 0x108: /* RCGC2 */
481 return s->rcgc[2];
482 case 0x110: /* SCGC0 */
483 return s->scgc[0];
484 case 0x114: /* SCGC1 */
485 return s->scgc[1];
486 case 0x118: /* SCGC2 */
487 return s->scgc[2];
488 case 0x120: /* DCGC0 */
489 return s->dcgc[0];
490 case 0x124: /* DCGC1 */
491 return s->dcgc[1];
492 case 0x128: /* DCGC2 */
493 return s->dcgc[2];
494 case 0x150: /* CLKVCLR */
495 return s->clkvclr;
496 case 0x160: /* LDOARST */
497 return s->ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000498 case 0x1e0: /* USER0 */
499 return s->user0;
500 case 0x1e4: /* USER1 */
501 return s->user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000502 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100503 hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000504 return 0;
505 }
506}
507
pbrook23e39292008-07-02 16:48:32 +0000508static void ssys_calculate_system_clock(ssys_state *s)
509{
510 system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
511}
512
Anthony Liguoric227f092009-10-01 16:12:16 -0500513static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
pbrook9ee6e8b2007-11-11 00:04:49 +0000514{
515 ssys_state *s = (ssys_state *)opaque;
516
pbrook9ee6e8b2007-11-11 00:04:49 +0000517 switch (offset) {
518 case 0x030: /* PBORCTL */
519 s->pborctl = value & 0xffff;
520 break;
521 case 0x034: /* LDOPCTL */
522 s->ldopctl = value & 0x1f;
523 break;
524 case 0x040: /* SRCR0 */
525 case 0x044: /* SRCR1 */
526 case 0x048: /* SRCR2 */
527 fprintf(stderr, "Peripheral reset not implemented\n");
528 break;
529 case 0x054: /* IMC */
530 s->int_mask = value & 0x7f;
531 break;
532 case 0x058: /* MISC */
533 s->int_status &= ~value;
534 break;
535 case 0x05c: /* RESC */
536 s->resc = value & 0x3f;
537 break;
538 case 0x060: /* RCC */
539 if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
540 /* PLL enable. */
541 s->int_status |= (1 << 6);
542 }
543 s->rcc = value;
pbrook23e39292008-07-02 16:48:32 +0000544 ssys_calculate_system_clock(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000545 break;
546 case 0x100: /* RCGC0 */
547 s->rcgc[0] = value;
548 break;
549 case 0x104: /* RCGC1 */
550 s->rcgc[1] = value;
551 break;
552 case 0x108: /* RCGC2 */
553 s->rcgc[2] = value;
554 break;
555 case 0x110: /* SCGC0 */
556 s->scgc[0] = value;
557 break;
558 case 0x114: /* SCGC1 */
559 s->scgc[1] = value;
560 break;
561 case 0x118: /* SCGC2 */
562 s->scgc[2] = value;
563 break;
564 case 0x120: /* DCGC0 */
565 s->dcgc[0] = value;
566 break;
567 case 0x124: /* DCGC1 */
568 s->dcgc[1] = value;
569 break;
570 case 0x128: /* DCGC2 */
571 s->dcgc[2] = value;
572 break;
573 case 0x150: /* CLKVCLR */
574 s->clkvclr = value;
575 break;
576 case 0x160: /* LDOARST */
577 s->ldoarst = value;
578 break;
579 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100580 hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000581 }
582 ssys_update(s);
583}
584
Blue Swirld60efc62009-08-25 18:29:31 +0000585static CPUReadMemoryFunc * const ssys_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000586 ssys_read,
587 ssys_read,
588 ssys_read
589};
590
Blue Swirld60efc62009-08-25 18:29:31 +0000591static CPUWriteMemoryFunc * const ssys_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000592 ssys_write,
593 ssys_write,
594 ssys_write
595};
596
pbrook9596ebb2007-11-18 01:44:38 +0000597static void ssys_reset(void *opaque)
pbrook9ee6e8b2007-11-11 00:04:49 +0000598{
599 ssys_state *s = (ssys_state *)opaque;
600
601 s->pborctl = 0x7ffd;
602 s->rcc = 0x078e3ac0;
603 s->rcgc[0] = 1;
604 s->scgc[0] = 1;
605 s->dcgc[0] = 1;
606}
607
pbrook23e39292008-07-02 16:48:32 +0000608static void ssys_save(QEMUFile *f, void *opaque)
609{
610 ssys_state *s = (ssys_state *)opaque;
611
612 qemu_put_be32(f, s->pborctl);
613 qemu_put_be32(f, s->ldopctl);
614 qemu_put_be32(f, s->int_mask);
615 qemu_put_be32(f, s->int_status);
616 qemu_put_be32(f, s->resc);
617 qemu_put_be32(f, s->rcc);
618 qemu_put_be32(f, s->rcgc[0]);
619 qemu_put_be32(f, s->rcgc[1]);
620 qemu_put_be32(f, s->rcgc[2]);
621 qemu_put_be32(f, s->scgc[0]);
622 qemu_put_be32(f, s->scgc[1]);
623 qemu_put_be32(f, s->scgc[2]);
624 qemu_put_be32(f, s->dcgc[0]);
625 qemu_put_be32(f, s->dcgc[1]);
626 qemu_put_be32(f, s->dcgc[2]);
627 qemu_put_be32(f, s->clkvclr);
628 qemu_put_be32(f, s->ldoarst);
629}
630
631static int ssys_load(QEMUFile *f, void *opaque, int version_id)
632{
633 ssys_state *s = (ssys_state *)opaque;
634
635 if (version_id != 1)
636 return -EINVAL;
637
638 s->pborctl = qemu_get_be32(f);
639 s->ldopctl = qemu_get_be32(f);
640 s->int_mask = qemu_get_be32(f);
641 s->int_status = qemu_get_be32(f);
642 s->resc = qemu_get_be32(f);
643 s->rcc = qemu_get_be32(f);
644 s->rcgc[0] = qemu_get_be32(f);
645 s->rcgc[1] = qemu_get_be32(f);
646 s->rcgc[2] = qemu_get_be32(f);
647 s->scgc[0] = qemu_get_be32(f);
648 s->scgc[1] = qemu_get_be32(f);
649 s->scgc[2] = qemu_get_be32(f);
650 s->dcgc[0] = qemu_get_be32(f);
651 s->dcgc[1] = qemu_get_be32(f);
652 s->dcgc[2] = qemu_get_be32(f);
653 s->clkvclr = qemu_get_be32(f);
654 s->ldoarst = qemu_get_be32(f);
655 ssys_calculate_system_clock(s);
656
657 return 0;
658}
659
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200660static int stellaris_sys_init(uint32_t base, qemu_irq irq,
661 stellaris_board_info * board,
662 uint8_t *macaddr)
pbrook9ee6e8b2007-11-11 00:04:49 +0000663{
664 int iomemtype;
665 ssys_state *s;
666
667 s = (ssys_state *)qemu_mallocz(sizeof(ssys_state));
pbrook9ee6e8b2007-11-11 00:04:49 +0000668 s->irq = irq;
669 s->board = board;
pbrookeea589c2007-11-24 03:13:04 +0000670 /* Most devices come preprogrammed with a MAC address in the user data. */
671 s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
672 s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +0000673
Avi Kivity1eed09c2009-06-14 11:38:51 +0300674 iomemtype = cpu_register_io_memory(ssys_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +0100675 ssys_writefn, s,
676 DEVICE_NATIVE_ENDIAN);
pbrook9ee6e8b2007-11-11 00:04:49 +0000677 cpu_register_physical_memory(base, 0x00001000, iomemtype);
678 ssys_reset(s);
Alex Williamson0be71e32010-06-25 11:09:07 -0600679 register_savevm(NULL, "stellaris_sys", -1, 1, ssys_save, ssys_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200680 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000681}
682
683
684/* I2C controller. */
685
686typedef struct {
Paul Brook1de96102009-05-14 22:35:09 +0100687 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000688 i2c_bus *bus;
689 qemu_irq irq;
pbrook9ee6e8b2007-11-11 00:04:49 +0000690 uint32_t msa;
691 uint32_t mcs;
692 uint32_t mdr;
693 uint32_t mtpr;
694 uint32_t mimr;
695 uint32_t mris;
696 uint32_t mcr;
697} stellaris_i2c_state;
698
699#define STELLARIS_I2C_MCS_BUSY 0x01
700#define STELLARIS_I2C_MCS_ERROR 0x02
701#define STELLARIS_I2C_MCS_ADRACK 0x04
702#define STELLARIS_I2C_MCS_DATACK 0x08
703#define STELLARIS_I2C_MCS_ARBLST 0x10
704#define STELLARIS_I2C_MCS_IDLE 0x20
705#define STELLARIS_I2C_MCS_BUSBSY 0x40
706
Anthony Liguoric227f092009-10-01 16:12:16 -0500707static uint32_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000708{
709 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
710
pbrook9ee6e8b2007-11-11 00:04:49 +0000711 switch (offset) {
712 case 0x00: /* MSA */
713 return s->msa;
714 case 0x04: /* MCS */
715 /* We don't emulate timing, so the controller is never busy. */
716 return s->mcs | STELLARIS_I2C_MCS_IDLE;
717 case 0x08: /* MDR */
718 return s->mdr;
719 case 0x0c: /* MTPR */
720 return s->mtpr;
721 case 0x10: /* MIMR */
722 return s->mimr;
723 case 0x14: /* MRIS */
724 return s->mris;
725 case 0x18: /* MMIS */
726 return s->mris & s->mimr;
727 case 0x20: /* MCR */
728 return s->mcr;
729 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100730 hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000731 return 0;
732 }
733}
734
735static void stellaris_i2c_update(stellaris_i2c_state *s)
736{
737 int level;
738
739 level = (s->mris & s->mimr) != 0;
740 qemu_set_irq(s->irq, level);
741}
742
Anthony Liguoric227f092009-10-01 16:12:16 -0500743static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset,
pbrook9ee6e8b2007-11-11 00:04:49 +0000744 uint32_t value)
745{
746 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
747
pbrook9ee6e8b2007-11-11 00:04:49 +0000748 switch (offset) {
749 case 0x00: /* MSA */
750 s->msa = value & 0xff;
751 break;
752 case 0x04: /* MCS */
753 if ((s->mcr & 0x10) == 0) {
754 /* Disabled. Do nothing. */
755 break;
756 }
757 /* Grab the bus if this is starting a transfer. */
758 if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
759 if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
760 s->mcs |= STELLARIS_I2C_MCS_ARBLST;
761 } else {
762 s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
763 s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
764 }
765 }
766 /* If we don't have the bus then indicate an error. */
767 if (!i2c_bus_busy(s->bus)
768 || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
769 s->mcs |= STELLARIS_I2C_MCS_ERROR;
770 break;
771 }
772 s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
773 if (value & 1) {
774 /* Transfer a byte. */
775 /* TODO: Handle errors. */
776 if (s->msa & 1) {
777 /* Recv */
778 s->mdr = i2c_recv(s->bus) & 0xff;
779 } else {
780 /* Send */
781 i2c_send(s->bus, s->mdr);
782 }
783 /* Raise an interrupt. */
784 s->mris |= 1;
785 }
786 if (value & 4) {
787 /* Finish transfer. */
788 i2c_end_transfer(s->bus);
789 s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
790 }
791 break;
792 case 0x08: /* MDR */
793 s->mdr = value & 0xff;
794 break;
795 case 0x0c: /* MTPR */
796 s->mtpr = value & 0xff;
797 break;
798 case 0x10: /* MIMR */
799 s->mimr = 1;
800 break;
801 case 0x1c: /* MICR */
802 s->mris &= ~value;
803 break;
804 case 0x20: /* MCR */
805 if (value & 1)
Paul Brook2ac71172009-05-08 02:35:15 +0100806 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000807 "stellaris_i2c_write: Loopback not implemented\n");
808 if (value & 0x20)
Paul Brook2ac71172009-05-08 02:35:15 +0100809 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000810 "stellaris_i2c_write: Slave mode not implemented\n");
811 s->mcr = value & 0x31;
812 break;
813 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100814 hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +0000815 (int)offset);
816 }
817 stellaris_i2c_update(s);
818}
819
820static void stellaris_i2c_reset(stellaris_i2c_state *s)
821{
822 if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
823 i2c_end_transfer(s->bus);
824
825 s->msa = 0;
826 s->mcs = 0;
827 s->mdr = 0;
828 s->mtpr = 1;
829 s->mimr = 0;
830 s->mris = 0;
831 s->mcr = 0;
832 stellaris_i2c_update(s);
833}
834
Blue Swirld60efc62009-08-25 18:29:31 +0000835static CPUReadMemoryFunc * const stellaris_i2c_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000836 stellaris_i2c_read,
837 stellaris_i2c_read,
838 stellaris_i2c_read
839};
840
Blue Swirld60efc62009-08-25 18:29:31 +0000841static CPUWriteMemoryFunc * const stellaris_i2c_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000842 stellaris_i2c_write,
843 stellaris_i2c_write,
844 stellaris_i2c_write
845};
846
pbrook23e39292008-07-02 16:48:32 +0000847static void stellaris_i2c_save(QEMUFile *f, void *opaque)
848{
849 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
850
851 qemu_put_be32(f, s->msa);
852 qemu_put_be32(f, s->mcs);
853 qemu_put_be32(f, s->mdr);
854 qemu_put_be32(f, s->mtpr);
855 qemu_put_be32(f, s->mimr);
856 qemu_put_be32(f, s->mris);
857 qemu_put_be32(f, s->mcr);
858}
859
860static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id)
861{
862 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
863
864 if (version_id != 1)
865 return -EINVAL;
866
867 s->msa = qemu_get_be32(f);
868 s->mcs = qemu_get_be32(f);
869 s->mdr = qemu_get_be32(f);
870 s->mtpr = qemu_get_be32(f);
871 s->mimr = qemu_get_be32(f);
872 s->mris = qemu_get_be32(f);
873 s->mcr = qemu_get_be32(f);
874
875 return 0;
876}
877
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200878static int stellaris_i2c_init(SysBusDevice * dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000879{
Paul Brook1de96102009-05-14 22:35:09 +0100880 stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100881 i2c_bus *bus;
pbrook9ee6e8b2007-11-11 00:04:49 +0000882 int iomemtype;
883
Paul Brook1de96102009-05-14 22:35:09 +0100884 sysbus_init_irq(dev, &s->irq);
Paul Brook02e2da42009-05-23 00:05:19 +0100885 bus = i2c_init_bus(&dev->qdev, "i2c");
pbrook9ee6e8b2007-11-11 00:04:49 +0000886 s->bus = bus;
887
Avi Kivity1eed09c2009-06-14 11:38:51 +0300888 iomemtype = cpu_register_io_memory(stellaris_i2c_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +0100889 stellaris_i2c_writefn, s,
890 DEVICE_NATIVE_ENDIAN);
Paul Brook1de96102009-05-14 22:35:09 +0100891 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +0000892 /* ??? For now we only implement the master interface. */
893 stellaris_i2c_reset(s);
Alex Williamson0be71e32010-06-25 11:09:07 -0600894 register_savevm(&dev->qdev, "stellaris_i2c", -1, 1,
pbrook23e39292008-07-02 16:48:32 +0000895 stellaris_i2c_save, stellaris_i2c_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200896 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000897}
898
899/* Analogue to Digital Converter. This is only partially implemented,
900 enough for applications that use a combined ADC and timer tick. */
901
902#define STELLARIS_ADC_EM_CONTROLLER 0
903#define STELLARIS_ADC_EM_COMP 1
904#define STELLARIS_ADC_EM_EXTERNAL 4
905#define STELLARIS_ADC_EM_TIMER 5
906#define STELLARIS_ADC_EM_PWM0 6
907#define STELLARIS_ADC_EM_PWM1 7
908#define STELLARIS_ADC_EM_PWM2 8
909
910#define STELLARIS_ADC_FIFO_EMPTY 0x0100
911#define STELLARIS_ADC_FIFO_FULL 0x1000
912
913typedef struct
914{
Paul Brook40905a62009-06-03 15:16:49 +0100915 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000916 uint32_t actss;
917 uint32_t ris;
918 uint32_t im;
919 uint32_t emux;
920 uint32_t ostat;
921 uint32_t ustat;
922 uint32_t sspri;
923 uint32_t sac;
924 struct {
925 uint32_t state;
926 uint32_t data[16];
927 } fifo[4];
928 uint32_t ssmux[4];
929 uint32_t ssctl[4];
pbrook23e39292008-07-02 16:48:32 +0000930 uint32_t noise;
Paul Brook2c6554b2009-06-02 15:30:27 +0100931 qemu_irq irq[4];
pbrook9ee6e8b2007-11-11 00:04:49 +0000932} stellaris_adc_state;
933
934static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
935{
936 int tail;
937
938 tail = s->fifo[n].state & 0xf;
939 if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
940 s->ustat |= 1 << n;
941 } else {
942 s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
943 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
944 if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
945 s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
946 }
947 return s->fifo[n].data[tail];
948}
949
950static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
951 uint32_t value)
952{
953 int head;
954
Paul Brook2c6554b2009-06-02 15:30:27 +0100955 /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry
956 FIFO fir each sequencer. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000957 head = (s->fifo[n].state >> 4) & 0xf;
958 if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
959 s->ostat |= 1 << n;
960 return;
961 }
962 s->fifo[n].data[head] = value;
963 head = (head + 1) & 0xf;
964 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
965 s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
966 if ((s->fifo[n].state & 0xf) == head)
967 s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
968}
969
970static void stellaris_adc_update(stellaris_adc_state *s)
971{
972 int level;
Paul Brook2c6554b2009-06-02 15:30:27 +0100973 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000974
Paul Brook2c6554b2009-06-02 15:30:27 +0100975 for (n = 0; n < 4; n++) {
976 level = (s->ris & s->im & (1 << n)) != 0;
977 qemu_set_irq(s->irq[n], level);
978 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000979}
980
981static void stellaris_adc_trigger(void *opaque, int irq, int level)
982{
983 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
Paul Brook2c6554b2009-06-02 15:30:27 +0100984 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000985
Paul Brook2c6554b2009-06-02 15:30:27 +0100986 for (n = 0; n < 4; n++) {
987 if ((s->actss & (1 << n)) == 0) {
988 continue;
989 }
990
991 if (((s->emux >> (n * 4)) & 0xff) != 5) {
992 continue;
993 }
994
995 /* Some applications use the ADC as a random number source, so introduce
996 some variation into the signal. */
997 s->noise = s->noise * 314159 + 1;
998 /* ??? actual inputs not implemented. Return an arbitrary value. */
999 stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
1000 s->ris |= (1 << n);
1001 stellaris_adc_update(s);
pbrook9ee6e8b2007-11-11 00:04:49 +00001002 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001003}
1004
1005static void stellaris_adc_reset(stellaris_adc_state *s)
1006{
1007 int n;
1008
1009 for (n = 0; n < 4; n++) {
1010 s->ssmux[n] = 0;
1011 s->ssctl[n] = 0;
1012 s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
1013 }
1014}
1015
Anthony Liguoric227f092009-10-01 16:12:16 -05001016static uint32_t stellaris_adc_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +00001017{
1018 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1019
1020 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001021 if (offset >= 0x40 && offset < 0xc0) {
1022 int n;
1023 n = (offset - 0x40) >> 5;
1024 switch (offset & 0x1f) {
1025 case 0x00: /* SSMUX */
1026 return s->ssmux[n];
1027 case 0x04: /* SSCTL */
1028 return s->ssctl[n];
1029 case 0x08: /* SSFIFO */
1030 return stellaris_adc_fifo_read(s, n);
1031 case 0x0c: /* SSFSTAT */
1032 return s->fifo[n].state;
1033 default:
1034 break;
1035 }
1036 }
1037 switch (offset) {
1038 case 0x00: /* ACTSS */
1039 return s->actss;
1040 case 0x04: /* RIS */
1041 return s->ris;
1042 case 0x08: /* IM */
1043 return s->im;
1044 case 0x0c: /* ISC */
1045 return s->ris & s->im;
1046 case 0x10: /* OSTAT */
1047 return s->ostat;
1048 case 0x14: /* EMUX */
1049 return s->emux;
1050 case 0x18: /* USTAT */
1051 return s->ustat;
1052 case 0x20: /* SSPRI */
1053 return s->sspri;
1054 case 0x30: /* SAC */
1055 return s->sac;
1056 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001057 hw_error("strllaris_adc_read: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001058 (int)offset);
1059 return 0;
1060 }
1061}
1062
Anthony Liguoric227f092009-10-01 16:12:16 -05001063static void stellaris_adc_write(void *opaque, target_phys_addr_t offset,
pbrook9ee6e8b2007-11-11 00:04:49 +00001064 uint32_t value)
1065{
1066 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1067
1068 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001069 if (offset >= 0x40 && offset < 0xc0) {
1070 int n;
1071 n = (offset - 0x40) >> 5;
1072 switch (offset & 0x1f) {
1073 case 0x00: /* SSMUX */
1074 s->ssmux[n] = value & 0x33333333;
1075 return;
1076 case 0x04: /* SSCTL */
1077 if (value != 6) {
Paul Brook2ac71172009-05-08 02:35:15 +01001078 hw_error("ADC: Unimplemented sequence %x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001079 value);
1080 }
1081 s->ssctl[n] = value;
1082 return;
1083 default:
1084 break;
1085 }
1086 }
1087 switch (offset) {
1088 case 0x00: /* ACTSS */
1089 s->actss = value & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00001090 break;
1091 case 0x08: /* IM */
1092 s->im = value;
1093 break;
1094 case 0x0c: /* ISC */
1095 s->ris &= ~value;
1096 break;
1097 case 0x10: /* OSTAT */
1098 s->ostat &= ~value;
1099 break;
1100 case 0x14: /* EMUX */
1101 s->emux = value;
1102 break;
1103 case 0x18: /* USTAT */
1104 s->ustat &= ~value;
1105 break;
1106 case 0x20: /* SSPRI */
1107 s->sspri = value;
1108 break;
1109 case 0x28: /* PSSI */
Paul Brook2ac71172009-05-08 02:35:15 +01001110 hw_error("Not implemented: ADC sample initiate\n");
pbrook9ee6e8b2007-11-11 00:04:49 +00001111 break;
1112 case 0x30: /* SAC */
1113 s->sac = value;
1114 break;
1115 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001116 hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00001117 }
1118 stellaris_adc_update(s);
1119}
1120
Blue Swirld60efc62009-08-25 18:29:31 +00001121static CPUReadMemoryFunc * const stellaris_adc_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +00001122 stellaris_adc_read,
1123 stellaris_adc_read,
1124 stellaris_adc_read
1125};
1126
Blue Swirld60efc62009-08-25 18:29:31 +00001127static CPUWriteMemoryFunc * const stellaris_adc_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +00001128 stellaris_adc_write,
1129 stellaris_adc_write,
1130 stellaris_adc_write
1131};
1132
pbrook23e39292008-07-02 16:48:32 +00001133static void stellaris_adc_save(QEMUFile *f, void *opaque)
1134{
1135 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1136 int i;
1137 int j;
1138
1139 qemu_put_be32(f, s->actss);
1140 qemu_put_be32(f, s->ris);
1141 qemu_put_be32(f, s->im);
1142 qemu_put_be32(f, s->emux);
1143 qemu_put_be32(f, s->ostat);
1144 qemu_put_be32(f, s->ustat);
1145 qemu_put_be32(f, s->sspri);
1146 qemu_put_be32(f, s->sac);
1147 for (i = 0; i < 4; i++) {
1148 qemu_put_be32(f, s->fifo[i].state);
1149 for (j = 0; j < 16; j++) {
1150 qemu_put_be32(f, s->fifo[i].data[j]);
1151 }
1152 qemu_put_be32(f, s->ssmux[i]);
1153 qemu_put_be32(f, s->ssctl[i]);
1154 }
1155 qemu_put_be32(f, s->noise);
1156}
1157
1158static int stellaris_adc_load(QEMUFile *f, void *opaque, int version_id)
1159{
1160 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1161 int i;
1162 int j;
1163
1164 if (version_id != 1)
1165 return -EINVAL;
1166
1167 s->actss = qemu_get_be32(f);
1168 s->ris = qemu_get_be32(f);
1169 s->im = qemu_get_be32(f);
1170 s->emux = qemu_get_be32(f);
1171 s->ostat = qemu_get_be32(f);
1172 s->ustat = qemu_get_be32(f);
1173 s->sspri = qemu_get_be32(f);
1174 s->sac = qemu_get_be32(f);
1175 for (i = 0; i < 4; i++) {
1176 s->fifo[i].state = qemu_get_be32(f);
1177 for (j = 0; j < 16; j++) {
1178 s->fifo[i].data[j] = qemu_get_be32(f);
1179 }
1180 s->ssmux[i] = qemu_get_be32(f);
1181 s->ssctl[i] = qemu_get_be32(f);
1182 }
1183 s->noise = qemu_get_be32(f);
1184
1185 return 0;
1186}
1187
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001188static int stellaris_adc_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +00001189{
Paul Brook40905a62009-06-03 15:16:49 +01001190 stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +00001191 int iomemtype;
Paul Brook2c6554b2009-06-02 15:30:27 +01001192 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +00001193
Paul Brook2c6554b2009-06-02 15:30:27 +01001194 for (n = 0; n < 4; n++) {
Paul Brook40905a62009-06-03 15:16:49 +01001195 sysbus_init_irq(dev, &s->irq[n]);
Paul Brook2c6554b2009-06-02 15:30:27 +01001196 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001197
Avi Kivity1eed09c2009-06-14 11:38:51 +03001198 iomemtype = cpu_register_io_memory(stellaris_adc_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +01001199 stellaris_adc_writefn, s,
1200 DEVICE_NATIVE_ENDIAN);
Paul Brook40905a62009-06-03 15:16:49 +01001201 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +00001202 stellaris_adc_reset(s);
Paul Brook40905a62009-06-03 15:16:49 +01001203 qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
Alex Williamson0be71e32010-06-25 11:09:07 -06001204 register_savevm(&dev->qdev, "stellaris_adc", -1, 1,
pbrook23e39292008-07-02 16:48:32 +00001205 stellaris_adc_save, stellaris_adc_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001206 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00001207}
1208
pbrook775616c2007-11-24 23:35:08 +00001209/* Some boards have both an OLED controller and SD card connected to
1210 the same SSI port, with the SD card chip select connected to a
1211 GPIO pin. Technically the OLED chip select is connected to the SSI
1212 Fss pin. We do not bother emulating that as both devices should
1213 never be selected simultaneously, and our OLED controller ignores stray
1214 0xff commands that occur when deselecting the SD card. */
1215
1216typedef struct {
Paul Brook5493e332009-05-14 22:35:09 +01001217 SSISlave ssidev;
pbrook775616c2007-11-24 23:35:08 +00001218 qemu_irq irq;
1219 int current_dev;
Paul Brook5493e332009-05-14 22:35:09 +01001220 SSIBus *bus[2];
pbrook775616c2007-11-24 23:35:08 +00001221} stellaris_ssi_bus_state;
1222
1223static void stellaris_ssi_bus_select(void *opaque, int irq, int level)
1224{
1225 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1226
1227 s->current_dev = level;
1228}
1229
Paul Brook5493e332009-05-14 22:35:09 +01001230static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
pbrook775616c2007-11-24 23:35:08 +00001231{
Paul Brook5493e332009-05-14 22:35:09 +01001232 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001233
Paul Brook5493e332009-05-14 22:35:09 +01001234 return ssi_transfer(s->bus[s->current_dev], val);
pbrook775616c2007-11-24 23:35:08 +00001235}
1236
pbrook23e39292008-07-02 16:48:32 +00001237static void stellaris_ssi_bus_save(QEMUFile *f, void *opaque)
1238{
1239 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1240
1241 qemu_put_be32(f, s->current_dev);
1242}
1243
1244static int stellaris_ssi_bus_load(QEMUFile *f, void *opaque, int version_id)
1245{
1246 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1247
1248 if (version_id != 1)
1249 return -EINVAL;
1250
1251 s->current_dev = qemu_get_be32(f);
1252
1253 return 0;
1254}
1255
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001256static int stellaris_ssi_bus_init(SSISlave *dev)
pbrook775616c2007-11-24 23:35:08 +00001257{
Paul Brook5493e332009-05-14 22:35:09 +01001258 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001259
Paul Brook02e2da42009-05-23 00:05:19 +01001260 s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
1261 s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
Paul Brook5493e332009-05-14 22:35:09 +01001262 qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
1263
Alex Williamson0be71e32010-06-25 11:09:07 -06001264 register_savevm(&dev->qdev, "stellaris_ssi_bus", -1, 1,
pbrook23e39292008-07-02 16:48:32 +00001265 stellaris_ssi_bus_save, stellaris_ssi_bus_load, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001266 return 0;
pbrook775616c2007-11-24 23:35:08 +00001267}
1268
pbrook9ee6e8b2007-11-11 00:04:49 +00001269/* Board init. */
1270static stellaris_board_info stellaris_boards[] = {
1271 { "LM3S811EVB",
1272 0,
1273 0x0032000e,
1274 0x001f001f, /* dc0 */
1275 0x001132bf,
1276 0x01071013,
1277 0x3f0f01ff,
1278 0x0000001f,
pbrookcf0dbb22007-11-18 14:36:08 +00001279 BP_OLED_I2C
pbrook9ee6e8b2007-11-11 00:04:49 +00001280 },
1281 { "LM3S6965EVB",
1282 0x10010002,
1283 0x1073402e,
1284 0x00ff007f, /* dc0 */
1285 0x001133ff,
1286 0x030f5317,
1287 0x0f0f87ff,
1288 0x5000007f,
pbrookcf0dbb22007-11-18 14:36:08 +00001289 BP_OLED_SSI | BP_GAMEPAD
pbrook9ee6e8b2007-11-11 00:04:49 +00001290 }
1291};
1292
1293static void stellaris_init(const char *kernel_filename, const char *cpu_model,
aliguori3023f332009-01-16 19:04:14 +00001294 stellaris_board_info *board)
pbrook9ee6e8b2007-11-11 00:04:49 +00001295{
1296 static const int uart_irq[] = {5, 6, 33, 34};
1297 static const int timer_irq[] = {19, 21, 23, 35};
1298 static const uint32_t gpio_addr[7] =
1299 { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
1300 0x40024000, 0x40025000, 0x40026000};
1301 static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
1302
1303 qemu_irq *pic;
Paul Brook40905a62009-06-03 15:16:49 +01001304 DeviceState *gpio_dev[7];
1305 qemu_irq gpio_in[7][8];
1306 qemu_irq gpio_out[7][8];
pbrook9ee6e8b2007-11-11 00:04:49 +00001307 qemu_irq adc;
1308 int sram_size;
1309 int flash_size;
1310 i2c_bus *i2c;
Paul Brook40905a62009-06-03 15:16:49 +01001311 DeviceState *dev;
pbrook9ee6e8b2007-11-11 00:04:49 +00001312 int i;
Paul Brook40905a62009-06-03 15:16:49 +01001313 int j;
pbrook9ee6e8b2007-11-11 00:04:49 +00001314
1315 flash_size = ((board->dc0 & 0xffff) + 1) << 1;
1316 sram_size = (board->dc0 >> 18) + 1;
1317 pic = armv7m_init(flash_size, sram_size, kernel_filename, cpu_model);
1318
1319 if (board->dc1 & (1 << 16)) {
Paul Brook40905a62009-06-03 15:16:49 +01001320 dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
1321 pic[14], pic[15], pic[16], pic[17], NULL);
1322 adc = qdev_get_gpio_in(dev, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00001323 } else {
1324 adc = NULL;
1325 }
1326 for (i = 0; i < 4; i++) {
1327 if (board->dc2 & (0x10000 << i)) {
Paul Brook40905a62009-06-03 15:16:49 +01001328 dev = sysbus_create_simple("stellaris-gptm",
1329 0x40030000 + i * 0x1000,
1330 pic[timer_irq[i]]);
1331 /* TODO: This is incorrect, but we get away with it because
1332 the ADC output is only ever pulsed. */
1333 qdev_connect_gpio_out(dev, 0, adc);
pbrook9ee6e8b2007-11-11 00:04:49 +00001334 }
1335 }
1336
pbrookeea589c2007-11-24 03:13:04 +00001337 stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr);
pbrook9ee6e8b2007-11-11 00:04:49 +00001338
1339 for (i = 0; i < 7; i++) {
1340 if (board->dc4 & (1 << i)) {
Peter Maydell7063f492011-02-21 20:57:51 +00001341 gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
Paul Brook40905a62009-06-03 15:16:49 +01001342 pic[gpio_irq[i]]);
1343 for (j = 0; j < 8; j++) {
1344 gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
1345 gpio_out[i][j] = NULL;
1346 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001347 }
1348 }
1349
1350 if (board->dc2 & (1 << 12)) {
Paul Brook1de96102009-05-14 22:35:09 +01001351 dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
Paul Brook02e2da42009-05-23 00:05:19 +01001352 i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
pbrookcf0dbb22007-11-18 14:36:08 +00001353 if (board->peripherals & BP_OLED_I2C) {
Paul Brookd2199002009-05-14 22:35:08 +01001354 i2c_create_slave(i2c, "ssd0303", 0x3d);
pbrook9ee6e8b2007-11-11 00:04:49 +00001355 }
1356 }
1357
1358 for (i = 0; i < 4; i++) {
1359 if (board->dc2 & (1 << i)) {
Paul Brooka7d518a2009-05-14 22:35:07 +01001360 sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
1361 pic[uart_irq[i]]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001362 }
1363 }
1364 if (board->dc2 & (1 << 4)) {
Paul Brook5493e332009-05-14 22:35:09 +01001365 dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
pbrookcf0dbb22007-11-18 14:36:08 +00001366 if (board->peripherals & BP_OLED_SSI) {
Paul Brook5493e332009-05-14 22:35:09 +01001367 DeviceState *mux;
1368 void *bus;
pbrook775616c2007-11-24 23:35:08 +00001369
Paul Brook5493e332009-05-14 22:35:09 +01001370 bus = qdev_get_child_bus(dev, "ssi");
1371 mux = ssi_create_slave(bus, "evb6965-ssi");
1372 gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
pbrook775616c2007-11-24 23:35:08 +00001373
Paul Brook5493e332009-05-14 22:35:09 +01001374 bus = qdev_get_child_bus(mux, "ssi0");
Blue Swirl22ed1d342010-04-25 19:31:06 +00001375 ssi_create_slave(bus, "ssi-sd");
pbrook775616c2007-11-24 23:35:08 +00001376
Paul Brook5493e332009-05-14 22:35:09 +01001377 bus = qdev_get_child_bus(mux, "ssi1");
1378 dev = ssi_create_slave(bus, "ssd0323");
1379 gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
1380
pbrook775616c2007-11-24 23:35:08 +00001381 /* Make sure the select pin is high. */
1382 qemu_irq_raise(gpio_out[GPIO_D][0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001383 }
1384 }
Paul Brooka5580462009-05-14 22:35:07 +01001385 if (board->dc4 & (1 << 28)) {
1386 DeviceState *enet;
1387
1388 qemu_check_nic_model(&nd_table[0], "stellaris");
1389
1390 enet = qdev_create(NULL, "stellaris_enet");
Gerd Hoffmann540f0062009-10-21 15:25:39 +02001391 qdev_set_nic_properties(enet, &nd_table[0]);
Markus Armbrustere23a1b32009-10-07 01:15:58 +02001392 qdev_init_nofail(enet);
Paul Brooka5580462009-05-14 22:35:07 +01001393 sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000);
1394 sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]);
1395 }
pbrookcf0dbb22007-11-18 14:36:08 +00001396 if (board->peripherals & BP_GAMEPAD) {
1397 qemu_irq gpad_irq[5];
1398 static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
1399
1400 gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
1401 gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
1402 gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
1403 gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
1404 gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
1405
1406 stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
1407 }
Paul Brook40905a62009-06-03 15:16:49 +01001408 for (i = 0; i < 7; i++) {
1409 if (board->dc4 & (1 << i)) {
1410 for (j = 0; j < 8; j++) {
1411 if (gpio_out[i][j]) {
1412 qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
1413 }
1414 }
1415 }
1416 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001417}
1418
1419/* FIXME: Figure out how to generate these from stellaris_boards. */
Anthony Liguoric227f092009-10-01 16:12:16 -05001420static void lm3s811evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001421 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001422 const char *kernel_filename, const char *kernel_cmdline,
1423 const char *initrd_filename, const char *cpu_model)
1424{
aliguori3023f332009-01-16 19:04:14 +00001425 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001426}
1427
Anthony Liguoric227f092009-10-01 16:12:16 -05001428static void lm3s6965evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001429 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001430 const char *kernel_filename, const char *kernel_cmdline,
1431 const char *initrd_filename, const char *cpu_model)
1432{
aliguori3023f332009-01-16 19:04:14 +00001433 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001434}
1435
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001436static QEMUMachine lm3s811evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001437 .name = "lm3s811evb",
1438 .desc = "Stellaris LM3S811EVB",
1439 .init = lm3s811evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001440};
1441
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001442static QEMUMachine lm3s6965evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001443 .name = "lm3s6965evb",
1444 .desc = "Stellaris LM3S6965EVB",
1445 .init = lm3s6965evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001446};
Paul Brook1de96102009-05-14 22:35:09 +01001447
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001448static void stellaris_machine_init(void)
1449{
1450 qemu_register_machine(&lm3s811evb_machine);
1451 qemu_register_machine(&lm3s6965evb_machine);
1452}
1453
1454machine_init(stellaris_machine_init);
1455
Paul Brook5493e332009-05-14 22:35:09 +01001456static SSISlaveInfo stellaris_ssi_bus_info = {
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +02001457 .qdev.name = "evb6965-ssi",
1458 .qdev.size = sizeof(stellaris_ssi_bus_state),
Paul Brook5493e332009-05-14 22:35:09 +01001459 .init = stellaris_ssi_bus_init,
1460 .transfer = stellaris_ssi_bus_transfer
1461};
1462
Paul Brook1de96102009-05-14 22:35:09 +01001463static void stellaris_register_devices(void)
1464{
1465 sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
1466 stellaris_i2c_init);
Paul Brook40905a62009-06-03 15:16:49 +01001467 sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
1468 stellaris_gptm_init);
1469 sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state),
1470 stellaris_adc_init);
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +02001471 ssi_register_slave(&stellaris_ssi_bus_info);
Paul Brook1de96102009-05-14 22:35:09 +01001472}
1473
1474device_init(stellaris_register_devices)