blob: 562fbbf4943dce2092ff4831b98bfaf5063ae8e1 [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;
Benoît Canet2443fa22011-10-17 17:28:32 +020048 MemoryRegion iomem;
pbrook9ee6e8b2007-11-11 00:04:49 +000049 uint32_t config;
50 uint32_t mode[2];
51 uint32_t control;
52 uint32_t state;
53 uint32_t mask;
54 uint32_t load[2];
55 uint32_t match[2];
56 uint32_t prescale[2];
57 uint32_t match_prescale[2];
58 uint32_t rtc;
59 int64_t tick[2];
60 struct gptm_state *opaque[2];
pbrook9ee6e8b2007-11-11 00:04:49 +000061 QEMUTimer *timer[2];
62 /* The timers have an alternate output used to trigger the ADC. */
63 qemu_irq trigger;
64 qemu_irq irq;
65} gptm_state;
66
67static void gptm_update_irq(gptm_state *s)
68{
69 int level;
70 level = (s->state & s->mask) != 0;
71 qemu_set_irq(s->irq, level);
72}
73
74static void gptm_stop(gptm_state *s, int n)
75{
76 qemu_del_timer(s->timer[n]);
77}
78
79static void gptm_reload(gptm_state *s, int n, int reset)
80{
81 int64_t tick;
82 if (reset)
Paolo Bonzini74475452011-03-11 16:47:48 +010083 tick = qemu_get_clock_ns(vm_clock);
pbrook9ee6e8b2007-11-11 00:04:49 +000084 else
85 tick = s->tick[n];
86
87 if (s->config == 0) {
88 /* 32-bit CountDown. */
89 uint32_t count;
90 count = s->load[0] | (s->load[1] << 16);
pbrooke57ec012007-11-24 03:09:07 +000091 tick += (int64_t)count * system_clock_scale;
pbrook9ee6e8b2007-11-11 00:04:49 +000092 } else if (s->config == 1) {
93 /* 32-bit RTC. 1Hz tick. */
Juan Quintela6ee093c2009-09-10 03:04:26 +020094 tick += get_ticks_per_sec();
pbrook9ee6e8b2007-11-11 00:04:49 +000095 } else if (s->mode[n] == 0xa) {
96 /* PWM mode. Not implemented. */
97 } else {
Paul Brook2ac71172009-05-08 02:35:15 +010098 hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
pbrook9ee6e8b2007-11-11 00:04:49 +000099 }
100 s->tick[n] = tick;
101 qemu_mod_timer(s->timer[n], tick);
102}
103
104static void gptm_tick(void *opaque)
105{
106 gptm_state **p = (gptm_state **)opaque;
107 gptm_state *s;
108 int n;
109
110 s = *p;
111 n = p - s->opaque;
112 if (s->config == 0) {
113 s->state |= 1;
114 if ((s->control & 0x20)) {
115 /* Output trigger. */
Paul Brook40905a62009-06-03 15:16:49 +0100116 qemu_irq_pulse(s->trigger);
pbrook9ee6e8b2007-11-11 00:04:49 +0000117 }
118 if (s->mode[0] & 1) {
119 /* One-shot. */
120 s->control &= ~1;
121 } else {
122 /* Periodic. */
123 gptm_reload(s, 0, 0);
124 }
125 } else if (s->config == 1) {
126 /* RTC. */
127 uint32_t match;
128 s->rtc++;
129 match = s->match[0] | (s->match[1] << 16);
130 if (s->rtc > match)
131 s->rtc = 0;
132 if (s->rtc == 0) {
133 s->state |= 8;
134 }
135 gptm_reload(s, 0, 0);
136 } else if (s->mode[n] == 0xa) {
137 /* PWM mode. Not implemented. */
138 } else {
Paul Brook2ac71172009-05-08 02:35:15 +0100139 hw_error("TODO: 16-bit timer mode 0x%x\n", s->mode[n]);
pbrook9ee6e8b2007-11-11 00:04:49 +0000140 }
141 gptm_update_irq(s);
142}
143
Benoît Canet2443fa22011-10-17 17:28:32 +0200144static uint64_t gptm_read(void *opaque, target_phys_addr_t offset,
145 unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000146{
147 gptm_state *s = (gptm_state *)opaque;
148
pbrook9ee6e8b2007-11-11 00:04:49 +0000149 switch (offset) {
150 case 0x00: /* CFG */
151 return s->config;
152 case 0x04: /* TAMR */
153 return s->mode[0];
154 case 0x08: /* TBMR */
155 return s->mode[1];
156 case 0x0c: /* CTL */
157 return s->control;
158 case 0x18: /* IMR */
159 return s->mask;
160 case 0x1c: /* RIS */
161 return s->state;
162 case 0x20: /* MIS */
163 return s->state & s->mask;
164 case 0x24: /* CR */
165 return 0;
166 case 0x28: /* TAILR */
167 return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0);
168 case 0x2c: /* TBILR */
169 return s->load[1];
170 case 0x30: /* TAMARCHR */
171 return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0);
172 case 0x34: /* TBMATCHR */
173 return s->match[1];
174 case 0x38: /* TAPR */
175 return s->prescale[0];
176 case 0x3c: /* TBPR */
177 return s->prescale[1];
178 case 0x40: /* TAPMR */
179 return s->match_prescale[0];
180 case 0x44: /* TBPMR */
181 return s->match_prescale[1];
182 case 0x48: /* TAR */
183 if (s->control == 1)
184 return s->rtc;
185 case 0x4c: /* TBR */
Paul Brook2ac71172009-05-08 02:35:15 +0100186 hw_error("TODO: Timer value read\n");
pbrook9ee6e8b2007-11-11 00:04:49 +0000187 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100188 hw_error("gptm_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000189 return 0;
190 }
191}
192
Benoît Canet2443fa22011-10-17 17:28:32 +0200193static void gptm_write(void *opaque, target_phys_addr_t offset,
194 uint64_t value, unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000195{
196 gptm_state *s = (gptm_state *)opaque;
197 uint32_t oldval;
198
pbrook9ee6e8b2007-11-11 00:04:49 +0000199 /* The timers should be disabled before changing the configuration.
200 We take advantage of this and defer everything until the timer
201 is enabled. */
202 switch (offset) {
203 case 0x00: /* CFG */
204 s->config = value;
205 break;
206 case 0x04: /* TAMR */
207 s->mode[0] = value;
208 break;
209 case 0x08: /* TBMR */
210 s->mode[1] = value;
211 break;
212 case 0x0c: /* CTL */
213 oldval = s->control;
214 s->control = value;
215 /* TODO: Implement pause. */
216 if ((oldval ^ value) & 1) {
217 if (value & 1) {
218 gptm_reload(s, 0, 1);
219 } else {
220 gptm_stop(s, 0);
221 }
222 }
223 if (((oldval ^ value) & 0x100) && s->config >= 4) {
224 if (value & 0x100) {
225 gptm_reload(s, 1, 1);
226 } else {
227 gptm_stop(s, 1);
228 }
229 }
230 break;
231 case 0x18: /* IMR */
232 s->mask = value & 0x77;
233 gptm_update_irq(s);
234 break;
235 case 0x24: /* CR */
236 s->state &= ~value;
237 break;
238 case 0x28: /* TAILR */
239 s->load[0] = value & 0xffff;
240 if (s->config < 4) {
241 s->load[1] = value >> 16;
242 }
243 break;
244 case 0x2c: /* TBILR */
245 s->load[1] = value & 0xffff;
246 break;
247 case 0x30: /* TAMARCHR */
248 s->match[0] = value & 0xffff;
249 if (s->config < 4) {
250 s->match[1] = value >> 16;
251 }
252 break;
253 case 0x34: /* TBMATCHR */
254 s->match[1] = value >> 16;
255 break;
256 case 0x38: /* TAPR */
257 s->prescale[0] = value;
258 break;
259 case 0x3c: /* TBPR */
260 s->prescale[1] = value;
261 break;
262 case 0x40: /* TAPMR */
263 s->match_prescale[0] = value;
264 break;
265 case 0x44: /* TBPMR */
266 s->match_prescale[0] = value;
267 break;
268 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100269 hw_error("gptm_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000270 }
271 gptm_update_irq(s);
272}
273
Benoît Canet2443fa22011-10-17 17:28:32 +0200274static const MemoryRegionOps gptm_ops = {
275 .read = gptm_read,
276 .write = gptm_write,
277 .endianness = DEVICE_NATIVE_ENDIAN,
pbrook9ee6e8b2007-11-11 00:04:49 +0000278};
279
Juan Quintela10f85a22010-12-02 14:07:01 +0100280static const VMStateDescription vmstate_stellaris_gptm = {
281 .name = "stellaris_gptm",
282 .version_id = 1,
283 .minimum_version_id = 1,
284 .minimum_version_id_old = 1,
285 .fields = (VMStateField[]) {
286 VMSTATE_UINT32(config, gptm_state),
287 VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
288 VMSTATE_UINT32(control, gptm_state),
289 VMSTATE_UINT32(state, gptm_state),
290 VMSTATE_UINT32(mask, gptm_state),
Juan Quinteladd8a4dc2010-12-02 14:07:44 +0100291 VMSTATE_UNUSED(8),
Juan Quintela10f85a22010-12-02 14:07:01 +0100292 VMSTATE_UINT32_ARRAY(load, gptm_state, 2),
293 VMSTATE_UINT32_ARRAY(match, gptm_state, 2),
294 VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2),
295 VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2),
296 VMSTATE_UINT32(rtc, gptm_state),
297 VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
298 VMSTATE_TIMER_ARRAY(timer, gptm_state, 2),
299 VMSTATE_END_OF_LIST()
300 }
301};
pbrook23e39292008-07-02 16:48:32 +0000302
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200303static int stellaris_gptm_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000304{
Paul Brook40905a62009-06-03 15:16:49 +0100305 gptm_state *s = FROM_SYSBUS(gptm_state, dev);
pbrook9ee6e8b2007-11-11 00:04:49 +0000306
Paul Brook40905a62009-06-03 15:16:49 +0100307 sysbus_init_irq(dev, &s->irq);
308 qdev_init_gpio_out(&dev->qdev, &s->trigger, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +0000309
Benoît Canet2443fa22011-10-17 17:28:32 +0200310 memory_region_init_io(&s->iomem, &gptm_ops, s,
311 "gptm", 0x1000);
Avi Kivity750ecd42011-11-27 11:38:10 +0200312 sysbus_init_mmio(dev, &s->iomem);
Paul Brook40905a62009-06-03 15:16:49 +0100313
314 s->opaque[0] = s->opaque[1] = s;
Paolo Bonzini74475452011-03-11 16:47:48 +0100315 s->timer[0] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[0]);
316 s->timer[1] = qemu_new_timer_ns(vm_clock, gptm_tick, &s->opaque[1]);
Juan Quintela10f85a22010-12-02 14:07:01 +0100317 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_gptm, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200318 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000319}
320
321
322/* System controller. */
323
324typedef struct {
Benoît Canet56993012011-10-17 17:28:29 +0200325 MemoryRegion iomem;
pbrook9ee6e8b2007-11-11 00:04:49 +0000326 uint32_t pborctl;
327 uint32_t ldopctl;
328 uint32_t int_status;
329 uint32_t int_mask;
330 uint32_t resc;
331 uint32_t rcc;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100332 uint32_t rcc2;
pbrook9ee6e8b2007-11-11 00:04:49 +0000333 uint32_t rcgc[3];
334 uint32_t scgc[3];
335 uint32_t dcgc[3];
336 uint32_t clkvclr;
337 uint32_t ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000338 uint32_t user0;
339 uint32_t user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000340 qemu_irq irq;
341 stellaris_board_info *board;
342} ssys_state;
343
344static void ssys_update(ssys_state *s)
345{
346 qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
347}
348
349static uint32_t pllcfg_sandstorm[16] = {
350 0x31c0, /* 1 Mhz */
351 0x1ae0, /* 1.8432 Mhz */
352 0x18c0, /* 2 Mhz */
353 0xd573, /* 2.4576 Mhz */
354 0x37a6, /* 3.57954 Mhz */
355 0x1ae2, /* 3.6864 Mhz */
356 0x0c40, /* 4 Mhz */
357 0x98bc, /* 4.906 Mhz */
358 0x935b, /* 4.9152 Mhz */
359 0x09c0, /* 5 Mhz */
360 0x4dee, /* 5.12 Mhz */
361 0x0c41, /* 6 Mhz */
362 0x75db, /* 6.144 Mhz */
363 0x1ae6, /* 7.3728 Mhz */
364 0x0600, /* 8 Mhz */
365 0x585b /* 8.192 Mhz */
366};
367
368static uint32_t pllcfg_fury[16] = {
369 0x3200, /* 1 Mhz */
370 0x1b20, /* 1.8432 Mhz */
371 0x1900, /* 2 Mhz */
372 0xf42b, /* 2.4576 Mhz */
373 0x37e3, /* 3.57954 Mhz */
374 0x1b21, /* 3.6864 Mhz */
375 0x0c80, /* 4 Mhz */
376 0x98ee, /* 4.906 Mhz */
377 0xd5b4, /* 4.9152 Mhz */
378 0x0a00, /* 5 Mhz */
379 0x4e27, /* 5.12 Mhz */
380 0x1902, /* 6 Mhz */
381 0xec1c, /* 6.144 Mhz */
382 0x1b23, /* 7.3728 Mhz */
383 0x0640, /* 8 Mhz */
384 0xb11c /* 8.192 Mhz */
385};
386
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100387#define DID0_VER_MASK 0x70000000
388#define DID0_VER_0 0x00000000
389#define DID0_VER_1 0x10000000
390
391#define DID0_CLASS_MASK 0x00FF0000
392#define DID0_CLASS_SANDSTORM 0x00000000
393#define DID0_CLASS_FURY 0x00010000
394
395static int ssys_board_class(const ssys_state *s)
396{
397 uint32_t did0 = s->board->did0;
398 switch (did0 & DID0_VER_MASK) {
399 case DID0_VER_0:
400 return DID0_CLASS_SANDSTORM;
401 case DID0_VER_1:
402 switch (did0 & DID0_CLASS_MASK) {
403 case DID0_CLASS_SANDSTORM:
404 case DID0_CLASS_FURY:
405 return did0 & DID0_CLASS_MASK;
406 }
407 /* for unknown classes, fall through */
408 default:
409 hw_error("ssys_board_class: Unknown class 0x%08x\n", did0);
410 }
411}
412
Benoît Canet56993012011-10-17 17:28:29 +0200413static uint64_t ssys_read(void *opaque, target_phys_addr_t offset,
414 unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000415{
416 ssys_state *s = (ssys_state *)opaque;
417
pbrook9ee6e8b2007-11-11 00:04:49 +0000418 switch (offset) {
419 case 0x000: /* DID0 */
420 return s->board->did0;
421 case 0x004: /* DID1 */
422 return s->board->did1;
423 case 0x008: /* DC0 */
424 return s->board->dc0;
425 case 0x010: /* DC1 */
426 return s->board->dc1;
427 case 0x014: /* DC2 */
428 return s->board->dc2;
429 case 0x018: /* DC3 */
430 return s->board->dc3;
431 case 0x01c: /* DC4 */
432 return s->board->dc4;
433 case 0x030: /* PBORCTL */
434 return s->pborctl;
435 case 0x034: /* LDOPCTL */
436 return s->ldopctl;
437 case 0x040: /* SRCR0 */
438 return 0;
439 case 0x044: /* SRCR1 */
440 return 0;
441 case 0x048: /* SRCR2 */
442 return 0;
443 case 0x050: /* RIS */
444 return s->int_status;
445 case 0x054: /* IMC */
446 return s->int_mask;
447 case 0x058: /* MISC */
448 return s->int_status & s->int_mask;
449 case 0x05c: /* RESC */
450 return s->resc;
451 case 0x060: /* RCC */
452 return s->rcc;
453 case 0x064: /* PLLCFG */
454 {
455 int xtal;
456 xtal = (s->rcc >> 6) & 0xf;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100457 switch (ssys_board_class(s)) {
458 case DID0_CLASS_FURY:
pbrook9ee6e8b2007-11-11 00:04:49 +0000459 return pllcfg_fury[xtal];
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100460 case DID0_CLASS_SANDSTORM:
pbrook9ee6e8b2007-11-11 00:04:49 +0000461 return pllcfg_sandstorm[xtal];
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100462 default:
463 hw_error("ssys_read: Unhandled class for PLLCFG read.\n");
464 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000465 }
466 }
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100467 case 0x070: /* RCC2 */
468 return s->rcc2;
pbrook9ee6e8b2007-11-11 00:04:49 +0000469 case 0x100: /* RCGC0 */
470 return s->rcgc[0];
471 case 0x104: /* RCGC1 */
472 return s->rcgc[1];
473 case 0x108: /* RCGC2 */
474 return s->rcgc[2];
475 case 0x110: /* SCGC0 */
476 return s->scgc[0];
477 case 0x114: /* SCGC1 */
478 return s->scgc[1];
479 case 0x118: /* SCGC2 */
480 return s->scgc[2];
481 case 0x120: /* DCGC0 */
482 return s->dcgc[0];
483 case 0x124: /* DCGC1 */
484 return s->dcgc[1];
485 case 0x128: /* DCGC2 */
486 return s->dcgc[2];
487 case 0x150: /* CLKVCLR */
488 return s->clkvclr;
489 case 0x160: /* LDOARST */
490 return s->ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000491 case 0x1e0: /* USER0 */
492 return s->user0;
493 case 0x1e4: /* USER1 */
494 return s->user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000495 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100496 hw_error("ssys_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000497 return 0;
498 }
499}
500
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100501static bool ssys_use_rcc2(ssys_state *s)
502{
503 return (s->rcc2 >> 31) & 0x1;
504}
505
506/*
507 * Caculate the sys. clock period in ms.
508 */
pbrook23e39292008-07-02 16:48:32 +0000509static void ssys_calculate_system_clock(ssys_state *s)
510{
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100511 if (ssys_use_rcc2(s)) {
512 system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
513 } else {
514 system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
515 }
pbrook23e39292008-07-02 16:48:32 +0000516}
517
Benoît Canet56993012011-10-17 17:28:29 +0200518static void ssys_write(void *opaque, target_phys_addr_t offset,
519 uint64_t value, unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000520{
521 ssys_state *s = (ssys_state *)opaque;
522
pbrook9ee6e8b2007-11-11 00:04:49 +0000523 switch (offset) {
524 case 0x030: /* PBORCTL */
525 s->pborctl = value & 0xffff;
526 break;
527 case 0x034: /* LDOPCTL */
528 s->ldopctl = value & 0x1f;
529 break;
530 case 0x040: /* SRCR0 */
531 case 0x044: /* SRCR1 */
532 case 0x048: /* SRCR2 */
533 fprintf(stderr, "Peripheral reset not implemented\n");
534 break;
535 case 0x054: /* IMC */
536 s->int_mask = value & 0x7f;
537 break;
538 case 0x058: /* MISC */
539 s->int_status &= ~value;
540 break;
541 case 0x05c: /* RESC */
542 s->resc = value & 0x3f;
543 break;
544 case 0x060: /* RCC */
545 if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
546 /* PLL enable. */
547 s->int_status |= (1 << 6);
548 }
549 s->rcc = value;
pbrook23e39292008-07-02 16:48:32 +0000550 ssys_calculate_system_clock(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000551 break;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100552 case 0x070: /* RCC2 */
553 if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
554 break;
555 }
556
557 if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
558 /* PLL enable. */
559 s->int_status |= (1 << 6);
560 }
561 s->rcc2 = value;
562 ssys_calculate_system_clock(s);
563 break;
pbrook9ee6e8b2007-11-11 00:04:49 +0000564 case 0x100: /* RCGC0 */
565 s->rcgc[0] = value;
566 break;
567 case 0x104: /* RCGC1 */
568 s->rcgc[1] = value;
569 break;
570 case 0x108: /* RCGC2 */
571 s->rcgc[2] = value;
572 break;
573 case 0x110: /* SCGC0 */
574 s->scgc[0] = value;
575 break;
576 case 0x114: /* SCGC1 */
577 s->scgc[1] = value;
578 break;
579 case 0x118: /* SCGC2 */
580 s->scgc[2] = value;
581 break;
582 case 0x120: /* DCGC0 */
583 s->dcgc[0] = value;
584 break;
585 case 0x124: /* DCGC1 */
586 s->dcgc[1] = value;
587 break;
588 case 0x128: /* DCGC2 */
589 s->dcgc[2] = value;
590 break;
591 case 0x150: /* CLKVCLR */
592 s->clkvclr = value;
593 break;
594 case 0x160: /* LDOARST */
595 s->ldoarst = value;
596 break;
597 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100598 hw_error("ssys_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000599 }
600 ssys_update(s);
601}
602
Benoît Canet56993012011-10-17 17:28:29 +0200603static const MemoryRegionOps ssys_ops = {
604 .read = ssys_read,
605 .write = ssys_write,
606 .endianness = DEVICE_NATIVE_ENDIAN,
pbrook9ee6e8b2007-11-11 00:04:49 +0000607};
608
pbrook9596ebb2007-11-18 01:44:38 +0000609static void ssys_reset(void *opaque)
pbrook9ee6e8b2007-11-11 00:04:49 +0000610{
611 ssys_state *s = (ssys_state *)opaque;
612
613 s->pborctl = 0x7ffd;
614 s->rcc = 0x078e3ac0;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100615
616 if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
617 s->rcc2 = 0;
618 } else {
619 s->rcc2 = 0x07802810;
620 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000621 s->rcgc[0] = 1;
622 s->scgc[0] = 1;
623 s->dcgc[0] = 1;
Peter Maydellbfc213a2011-12-15 18:58:26 +0000624 ssys_calculate_system_clock(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000625}
626
Juan Quintela293c16a2010-12-02 03:03:11 +0100627static int stellaris_sys_post_load(void *opaque, int version_id)
pbrook23e39292008-07-02 16:48:32 +0000628{
Juan Quintela293c16a2010-12-02 03:03:11 +0100629 ssys_state *s = opaque;
pbrook23e39292008-07-02 16:48:32 +0000630
pbrook23e39292008-07-02 16:48:32 +0000631 ssys_calculate_system_clock(s);
632
633 return 0;
634}
635
Juan Quintela293c16a2010-12-02 03:03:11 +0100636static const VMStateDescription vmstate_stellaris_sys = {
637 .name = "stellaris_sys",
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100638 .version_id = 2,
Juan Quintela293c16a2010-12-02 03:03:11 +0100639 .minimum_version_id = 1,
640 .minimum_version_id_old = 1,
641 .post_load = stellaris_sys_post_load,
642 .fields = (VMStateField[]) {
643 VMSTATE_UINT32(pborctl, ssys_state),
644 VMSTATE_UINT32(ldopctl, ssys_state),
645 VMSTATE_UINT32(int_mask, ssys_state),
646 VMSTATE_UINT32(int_status, ssys_state),
647 VMSTATE_UINT32(resc, ssys_state),
648 VMSTATE_UINT32(rcc, ssys_state),
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100649 VMSTATE_UINT32_V(rcc2, ssys_state, 2),
Juan Quintela293c16a2010-12-02 03:03:11 +0100650 VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
651 VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
652 VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
653 VMSTATE_UINT32(clkvclr, ssys_state),
654 VMSTATE_UINT32(ldoarst, ssys_state),
655 VMSTATE_END_OF_LIST()
656 }
657};
658
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200659static int stellaris_sys_init(uint32_t base, qemu_irq irq,
660 stellaris_board_info * board,
661 uint8_t *macaddr)
pbrook9ee6e8b2007-11-11 00:04:49 +0000662{
pbrook9ee6e8b2007-11-11 00:04:49 +0000663 ssys_state *s;
664
Anthony Liguori7267c092011-08-20 22:09:37 -0500665 s = (ssys_state *)g_malloc0(sizeof(ssys_state));
pbrook9ee6e8b2007-11-11 00:04:49 +0000666 s->irq = irq;
667 s->board = board;
pbrookeea589c2007-11-24 03:13:04 +0000668 /* Most devices come preprogrammed with a MAC address in the user data. */
669 s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
670 s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +0000671
Benoît Canet56993012011-10-17 17:28:29 +0200672 memory_region_init_io(&s->iomem, &ssys_ops, s, "ssys", 0x00001000);
673 memory_region_add_subregion(get_system_memory(), base, &s->iomem);
pbrook9ee6e8b2007-11-11 00:04:49 +0000674 ssys_reset(s);
Juan Quintela293c16a2010-12-02 03:03:11 +0100675 vmstate_register(NULL, -1, &vmstate_stellaris_sys, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200676 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000677}
678
679
680/* I2C controller. */
681
682typedef struct {
Paul Brook1de96102009-05-14 22:35:09 +0100683 SysBusDevice busdev;
pbrook9ee6e8b2007-11-11 00:04:49 +0000684 i2c_bus *bus;
685 qemu_irq irq;
Benoît Canet8ea72f32011-10-17 17:28:30 +0200686 MemoryRegion iomem;
pbrook9ee6e8b2007-11-11 00:04:49 +0000687 uint32_t msa;
688 uint32_t mcs;
689 uint32_t mdr;
690 uint32_t mtpr;
691 uint32_t mimr;
692 uint32_t mris;
693 uint32_t mcr;
694} stellaris_i2c_state;
695
696#define STELLARIS_I2C_MCS_BUSY 0x01
697#define STELLARIS_I2C_MCS_ERROR 0x02
698#define STELLARIS_I2C_MCS_ADRACK 0x04
699#define STELLARIS_I2C_MCS_DATACK 0x08
700#define STELLARIS_I2C_MCS_ARBLST 0x10
701#define STELLARIS_I2C_MCS_IDLE 0x20
702#define STELLARIS_I2C_MCS_BUSBSY 0x40
703
Benoît Canet8ea72f32011-10-17 17:28:30 +0200704static uint64_t stellaris_i2c_read(void *opaque, target_phys_addr_t offset,
705 unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000706{
707 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
708
pbrook9ee6e8b2007-11-11 00:04:49 +0000709 switch (offset) {
710 case 0x00: /* MSA */
711 return s->msa;
712 case 0x04: /* MCS */
713 /* We don't emulate timing, so the controller is never busy. */
714 return s->mcs | STELLARIS_I2C_MCS_IDLE;
715 case 0x08: /* MDR */
716 return s->mdr;
717 case 0x0c: /* MTPR */
718 return s->mtpr;
719 case 0x10: /* MIMR */
720 return s->mimr;
721 case 0x14: /* MRIS */
722 return s->mris;
723 case 0x18: /* MMIS */
724 return s->mris & s->mimr;
725 case 0x20: /* MCR */
726 return s->mcr;
727 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100728 hw_error("strllaris_i2c_read: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000729 return 0;
730 }
731}
732
733static void stellaris_i2c_update(stellaris_i2c_state *s)
734{
735 int level;
736
737 level = (s->mris & s->mimr) != 0;
738 qemu_set_irq(s->irq, level);
739}
740
Anthony Liguoric227f092009-10-01 16:12:16 -0500741static void stellaris_i2c_write(void *opaque, target_phys_addr_t offset,
Benoît Canet8ea72f32011-10-17 17:28:30 +0200742 uint64_t value, unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000743{
744 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
745
pbrook9ee6e8b2007-11-11 00:04:49 +0000746 switch (offset) {
747 case 0x00: /* MSA */
748 s->msa = value & 0xff;
749 break;
750 case 0x04: /* MCS */
751 if ((s->mcr & 0x10) == 0) {
752 /* Disabled. Do nothing. */
753 break;
754 }
755 /* Grab the bus if this is starting a transfer. */
756 if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
757 if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
758 s->mcs |= STELLARIS_I2C_MCS_ARBLST;
759 } else {
760 s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
761 s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
762 }
763 }
764 /* If we don't have the bus then indicate an error. */
765 if (!i2c_bus_busy(s->bus)
766 || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
767 s->mcs |= STELLARIS_I2C_MCS_ERROR;
768 break;
769 }
770 s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
771 if (value & 1) {
772 /* Transfer a byte. */
773 /* TODO: Handle errors. */
774 if (s->msa & 1) {
775 /* Recv */
776 s->mdr = i2c_recv(s->bus) & 0xff;
777 } else {
778 /* Send */
779 i2c_send(s->bus, s->mdr);
780 }
781 /* Raise an interrupt. */
782 s->mris |= 1;
783 }
784 if (value & 4) {
785 /* Finish transfer. */
786 i2c_end_transfer(s->bus);
787 s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
788 }
789 break;
790 case 0x08: /* MDR */
791 s->mdr = value & 0xff;
792 break;
793 case 0x0c: /* MTPR */
794 s->mtpr = value & 0xff;
795 break;
796 case 0x10: /* MIMR */
797 s->mimr = 1;
798 break;
799 case 0x1c: /* MICR */
800 s->mris &= ~value;
801 break;
802 case 0x20: /* MCR */
803 if (value & 1)
Paul Brook2ac71172009-05-08 02:35:15 +0100804 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000805 "stellaris_i2c_write: Loopback not implemented\n");
806 if (value & 0x20)
Paul Brook2ac71172009-05-08 02:35:15 +0100807 hw_error(
pbrook9ee6e8b2007-11-11 00:04:49 +0000808 "stellaris_i2c_write: Slave mode not implemented\n");
809 s->mcr = value & 0x31;
810 break;
811 default:
Paul Brook2ac71172009-05-08 02:35:15 +0100812 hw_error("stellaris_i2c_write: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +0000813 (int)offset);
814 }
815 stellaris_i2c_update(s);
816}
817
818static void stellaris_i2c_reset(stellaris_i2c_state *s)
819{
820 if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
821 i2c_end_transfer(s->bus);
822
823 s->msa = 0;
824 s->mcs = 0;
825 s->mdr = 0;
826 s->mtpr = 1;
827 s->mimr = 0;
828 s->mris = 0;
829 s->mcr = 0;
830 stellaris_i2c_update(s);
831}
832
Benoît Canet8ea72f32011-10-17 17:28:30 +0200833static const MemoryRegionOps stellaris_i2c_ops = {
834 .read = stellaris_i2c_read,
835 .write = stellaris_i2c_write,
836 .endianness = DEVICE_NATIVE_ENDIAN,
pbrook9ee6e8b2007-11-11 00:04:49 +0000837};
838
Juan Quintelaff269cd2010-12-02 02:48:43 +0100839static const VMStateDescription vmstate_stellaris_i2c = {
840 .name = "stellaris_i2c",
841 .version_id = 1,
842 .minimum_version_id = 1,
843 .minimum_version_id_old = 1,
844 .fields = (VMStateField[]) {
845 VMSTATE_UINT32(msa, stellaris_i2c_state),
846 VMSTATE_UINT32(mcs, stellaris_i2c_state),
847 VMSTATE_UINT32(mdr, stellaris_i2c_state),
848 VMSTATE_UINT32(mtpr, stellaris_i2c_state),
849 VMSTATE_UINT32(mimr, stellaris_i2c_state),
850 VMSTATE_UINT32(mris, stellaris_i2c_state),
851 VMSTATE_UINT32(mcr, stellaris_i2c_state),
852 VMSTATE_END_OF_LIST()
853 }
854};
pbrook23e39292008-07-02 16:48:32 +0000855
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200856static int stellaris_i2c_init(SysBusDevice * dev)
pbrook9ee6e8b2007-11-11 00:04:49 +0000857{
Paul Brook1de96102009-05-14 22:35:09 +0100858 stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
Paul Brook02e2da42009-05-23 00:05:19 +0100859 i2c_bus *bus;
pbrook9ee6e8b2007-11-11 00:04:49 +0000860
Paul Brook1de96102009-05-14 22:35:09 +0100861 sysbus_init_irq(dev, &s->irq);
Paul Brook02e2da42009-05-23 00:05:19 +0100862 bus = i2c_init_bus(&dev->qdev, "i2c");
pbrook9ee6e8b2007-11-11 00:04:49 +0000863 s->bus = bus;
864
Benoît Canet8ea72f32011-10-17 17:28:30 +0200865 memory_region_init_io(&s->iomem, &stellaris_i2c_ops, s,
866 "i2c", 0x1000);
Avi Kivity750ecd42011-11-27 11:38:10 +0200867 sysbus_init_mmio(dev, &s->iomem);
pbrook9ee6e8b2007-11-11 00:04:49 +0000868 /* ??? For now we only implement the master interface. */
869 stellaris_i2c_reset(s);
Juan Quintelaff269cd2010-12-02 02:48:43 +0100870 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_i2c, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200871 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000872}
873
874/* Analogue to Digital Converter. This is only partially implemented,
875 enough for applications that use a combined ADC and timer tick. */
876
877#define STELLARIS_ADC_EM_CONTROLLER 0
878#define STELLARIS_ADC_EM_COMP 1
879#define STELLARIS_ADC_EM_EXTERNAL 4
880#define STELLARIS_ADC_EM_TIMER 5
881#define STELLARIS_ADC_EM_PWM0 6
882#define STELLARIS_ADC_EM_PWM1 7
883#define STELLARIS_ADC_EM_PWM2 8
884
885#define STELLARIS_ADC_FIFO_EMPTY 0x0100
886#define STELLARIS_ADC_FIFO_FULL 0x1000
887
888typedef struct
889{
Paul Brook40905a62009-06-03 15:16:49 +0100890 SysBusDevice busdev;
Benoît Canet71a2df02011-10-17 17:28:31 +0200891 MemoryRegion iomem;
pbrook9ee6e8b2007-11-11 00:04:49 +0000892 uint32_t actss;
893 uint32_t ris;
894 uint32_t im;
895 uint32_t emux;
896 uint32_t ostat;
897 uint32_t ustat;
898 uint32_t sspri;
899 uint32_t sac;
900 struct {
901 uint32_t state;
902 uint32_t data[16];
903 } fifo[4];
904 uint32_t ssmux[4];
905 uint32_t ssctl[4];
pbrook23e39292008-07-02 16:48:32 +0000906 uint32_t noise;
Paul Brook2c6554b2009-06-02 15:30:27 +0100907 qemu_irq irq[4];
pbrook9ee6e8b2007-11-11 00:04:49 +0000908} stellaris_adc_state;
909
910static uint32_t stellaris_adc_fifo_read(stellaris_adc_state *s, int n)
911{
912 int tail;
913
914 tail = s->fifo[n].state & 0xf;
915 if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
916 s->ustat |= 1 << n;
917 } else {
918 s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
919 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
920 if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
921 s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
922 }
923 return s->fifo[n].data[tail];
924}
925
926static void stellaris_adc_fifo_write(stellaris_adc_state *s, int n,
927 uint32_t value)
928{
929 int head;
930
Paul Brook2c6554b2009-06-02 15:30:27 +0100931 /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry
932 FIFO fir each sequencer. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000933 head = (s->fifo[n].state >> 4) & 0xf;
934 if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
935 s->ostat |= 1 << n;
936 return;
937 }
938 s->fifo[n].data[head] = value;
939 head = (head + 1) & 0xf;
940 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
941 s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
942 if ((s->fifo[n].state & 0xf) == head)
943 s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
944}
945
946static void stellaris_adc_update(stellaris_adc_state *s)
947{
948 int level;
Paul Brook2c6554b2009-06-02 15:30:27 +0100949 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000950
Paul Brook2c6554b2009-06-02 15:30:27 +0100951 for (n = 0; n < 4; n++) {
952 level = (s->ris & s->im & (1 << n)) != 0;
953 qemu_set_irq(s->irq[n], level);
954 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000955}
956
957static void stellaris_adc_trigger(void *opaque, int irq, int level)
958{
959 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
Paul Brook2c6554b2009-06-02 15:30:27 +0100960 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000961
Paul Brook2c6554b2009-06-02 15:30:27 +0100962 for (n = 0; n < 4; n++) {
963 if ((s->actss & (1 << n)) == 0) {
964 continue;
965 }
966
967 if (((s->emux >> (n * 4)) & 0xff) != 5) {
968 continue;
969 }
970
971 /* Some applications use the ADC as a random number source, so introduce
972 some variation into the signal. */
973 s->noise = s->noise * 314159 + 1;
974 /* ??? actual inputs not implemented. Return an arbitrary value. */
975 stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
976 s->ris |= (1 << n);
977 stellaris_adc_update(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000978 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000979}
980
981static void stellaris_adc_reset(stellaris_adc_state *s)
982{
983 int n;
984
985 for (n = 0; n < 4; n++) {
986 s->ssmux[n] = 0;
987 s->ssctl[n] = 0;
988 s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
989 }
990}
991
Benoît Canet71a2df02011-10-17 17:28:31 +0200992static uint64_t stellaris_adc_read(void *opaque, target_phys_addr_t offset,
993 unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000994{
995 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
996
997 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000998 if (offset >= 0x40 && offset < 0xc0) {
999 int n;
1000 n = (offset - 0x40) >> 5;
1001 switch (offset & 0x1f) {
1002 case 0x00: /* SSMUX */
1003 return s->ssmux[n];
1004 case 0x04: /* SSCTL */
1005 return s->ssctl[n];
1006 case 0x08: /* SSFIFO */
1007 return stellaris_adc_fifo_read(s, n);
1008 case 0x0c: /* SSFSTAT */
1009 return s->fifo[n].state;
1010 default:
1011 break;
1012 }
1013 }
1014 switch (offset) {
1015 case 0x00: /* ACTSS */
1016 return s->actss;
1017 case 0x04: /* RIS */
1018 return s->ris;
1019 case 0x08: /* IM */
1020 return s->im;
1021 case 0x0c: /* ISC */
1022 return s->ris & s->im;
1023 case 0x10: /* OSTAT */
1024 return s->ostat;
1025 case 0x14: /* EMUX */
1026 return s->emux;
1027 case 0x18: /* USTAT */
1028 return s->ustat;
1029 case 0x20: /* SSPRI */
1030 return s->sspri;
1031 case 0x30: /* SAC */
1032 return s->sac;
1033 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001034 hw_error("strllaris_adc_read: Bad offset 0x%x\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001035 (int)offset);
1036 return 0;
1037 }
1038}
1039
Anthony Liguoric227f092009-10-01 16:12:16 -05001040static void stellaris_adc_write(void *opaque, target_phys_addr_t offset,
Benoît Canet71a2df02011-10-17 17:28:31 +02001041 uint64_t value, unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +00001042{
1043 stellaris_adc_state *s = (stellaris_adc_state *)opaque;
1044
1045 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +00001046 if (offset >= 0x40 && offset < 0xc0) {
1047 int n;
1048 n = (offset - 0x40) >> 5;
1049 switch (offset & 0x1f) {
1050 case 0x00: /* SSMUX */
1051 s->ssmux[n] = value & 0x33333333;
1052 return;
1053 case 0x04: /* SSCTL */
1054 if (value != 6) {
Benoît Canet71a2df02011-10-17 17:28:31 +02001055 hw_error("ADC: Unimplemented sequence %" PRIx64 "\n",
pbrook9ee6e8b2007-11-11 00:04:49 +00001056 value);
1057 }
1058 s->ssctl[n] = value;
1059 return;
1060 default:
1061 break;
1062 }
1063 }
1064 switch (offset) {
1065 case 0x00: /* ACTSS */
1066 s->actss = value & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00001067 break;
1068 case 0x08: /* IM */
1069 s->im = value;
1070 break;
1071 case 0x0c: /* ISC */
1072 s->ris &= ~value;
1073 break;
1074 case 0x10: /* OSTAT */
1075 s->ostat &= ~value;
1076 break;
1077 case 0x14: /* EMUX */
1078 s->emux = value;
1079 break;
1080 case 0x18: /* USTAT */
1081 s->ustat &= ~value;
1082 break;
1083 case 0x20: /* SSPRI */
1084 s->sspri = value;
1085 break;
1086 case 0x28: /* PSSI */
Paul Brook2ac71172009-05-08 02:35:15 +01001087 hw_error("Not implemented: ADC sample initiate\n");
pbrook9ee6e8b2007-11-11 00:04:49 +00001088 break;
1089 case 0x30: /* SAC */
1090 s->sac = value;
1091 break;
1092 default:
Paul Brook2ac71172009-05-08 02:35:15 +01001093 hw_error("stellaris_adc_write: Bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00001094 }
1095 stellaris_adc_update(s);
1096}
1097
Benoît Canet71a2df02011-10-17 17:28:31 +02001098static const MemoryRegionOps stellaris_adc_ops = {
1099 .read = stellaris_adc_read,
1100 .write = stellaris_adc_write,
1101 .endianness = DEVICE_NATIVE_ENDIAN,
pbrook9ee6e8b2007-11-11 00:04:49 +00001102};
1103
Juan Quintelacf1d31d2010-12-03 01:27:58 +01001104static const VMStateDescription vmstate_stellaris_adc = {
1105 .name = "stellaris_adc",
1106 .version_id = 1,
1107 .minimum_version_id = 1,
1108 .minimum_version_id_old = 1,
1109 .fields = (VMStateField[]) {
1110 VMSTATE_UINT32(actss, stellaris_adc_state),
1111 VMSTATE_UINT32(ris, stellaris_adc_state),
1112 VMSTATE_UINT32(im, stellaris_adc_state),
1113 VMSTATE_UINT32(emux, stellaris_adc_state),
1114 VMSTATE_UINT32(ostat, stellaris_adc_state),
1115 VMSTATE_UINT32(ustat, stellaris_adc_state),
1116 VMSTATE_UINT32(sspri, stellaris_adc_state),
1117 VMSTATE_UINT32(sac, stellaris_adc_state),
1118 VMSTATE_UINT32(fifo[0].state, stellaris_adc_state),
1119 VMSTATE_UINT32_ARRAY(fifo[0].data, stellaris_adc_state, 16),
1120 VMSTATE_UINT32(ssmux[0], stellaris_adc_state),
1121 VMSTATE_UINT32(ssctl[0], stellaris_adc_state),
1122 VMSTATE_UINT32(fifo[1].state, stellaris_adc_state),
1123 VMSTATE_UINT32_ARRAY(fifo[1].data, stellaris_adc_state, 16),
1124 VMSTATE_UINT32(ssmux[1], stellaris_adc_state),
1125 VMSTATE_UINT32(ssctl[1], stellaris_adc_state),
1126 VMSTATE_UINT32(fifo[2].state, stellaris_adc_state),
1127 VMSTATE_UINT32_ARRAY(fifo[2].data, stellaris_adc_state, 16),
1128 VMSTATE_UINT32(ssmux[2], stellaris_adc_state),
1129 VMSTATE_UINT32(ssctl[2], stellaris_adc_state),
1130 VMSTATE_UINT32(fifo[3].state, stellaris_adc_state),
1131 VMSTATE_UINT32_ARRAY(fifo[3].data, stellaris_adc_state, 16),
1132 VMSTATE_UINT32(ssmux[3], stellaris_adc_state),
1133 VMSTATE_UINT32(ssctl[3], stellaris_adc_state),
1134 VMSTATE_UINT32(noise, stellaris_adc_state),
1135 VMSTATE_END_OF_LIST()
pbrook23e39292008-07-02 16:48:32 +00001136 }
Juan Quintelacf1d31d2010-12-03 01:27:58 +01001137};
pbrook23e39292008-07-02 16:48:32 +00001138
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001139static int stellaris_adc_init(SysBusDevice *dev)
pbrook9ee6e8b2007-11-11 00:04:49 +00001140{
Paul Brook40905a62009-06-03 15:16:49 +01001141 stellaris_adc_state *s = FROM_SYSBUS(stellaris_adc_state, dev);
Paul Brook2c6554b2009-06-02 15:30:27 +01001142 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +00001143
Paul Brook2c6554b2009-06-02 15:30:27 +01001144 for (n = 0; n < 4; n++) {
Paul Brook40905a62009-06-03 15:16:49 +01001145 sysbus_init_irq(dev, &s->irq[n]);
Paul Brook2c6554b2009-06-02 15:30:27 +01001146 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001147
Benoît Canet71a2df02011-10-17 17:28:31 +02001148 memory_region_init_io(&s->iomem, &stellaris_adc_ops, s,
1149 "adc", 0x1000);
Avi Kivity750ecd42011-11-27 11:38:10 +02001150 sysbus_init_mmio(dev, &s->iomem);
pbrook9ee6e8b2007-11-11 00:04:49 +00001151 stellaris_adc_reset(s);
Paul Brook40905a62009-06-03 15:16:49 +01001152 qdev_init_gpio_in(&dev->qdev, stellaris_adc_trigger, 1);
Juan Quintelacf1d31d2010-12-03 01:27:58 +01001153 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_adc, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001154 return 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00001155}
1156
pbrook775616c2007-11-24 23:35:08 +00001157/* Some boards have both an OLED controller and SD card connected to
1158 the same SSI port, with the SD card chip select connected to a
1159 GPIO pin. Technically the OLED chip select is connected to the SSI
1160 Fss pin. We do not bother emulating that as both devices should
1161 never be selected simultaneously, and our OLED controller ignores stray
1162 0xff commands that occur when deselecting the SD card. */
1163
1164typedef struct {
Paul Brook5493e332009-05-14 22:35:09 +01001165 SSISlave ssidev;
pbrook775616c2007-11-24 23:35:08 +00001166 qemu_irq irq;
1167 int current_dev;
Paul Brook5493e332009-05-14 22:35:09 +01001168 SSIBus *bus[2];
pbrook775616c2007-11-24 23:35:08 +00001169} stellaris_ssi_bus_state;
1170
1171static void stellaris_ssi_bus_select(void *opaque, int irq, int level)
1172{
1173 stellaris_ssi_bus_state *s = (stellaris_ssi_bus_state *)opaque;
1174
1175 s->current_dev = level;
1176}
1177
Paul Brook5493e332009-05-14 22:35:09 +01001178static uint32_t stellaris_ssi_bus_transfer(SSISlave *dev, uint32_t val)
pbrook775616c2007-11-24 23:35:08 +00001179{
Paul Brook5493e332009-05-14 22:35:09 +01001180 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001181
Paul Brook5493e332009-05-14 22:35:09 +01001182 return ssi_transfer(s->bus[s->current_dev], val);
pbrook775616c2007-11-24 23:35:08 +00001183}
1184
Juan Quintelaa4dec1d2010-12-02 02:51:29 +01001185static const VMStateDescription vmstate_stellaris_ssi_bus = {
1186 .name = "stellaris_ssi_bus",
1187 .version_id = 1,
1188 .minimum_version_id = 1,
1189 .minimum_version_id_old = 1,
1190 .fields = (VMStateField[]) {
1191 VMSTATE_INT32(current_dev, stellaris_ssi_bus_state),
1192 VMSTATE_END_OF_LIST()
1193 }
1194};
pbrook23e39292008-07-02 16:48:32 +00001195
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001196static int stellaris_ssi_bus_init(SSISlave *dev)
pbrook775616c2007-11-24 23:35:08 +00001197{
Paul Brook5493e332009-05-14 22:35:09 +01001198 stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
pbrook775616c2007-11-24 23:35:08 +00001199
Paul Brook02e2da42009-05-23 00:05:19 +01001200 s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
1201 s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
Paul Brook5493e332009-05-14 22:35:09 +01001202 qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
1203
Juan Quintelaa4dec1d2010-12-02 02:51:29 +01001204 vmstate_register(&dev->qdev, -1, &vmstate_stellaris_ssi_bus, s);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +02001205 return 0;
pbrook775616c2007-11-24 23:35:08 +00001206}
1207
pbrook9ee6e8b2007-11-11 00:04:49 +00001208/* Board init. */
1209static stellaris_board_info stellaris_boards[] = {
1210 { "LM3S811EVB",
1211 0,
1212 0x0032000e,
1213 0x001f001f, /* dc0 */
1214 0x001132bf,
1215 0x01071013,
1216 0x3f0f01ff,
1217 0x0000001f,
pbrookcf0dbb22007-11-18 14:36:08 +00001218 BP_OLED_I2C
pbrook9ee6e8b2007-11-11 00:04:49 +00001219 },
1220 { "LM3S6965EVB",
1221 0x10010002,
1222 0x1073402e,
1223 0x00ff007f, /* dc0 */
1224 0x001133ff,
1225 0x030f5317,
1226 0x0f0f87ff,
1227 0x5000007f,
pbrookcf0dbb22007-11-18 14:36:08 +00001228 BP_OLED_SSI | BP_GAMEPAD
pbrook9ee6e8b2007-11-11 00:04:49 +00001229 }
1230};
1231
1232static void stellaris_init(const char *kernel_filename, const char *cpu_model,
aliguori3023f332009-01-16 19:04:14 +00001233 stellaris_board_info *board)
pbrook9ee6e8b2007-11-11 00:04:49 +00001234{
1235 static const int uart_irq[] = {5, 6, 33, 34};
1236 static const int timer_irq[] = {19, 21, 23, 35};
1237 static const uint32_t gpio_addr[7] =
1238 { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
1239 0x40024000, 0x40025000, 0x40026000};
1240 static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
1241
Avi Kivity7d6f78c2011-07-25 14:27:01 +03001242 MemoryRegion *address_space_mem = get_system_memory();
pbrook9ee6e8b2007-11-11 00:04:49 +00001243 qemu_irq *pic;
Paul Brook40905a62009-06-03 15:16:49 +01001244 DeviceState *gpio_dev[7];
1245 qemu_irq gpio_in[7][8];
1246 qemu_irq gpio_out[7][8];
pbrook9ee6e8b2007-11-11 00:04:49 +00001247 qemu_irq adc;
1248 int sram_size;
1249 int flash_size;
1250 i2c_bus *i2c;
Paul Brook40905a62009-06-03 15:16:49 +01001251 DeviceState *dev;
pbrook9ee6e8b2007-11-11 00:04:49 +00001252 int i;
Paul Brook40905a62009-06-03 15:16:49 +01001253 int j;
pbrook9ee6e8b2007-11-11 00:04:49 +00001254
1255 flash_size = ((board->dc0 & 0xffff) + 1) << 1;
1256 sram_size = (board->dc0 >> 18) + 1;
Avi Kivity7d6f78c2011-07-25 14:27:01 +03001257 pic = armv7m_init(address_space_mem,
1258 flash_size, sram_size, kernel_filename, cpu_model);
pbrook9ee6e8b2007-11-11 00:04:49 +00001259
1260 if (board->dc1 & (1 << 16)) {
Paul Brook40905a62009-06-03 15:16:49 +01001261 dev = sysbus_create_varargs("stellaris-adc", 0x40038000,
1262 pic[14], pic[15], pic[16], pic[17], NULL);
1263 adc = qdev_get_gpio_in(dev, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00001264 } else {
1265 adc = NULL;
1266 }
1267 for (i = 0; i < 4; i++) {
1268 if (board->dc2 & (0x10000 << i)) {
Paul Brook40905a62009-06-03 15:16:49 +01001269 dev = sysbus_create_simple("stellaris-gptm",
1270 0x40030000 + i * 0x1000,
1271 pic[timer_irq[i]]);
1272 /* TODO: This is incorrect, but we get away with it because
1273 the ADC output is only ever pulsed. */
1274 qdev_connect_gpio_out(dev, 0, adc);
pbrook9ee6e8b2007-11-11 00:04:49 +00001275 }
1276 }
1277
Jan Kiszka6eed1852011-07-20 12:20:22 +02001278 stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a);
pbrook9ee6e8b2007-11-11 00:04:49 +00001279
1280 for (i = 0; i < 7; i++) {
1281 if (board->dc4 & (1 << i)) {
Peter Maydell7063f492011-02-21 20:57:51 +00001282 gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
Paul Brook40905a62009-06-03 15:16:49 +01001283 pic[gpio_irq[i]]);
1284 for (j = 0; j < 8; j++) {
1285 gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
1286 gpio_out[i][j] = NULL;
1287 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001288 }
1289 }
1290
1291 if (board->dc2 & (1 << 12)) {
Paul Brook1de96102009-05-14 22:35:09 +01001292 dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
Paul Brook02e2da42009-05-23 00:05:19 +01001293 i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
pbrookcf0dbb22007-11-18 14:36:08 +00001294 if (board->peripherals & BP_OLED_I2C) {
Paul Brookd2199002009-05-14 22:35:08 +01001295 i2c_create_slave(i2c, "ssd0303", 0x3d);
pbrook9ee6e8b2007-11-11 00:04:49 +00001296 }
1297 }
1298
1299 for (i = 0; i < 4; i++) {
1300 if (board->dc2 & (1 << i)) {
Paul Brooka7d518a2009-05-14 22:35:07 +01001301 sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000,
1302 pic[uart_irq[i]]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001303 }
1304 }
1305 if (board->dc2 & (1 << 4)) {
Paul Brook5493e332009-05-14 22:35:09 +01001306 dev = sysbus_create_simple("pl022", 0x40008000, pic[7]);
pbrookcf0dbb22007-11-18 14:36:08 +00001307 if (board->peripherals & BP_OLED_SSI) {
Paul Brook5493e332009-05-14 22:35:09 +01001308 DeviceState *mux;
1309 void *bus;
pbrook775616c2007-11-24 23:35:08 +00001310
Paul Brook5493e332009-05-14 22:35:09 +01001311 bus = qdev_get_child_bus(dev, "ssi");
1312 mux = ssi_create_slave(bus, "evb6965-ssi");
1313 gpio_out[GPIO_D][0] = qdev_get_gpio_in(mux, 0);
pbrook775616c2007-11-24 23:35:08 +00001314
Paul Brook5493e332009-05-14 22:35:09 +01001315 bus = qdev_get_child_bus(mux, "ssi0");
Blue Swirl22ed1d342010-04-25 19:31:06 +00001316 ssi_create_slave(bus, "ssi-sd");
pbrook775616c2007-11-24 23:35:08 +00001317
Paul Brook5493e332009-05-14 22:35:09 +01001318 bus = qdev_get_child_bus(mux, "ssi1");
1319 dev = ssi_create_slave(bus, "ssd0323");
1320 gpio_out[GPIO_C][7] = qdev_get_gpio_in(dev, 0);
1321
pbrook775616c2007-11-24 23:35:08 +00001322 /* Make sure the select pin is high. */
1323 qemu_irq_raise(gpio_out[GPIO_D][0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001324 }
1325 }
Paul Brooka5580462009-05-14 22:35:07 +01001326 if (board->dc4 & (1 << 28)) {
1327 DeviceState *enet;
1328
1329 qemu_check_nic_model(&nd_table[0], "stellaris");
1330
1331 enet = qdev_create(NULL, "stellaris_enet");
Gerd Hoffmann540f0062009-10-21 15:25:39 +02001332 qdev_set_nic_properties(enet, &nd_table[0]);
Markus Armbrustere23a1b32009-10-07 01:15:58 +02001333 qdev_init_nofail(enet);
Paul Brooka5580462009-05-14 22:35:07 +01001334 sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000);
1335 sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]);
1336 }
pbrookcf0dbb22007-11-18 14:36:08 +00001337 if (board->peripherals & BP_GAMEPAD) {
1338 qemu_irq gpad_irq[5];
1339 static const int gpad_keycode[5] = { 0xc8, 0xd0, 0xcb, 0xcd, 0x1d };
1340
1341 gpad_irq[0] = qemu_irq_invert(gpio_in[GPIO_E][0]); /* up */
1342 gpad_irq[1] = qemu_irq_invert(gpio_in[GPIO_E][1]); /* down */
1343 gpad_irq[2] = qemu_irq_invert(gpio_in[GPIO_E][2]); /* left */
1344 gpad_irq[3] = qemu_irq_invert(gpio_in[GPIO_E][3]); /* right */
1345 gpad_irq[4] = qemu_irq_invert(gpio_in[GPIO_F][1]); /* select */
1346
1347 stellaris_gamepad_init(5, gpad_irq, gpad_keycode);
1348 }
Paul Brook40905a62009-06-03 15:16:49 +01001349 for (i = 0; i < 7; i++) {
1350 if (board->dc4 & (1 << i)) {
1351 for (j = 0; j < 8; j++) {
1352 if (gpio_out[i][j]) {
1353 qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
1354 }
1355 }
1356 }
1357 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001358}
1359
1360/* FIXME: Figure out how to generate these from stellaris_boards. */
Anthony Liguoric227f092009-10-01 16:12:16 -05001361static void lm3s811evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001362 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001363 const char *kernel_filename, const char *kernel_cmdline,
1364 const char *initrd_filename, const char *cpu_model)
1365{
aliguori3023f332009-01-16 19:04:14 +00001366 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001367}
1368
Anthony Liguoric227f092009-10-01 16:12:16 -05001369static void lm3s6965evb_init(ram_addr_t ram_size,
aliguori3023f332009-01-16 19:04:14 +00001370 const char *boot_device,
pbrook9ee6e8b2007-11-11 00:04:49 +00001371 const char *kernel_filename, const char *kernel_cmdline,
1372 const char *initrd_filename, const char *cpu_model)
1373{
aliguori3023f332009-01-16 19:04:14 +00001374 stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001375}
1376
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001377static QEMUMachine lm3s811evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001378 .name = "lm3s811evb",
1379 .desc = "Stellaris LM3S811EVB",
1380 .init = lm3s811evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001381};
1382
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001383static QEMUMachine lm3s6965evb_machine = {
aliguori4b32e162008-10-07 20:34:35 +00001384 .name = "lm3s6965evb",
1385 .desc = "Stellaris LM3S6965EVB",
1386 .init = lm3s6965evb_init,
pbrook9ee6e8b2007-11-11 00:04:49 +00001387};
Paul Brook1de96102009-05-14 22:35:09 +01001388
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001389static void stellaris_machine_init(void)
1390{
1391 qemu_register_machine(&lm3s811evb_machine);
1392 qemu_register_machine(&lm3s6965evb_machine);
1393}
1394
1395machine_init(stellaris_machine_init);
1396
Anthony Liguoricd6c4cf2011-12-16 13:36:39 -06001397static void stellaris_ssi_bus_class_init(ObjectClass *klass, void *data)
1398{
1399 SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
1400
1401 k->init = stellaris_ssi_bus_init;
1402 k->transfer = stellaris_ssi_bus_transfer;
1403}
1404
Anthony Liguori39bffca2011-12-07 21:34:16 -06001405static TypeInfo stellaris_ssi_bus_info = {
1406 .name = "evb6965-ssi",
1407 .parent = TYPE_SSI_SLAVE,
1408 .instance_size = sizeof(stellaris_ssi_bus_state),
1409 .class_init = stellaris_ssi_bus_class_init,
Paul Brook5493e332009-05-14 22:35:09 +01001410};
1411
Anthony Liguori999e12b2012-01-24 13:12:29 -06001412static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
1413{
1414 SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
1415
1416 sdc->init = stellaris_i2c_init;
1417}
1418
Anthony Liguori39bffca2011-12-07 21:34:16 -06001419static TypeInfo stellaris_i2c_info = {
1420 .name = "stellaris-i2c",
1421 .parent = TYPE_SYS_BUS_DEVICE,
1422 .instance_size = sizeof(stellaris_i2c_state),
1423 .class_init = stellaris_i2c_class_init,
Anthony Liguori999e12b2012-01-24 13:12:29 -06001424};
1425
1426static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
1427{
1428 SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
1429
1430 sdc->init = stellaris_gptm_init;
1431}
1432
Anthony Liguori39bffca2011-12-07 21:34:16 -06001433static TypeInfo stellaris_gptm_info = {
1434 .name = "stellaris-gptm",
1435 .parent = TYPE_SYS_BUS_DEVICE,
1436 .instance_size = sizeof(gptm_state),
1437 .class_init = stellaris_gptm_class_init,
Anthony Liguori999e12b2012-01-24 13:12:29 -06001438};
1439
1440static void stellaris_adc_class_init(ObjectClass *klass, void *data)
1441{
1442 SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
1443
1444 sdc->init = stellaris_adc_init;
1445}
1446
Anthony Liguori39bffca2011-12-07 21:34:16 -06001447static TypeInfo stellaris_adc_info = {
1448 .name = "stellaris-adc",
1449 .parent = TYPE_SYS_BUS_DEVICE,
1450 .instance_size = sizeof(stellaris_adc_state),
1451 .class_init = stellaris_adc_class_init,
Anthony Liguori999e12b2012-01-24 13:12:29 -06001452};
1453
Andreas Färber83f7d432012-02-09 15:20:55 +01001454static void stellaris_register_types(void)
Paul Brook1de96102009-05-14 22:35:09 +01001455{
Anthony Liguori39bffca2011-12-07 21:34:16 -06001456 type_register_static(&stellaris_i2c_info);
1457 type_register_static(&stellaris_gptm_info);
1458 type_register_static(&stellaris_adc_info);
1459 type_register_static(&stellaris_ssi_bus_info);
Paul Brook1de96102009-05-14 22:35:09 +01001460}
1461
Andreas Färber83f7d432012-02-09 15:20:55 +01001462type_init(stellaris_register_types)