blob: 2bf1c235dc657bc8b8ccd8cd0094166d95f6f9ed [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 *
Matthew Fernandez8e31bf32011-06-26 12:21:35 +10007 * This code is licensed under the GPL.
pbrook9ee6e8b2007-11-11 00:04:49 +00008 */
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"
Avi Kivity7d6f78c2011-07-25 14:27:01 +030018#include "exec-memory.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)
Paolo Bonzini74475452011-03-11 16:47:48 +010082 tick = qemu_get_clock_ns(vm_clock);
pbrook9ee6e8b2007-11-11 00:04:49 +000083 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
Juan Quintela10f85a22010-12-02 14:07:01 +0100283static const VMStateDescription vmstate_stellaris_gptm = {
284 .name = "stellaris_gptm",
285 .version_id = 1,
286 .minimum_version_id = 1,
287 .minimum_version_id_old = 1,
288 .fields = (VMStateField[]) {
289 VMSTATE_UINT32(config, gptm_state),
290 VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
291 VMSTATE_UINT32(control, gptm_state),
292 VMSTATE_UINT32(state, gptm_state),
293 VMSTATE_UINT32(mask, gptm_state),
Juan Quinteladd8a4dc2010-12-02 14:07:44 +0100294 VMSTATE_UNUSED(8),
Juan Quintela10f85a22010-12-02 14:07:01 +0100295 VMSTATE_UINT32_ARRAY(load, gptm_state, 2),
296 VMSTATE_UINT32_ARRAY(match, gptm_state, 2),
297 VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2),
298 VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2),
299 VMSTATE_UINT32(rtc, gptm_state),
300 VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
301 VMSTATE_TIMER_ARRAY(timer, gptm_state, 2),
302 VMSTATE_END_OF_LIST()
303 }
304};
pbrook23e39292008-07-02 16:48:32 +0000305
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200306static int stellaris_gptm_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000307{
308 int iomemtype;
Paul Brook40905a62009-06-03 15:16:49 +0100309 gptm_state *s = FROM_SYSBUS(gptm_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +0000310
Paul Brook40905a62009-06-03 15:16:49 +0100311 sysbus_init_irq(dev, &s->irq);
312 qdev_init_gpio_out(&dev->qdev, &s->trigger, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +0000313
Avi Kivity1eed09c2009-06-14 11:38:51 +0300314 iomemtype = cpu_register_io_memory(gptm_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +0100315 gptm_writefn, s,
316 DEVICE_NATIVE_ENDIAN);
Paul Brook40905a62009-06-03 15:16:49 +0100317 sysbus_init_mmio(dev, 0x1000, iomemtype);
318
319 s->opaque[0] = s->opaque[1] = s;
Paolo Bonzini74475452011-03-11 16:47:48 +0100320 s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]);
321 s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]);
Juan Quintela10f85a22010-12-02 14:07:01 +0100322 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200323 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000324}
325
326
327/* System controller. */
328
329typedef struct {
pbrook9ee6e8b2007-11-11 00:04:49 +0000330 uint32_t pborctl;
331 uint32_t ldopctl;
332 uint32_t int_status;
333 uint32_t int_mask;
334 uint32_t resc;
335 uint32_t rcc;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100336 uint32_t rcc2;
pbrook9ee6e8b2007-11-11 00:04:49 +0000337 uint32_t rcgc[3];
338 uint32_t scgc[3];
339 uint32_t dcgc[3];
340 uint32_t clkvclr;
341 uint32_t ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000342 uint32_t user0;
343 uint32_t user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000344 qemu_irq irq;
345 stellaris_board_info *board;
346} ssys_state;
347
348static void ssys_update(ssys_state *s)
349{
350 qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
351}
352
353static uint32_t pllcfg_sandstorm[16] = {
354 0x31c0, /* 1 Mhz */
355 0x1ae0, /* 1.8432 Mhz */
356 0x18c0, /* 2 Mhz */
357 0xd573, /* 2.4576 Mhz */
358 0x37a6, /* 3.57954 Mhz */
359 0x1ae2, /* 3.6864 Mhz */
360 0x0c40, /* 4 Mhz */
361 0x98bc, /* 4.906 Mhz */
362 0x935b, /* 4.9152 Mhz */
363 0x09c0, /* 5 Mhz */
364 0x4dee, /* 5.12 Mhz */
365 0x0c41, /* 6 Mhz */
366 0x75db, /* 6.144 Mhz */
367 0x1ae6, /* 7.3728 Mhz */
368 0x0600, /* 8 Mhz */
369 0x585b /* 8.192 Mhz */
370};
371
372static uint32_t pllcfg_fury[16] = {
373 0x3200, /* 1 Mhz */
374 0x1b20, /* 1.8432 Mhz */
375 0x1900, /* 2 Mhz */
376 0xf42b, /* 2.4576 Mhz */
377 0x37e3, /* 3.57954 Mhz */
378 0x1b21, /* 3.6864 Mhz */
379 0x0c80, /* 4 Mhz */
380 0x98ee, /* 4.906 Mhz */
381 0xd5b4, /* 4.9152 Mhz */
382 0x0a00, /* 5 Mhz */
383 0x4e27, /* 5.12 Mhz */
384 0x1902, /* 6 Mhz */
385 0xec1c, /* 6.144 Mhz */
386 0x1b23, /* 7.3728 Mhz */
387 0x0640, /* 8 Mhz */
388 0xb11c /* 8.192 Mhz */
389};
390
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100391#define DID0_VER_MASK 0x70000000
392#define DID0_VER_0 0x00000000
393#define DID0_VER_1 0x10000000
394
395#define DID0_CLASS_MASK 0x00FF0000
396#define DID0_CLASS_SANDSTORM 0x00000000
397#define DID0_CLASS_FURY 0x00010000
398
399static int ssys_board_class(const ssys_state *s)
400{
401 uint32_t did0 = s->board->did0;
402 switch (did0 & DID0_VER_MASK) {
403 case DID0_VER_0:
404 return DID0_CLASS_SANDSTORM;
405 case DID0_VER_1:
406 switch (did0 & DID0_CLASS_MASK) {
407 case DID0_CLASS_SANDSTORM:
408 case DID0_CLASS_FURY:
409 return did0 & DID0_CLASS_MASK;
410 }
411 /* for unknown classes, fall through */
412 default:
413 hw_error("ssys_board_class: Unknown class 0x%08x\n", did0);
414 }
415}
416
Anthony Liguoric227f092009-10-01 16:12:16 -0500417static uint32_t ssys_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000418{
419 ssys_state *s = (ssys_state *)opaque;
420
pbrook9ee6e8b2007-11-11 00:04:49 +0000421 switch (offset) {
422 case 0x000: /* DID0 */
423 return s->board->did0;
424 case 0x004: /* DID1 */
425 return s->board->did1;
426 case 0x008: /* DC0 */
427 return s->board->dc0;
428 case 0x010: /* DC1 */
429 return s->board->dc1;
430 case 0x014: /* DC2 */
431 return s->board->dc2;
432 case 0x018: /* DC3 */
433 return s->board->dc3;
434 case 0x01c: /* DC4 */
435 return s->board->dc4;
436 case 0x030: /* PBORCTL */
437 return s->pborctl;
438 case 0x034: /* LDOPCTL */
439 return s->ldopctl;
440 case 0x040: /* SRCR0 */
441 return 0;
442 case 0x044: /* SRCR1 */
443 return 0;
444 case 0x048: /* SRCR2 */
445 return 0;
446 case 0x050: /* RIS */
447 return s->int_status;
448 case 0x054: /* IMC */
449 return s->int_mask;
450 case 0x058: /* MISC */
451 return s->int_status & s->int_mask;
452 case 0x05c: /* RESC */
453 return s->resc;
454 case 0x060: /* RCC */
455 return s->rcc;
456 case 0x064: /* PLLCFG */
457 {
458 int xtal;
459 xtal = (s->rcc >> 6) & 0xf;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100460 switch (ssys_board_class(s)) {
461 case DID0_CLASS_FURY:
pbrook9ee6e8b2007-11-11 00:04:49 +0000462 return pllcfg_fury[xtal];
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100463 case DID0_CLASS_SANDSTORM:
pbrook9ee6e8b2007-11-11 00:04:49 +0000464 return pllcfg_sandstorm[xtal];
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100465 default:
466 hw_error("ssys_read: Unhandled class for PLLCFG read.\n");
467 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000468 }
469 }
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100470 case 0x070: /* RCC2 */
471 return s->rcc2;
pbrook9ee6e8b2007-11-11 00:04:49 +0000472 case 0x100: /* RCGC0 */
473 return s->rcgc[0];
474 case 0x104: /* RCGC1 */
475 return s->rcgc[1];
476 case 0x108: /* RCGC2 */
477 return s->rcgc[2];
478 case 0x110: /* SCGC0 */
479 return s->scgc[0];
480 case 0x114: /* SCGC1 */
481 return s->scgc[1];
482 case 0x118: /* SCGC2 */
483 return s->scgc[2];
484 case 0x120: /* DCGC0 */
485 return s->dcgc[0];
486 case 0x124: /* DCGC1 */
487 return s->dcgc[1];
488 case 0x128: /* DCGC2 */
489 return s->dcgc[2];
490 case 0x150: /* CLKVCLR */
491 return s->clkvclr;
492 case 0x160: /* LDOARST */
493 return s->ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000494 case 0x1e0: /* USER0 */
495 return s->user0;
496 case 0x1e4: /* USER1 */
497 return s->user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000498 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100499 hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000500 return 0;
501 }
502}
503
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100504static bool ssys_use_rcc2(ssys_state *s)
505{
506 return (s->rcc2 >> 31) & 0x1;
507}
508
509/*
510 * Caculate the sys. clock period in ms.
511 */
pbrook23e39292008-07-02 16:48:32 +0000512static void ssys_calculate_system_clock(ssys_state *s)
513{
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100514 if (ssys_use_rcc2(s)) {
515 system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
516 } else {
517 system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
518 }
pbrook23e39292008-07-02 16:48:32 +0000519}
520
Anthony Liguoric227f092009-10-01 16:12:16 -0500521static void ssys_write(void *opaque, target_phys_addr_t offset, uint32_t value)
pbrook9ee6e8b2007-11-11 00:04:49 +0000522{
523 ssys_state *s = (ssys_state *)opaque;
524
pbrook9ee6e8b2007-11-11 00:04:49 +0000525 switch (offset) {
526 case 0x030: /* PBORCTL */
527 s->pborctl = value & 0xffff;
528 break;
529 case 0x034: /* LDOPCTL */
530 s->ldopctl = value & 0x1f;
531 break;
532 case 0x040: /* SRCR0 */
533 case 0x044: /* SRCR1 */
534 case 0x048: /* SRCR2 */
535 fprintf(stderr, "Peripheral reset not implemented\n");
536 break;
537 case 0x054: /* IMC */
538 s->int_mask = value & 0x7f;
539 break;
540 case 0x058: /* MISC */
541 s->int_status &= ~value;
542 break;
543 case 0x05c: /* RESC */
544 s->resc = value & 0x3f;
545 break;
546 case 0x060: /* RCC */
547 if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
548 /* PLL enable. */
549 s->int_status |= (1 << 6);
550 }
551 s->rcc = value;
pbrook23e39292008-07-02 16:48:32 +0000552 ssys_calculate_system_clock(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000553 break;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100554 case 0x070: /* RCC2 */
555 if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
556 break;
557 }
558
559 if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
560 /* PLL enable. */
561 s->int_status |= (1 << 6);
562 }
563 s->rcc2 = value;
564 ssys_calculate_system_clock(s);
565 break;
pbrook9ee6e8b2007-11-11 00:04:49 +0000566 case 0x100: /* RCGC0 */
567 s->rcgc[0] = value;
568 break;
569 case 0x104: /* RCGC1 */
570 s->rcgc[1] = value;
571 break;
572 case 0x108: /* RCGC2 */
573 s->rcgc[2] = value;
574 break;
575 case 0x110: /* SCGC0 */
576 s->scgc[0] = value;
577 break;
578 case 0x114: /* SCGC1 */
579 s->scgc[1] = value;
580 break;
581 case 0x118: /* SCGC2 */
582 s->scgc[2] = value;
583 break;
584 case 0x120: /* DCGC0 */
585 s->dcgc[0] = value;
586 break;
587 case 0x124: /* DCGC1 */
588 s->dcgc[1] = value;
589 break;
590 case 0x128: /* DCGC2 */
591 s->dcgc[2] = value;
592 break;
593 case 0x150: /* CLKVCLR */
594 s->clkvclr = value;
595 break;
596 case 0x160: /* LDOARST */
597 s->ldoarst = value;
598 break;
599 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100600 hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000601 }
602 ssys_update(s);
603}
604
Blue Swirld60efc62009-08-25 18:29:31 +0000605static CPUReadMemoryFunc * const ssys_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000606 ssys_read,
607 ssys_read,
608 ssys_read
609};
610
Blue Swirld60efc62009-08-25 18:29:31 +0000611static CPUWriteMemoryFunc * const ssys_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000612 ssys_write,
613 ssys_write,
614 ssys_write
615};
616
pbrook9596ebb2007-11-18 01:44:38 +0000617static void ssys_reset(void *opaque)
pbrook9ee6e8b2007-11-11 00:04:49 +0000618{
619 ssys_state *s = (ssys_state *)opaque;
620
621 s->pborctl = 0x7ffd;
622 s->rcc = 0x078e3ac0;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100623
624 if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
625 s->rcc2 = 0;
626 } else {
627 s->rcc2 = 0x07802810;
628 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000629 s->rcgc[0] = 1;
630 s->scgc[0] = 1;
631 s->dcgc[0] = 1;
632}
633
Juan Quintela293c16a2010-12-02 03:03:11 +0100634static int stellaris_sys_post_load(void *opaque, int version_id)
pbrook23e39292008-07-02 16:48:32 +0000635{
Juan Quintela293c16a2010-12-02 03:03:11 +0100636 ssys_state *s = opaque;
pbrook23e39292008-07-02 16:48:32 +0000637
pbrook23e39292008-07-02 16:48:32 +0000638 ssys_calculate_system_clock(s);
639
640 return 0;
641}
642
Juan Quintela293c16a2010-12-02 03:03:11 +0100643static const VMStateDescription vmstate_stellaris_sys = {
644 .name = "stellaris_sys",
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100645 .version_id = 2,
Juan Quintela293c16a2010-12-02 03:03:11 +0100646 .minimum_version_id = 1,
647 .minimum_version_id_old = 1,
648 .post_load = stellaris_sys_post_load,
649 .fields = (VMStateField[]) {
650 VMSTATE_UINT32(pborctl, ssys_state),
651 VMSTATE_UINT32(ldopctl, ssys_state),
652 VMSTATE_UINT32(int_mask, ssys_state),
653 VMSTATE_UINT32(int_status, ssys_state),
654 VMSTATE_UINT32(resc, ssys_state),
655 VMSTATE_UINT32(rcc, ssys_state),
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100656 VMSTATE_UINT32_V(rcc2, ssys_state, 2),
Juan Quintela293c16a2010-12-02 03:03:11 +0100657 VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
658 VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
659 VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
660 VMSTATE_UINT32(clkvclr, ssys_state),
661 VMSTATE_UINT32(ldoarst, ssys_state),
662 VMSTATE_END_OF_LIST()
663 }
664};
665
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200666static int stellaris_sys_init(uint32_t base, qemu_irq irq,
667 stellaris_board_info * board,
668 uint8_t *macaddr)
pbrook9ee6e8b2007-11-11 00:04:49 +0000669{
670 int iomemtype;
671 ssys_state *s;
672
Anthony Liguori7267c092011-08-20 22:09:37 -0500673 s = (ssys_state *)g_malloc0(sizeof(ssys_state));
pbrook9ee6e8b2007-11-11 00:04:49 +0000674 s->irq = irq;
675 s->board = board;
pbrookeea589c2007-11-24 03:13:04 +0000676 /* Most devices come preprogrammed with a MAC address in the user data. */
677 s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
678 s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +0000679
Avi Kivity1eed09c2009-06-14 11:38:51 +0300680 iomemtype = cpu_register_io_memory(ssys_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +0100681 ssys_writefn, s,
682 DEVICE_NATIVE_ENDIAN);
pbrook9ee6e8b2007-11-11 00:04:49 +0000683 cpu_register_physical_memory(base, 0x00001000, iomemtype);
684 ssys_reset(s);
Juan Quintela293c16a2010-12-02 03:03:11 +0100685 vmstate_register(NULL, -1, &vmstate_stellaris_sys, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200686 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000687}
688
689
690/* I2C controller. */
691
692typedef struct {
Paul Brook1de96102009-05-14 22:35:09 +0100693 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000694 i2c_bus *bus;
695 qemu_irq irq;
pbrook9ee6e8b2007-11-11 00:04:49 +0000696 uint32_t msa;
697 uint32_t mcs;
698 uint32_t mdr;
699 uint32_t mtpr;
700 uint32_t mimr;
701 uint32_t mris;
702 uint32_t mcr;
703} stellaris_i2c_state;
704
705#define STELLARIS_I2C_MCS_BUSY 0x01
706#define STELLARIS_I2C_MCS_ERROR 0x02
707#define STELLARIS_I2C_MCS_ADRACK 0x04
708#define STELLARIS_I2C_MCS_DATACK 0x08
709#define STELLARIS_I2C_MCS_ARBLST 0x10
710#define STELLARIS_I2C_MCS_IDLE 0x20
711#define STELLARIS_I2C_MCS_BUSBSY 0x40
712
Anthony Liguoric227f092009-10-01 16:12:16 -0500713static uint32_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +0000714{
715 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
716
pbrook9ee6e8b2007-11-11 00:04:49 +0000717 switch (offset) {
718 case 0x00: /* MSA */
719 return s->msa;
720 case 0x04: /* MCS */
721 /* We don't emulate timing, so the controller is never busy. */
722 return s->mcs | STELLARIS_I2C_MCS_IDLE;
723 case 0x08: /* MDR */
724 return s->mdr;
725 case 0x0c: /* MTPR */
726 return s->mtpr;
727 case 0x10: /* MIMR */
728 return s->mimr;
729 case 0x14: /* MRIS */
730 return s->mris;
731 case 0x18: /* MMIS */
732 return s->mris & s->mimr;
733 case 0x20: /* MCR */
734 return s->mcr;
735 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100736 hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000737 return 0;
738 }
739}
740
741static void stellaris_i2c_update(stellaris_i2c_state *s)
742{
743 int level;
744
745 level = (s->mris & s->mimr) != 0;
746 qemu_set_irq(s->irq, level);
747}
748
Anthony Liguoric227f092009-10-01 16:12:16 -0500749static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset,
pbrook9ee6e8b2007-11-11 00:04:49 +0000750 uint32_t value)
751{
752 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
753
pbrook9ee6e8b2007-11-11 00:04:49 +0000754 switch (offset) {
755 case 0x00: /* MSA */
756 s->msa = value & 0xff;
757 break;
758 case 0x04: /* MCS */
759 if ((s->mcr & 0x10) == 0) {
760 /* Disabled. Do nothing. */
761 break;
762 }
763 /* Grab the bus if this is starting a transfer. */
764 if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
765 if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
766 s->mcs |= STELLARIS_I2C_MCS_ARBLST;
767 } else {
768 s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
769 s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
770 }
771 }
772 /* If we don't have the bus then indicate an error. */
773 if (!i2c_bus_busy(s->bus)
774 || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
775 s->mcs |= STELLARIS_I2C_MCS_ERROR;
776 break;
777 }
778 s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
779 if (value & 1) {
780 /* Transfer a byte. */
781 /* TODO: Handle errors. */
782 if (s->msa & 1) {
783 /* Recv */
784 s->mdr = i2c_recv(s->bus) & 0xff;
785 } else {
786 /* Send */
787 i2c_send(s->bus, s->mdr);
788 }
789 /* Raise an interrupt. */
790 s->mris |= 1;
791 }
792 if (value & 4) {
793 /* Finish transfer. */
794 i2c_end_transfer(s->bus);
795 s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
796 }
797 break;
798 case 0x08: /* MDR */
799 s->mdr = value & 0xff;
800 break;
801 case 0x0c: /* MTPR */
802 s->mtpr = value & 0xff;
803 break;
804 case 0x10: /* MIMR */
805 s->mimr = 1;
806 break;
807 case 0x1c: /* MICR */
808 s->mris &= ~value;
809 break;
810 case 0x20: /* MCR */
811 if (value & 1)
Paul Brook2ac71172009-05-08 02:35:15 +0100812 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000813 "stellaris_i2c_write: Loopback not implemented\n");
814 if (value & 0x20)
Paul Brook2ac71172009-05-08 02:35:15 +0100815 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000816 "stellaris_i2c_write: Slave mode not implemented\n");
817 s->mcr = value & 0x31;
818 break;
819 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100820 hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +0000821 (int)offset);
822 }
823 stellaris_i2c_update(s);
824}
825
826static void stellaris_i2c_reset(stellaris_i2c_state *s)
827{
828 if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
829 i2c_end_transfer(s->bus);
830
831 s->msa = 0;
832 s->mcs = 0;
833 s->mdr = 0;
834 s->mtpr = 1;
835 s->mimr = 0;
836 s->mris = 0;
837 s->mcr = 0;
838 stellaris_i2c_update(s);
839}
840
Blue Swirld60efc62009-08-25 18:29:31 +0000841static CPUReadMemoryFunc * const stellaris_i2c_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000842 stellaris_i2c_read,
843 stellaris_i2c_read,
844 stellaris_i2c_read
845};
846
Blue Swirld60efc62009-08-25 18:29:31 +0000847static CPUWriteMemoryFunc * const stellaris_i2c_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +0000848 stellaris_i2c_write,
849 stellaris_i2c_write,
850 stellaris_i2c_write
851};
852
Juan Quintelaff269cd2010-12-02 02:48:43 +0100853static const VMStateDescription vmstate_stellaris_i2c = {
854 .name = "stellaris_i2c",
855 .version_id = 1,
856 .minimum_version_id = 1,
857 .minimum_version_id_old = 1,
858 .fields = (VMStateField[]) {
859 VMSTATE_UINT32(msa, stellaris_i2c_state),
860 VMSTATE_UINT32(mcs, stellaris_i2c_state),
861 VMSTATE_UINT32(mdr, stellaris_i2c_state),
862 VMSTATE_UINT32(mtpr, stellaris_i2c_state),
863 VMSTATE_UINT32(mimr, stellaris_i2c_state),
864 VMSTATE_UINT32(mris, stellaris_i2c_state),
865 VMSTATE_UINT32(mcr, stellaris_i2c_state),
866 VMSTATE_END_OF_LIST()
867 }
868};
pbrook23e39292008-07-02 16:48:32 +0000869
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200870static int stellaris_i2c_init(SysBusDevice * dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000871{
Paul Brook1de96102009-05-14 22:35:09 +0100872 stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100873 i2c_bus *bus;
pbrook9ee6e8b2007-11-11 00:04:49 +0000874 int iomemtype;
875
Paul Brook1de96102009-05-14 22:35:09 +0100876 sysbus_init_irq(dev, &s->irq);
Paul Brook02e2da42009-05-23 00:05:19 +0100877 bus = i2c_init_bus(&dev->qdev, "i2c");
pbrook9ee6e8b2007-11-11 00:04:49 +0000878 s->bus = bus;
879
Avi Kivity1eed09c2009-06-14 11:38:51 +0300880 iomemtype = cpu_register_io_memory(stellaris_i2c_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +0100881 stellaris_i2c_writefn, s,
882 DEVICE_NATIVE_ENDIAN);
Paul Brook1de96102009-05-14 22:35:09 +0100883 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +0000884 /* ??? For now we only implement the master interface. */
885 stellaris_i2c_reset(s);
Juan Quintelaff269cd2010-12-02 02:48:43 +0100886 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200887 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000888}
889
890/* Analogue to Digital Converter. This is only partially implemented,
891 enough for applications that use a combined ADC and timer tick. */
892
893#define STELLARIS_ADC_EM_CONTROLLER 0
894#define STELLARIS_ADC_EM_COMP 1
895#define STELLARIS_ADC_EM_EXTERNAL 4
896#define STELLARIS_ADC_EM_TIMER 5
897#define STELLARIS_ADC_EM_PWM0 6
898#define STELLARIS_ADC_EM_PWM1 7
899#define STELLARIS_ADC_EM_PWM2 8
900
901#define STELLARIS_ADC_FIFO_EMPTY 0x0100
902#define STELLARIS_ADC_FIFO_FULL 0x1000
903
904typedef struct
905{
Paul Brook40905a62009-06-03 15:16:49 +0100906 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000907 uint32_t actss;
908 uint32_t ris;
909 uint32_t im;
910 uint32_t emux;
911 uint32_t ostat;
912 uint32_t ustat;
913 uint32_t sspri;
914 uint32_t sac;
915 struct {
916 uint32_t state;
917 uint32_t data[16];
918 } fifo[4];
919 uint32_t ssmux[4];
920 uint32_t ssctl[4];
pbrook23e39292008-07-02 16:48:32 +0000921 uint32_t noise;
Paul Brook2c6554b2009-06-02 15:30:27 +0100922 qemu_irq irq[4];
pbrook9ee6e8b2007-11-11 00:04:49 +0000923} stellaris_adc_state;
924
925static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
926{
927 int tail;
928
929 tail = s->fifo[n].state & 0xf;
930 if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
931 s->ustat |= 1 << n;
932 } else {
933 s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
934 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
935 if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
936 s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
937 }
938 return s->fifo[n].data[tail];
939}
940
941static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
942 uint32_t value)
943{
944 int head;
945
Paul Brook2c6554b2009-06-02 15:30:27 +0100946 /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry
947 FIFO fir each sequencer. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000948 head = (s->fifo[n].state >> 4) & 0xf;
949 if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
950 s->ostat |= 1 << n;
951 return;
952 }
953 s->fifo[n].data[head] = value;
954 head = (head + 1) & 0xf;
955 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
956 s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
957 if ((s->fifo[n].state & 0xf) == head)
958 s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
959}
960
961static void stellaris_adc_update(stellaris_adc_state *s)
962{
963 int level;
Paul Brook2c6554b2009-06-02 15:30:27 +0100964 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000965
Paul Brook2c6554b2009-06-02 15:30:27 +0100966 for (n = 0; n < 4; n++) {
967 level = (s->ris & s->im & (1 << n)) != 0;
968 qemu_set_irq(s->irq[n], level);
969 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000970}
971
972static void stellaris_adc_trigger(void *opaque, int irq, int level)
973{
974 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
Paul Brook2c6554b2009-06-02 15:30:27 +0100975 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000976
Paul Brook2c6554b2009-06-02 15:30:27 +0100977 for (n = 0; n < 4; n++) {
978 if ((s->actss & (1 << n)) == 0) {
979 continue;
980 }
981
982 if (((s->emux >> (n * 4)) & 0xff) != 5) {
983 continue;
984 }
985
986 /* Some applications use the ADC as a random number source, so introduce
987 some variation into the signal. */
988 s->noise = s->noise * 314159 + 1;
989 /* ??? actual inputs not implemented. Return an arbitrary value. */
990 stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
991 s->ris |= (1 << n);
992 stellaris_adc_update(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000993 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000994}
995
996static void stellaris_adc_reset(stellaris_adc_state *s)
997{
998 int n;
999
1000 for (n = 0; n < 4; n++) {
1001 s->ssmux[n] = 0;
1002 s->ssctl[n] = 0;
1003 s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
1004 }
1005}
1006
Anthony Liguoric227f092009-10-01 16:12:16 -05001007static uint32_t stellaris_adc_read(void *opaque, target_phys_addr_t offset)
pbrook9ee6e8b2007-11-11 00:04:49 +00001008{
1009 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1010
1011 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001012 if (offset >= 0x40 && offset < 0xc0) {
1013 int n;
1014 n = (offset - 0x40) >> 5;
1015 switch (offset & 0x1f) {
1016 case 0x00: /* SSMUX */
1017 return s->ssmux[n];
1018 case 0x04: /* SSCTL */
1019 return s->ssctl[n];
1020 case 0x08: /* SSFIFO */
1021 return stellaris_adc_fifo_read(s, n);
1022 case 0x0c: /* SSFSTAT */
1023 return s->fifo[n].state;
1024 default:
1025 break;
1026 }
1027 }
1028 switch (offset) {
1029 case 0x00: /* ACTSS */
1030 return s->actss;
1031 case 0x04: /* RIS */
1032 return s->ris;
1033 case 0x08: /* IM */
1034 return s->im;
1035 case 0x0c: /* ISC */
1036 return s->ris & s->im;
1037 case 0x10: /* OSTAT */
1038 return s->ostat;
1039 case 0x14: /* EMUX */
1040 return s->emux;
1041 case 0x18: /* USTAT */
1042 return s->ustat;
1043 case 0x20: /* SSPRI */
1044 return s->sspri;
1045 case 0x30: /* SAC */
1046 return s->sac;
1047 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001048 hw_error("strllaris_adc_read: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001049 (int)offset);
1050 return 0;
1051 }
1052}
1053
Anthony Liguoric227f092009-10-01 16:12:16 -05001054static void stellaris_adc_write(void *opaque, target_phys_addr_t offset,
pbrook9ee6e8b2007-11-11 00:04:49 +00001055 uint32_t value)
1056{
1057 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1058
1059 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001060 if (offset >= 0x40 && offset < 0xc0) {
1061 int n;
1062 n = (offset - 0x40) >> 5;
1063 switch (offset & 0x1f) {
1064 case 0x00: /* SSMUX */
1065 s->ssmux[n] = value & 0x33333333;
1066 return;
1067 case 0x04: /* SSCTL */
1068 if (value != 6) {
Paul Brook2ac71172009-05-08 02:35:15 +01001069 hw_error("ADC: Unimplemented sequence %x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001070 value);
1071 }
1072 s->ssctl[n] = value;
1073 return;
1074 default:
1075 break;
1076 }
1077 }
1078 switch (offset) {
1079 case 0x00: /* ACTSS */
1080 s->actss = value & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00001081 break;
1082 case 0x08: /* IM */
1083 s->im = value;
1084 break;
1085 case 0x0c: /* ISC */
1086 s->ris &= ~value;
1087 break;
1088 case 0x10: /* OSTAT */
1089 s->ostat &= ~value;
1090 break;
1091 case 0x14: /* EMUX */
1092 s->emux = value;
1093 break;
1094 case 0x18: /* USTAT */
1095 s->ustat &= ~value;
1096 break;
1097 case 0x20: /* SSPRI */
1098 s->sspri = value;
1099 break;
1100 case 0x28: /* PSSI */
Paul Brook2ac71172009-05-08 02:35:15 +01001101 hw_error("Not implemented: ADC sample initiate\n");
pbrook9ee6e8b2007-11-11 00:04:49 +00001102 break;
1103 case 0x30: /* SAC */
1104 s->sac = value;
1105 break;
1106 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001107 hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00001108 }
1109 stellaris_adc_update(s);
1110}
1111
Blue Swirld60efc62009-08-25 18:29:31 +00001112static CPUReadMemoryFunc * const stellaris_adc_readfn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +00001113 stellaris_adc_read,
1114 stellaris_adc_read,
1115 stellaris_adc_read
1116};
1117
Blue Swirld60efc62009-08-25 18:29:31 +00001118static CPUWriteMemoryFunc * const stellaris_adc_writefn[] = {
pbrook9ee6e8b2007-11-11 00:04:49 +00001119 stellaris_adc_write,
1120 stellaris_adc_write,
1121 stellaris_adc_write
1122};
1123
Juan Quintelacf1d31d2010-12-03 01:27:58 +01001124static const VMStateDescription vmstate_stellaris_adc = {
1125 .name = "stellaris_adc",
1126 .version_id = 1,
1127 .minimum_version_id = 1,
1128 .minimum_version_id_old = 1,
1129 .fields = (VMStateField[]) {
1130 VMSTATE_UINT32(actss, stellaris_adc_state),
1131 VMSTATE_UINT32(ris, stellaris_adc_state),
1132 VMSTATE_UINT32(im, stellaris_adc_state),
1133 VMSTATE_UINT32(emux, stellaris_adc_state),
1134 VMSTATE_UINT32(ostat, stellaris_adc_state),
1135 VMSTATE_UINT32(ustat, stellaris_adc_state),
1136 VMSTATE_UINT32(sspri, stellaris_adc_state),
1137 VMSTATE_UINT32(sac, stellaris_adc_state),
1138 VMSTATE_UINT32(fifo[0].state, stellaris_adc_state),
1139 VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16),
1140 VMSTATE_UINT32(ssmux[0], stellaris_adc_state),
1141 VMSTATE_UINT32(ssctl[0], stellaris_adc_state),
1142 VMSTATE_UINT32(fifo[1].state, stellaris_adc_state),
1143 VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16),
1144 VMSTATE_UINT32(ssmux[1], stellaris_adc_state),
1145 VMSTATE_UINT32(ssctl[1], stellaris_adc_state),
1146 VMSTATE_UINT32(fifo[2].state, stellaris_adc_state),
1147 VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16),
1148 VMSTATE_UINT32(ssmux[2], stellaris_adc_state),
1149 VMSTATE_UINT32(ssctl[2], stellaris_adc_state),
1150 VMSTATE_UINT32(fifo[3].state, stellaris_adc_state),
1151 VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16),
1152 VMSTATE_UINT32(ssmux[3], stellaris_adc_state),
1153 VMSTATE_UINT32(ssctl[3], stellaris_adc_state),
1154 VMSTATE_UINT32(noise, stellaris_adc_state),
1155 VMSTATE_END_OF_LIST()
pbrook23e39292008-07-02 16:48:32 +00001156 }
Juan Quintelacf1d31d2010-12-03 01:27:58 +01001157};
pbrook23e39292008-07-02 16:48:32 +00001158
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001159static int stellaris_adc_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +00001160{
Paul Brook40905a62009-06-03 15:16:49 +01001161 stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +00001162 int iomemtype;
Paul Brook2c6554b2009-06-02 15:30:27 +01001163 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +00001164
Paul Brook2c6554b2009-06-02 15:30:27 +01001165 for (n = 0; n < 4; n++) {
Paul Brook40905a62009-06-03 15:16:49 +01001166 sysbus_init_irq(dev, &s->irq[n]);
Paul Brook2c6554b2009-06-02 15:30:27 +01001167 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001168
Avi Kivity1eed09c2009-06-14 11:38:51 +03001169 iomemtype = cpu_register_io_memory(stellaris_adc_readfn,
Alexander Graf2507c122010-12-08 12:05:37 +01001170 stellaris_adc_writefn, s,
1171 DEVICE_NATIVE_ENDIAN);
Paul Brook40905a62009-06-03 15:16:49 +01001172 sysbus_init_mmio(dev, 0x1000, iomemtype);
pbrook9ee6e8b2007-11-11 00:04:49 +00001173 stellaris_adc_reset(s);
Paul Brook40905a62009-06-03 15:16:49 +01001174 qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
Juan Quintelacf1d31d2010-12-03 01:27:58 +01001175 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001176 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00001177}
1178
pbrook775616c2007-11-24 23:35:08 +00001179/* Some boards have both an OLED controller and SD card connected to
1180 the same SSI port, with the SD card chip select connected to a
1181 GPIO pin. Technically the OLED chip select is connected to the SSI
1182 Fss pin. We do not bother emulating that as both devices should
1183 never be selected simultaneously, and our OLED controller ignores stray
1184 0xff commands that occur when deselecting the SD card. */
1185
1186typedef struct {
Paul Brook5493e332009-05-14 22:35:09 +01001187 SSISlave ssidev;
pbrook775616c2007-11-24 23:35:08 +00001188 qemu_irq irq;
1189 int current_dev;
Paul Brook5493e332009-05-14 22:35:09 +01001190 SSIBus *bus[2];
pbrook775616c2007-11-24 23:35:08 +00001191} stellaris_ssi_bus_state;
1192
1193static void stellaris_ssi_bus_select(void *opaque, int irq, int level)
1194{
1195 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1196
1197 s->current_dev = level;
1198}
1199
Paul Brook5493e332009-05-14 22:35:09 +01001200static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
pbrook775616c2007-11-24 23:35:08 +00001201{
Paul Brook5493e332009-05-14 22:35:09 +01001202 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001203
Paul Brook5493e332009-05-14 22:35:09 +01001204 return ssi_transfer(s->bus[s->current_dev], val);
pbrook775616c2007-11-24 23:35:08 +00001205}
1206
Juan Quintelaa4dec1d2010-12-02 02:51:29 +01001207static const VMStateDescription vmstate_stellaris_ssi_bus = {
1208 .name = "stellaris_ssi_bus",
1209 .version_id = 1,
1210 .minimum_version_id = 1,
1211 .minimum_version_id_old = 1,
1212 .fields = (VMStateField[]) {
1213 VMSTATE_INT32(current_dev, stellaris_ssi_bus_state),
1214 VMSTATE_END_OF_LIST()
1215 }
1216};
pbrook23e39292008-07-02 16:48:32 +00001217
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001218static int stellaris_ssi_bus_init(SSISlave *dev)
pbrook775616c2007-11-24 23:35:08 +00001219{
Paul Brook5493e332009-05-14 22:35:09 +01001220 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001221
Paul Brook02e2da42009-05-23 00:05:19 +01001222 s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
1223 s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
Paul Brook5493e332009-05-14 22:35:09 +01001224 qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
1225
Juan Quintelaa4dec1d2010-12-02 02:51:29 +01001226 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001227 return 0;
pbrook775616c2007-11-24 23:35:08 +00001228}
1229
pbrook9ee6e8b2007-11-11 00:04:49 +00001230/* Board init. */
1231static stellaris_board_info stellaris_boards[] = {
1232 { "LM3S811EVB",
1233 0,
1234 0x0032000e,
1235 0x001f001f, /* dc0 */
1236 0x001132bf,
1237 0x01071013,
1238 0x3f0f01ff,
1239 0x0000001f,
pbrookcf0dbb22007-11-18 14:36:08 +00001240 BP_OLED_I2C
pbrook9ee6e8b2007-11-11 00:04:49 +00001241 },
1242 { "LM3S6965EVB",
1243 0x10010002,
1244 0x1073402e,
1245 0x00ff007f, /* dc0 */
1246 0x001133ff,
1247 0x030f5317,
1248 0x0f0f87ff,
1249 0x5000007f,
pbrookcf0dbb22007-11-18 14:36:08 +00001250 BP_OLED_SSI | BP_GAMEPAD
pbrook9ee6e8b2007-11-11 00:04:49 +00001251 }
1252};
1253
1254static void stellaris_init(const char *kernel_filename, const char *cpu_model,
aliguori3023f332009-01-16 19:04:14 +00001255 stellaris_board_info *board)
pbrook9ee6e8b2007-11-11 00:04:49 +00001256{
1257 static const int uart_irq[] = {5, 6, 33, 34};
1258 static const int timer_irq[] = {19, 21, 23, 35};
1259 static const uint32_t gpio_addr[7] =
1260 { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
1261 0x40024000, 0x40025000, 0x40026000};
1262 static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
1263
Avi Kivity7d6f78c2011-07-25 14:27:01 +03001264 MemoryRegion *address_space_mem = get_system_memory();
pbrook9ee6e8b2007-11-11 00:04:49 +00001265 qemu_irq *pic;
Paul Brook40905a62009-06-03 15:16:49 +01001266 DeviceState *gpio_dev[7];
1267 qemu_irq gpio_in[7][8];
1268 qemu_irq gpio_out[7][8];
pbrook9ee6e8b2007-11-11 00:04:49 +00001269 qemu_irq adc;
1270 int sram_size;
1271 int flash_size;
1272 i2c_bus *i2c;
Paul Brook40905a62009-06-03 15:16:49 +01001273 DeviceState *dev;
pbrook9ee6e8b2007-11-11 00:04:49 +00001274 int i;
Paul Brook40905a62009-06-03 15:16:49 +01001275 int j;
pbrook9ee6e8b2007-11-11 00:04:49 +00001276
1277 flash_size = ((board->dc0 & 0xffff) + 1) << 1;
1278 sram_size = (board->dc0 >> 18) + 1;
Avi Kivity7d6f78c2011-07-25 14:27:01 +03001279 pic = armv7m_init(address_space_mem,
1280 flash_size, sram_size, kernel_filename, cpu_model);
pbrook9ee6e8b2007-11-11 00:04:49 +00001281
1282 if (board->dc1 & (1 << 16)) {
Paul Brook40905a62009-06-03 15:16:49 +01001283 dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
1284 pic[14], pic[15], pic[16], pic[17], NULL);
1285 adc = qdev_get_gpio_in(dev, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00001286 } else {
1287 adc = NULL;
1288 }
1289 for (i = 0; i < 4; i++) {
1290 if (board->dc2 & (0x10000 << i)) {
Paul Brook40905a62009-06-03 15:16:49 +01001291 dev = sysbus_create_simple("stellaris-gptm",
1292 0x40030000 + i * 0x1000,
1293 pic[timer_irq[i]]);
1294 /* TODO: This is incorrect, but we get away with it because
1295 the ADC output is only ever pulsed. */
1296 qdev_connect_gpio_out(dev, 0, adc);
pbrook9ee6e8b2007-11-11 00:04:49 +00001297 }
1298 }
1299
Jan Kiszka6eed1852011-07-20 12:20:22 +02001300 stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a);
pbrook9ee6e8b2007-11-11 00:04:49 +00001301
1302 for (i = 0; i < 7; i++) {
1303 if (board->dc4 & (1 << i)) {
Peter Maydell7063f492011-02-21 20:57:51 +00001304 gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
Paul Brook40905a62009-06-03 15:16:49 +01001305 pic[gpio_irq[i]]);
1306 for (j = 0; j < 8; j++) {
1307 gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
1308 gpio_out[i][j] = NULL;
1309 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001310 }
1311 }
1312
1313 if (board->dc2 & (1 << 12)) {
Paul Brook1de96102009-05-14 22:35:09 +01001314 dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
Paul Brook02e2da42009-05-23 00:05:19 +01001315 i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
pbrookcf0dbb22007-11-18 14:36:08 +00001316 if (board->peripherals & BP_OLED_I2C) {
Paul Brookd2199002009-05-14 22:35:08 +01001317 i2c_create_slave(i2c, "ssd0303", 0x3d);
pbrook9ee6e8b2007-11-11 00:04:49 +00001318 }
1319 }
1320
1321 for (i = 0; i < 4; i++) {
1322 if (board->dc2 & (1 << i)) {
Paul Brooka7d518a2009-05-14 22:35:07 +01001323 sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
1324 pic[uart_irq[i]]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001325 }
1326 }
1327 if (board->dc2 & (1 << 4)) {
Paul Brook5493e332009-05-14 22:35:09 +01001328 dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
pbrookcf0dbb22007-11-18 14:36:08 +00001329 if (board->peripherals & BP_OLED_SSI) {
Paul Brook5493e332009-05-14 22:35:09 +01001330 DeviceState *mux;
1331 void *bus;
pbrook775616c2007-11-24 23:35:08 +00001332
Paul Brook5493e332009-05-14 22:35:09 +01001333 bus = qdev_get_child_bus(dev, "ssi");
1334 mux = ssi_create_slave(bus, "evb6965-ssi");
1335 gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
pbrook775616c2007-11-24 23:35:08 +00001336
Paul Brook5493e332009-05-14 22:35:09 +01001337 bus = qdev_get_child_bus(mux, "ssi0");
Blue Swirl22ed1d342010-04-25 19:31:06 +00001338 ssi_create_slave(bus, "ssi-sd");
pbrook775616c2007-11-24 23:35:08 +00001339
Paul Brook5493e332009-05-14 22:35:09 +01001340 bus = qdev_get_child_bus(mux, "ssi1");
1341 dev = ssi_create_slave(bus, "ssd0323");
1342 gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
1343
pbrook775616c2007-11-24 23:35:08 +00001344 /* Make sure the select pin is high. */
1345 qemu_irq_raise(gpio_out[GPIO_D][0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001346 }
1347 }
Paul Brooka5580462009-05-14 22:35:07 +01001348 if (board->dc4 & (1 << 28)) {
1349 DeviceState *enet;
1350
1351 qemu_check_nic_model(&nd_table[0], "stellaris");
1352
1353 enet = qdev_create(NULL, "stellaris_enet");
Gerd Hoffmann540f0062009-10-21 15:25:39 +02001354 qdev_set_nic_properties(enet, &nd_table[0]);
Markus Armbrustere23a1b32009-10-07 01:15:58 +02001355 qdev_init_nofail(enet);
Paul Brooka5580462009-05-14 22:35:07 +01001356 sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000);
1357 sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]);
1358 }
pbrookcf0dbb22007-11-18 14:36:08 +00001359 if (board->peripherals & BP_GAMEPAD) {
1360 qemu_irq gpad_irq[5];
1361 static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
1362
1363 gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
1364 gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
1365 gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
1366 gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
1367 gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
1368
1369 stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
1370 }
Paul Brook40905a62009-06-03 15:16:49 +01001371 for (i = 0; i < 7; i++) {
1372 if (board->dc4 & (1 << i)) {
1373 for (j = 0; j < 8; j++) {
1374 if (gpio_out[i][j]) {
1375 qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
1376 }
1377 }
1378 }
1379 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001380}
1381
1382/* FIXME: Figure out how to generate these from stellaris_boards. */
Anthony Liguoric227f092009-10-01 16:12:16 -05001383static void lm3s811evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001384 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001385 const char *kernel_filename, const char *kernel_cmdline,
1386 const char *initrd_filename, const char *cpu_model)
1387{
aliguori3023f332009-01-16 19:04:14 +00001388 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001389}
1390
Anthony Liguoric227f092009-10-01 16:12:16 -05001391static void lm3s6965evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001392 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001393 const char *kernel_filename, const char *kernel_cmdline,
1394 const char *initrd_filename, const char *cpu_model)
1395{
aliguori3023f332009-01-16 19:04:14 +00001396 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001397}
1398
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001399static QEMUMachine lm3s811evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001400 .name = "lm3s811evb",
1401 .desc = "Stellaris LM3S811EVB",
1402 .init = lm3s811evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001403};
1404
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001405static QEMUMachine lm3s6965evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001406 .name = "lm3s6965evb",
1407 .desc = "Stellaris LM3S6965EVB",
1408 .init = lm3s6965evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001409};
Paul Brook1de96102009-05-14 22:35:09 +01001410
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001411static void stellaris_machine_init(void)
1412{
1413 qemu_register_machine(&lm3s811evb_machine);
1414 qemu_register_machine(&lm3s6965evb_machine);
1415}
1416
1417machine_init(stellaris_machine_init);
1418
Paul Brook5493e332009-05-14 22:35:09 +01001419static SSISlaveInfo stellaris_ssi_bus_info = {
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +02001420 .qdev.name = "evb6965-ssi",
1421 .qdev.size = sizeof(stellaris_ssi_bus_state),
Paul Brook5493e332009-05-14 22:35:09 +01001422 .init = stellaris_ssi_bus_init,
1423 .transfer = stellaris_ssi_bus_transfer
1424};
1425
Paul Brook1de96102009-05-14 22:35:09 +01001426static void stellaris_register_devices(void)
1427{
1428 sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
1429 stellaris_i2c_init);
Paul Brook40905a62009-06-03 15:16:49 +01001430 sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
1431 stellaris_gptm_init);
1432 sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state),
1433 stellaris_adc_init);
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +02001434 ssi_register_slave(&stellaris_ssi_bus_info);
Paul Brook1de96102009-05-14 22:35:09 +01001435}
1436
1437device_init(stellaris_register_devices)