19ee6e8bbSpbrook /*
21654b2d6Saurel32 * Luminary Micro Stellaris peripherals
39ee6e8bbSpbrook *
49ee6e8bbSpbrook * Copyright (c) 2006 CodeSourcery.
59ee6e8bbSpbrook * Written by Paul Brook
69ee6e8bbSpbrook *
78e31bf38SMatthew Fernandez * This code is licensed under the GPL.
89ee6e8bbSpbrook */
99ee6e8bbSpbrook
1012b16722SPeter Maydell #include "qemu/osdep.h"
11b7c55f59SPhilippe Mathieu-Daudé #include "qemu/bitops.h"
12da34e65cSMarkus Armbruster #include "qapi/error.h"
13d0a030d8SZongyuan Li #include "hw/core/split-irq.h"
1483c9f4caSPaolo Bonzini #include "hw/sysbus.h"
1536aa285fSMarkus Armbruster #include "hw/sd/sd.h"
168fd06719SAlistair Francis #include "hw/ssi/ssi.h"
1712ec8bd5SPeter Maydell #include "hw/arm/boot.h"
181de7afc9SPaolo Bonzini #include "qemu/timer.h"
190d09e41aSPaolo Bonzini #include "hw/i2c/i2c.h"
201422e32dSPaolo Bonzini #include "net/net.h"
2183c9f4caSPaolo Bonzini #include "hw/boards.h"
2203dd024fSPaolo Bonzini #include "qemu/log.h"
23dfc56946SRichard Henderson #include "system/address-spaces.h"
2432cad1ffSPhilippe Mathieu-Daudé #include "system/system.h"
25f04d4465SPeter Maydell #include "hw/arm/armv7m.h"
26f0d1d2c1Sxiaoqiang zhao #include "hw/char/pl011.h"
27c45460deSPeter Maydell #include "hw/input/stellaris_gamepad.h"
2864552b6bSMarkus Armbruster #include "hw/irq.h"
29566528f8SMichel Heily #include "hw/watchdog/cmsdk-apb-watchdog.h"
30d6454270SMarkus Armbruster #include "migration/vmstate.h"
31aecfbbc9SPeter Maydell #include "hw/misc/unimp.h"
32f3eb7557SPeter Maydell #include "hw/timer/stellaris-gptm.h"
331e31d8eeSPeter Maydell #include "hw/qdev-clock.h"
34db1015e9SEduardo Habkost #include "qom/object.h"
35407bc4bfSDaniel P. Berrangé #include "qobject/qlist.h"
367c76f397SPeter Maydell #include "ui/input.h"
379ee6e8bbSpbrook
38cf0dbb21Spbrook #define GPIO_A 0
39cf0dbb21Spbrook #define GPIO_B 1
40cf0dbb21Spbrook #define GPIO_C 2
41cf0dbb21Spbrook #define GPIO_D 3
42cf0dbb21Spbrook #define GPIO_E 4
43cf0dbb21Spbrook #define GPIO_F 5
44cf0dbb21Spbrook #define GPIO_G 6
45cf0dbb21Spbrook
46cf0dbb21Spbrook #define BP_OLED_I2C 0x01
47cf0dbb21Spbrook #define BP_OLED_SSI 0x02
48cf0dbb21Spbrook #define BP_GAMEPAD 0x04
49cf0dbb21Spbrook
508b47b7daSAlistair Francis #define NUM_IRQ_LINES 64
514a04655cSSamuel Tardieu #define NUM_PRIO_BITS 3
528b47b7daSAlistair Francis
537330c1c5SPhilippe Mathieu-Daudé #define NUM_GPIO 7
547330c1c5SPhilippe Mathieu-Daudé #define NUM_UART 4
557330c1c5SPhilippe Mathieu-Daudé #define NUM_GPTM 4
567330c1c5SPhilippe Mathieu-Daudé #define NUM_I2C 2
577330c1c5SPhilippe Mathieu-Daudé
58b7c55f59SPhilippe Mathieu-Daudé /*
59b7c55f59SPhilippe Mathieu-Daudé * See Stellaris Data Sheet chapter 5.2.5 "System Control",
60b7c55f59SPhilippe Mathieu-Daudé * Register 13 .. 17: Device Capabilities 0 .. 4 (DC0 .. DC4).
61b7c55f59SPhilippe Mathieu-Daudé */
62b7c55f59SPhilippe Mathieu-Daudé #define DC1_WDT 3
63b7c55f59SPhilippe Mathieu-Daudé #define DC1_HIB 6
64b7c55f59SPhilippe Mathieu-Daudé #define DC1_MPU 7
65b7c55f59SPhilippe Mathieu-Daudé #define DC1_ADC 16
66b7c55f59SPhilippe Mathieu-Daudé #define DC1_PWM 20
67b7c55f59SPhilippe Mathieu-Daudé #define DC2_UART(n) (n)
68b7c55f59SPhilippe Mathieu-Daudé #define DC2_SSI 4
69b7c55f59SPhilippe Mathieu-Daudé #define DC2_QEI(n) (8 + n)
70b7c55f59SPhilippe Mathieu-Daudé #define DC2_I2C(n) (12 + 2 * n)
71b7c55f59SPhilippe Mathieu-Daudé #define DC2_GPTM(n) (16 + n)
72b7c55f59SPhilippe Mathieu-Daudé #define DC2_COMP(n) (24 + n)
73b7c55f59SPhilippe Mathieu-Daudé #define DC4_GPIO(n) (n)
74b7c55f59SPhilippe Mathieu-Daudé #define DC4_EMAC 28
75b7c55f59SPhilippe Mathieu-Daudé
76b7c55f59SPhilippe Mathieu-Daudé #define DEV_CAP(_dc, _cap) extract32(board->dc##_dc, DC##_dc##_##_cap, 1)
77b7c55f59SPhilippe Mathieu-Daudé
789ee6e8bbSpbrook typedef const struct {
799ee6e8bbSpbrook const char *name;
809ee6e8bbSpbrook uint32_t did0;
819ee6e8bbSpbrook uint32_t did1;
829ee6e8bbSpbrook uint32_t dc0;
839ee6e8bbSpbrook uint32_t dc1;
849ee6e8bbSpbrook uint32_t dc2;
859ee6e8bbSpbrook uint32_t dc3;
869ee6e8bbSpbrook uint32_t dc4;
87cf0dbb21Spbrook uint32_t peripherals;
889ee6e8bbSpbrook } stellaris_board_info;
899ee6e8bbSpbrook
909ee6e8bbSpbrook /* System controller. */
919ee6e8bbSpbrook
924bebb9adSPeter Maydell #define TYPE_STELLARIS_SYS "stellaris-sys"
934bebb9adSPeter Maydell OBJECT_DECLARE_SIMPLE_TYPE(ssys_state, STELLARIS_SYS)
944bebb9adSPeter Maydell
954bebb9adSPeter Maydell struct ssys_state {
964bebb9adSPeter Maydell SysBusDevice parent_obj;
974bebb9adSPeter Maydell
985699301fSBenoît Canet MemoryRegion iomem;
999ee6e8bbSpbrook uint32_t pborctl;
1009ee6e8bbSpbrook uint32_t ldopctl;
1019ee6e8bbSpbrook uint32_t int_status;
1029ee6e8bbSpbrook uint32_t int_mask;
1039ee6e8bbSpbrook uint32_t resc;
1049ee6e8bbSpbrook uint32_t rcc;
105dc804ab7SEngin AYDOGAN uint32_t rcc2;
1069ee6e8bbSpbrook uint32_t rcgc[3];
1079ee6e8bbSpbrook uint32_t scgc[3];
1089ee6e8bbSpbrook uint32_t dcgc[3];
1099ee6e8bbSpbrook uint32_t clkvclr;
1109ee6e8bbSpbrook uint32_t ldoarst;
1114bebb9adSPeter Maydell qemu_irq irq;
1121e31d8eeSPeter Maydell Clock *sysclk;
1134bebb9adSPeter Maydell /* Properties (all read-only registers) */
114eea589ccSpbrook uint32_t user0;
115eea589ccSpbrook uint32_t user1;
1164bebb9adSPeter Maydell uint32_t did0;
1174bebb9adSPeter Maydell uint32_t did1;
1184bebb9adSPeter Maydell uint32_t dc0;
1194bebb9adSPeter Maydell uint32_t dc1;
1204bebb9adSPeter Maydell uint32_t dc2;
1214bebb9adSPeter Maydell uint32_t dc3;
1224bebb9adSPeter Maydell uint32_t dc4;
1234bebb9adSPeter Maydell };
1249ee6e8bbSpbrook
ssys_update(ssys_state * s)1259ee6e8bbSpbrook static void ssys_update(ssys_state *s)
1269ee6e8bbSpbrook {
1279ee6e8bbSpbrook qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
1289ee6e8bbSpbrook }
1299ee6e8bbSpbrook
13087409ea9SPhilippe Mathieu-Daudé static const uint32_t pllcfg_sandstorm[16] = {
1319ee6e8bbSpbrook 0x31c0, /* 1 Mhz */
1329ee6e8bbSpbrook 0x1ae0, /* 1.8432 Mhz */
1339ee6e8bbSpbrook 0x18c0, /* 2 Mhz */
1349ee6e8bbSpbrook 0xd573, /* 2.4576 Mhz */
1359ee6e8bbSpbrook 0x37a6, /* 3.57954 Mhz */
1369ee6e8bbSpbrook 0x1ae2, /* 3.6864 Mhz */
1379ee6e8bbSpbrook 0x0c40, /* 4 Mhz */
1389ee6e8bbSpbrook 0x98bc, /* 4.906 Mhz */
1399ee6e8bbSpbrook 0x935b, /* 4.9152 Mhz */
1409ee6e8bbSpbrook 0x09c0, /* 5 Mhz */
1419ee6e8bbSpbrook 0x4dee, /* 5.12 Mhz */
1429ee6e8bbSpbrook 0x0c41, /* 6 Mhz */
1439ee6e8bbSpbrook 0x75db, /* 6.144 Mhz */
1449ee6e8bbSpbrook 0x1ae6, /* 7.3728 Mhz */
1459ee6e8bbSpbrook 0x0600, /* 8 Mhz */
1469ee6e8bbSpbrook 0x585b /* 8.192 Mhz */
1479ee6e8bbSpbrook };
1489ee6e8bbSpbrook
14987409ea9SPhilippe Mathieu-Daudé static const uint32_t pllcfg_fury[16] = {
1509ee6e8bbSpbrook 0x3200, /* 1 Mhz */
1519ee6e8bbSpbrook 0x1b20, /* 1.8432 Mhz */
1529ee6e8bbSpbrook 0x1900, /* 2 Mhz */
1539ee6e8bbSpbrook 0xf42b, /* 2.4576 Mhz */
1549ee6e8bbSpbrook 0x37e3, /* 3.57954 Mhz */
1559ee6e8bbSpbrook 0x1b21, /* 3.6864 Mhz */
1569ee6e8bbSpbrook 0x0c80, /* 4 Mhz */
1579ee6e8bbSpbrook 0x98ee, /* 4.906 Mhz */
1589ee6e8bbSpbrook 0xd5b4, /* 4.9152 Mhz */
1599ee6e8bbSpbrook 0x0a00, /* 5 Mhz */
1609ee6e8bbSpbrook 0x4e27, /* 5.12 Mhz */
1619ee6e8bbSpbrook 0x1902, /* 6 Mhz */
1629ee6e8bbSpbrook 0xec1c, /* 6.144 Mhz */
1639ee6e8bbSpbrook 0x1b23, /* 7.3728 Mhz */
1649ee6e8bbSpbrook 0x0640, /* 8 Mhz */
1659ee6e8bbSpbrook 0xb11c /* 8.192 Mhz */
1669ee6e8bbSpbrook };
1679ee6e8bbSpbrook
168dc804ab7SEngin AYDOGAN #define DID0_VER_MASK 0x70000000
169dc804ab7SEngin AYDOGAN #define DID0_VER_0 0x00000000
170dc804ab7SEngin AYDOGAN #define DID0_VER_1 0x10000000
171dc804ab7SEngin AYDOGAN
172dc804ab7SEngin AYDOGAN #define DID0_CLASS_MASK 0x00FF0000
173dc804ab7SEngin AYDOGAN #define DID0_CLASS_SANDSTORM 0x00000000
174dc804ab7SEngin AYDOGAN #define DID0_CLASS_FURY 0x00010000
175dc804ab7SEngin AYDOGAN
ssys_board_class(const ssys_state * s)176dc804ab7SEngin AYDOGAN static int ssys_board_class(const ssys_state *s)
177dc804ab7SEngin AYDOGAN {
1784bebb9adSPeter Maydell uint32_t did0 = s->did0;
179dc804ab7SEngin AYDOGAN switch (did0 & DID0_VER_MASK) {
180dc804ab7SEngin AYDOGAN case DID0_VER_0:
181dc804ab7SEngin AYDOGAN return DID0_CLASS_SANDSTORM;
182dc804ab7SEngin AYDOGAN case DID0_VER_1:
183dc804ab7SEngin AYDOGAN switch (did0 & DID0_CLASS_MASK) {
184dc804ab7SEngin AYDOGAN case DID0_CLASS_SANDSTORM:
185dc804ab7SEngin AYDOGAN case DID0_CLASS_FURY:
186dc804ab7SEngin AYDOGAN return did0 & DID0_CLASS_MASK;
187dc804ab7SEngin AYDOGAN }
188dc804ab7SEngin AYDOGAN /* for unknown classes, fall through */
189dc804ab7SEngin AYDOGAN default:
190df3692e0SPeter Maydell /* This can only happen if the hardwired constant did0 value
191df3692e0SPeter Maydell * in this board's stellaris_board_info struct is wrong.
192df3692e0SPeter Maydell */
193df3692e0SPeter Maydell g_assert_not_reached();
194dc804ab7SEngin AYDOGAN }
195dc804ab7SEngin AYDOGAN }
196dc804ab7SEngin AYDOGAN
ssys_read(void * opaque,hwaddr offset,unsigned size)197a8170e5eSAvi Kivity static uint64_t ssys_read(void *opaque, hwaddr offset,
1985699301fSBenoît Canet unsigned size)
1999ee6e8bbSpbrook {
2009ee6e8bbSpbrook ssys_state *s = (ssys_state *)opaque;
2019ee6e8bbSpbrook
2029ee6e8bbSpbrook switch (offset) {
2039ee6e8bbSpbrook case 0x000: /* DID0 */
2044bebb9adSPeter Maydell return s->did0;
2059ee6e8bbSpbrook case 0x004: /* DID1 */
2064bebb9adSPeter Maydell return s->did1;
2079ee6e8bbSpbrook case 0x008: /* DC0 */
2084bebb9adSPeter Maydell return s->dc0;
2099ee6e8bbSpbrook case 0x010: /* DC1 */
2104bebb9adSPeter Maydell return s->dc1;
2119ee6e8bbSpbrook case 0x014: /* DC2 */
2124bebb9adSPeter Maydell return s->dc2;
2139ee6e8bbSpbrook case 0x018: /* DC3 */
2144bebb9adSPeter Maydell return s->dc3;
2159ee6e8bbSpbrook case 0x01c: /* DC4 */
2164bebb9adSPeter Maydell return s->dc4;
2179ee6e8bbSpbrook case 0x030: /* PBORCTL */
2189ee6e8bbSpbrook return s->pborctl;
2199ee6e8bbSpbrook case 0x034: /* LDOPCTL */
2209ee6e8bbSpbrook return s->ldopctl;
2219ee6e8bbSpbrook case 0x040: /* SRCR0 */
2229ee6e8bbSpbrook return 0;
2239ee6e8bbSpbrook case 0x044: /* SRCR1 */
2249ee6e8bbSpbrook return 0;
2259ee6e8bbSpbrook case 0x048: /* SRCR2 */
2269ee6e8bbSpbrook return 0;
2279ee6e8bbSpbrook case 0x050: /* RIS */
2289ee6e8bbSpbrook return s->int_status;
2299ee6e8bbSpbrook case 0x054: /* IMC */
2309ee6e8bbSpbrook return s->int_mask;
2319ee6e8bbSpbrook case 0x058: /* MISC */
2329ee6e8bbSpbrook return s->int_status & s->int_mask;
2339ee6e8bbSpbrook case 0x05c: /* RESC */
2349ee6e8bbSpbrook return s->resc;
2359ee6e8bbSpbrook case 0x060: /* RCC */
2369ee6e8bbSpbrook return s->rcc;
2379ee6e8bbSpbrook case 0x064: /* PLLCFG */
2389ee6e8bbSpbrook {
2399ee6e8bbSpbrook int xtal;
2409ee6e8bbSpbrook xtal = (s->rcc >> 6) & 0xf;
241dc804ab7SEngin AYDOGAN switch (ssys_board_class(s)) {
242dc804ab7SEngin AYDOGAN case DID0_CLASS_FURY:
2439ee6e8bbSpbrook return pllcfg_fury[xtal];
244dc804ab7SEngin AYDOGAN case DID0_CLASS_SANDSTORM:
2459ee6e8bbSpbrook return pllcfg_sandstorm[xtal];
246dc804ab7SEngin AYDOGAN default:
247df3692e0SPeter Maydell g_assert_not_reached();
2489ee6e8bbSpbrook }
2499ee6e8bbSpbrook }
250dc804ab7SEngin AYDOGAN case 0x070: /* RCC2 */
251dc804ab7SEngin AYDOGAN return s->rcc2;
2529ee6e8bbSpbrook case 0x100: /* RCGC0 */
2539ee6e8bbSpbrook return s->rcgc[0];
2549ee6e8bbSpbrook case 0x104: /* RCGC1 */
2559ee6e8bbSpbrook return s->rcgc[1];
2569ee6e8bbSpbrook case 0x108: /* RCGC2 */
2579ee6e8bbSpbrook return s->rcgc[2];
2589ee6e8bbSpbrook case 0x110: /* SCGC0 */
2599ee6e8bbSpbrook return s->scgc[0];
2609ee6e8bbSpbrook case 0x114: /* SCGC1 */
2619ee6e8bbSpbrook return s->scgc[1];
2629ee6e8bbSpbrook case 0x118: /* SCGC2 */
2639ee6e8bbSpbrook return s->scgc[2];
2649ee6e8bbSpbrook case 0x120: /* DCGC0 */
2659ee6e8bbSpbrook return s->dcgc[0];
2669ee6e8bbSpbrook case 0x124: /* DCGC1 */
2679ee6e8bbSpbrook return s->dcgc[1];
2689ee6e8bbSpbrook case 0x128: /* DCGC2 */
2699ee6e8bbSpbrook return s->dcgc[2];
2709ee6e8bbSpbrook case 0x150: /* CLKVCLR */
2719ee6e8bbSpbrook return s->clkvclr;
2729ee6e8bbSpbrook case 0x160: /* LDOARST */
2739ee6e8bbSpbrook return s->ldoarst;
274eea589ccSpbrook case 0x1e0: /* USER0 */
275eea589ccSpbrook return s->user0;
276eea589ccSpbrook case 0x1e4: /* USER1 */
277eea589ccSpbrook return s->user1;
2789ee6e8bbSpbrook default:
279df3692e0SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
280df3692e0SPeter Maydell "SSYS: read at bad offset 0x%x\n", (int)offset);
2819ee6e8bbSpbrook return 0;
2829ee6e8bbSpbrook }
2839ee6e8bbSpbrook }
2849ee6e8bbSpbrook
ssys_use_rcc2(ssys_state * s)285dc804ab7SEngin AYDOGAN static bool ssys_use_rcc2(ssys_state *s)
286dc804ab7SEngin AYDOGAN {
287dc804ab7SEngin AYDOGAN return (s->rcc2 >> 31) & 0x1;
288dc804ab7SEngin AYDOGAN }
289dc804ab7SEngin AYDOGAN
290dc804ab7SEngin AYDOGAN /*
2911e31d8eeSPeter Maydell * Calculate the system clock period. We only want to propagate
2921e31d8eeSPeter Maydell * this change to the rest of the system if we're not being called
2931e31d8eeSPeter Maydell * from migration post-load.
294dc804ab7SEngin AYDOGAN */
ssys_calculate_system_clock(ssys_state * s,bool propagate_clock)2951e31d8eeSPeter Maydell static void ssys_calculate_system_clock(ssys_state *s, bool propagate_clock)
29623e39294Spbrook {
297683754c7SPeter Maydell int period_ns;
2981e31d8eeSPeter Maydell /*
2991e31d8eeSPeter Maydell * SYSDIV field specifies divisor: 0 == /1, 1 == /2, etc. Input
3001e31d8eeSPeter Maydell * clock is 200MHz, which is a period of 5 ns. Dividing the clock
3011e31d8eeSPeter Maydell * frequency by X is the same as multiplying the period by X.
3021e31d8eeSPeter Maydell */
303dc804ab7SEngin AYDOGAN if (ssys_use_rcc2(s)) {
304683754c7SPeter Maydell period_ns = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
305dc804ab7SEngin AYDOGAN } else {
306683754c7SPeter Maydell period_ns = 5 * (((s->rcc >> 23) & 0xf) + 1);
30723e39294Spbrook }
308683754c7SPeter Maydell clock_set_ns(s->sysclk, period_ns);
3091e31d8eeSPeter Maydell if (propagate_clock) {
3101e31d8eeSPeter Maydell clock_propagate(s->sysclk);
3111e31d8eeSPeter Maydell }
312dc804ab7SEngin AYDOGAN }
31323e39294Spbrook
ssys_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)314a8170e5eSAvi Kivity static void ssys_write(void *opaque, hwaddr offset,
3155699301fSBenoît Canet uint64_t value, unsigned size)
3169ee6e8bbSpbrook {
3179ee6e8bbSpbrook ssys_state *s = (ssys_state *)opaque;
3189ee6e8bbSpbrook
3199ee6e8bbSpbrook switch (offset) {
3209ee6e8bbSpbrook case 0x030: /* PBORCTL */
3219ee6e8bbSpbrook s->pborctl = value & 0xffff;
3229ee6e8bbSpbrook break;
3239ee6e8bbSpbrook case 0x034: /* LDOPCTL */
3249ee6e8bbSpbrook s->ldopctl = value & 0x1f;
3259ee6e8bbSpbrook break;
3269ee6e8bbSpbrook case 0x040: /* SRCR0 */
3279ee6e8bbSpbrook case 0x044: /* SRCR1 */
3289ee6e8bbSpbrook case 0x048: /* SRCR2 */
3299194524bSPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, "Peripheral reset not implemented\n");
3309ee6e8bbSpbrook break;
3319ee6e8bbSpbrook case 0x054: /* IMC */
3329ee6e8bbSpbrook s->int_mask = value & 0x7f;
3339ee6e8bbSpbrook break;
3349ee6e8bbSpbrook case 0x058: /* MISC */
3359ee6e8bbSpbrook s->int_status &= ~value;
3369ee6e8bbSpbrook break;
3379ee6e8bbSpbrook case 0x05c: /* RESC */
3389ee6e8bbSpbrook s->resc = value & 0x3f;
3399ee6e8bbSpbrook break;
3409ee6e8bbSpbrook case 0x060: /* RCC */
3419ee6e8bbSpbrook if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
3429ee6e8bbSpbrook /* PLL enable. */
3439ee6e8bbSpbrook s->int_status |= (1 << 6);
3449ee6e8bbSpbrook }
3459ee6e8bbSpbrook s->rcc = value;
3461e31d8eeSPeter Maydell ssys_calculate_system_clock(s, true);
3479ee6e8bbSpbrook break;
348dc804ab7SEngin AYDOGAN case 0x070: /* RCC2 */
349dc804ab7SEngin AYDOGAN if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
350dc804ab7SEngin AYDOGAN break;
351dc804ab7SEngin AYDOGAN }
352dc804ab7SEngin AYDOGAN
353dc804ab7SEngin AYDOGAN if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
354dc804ab7SEngin AYDOGAN /* PLL enable. */
355dc804ab7SEngin AYDOGAN s->int_status |= (1 << 6);
356dc804ab7SEngin AYDOGAN }
357dc804ab7SEngin AYDOGAN s->rcc2 = value;
3581e31d8eeSPeter Maydell ssys_calculate_system_clock(s, true);
359dc804ab7SEngin AYDOGAN break;
3609ee6e8bbSpbrook case 0x100: /* RCGC0 */
3619ee6e8bbSpbrook s->rcgc[0] = value;
3629ee6e8bbSpbrook break;
3639ee6e8bbSpbrook case 0x104: /* RCGC1 */
3649ee6e8bbSpbrook s->rcgc[1] = value;
3659ee6e8bbSpbrook break;
3669ee6e8bbSpbrook case 0x108: /* RCGC2 */
3679ee6e8bbSpbrook s->rcgc[2] = value;
3689ee6e8bbSpbrook break;
3699ee6e8bbSpbrook case 0x110: /* SCGC0 */
3709ee6e8bbSpbrook s->scgc[0] = value;
3719ee6e8bbSpbrook break;
3729ee6e8bbSpbrook case 0x114: /* SCGC1 */
3739ee6e8bbSpbrook s->scgc[1] = value;
3749ee6e8bbSpbrook break;
3759ee6e8bbSpbrook case 0x118: /* SCGC2 */
3769ee6e8bbSpbrook s->scgc[2] = value;
3779ee6e8bbSpbrook break;
3789ee6e8bbSpbrook case 0x120: /* DCGC0 */
3799ee6e8bbSpbrook s->dcgc[0] = value;
3809ee6e8bbSpbrook break;
3819ee6e8bbSpbrook case 0x124: /* DCGC1 */
3829ee6e8bbSpbrook s->dcgc[1] = value;
3839ee6e8bbSpbrook break;
3849ee6e8bbSpbrook case 0x128: /* DCGC2 */
3859ee6e8bbSpbrook s->dcgc[2] = value;
3869ee6e8bbSpbrook break;
3879ee6e8bbSpbrook case 0x150: /* CLKVCLR */
3889ee6e8bbSpbrook s->clkvclr = value;
3899ee6e8bbSpbrook break;
3909ee6e8bbSpbrook case 0x160: /* LDOARST */
3919ee6e8bbSpbrook s->ldoarst = value;
3929ee6e8bbSpbrook break;
3939ee6e8bbSpbrook default:
394df3692e0SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
395df3692e0SPeter Maydell "SSYS: write at bad offset 0x%x\n", (int)offset);
3969ee6e8bbSpbrook }
3979ee6e8bbSpbrook ssys_update(s);
3989ee6e8bbSpbrook }
3999ee6e8bbSpbrook
4005699301fSBenoît Canet static const MemoryRegionOps ssys_ops = {
4015699301fSBenoît Canet .read = ssys_read,
4025699301fSBenoît Canet .write = ssys_write,
4035699301fSBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN,
4049ee6e8bbSpbrook };
4059ee6e8bbSpbrook
stellaris_sys_reset_enter(Object * obj,ResetType type)4064bebb9adSPeter Maydell static void stellaris_sys_reset_enter(Object *obj, ResetType type)
4079ee6e8bbSpbrook {
4084bebb9adSPeter Maydell ssys_state *s = STELLARIS_SYS(obj);
4099ee6e8bbSpbrook
4109ee6e8bbSpbrook s->pborctl = 0x7ffd;
4119ee6e8bbSpbrook s->rcc = 0x078e3ac0;
412dc804ab7SEngin AYDOGAN
413dc804ab7SEngin AYDOGAN if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
414dc804ab7SEngin AYDOGAN s->rcc2 = 0;
415dc804ab7SEngin AYDOGAN } else {
416dc804ab7SEngin AYDOGAN s->rcc2 = 0x07802810;
417dc804ab7SEngin AYDOGAN }
4189ee6e8bbSpbrook s->rcgc[0] = 1;
4199ee6e8bbSpbrook s->scgc[0] = 1;
4209ee6e8bbSpbrook s->dcgc[0] = 1;
4214bebb9adSPeter Maydell }
4224bebb9adSPeter Maydell
stellaris_sys_reset_hold(Object * obj,ResetType type)423ad80e367SPeter Maydell static void stellaris_sys_reset_hold(Object *obj, ResetType type)
4244bebb9adSPeter Maydell {
4254bebb9adSPeter Maydell ssys_state *s = STELLARIS_SYS(obj);
4264bebb9adSPeter Maydell
4271e31d8eeSPeter Maydell /* OK to propagate clocks from the hold phase */
4281e31d8eeSPeter Maydell ssys_calculate_system_clock(s, true);
4299ee6e8bbSpbrook }
4309ee6e8bbSpbrook
stellaris_sys_reset_exit(Object * obj,ResetType type)431ad80e367SPeter Maydell static void stellaris_sys_reset_exit(Object *obj, ResetType type)
4324bebb9adSPeter Maydell {
4334bebb9adSPeter Maydell }
4344bebb9adSPeter Maydell
stellaris_sys_post_load(void * opaque,int version_id)435293c16aaSJuan Quintela static int stellaris_sys_post_load(void *opaque, int version_id)
43623e39294Spbrook {
437293c16aaSJuan Quintela ssys_state *s = opaque;
43823e39294Spbrook
4391e31d8eeSPeter Maydell ssys_calculate_system_clock(s, false);
44023e39294Spbrook
44123e39294Spbrook return 0;
44223e39294Spbrook }
44323e39294Spbrook
444293c16aaSJuan Quintela static const VMStateDescription vmstate_stellaris_sys = {
445293c16aaSJuan Quintela .name = "stellaris_sys",
446dc804ab7SEngin AYDOGAN .version_id = 2,
447293c16aaSJuan Quintela .minimum_version_id = 1,
448293c16aaSJuan Quintela .post_load = stellaris_sys_post_load,
449607ef570SRichard Henderson .fields = (const VMStateField[]) {
450293c16aaSJuan Quintela VMSTATE_UINT32(pborctl, ssys_state),
451293c16aaSJuan Quintela VMSTATE_UINT32(ldopctl, ssys_state),
452293c16aaSJuan Quintela VMSTATE_UINT32(int_mask, ssys_state),
453293c16aaSJuan Quintela VMSTATE_UINT32(int_status, ssys_state),
454293c16aaSJuan Quintela VMSTATE_UINT32(resc, ssys_state),
455293c16aaSJuan Quintela VMSTATE_UINT32(rcc, ssys_state),
456dc804ab7SEngin AYDOGAN VMSTATE_UINT32_V(rcc2, ssys_state, 2),
457293c16aaSJuan Quintela VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
458293c16aaSJuan Quintela VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
459293c16aaSJuan Quintela VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
460293c16aaSJuan Quintela VMSTATE_UINT32(clkvclr, ssys_state),
461293c16aaSJuan Quintela VMSTATE_UINT32(ldoarst, ssys_state),
4621e31d8eeSPeter Maydell /* No field for sysclk -- handled in post-load instead */
463293c16aaSJuan Quintela VMSTATE_END_OF_LIST()
464293c16aaSJuan Quintela }
465293c16aaSJuan Quintela };
466293c16aaSJuan Quintela
467e15bd5ddSRichard Henderson static const Property stellaris_sys_properties[] = {
4684bebb9adSPeter Maydell DEFINE_PROP_UINT32("user0", ssys_state, user0, 0),
4694bebb9adSPeter Maydell DEFINE_PROP_UINT32("user1", ssys_state, user1, 0),
4704bebb9adSPeter Maydell DEFINE_PROP_UINT32("did0", ssys_state, did0, 0),
4714bebb9adSPeter Maydell DEFINE_PROP_UINT32("did1", ssys_state, did1, 0),
4724bebb9adSPeter Maydell DEFINE_PROP_UINT32("dc0", ssys_state, dc0, 0),
4734bebb9adSPeter Maydell DEFINE_PROP_UINT32("dc1", ssys_state, dc1, 0),
4744bebb9adSPeter Maydell DEFINE_PROP_UINT32("dc2", ssys_state, dc2, 0),
4754bebb9adSPeter Maydell DEFINE_PROP_UINT32("dc3", ssys_state, dc3, 0),
4764bebb9adSPeter Maydell DEFINE_PROP_UINT32("dc4", ssys_state, dc4, 0),
4774bebb9adSPeter Maydell };
4784bebb9adSPeter Maydell
stellaris_sys_instance_init(Object * obj)4794bebb9adSPeter Maydell static void stellaris_sys_instance_init(Object *obj)
4804bebb9adSPeter Maydell {
4814bebb9adSPeter Maydell ssys_state *s = STELLARIS_SYS(obj);
4824bebb9adSPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(s);
4834bebb9adSPeter Maydell
4844bebb9adSPeter Maydell memory_region_init_io(&s->iomem, obj, &ssys_ops, s, "ssys", 0x00001000);
4854bebb9adSPeter Maydell sysbus_init_mmio(sbd, &s->iomem);
4864bebb9adSPeter Maydell sysbus_init_irq(sbd, &s->irq);
4871e31d8eeSPeter Maydell s->sysclk = qdev_init_clock_out(DEVICE(s), "SYSCLK");
4884bebb9adSPeter Maydell }
4894bebb9adSPeter Maydell
490cee78fa5SPhilippe Mathieu-Daudé /*
491cee78fa5SPhilippe Mathieu-Daudé * I2C controller.
492cee78fa5SPhilippe Mathieu-Daudé * ??? For now we only implement the master interface.
493cee78fa5SPhilippe Mathieu-Daudé */
4949ee6e8bbSpbrook
495d94a4015SAndreas Färber #define TYPE_STELLARIS_I2C "stellaris-i2c"
4968063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(stellaris_i2c_state, STELLARIS_I2C)
497d94a4015SAndreas Färber
498db1015e9SEduardo Habkost struct stellaris_i2c_state {
499d94a4015SAndreas Färber SysBusDevice parent_obj;
500d94a4015SAndreas Färber
501a5c82852SAndreas Färber I2CBus *bus;
5029ee6e8bbSpbrook qemu_irq irq;
5038ea72f38SBenoît Canet MemoryRegion iomem;
5049ee6e8bbSpbrook uint32_t msa;
5059ee6e8bbSpbrook uint32_t mcs;
5069ee6e8bbSpbrook uint32_t mdr;
5079ee6e8bbSpbrook uint32_t mtpr;
5089ee6e8bbSpbrook uint32_t mimr;
5099ee6e8bbSpbrook uint32_t mris;
5109ee6e8bbSpbrook uint32_t mcr;
511db1015e9SEduardo Habkost };
5129ee6e8bbSpbrook
5139ee6e8bbSpbrook #define STELLARIS_I2C_MCS_BUSY 0x01
5149ee6e8bbSpbrook #define STELLARIS_I2C_MCS_ERROR 0x02
5159ee6e8bbSpbrook #define STELLARIS_I2C_MCS_ADRACK 0x04
5169ee6e8bbSpbrook #define STELLARIS_I2C_MCS_DATACK 0x08
5179ee6e8bbSpbrook #define STELLARIS_I2C_MCS_ARBLST 0x10
5189ee6e8bbSpbrook #define STELLARIS_I2C_MCS_IDLE 0x20
5199ee6e8bbSpbrook #define STELLARIS_I2C_MCS_BUSBSY 0x40
5209ee6e8bbSpbrook
stellaris_i2c_read(void * opaque,hwaddr offset,unsigned size)521a8170e5eSAvi Kivity static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset,
5228ea72f38SBenoît Canet unsigned size)
5239ee6e8bbSpbrook {
5249ee6e8bbSpbrook stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
5259ee6e8bbSpbrook
5269ee6e8bbSpbrook switch (offset) {
5279ee6e8bbSpbrook case 0x00: /* MSA */
5289ee6e8bbSpbrook return s->msa;
5299ee6e8bbSpbrook case 0x04: /* MCS */
5309ee6e8bbSpbrook /* We don't emulate timing, so the controller is never busy. */
5319ee6e8bbSpbrook return s->mcs | STELLARIS_I2C_MCS_IDLE;
5329ee6e8bbSpbrook case 0x08: /* MDR */
5339ee6e8bbSpbrook return s->mdr;
5349ee6e8bbSpbrook case 0x0c: /* MTPR */
5359ee6e8bbSpbrook return s->mtpr;
5369ee6e8bbSpbrook case 0x10: /* MIMR */
5379ee6e8bbSpbrook return s->mimr;
5389ee6e8bbSpbrook case 0x14: /* MRIS */
5399ee6e8bbSpbrook return s->mris;
5409ee6e8bbSpbrook case 0x18: /* MMIS */
5419ee6e8bbSpbrook return s->mris & s->mimr;
5429ee6e8bbSpbrook case 0x20: /* MCR */
5439ee6e8bbSpbrook return s->mcr;
5449ee6e8bbSpbrook default:
545df3692e0SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
546df3692e0SPeter Maydell "stellaris_i2c: read at bad offset 0x%x\n", (int)offset);
5479ee6e8bbSpbrook return 0;
5489ee6e8bbSpbrook }
5499ee6e8bbSpbrook }
5509ee6e8bbSpbrook
stellaris_i2c_update(stellaris_i2c_state * s)5519ee6e8bbSpbrook static void stellaris_i2c_update(stellaris_i2c_state *s)
5529ee6e8bbSpbrook {
5539ee6e8bbSpbrook int level;
5549ee6e8bbSpbrook
5559ee6e8bbSpbrook level = (s->mris & s->mimr) != 0;
5569ee6e8bbSpbrook qemu_set_irq(s->irq, level);
5579ee6e8bbSpbrook }
5589ee6e8bbSpbrook
stellaris_i2c_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)559a8170e5eSAvi Kivity static void stellaris_i2c_write(void *opaque, hwaddr offset,
5608ea72f38SBenoît Canet uint64_t value, unsigned size)
5619ee6e8bbSpbrook {
5629ee6e8bbSpbrook stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
5639ee6e8bbSpbrook
5649ee6e8bbSpbrook switch (offset) {
5659ee6e8bbSpbrook case 0x00: /* MSA */
5669ee6e8bbSpbrook s->msa = value & 0xff;
5679ee6e8bbSpbrook break;
5689ee6e8bbSpbrook case 0x04: /* MCS */
5699ee6e8bbSpbrook if ((s->mcr & 0x10) == 0) {
5709ee6e8bbSpbrook /* Disabled. Do nothing. */
5719ee6e8bbSpbrook break;
5729ee6e8bbSpbrook }
5739ee6e8bbSpbrook /* Grab the bus if this is starting a transfer. */
5749ee6e8bbSpbrook if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
5759ee6e8bbSpbrook if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
5769ee6e8bbSpbrook s->mcs |= STELLARIS_I2C_MCS_ARBLST;
5779ee6e8bbSpbrook } else {
5789ee6e8bbSpbrook s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
5799ee6e8bbSpbrook s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
5809ee6e8bbSpbrook }
5819ee6e8bbSpbrook }
5829ee6e8bbSpbrook /* If we don't have the bus then indicate an error. */
5839ee6e8bbSpbrook if (!i2c_bus_busy(s->bus)
5849ee6e8bbSpbrook || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
5859ee6e8bbSpbrook s->mcs |= STELLARIS_I2C_MCS_ERROR;
5869ee6e8bbSpbrook break;
5879ee6e8bbSpbrook }
5889ee6e8bbSpbrook s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
5899ee6e8bbSpbrook if (value & 1) {
5909ee6e8bbSpbrook /* Transfer a byte. */
5919ee6e8bbSpbrook /* TODO: Handle errors. */
5929ee6e8bbSpbrook if (s->msa & 1) {
5939ee6e8bbSpbrook /* Recv */
59405f9f17eSCorey Minyard s->mdr = i2c_recv(s->bus);
5959ee6e8bbSpbrook } else {
5969ee6e8bbSpbrook /* Send */
5979ee6e8bbSpbrook i2c_send(s->bus, s->mdr);
5989ee6e8bbSpbrook }
5999ee6e8bbSpbrook /* Raise an interrupt. */
6009ee6e8bbSpbrook s->mris |= 1;
6019ee6e8bbSpbrook }
6029ee6e8bbSpbrook if (value & 4) {
6039ee6e8bbSpbrook /* Finish transfer. */
6049ee6e8bbSpbrook i2c_end_transfer(s->bus);
6059ee6e8bbSpbrook s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
6069ee6e8bbSpbrook }
6079ee6e8bbSpbrook break;
6089ee6e8bbSpbrook case 0x08: /* MDR */
6099ee6e8bbSpbrook s->mdr = value & 0xff;
6109ee6e8bbSpbrook break;
6119ee6e8bbSpbrook case 0x0c: /* MTPR */
6129ee6e8bbSpbrook s->mtpr = value & 0xff;
6139ee6e8bbSpbrook break;
6149ee6e8bbSpbrook case 0x10: /* MIMR */
6159ee6e8bbSpbrook s->mimr = 1;
6169ee6e8bbSpbrook break;
6179ee6e8bbSpbrook case 0x1c: /* MICR */
6189ee6e8bbSpbrook s->mris &= ~value;
6199ee6e8bbSpbrook break;
6209ee6e8bbSpbrook case 0x20: /* MCR */
621df3692e0SPeter Maydell if (value & 1) {
6229492e4b2SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP,
6239492e4b2SPhilippe Mathieu-Daudé "stellaris_i2c: Loopback not implemented\n");
624df3692e0SPeter Maydell }
625df3692e0SPeter Maydell if (value & 0x20) {
626df3692e0SPeter Maydell qemu_log_mask(LOG_UNIMP,
6279492e4b2SPhilippe Mathieu-Daudé "stellaris_i2c: Slave mode not implemented\n");
628df3692e0SPeter Maydell }
6299ee6e8bbSpbrook s->mcr = value & 0x31;
6309ee6e8bbSpbrook break;
6319ee6e8bbSpbrook default:
632df3692e0SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
633df3692e0SPeter Maydell "stellaris_i2c: write at bad offset 0x%x\n", (int)offset);
6349ee6e8bbSpbrook }
6359ee6e8bbSpbrook stellaris_i2c_update(s);
6369ee6e8bbSpbrook }
6379ee6e8bbSpbrook
stellaris_i2c_reset_enter(Object * obj,ResetType type)638cee78fa5SPhilippe Mathieu-Daudé static void stellaris_i2c_reset_enter(Object *obj, ResetType type)
6399ee6e8bbSpbrook {
640cee78fa5SPhilippe Mathieu-Daudé stellaris_i2c_state *s = STELLARIS_I2C(obj);
641cee78fa5SPhilippe Mathieu-Daudé
6429ee6e8bbSpbrook if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
6439ee6e8bbSpbrook i2c_end_transfer(s->bus);
644cee78fa5SPhilippe Mathieu-Daudé }
645cee78fa5SPhilippe Mathieu-Daudé
stellaris_i2c_reset_hold(Object * obj,ResetType type)646ad80e367SPeter Maydell static void stellaris_i2c_reset_hold(Object *obj, ResetType type)
647cee78fa5SPhilippe Mathieu-Daudé {
648cee78fa5SPhilippe Mathieu-Daudé stellaris_i2c_state *s = STELLARIS_I2C(obj);
6499ee6e8bbSpbrook
6509ee6e8bbSpbrook s->msa = 0;
6519ee6e8bbSpbrook s->mcs = 0;
6529ee6e8bbSpbrook s->mdr = 0;
6539ee6e8bbSpbrook s->mtpr = 1;
6549ee6e8bbSpbrook s->mimr = 0;
6559ee6e8bbSpbrook s->mris = 0;
6569ee6e8bbSpbrook s->mcr = 0;
657cee78fa5SPhilippe Mathieu-Daudé }
658cee78fa5SPhilippe Mathieu-Daudé
stellaris_i2c_reset_exit(Object * obj,ResetType type)659ad80e367SPeter Maydell static void stellaris_i2c_reset_exit(Object *obj, ResetType type)
660cee78fa5SPhilippe Mathieu-Daudé {
661cee78fa5SPhilippe Mathieu-Daudé stellaris_i2c_state *s = STELLARIS_I2C(obj);
662cee78fa5SPhilippe Mathieu-Daudé
6639ee6e8bbSpbrook stellaris_i2c_update(s);
6649ee6e8bbSpbrook }
6659ee6e8bbSpbrook
6668ea72f38SBenoît Canet static const MemoryRegionOps stellaris_i2c_ops = {
6678ea72f38SBenoît Canet .read = stellaris_i2c_read,
6688ea72f38SBenoît Canet .write = stellaris_i2c_write,
6698ea72f38SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN,
6709ee6e8bbSpbrook };
6719ee6e8bbSpbrook
672ff269cd0SJuan Quintela static const VMStateDescription vmstate_stellaris_i2c = {
673ff269cd0SJuan Quintela .name = "stellaris_i2c",
674ff269cd0SJuan Quintela .version_id = 1,
675ff269cd0SJuan Quintela .minimum_version_id = 1,
676607ef570SRichard Henderson .fields = (const VMStateField[]) {
677ff269cd0SJuan Quintela VMSTATE_UINT32(msa, stellaris_i2c_state),
678ff269cd0SJuan Quintela VMSTATE_UINT32(mcs, stellaris_i2c_state),
679ff269cd0SJuan Quintela VMSTATE_UINT32(mdr, stellaris_i2c_state),
680ff269cd0SJuan Quintela VMSTATE_UINT32(mtpr, stellaris_i2c_state),
681ff269cd0SJuan Quintela VMSTATE_UINT32(mimr, stellaris_i2c_state),
682ff269cd0SJuan Quintela VMSTATE_UINT32(mris, stellaris_i2c_state),
683ff269cd0SJuan Quintela VMSTATE_UINT32(mcr, stellaris_i2c_state),
684ff269cd0SJuan Quintela VMSTATE_END_OF_LIST()
68523e39294Spbrook }
686ff269cd0SJuan Quintela };
68723e39294Spbrook
stellaris_i2c_init(Object * obj)68815c4fff5Sxiaoqiang.zhao static void stellaris_i2c_init(Object *obj)
6899ee6e8bbSpbrook {
69015c4fff5Sxiaoqiang.zhao DeviceState *dev = DEVICE(obj);
69115c4fff5Sxiaoqiang.zhao stellaris_i2c_state *s = STELLARIS_I2C(obj);
69215c4fff5Sxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
693a5c82852SAndreas Färber I2CBus *bus;
6949ee6e8bbSpbrook
695d94a4015SAndreas Färber sysbus_init_irq(sbd, &s->irq);
696d94a4015SAndreas Färber bus = i2c_init_bus(dev, "i2c");
6979ee6e8bbSpbrook s->bus = bus;
6989ee6e8bbSpbrook
69915c4fff5Sxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &stellaris_i2c_ops, s,
7008ea72f38SBenoît Canet "i2c", 0x1000);
701d94a4015SAndreas Färber sysbus_init_mmio(sbd, &s->iomem);
7029ee6e8bbSpbrook }
7039ee6e8bbSpbrook
7049ee6e8bbSpbrook /* Analogue to Digital Converter. This is only partially implemented,
7059ee6e8bbSpbrook enough for applications that use a combined ADC and timer tick. */
7069ee6e8bbSpbrook
7079ee6e8bbSpbrook #define STELLARIS_ADC_EM_CONTROLLER 0
7089ee6e8bbSpbrook #define STELLARIS_ADC_EM_COMP 1
7099ee6e8bbSpbrook #define STELLARIS_ADC_EM_EXTERNAL 4
7109ee6e8bbSpbrook #define STELLARIS_ADC_EM_TIMER 5
7119ee6e8bbSpbrook #define STELLARIS_ADC_EM_PWM0 6
7129ee6e8bbSpbrook #define STELLARIS_ADC_EM_PWM1 7
7139ee6e8bbSpbrook #define STELLARIS_ADC_EM_PWM2 8
7149ee6e8bbSpbrook
7159ee6e8bbSpbrook #define STELLARIS_ADC_FIFO_EMPTY 0x0100
7169ee6e8bbSpbrook #define STELLARIS_ADC_FIFO_FULL 0x1000
7179ee6e8bbSpbrook
7187df7f67aSAndreas Färber #define TYPE_STELLARIS_ADC "stellaris-adc"
719d6b109daSPhilippe Mathieu-Daudé typedef struct StellarisADCState StellarisADCState;
720d6b109daSPhilippe Mathieu-Daudé DECLARE_INSTANCE_CHECKER(StellarisADCState, STELLARIS_ADC, TYPE_STELLARIS_ADC)
7217df7f67aSAndreas Färber
722db1015e9SEduardo Habkost struct StellarisADCState {
7237df7f67aSAndreas Färber SysBusDevice parent_obj;
7247df7f67aSAndreas Färber
72571a2df05SBenoît Canet MemoryRegion iomem;
7269ee6e8bbSpbrook uint32_t actss;
7279ee6e8bbSpbrook uint32_t ris;
7289ee6e8bbSpbrook uint32_t im;
7299ee6e8bbSpbrook uint32_t emux;
7309ee6e8bbSpbrook uint32_t ostat;
7319ee6e8bbSpbrook uint32_t ustat;
7329ee6e8bbSpbrook uint32_t sspri;
7339ee6e8bbSpbrook uint32_t sac;
7349ee6e8bbSpbrook struct {
7359ee6e8bbSpbrook uint32_t state;
7369ee6e8bbSpbrook uint32_t data[16];
7379ee6e8bbSpbrook } fifo[4];
7389ee6e8bbSpbrook uint32_t ssmux[4];
7399ee6e8bbSpbrook uint32_t ssctl[4];
74023e39294Spbrook uint32_t noise;
7412c6554bcSPaul Brook qemu_irq irq[4];
742db1015e9SEduardo Habkost };
7439ee6e8bbSpbrook
stellaris_adc_fifo_read(StellarisADCState * s,int n)744d6b109daSPhilippe Mathieu-Daudé static uint32_t stellaris_adc_fifo_read(StellarisADCState *s, int n)
7459ee6e8bbSpbrook {
7469ee6e8bbSpbrook int tail;
7479ee6e8bbSpbrook
7489ee6e8bbSpbrook tail = s->fifo[n].state & 0xf;
7499ee6e8bbSpbrook if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
7509ee6e8bbSpbrook s->ustat |= 1 << n;
7519ee6e8bbSpbrook } else {
7529ee6e8bbSpbrook s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
7539ee6e8bbSpbrook s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
7549ee6e8bbSpbrook if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
7559ee6e8bbSpbrook s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
7569ee6e8bbSpbrook }
7579ee6e8bbSpbrook return s->fifo[n].data[tail];
7589ee6e8bbSpbrook }
7599ee6e8bbSpbrook
stellaris_adc_fifo_write(StellarisADCState * s,int n,uint32_t value)760d6b109daSPhilippe Mathieu-Daudé static void stellaris_adc_fifo_write(StellarisADCState *s, int n,
7619ee6e8bbSpbrook uint32_t value)
7629ee6e8bbSpbrook {
7639ee6e8bbSpbrook int head;
7649ee6e8bbSpbrook
7652c6554bcSPaul Brook /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry
7662c6554bcSPaul Brook FIFO fir each sequencer. */
7679ee6e8bbSpbrook head = (s->fifo[n].state >> 4) & 0xf;
7689ee6e8bbSpbrook if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
7699ee6e8bbSpbrook s->ostat |= 1 << n;
7709ee6e8bbSpbrook return;
7719ee6e8bbSpbrook }
7729ee6e8bbSpbrook s->fifo[n].data[head] = value;
7739ee6e8bbSpbrook head = (head + 1) & 0xf;
7749ee6e8bbSpbrook s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
7759ee6e8bbSpbrook s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
7769ee6e8bbSpbrook if ((s->fifo[n].state & 0xf) == head)
7779ee6e8bbSpbrook s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
7789ee6e8bbSpbrook }
7799ee6e8bbSpbrook
stellaris_adc_update(StellarisADCState * s)780d6b109daSPhilippe Mathieu-Daudé static void stellaris_adc_update(StellarisADCState *s)
7819ee6e8bbSpbrook {
7829ee6e8bbSpbrook int level;
7832c6554bcSPaul Brook int n;
7849ee6e8bbSpbrook
7852c6554bcSPaul Brook for (n = 0; n < 4; n++) {
7862c6554bcSPaul Brook level = (s->ris & s->im & (1 << n)) != 0;
7872c6554bcSPaul Brook qemu_set_irq(s->irq[n], level);
7882c6554bcSPaul Brook }
7899ee6e8bbSpbrook }
7909ee6e8bbSpbrook
stellaris_adc_trigger(void * opaque,int irq,int level)7919ee6e8bbSpbrook static void stellaris_adc_trigger(void *opaque, int irq, int level)
7929ee6e8bbSpbrook {
793d6b109daSPhilippe Mathieu-Daudé StellarisADCState *s = opaque;
7942c6554bcSPaul Brook int n;
7959ee6e8bbSpbrook
7962c6554bcSPaul Brook for (n = 0; n < 4; n++) {
7972c6554bcSPaul Brook if ((s->actss & (1 << n)) == 0) {
7982c6554bcSPaul Brook continue;
7992c6554bcSPaul Brook }
8002c6554bcSPaul Brook
8012c6554bcSPaul Brook if (((s->emux >> (n * 4)) & 0xff) != 5) {
8022c6554bcSPaul Brook continue;
8039ee6e8bbSpbrook }
8049ee6e8bbSpbrook
80523e39294Spbrook /* Some applications use the ADC as a random number source, so introduce
80623e39294Spbrook some variation into the signal. */
80723e39294Spbrook s->noise = s->noise * 314159 + 1;
8089ee6e8bbSpbrook /* ??? actual inputs not implemented. Return an arbitrary value. */
8092c6554bcSPaul Brook stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
8102c6554bcSPaul Brook s->ris |= (1 << n);
8119ee6e8bbSpbrook stellaris_adc_update(s);
8129ee6e8bbSpbrook }
8132c6554bcSPaul Brook }
8149ee6e8bbSpbrook
stellaris_adc_reset_hold(Object * obj,ResetType type)815ad80e367SPeter Maydell static void stellaris_adc_reset_hold(Object *obj, ResetType type)
8169ee6e8bbSpbrook {
817bebd89e1SPhilippe Mathieu-Daudé StellarisADCState *s = STELLARIS_ADC(obj);
8189ee6e8bbSpbrook int n;
8199ee6e8bbSpbrook
8209ee6e8bbSpbrook for (n = 0; n < 4; n++) {
8219ee6e8bbSpbrook s->ssmux[n] = 0;
8229ee6e8bbSpbrook s->ssctl[n] = 0;
8239ee6e8bbSpbrook s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
8249ee6e8bbSpbrook }
8259ee6e8bbSpbrook }
8269ee6e8bbSpbrook
stellaris_adc_read(void * opaque,hwaddr offset,unsigned size)827a8170e5eSAvi Kivity static uint64_t stellaris_adc_read(void *opaque, hwaddr offset,
82871a2df05SBenoît Canet unsigned size)
8299ee6e8bbSpbrook {
830d6b109daSPhilippe Mathieu-Daudé StellarisADCState *s = opaque;
8319ee6e8bbSpbrook
8329ee6e8bbSpbrook /* TODO: Implement this. */
8339ee6e8bbSpbrook if (offset >= 0x40 && offset < 0xc0) {
8349ee6e8bbSpbrook int n;
8359ee6e8bbSpbrook n = (offset - 0x40) >> 5;
8369ee6e8bbSpbrook switch (offset & 0x1f) {
8379ee6e8bbSpbrook case 0x00: /* SSMUX */
8389ee6e8bbSpbrook return s->ssmux[n];
8399ee6e8bbSpbrook case 0x04: /* SSCTL */
8409ee6e8bbSpbrook return s->ssctl[n];
8419ee6e8bbSpbrook case 0x08: /* SSFIFO */
8429ee6e8bbSpbrook return stellaris_adc_fifo_read(s, n);
8439ee6e8bbSpbrook case 0x0c: /* SSFSTAT */
8449ee6e8bbSpbrook return s->fifo[n].state;
8459ee6e8bbSpbrook default:
8469ee6e8bbSpbrook break;
8479ee6e8bbSpbrook }
8489ee6e8bbSpbrook }
8499ee6e8bbSpbrook switch (offset) {
8509ee6e8bbSpbrook case 0x00: /* ACTSS */
8519ee6e8bbSpbrook return s->actss;
8529ee6e8bbSpbrook case 0x04: /* RIS */
8539ee6e8bbSpbrook return s->ris;
8549ee6e8bbSpbrook case 0x08: /* IM */
8559ee6e8bbSpbrook return s->im;
8569ee6e8bbSpbrook case 0x0c: /* ISC */
8579ee6e8bbSpbrook return s->ris & s->im;
8589ee6e8bbSpbrook case 0x10: /* OSTAT */
8599ee6e8bbSpbrook return s->ostat;
8609ee6e8bbSpbrook case 0x14: /* EMUX */
8619ee6e8bbSpbrook return s->emux;
8629ee6e8bbSpbrook case 0x18: /* USTAT */
8639ee6e8bbSpbrook return s->ustat;
8649ee6e8bbSpbrook case 0x20: /* SSPRI */
8659ee6e8bbSpbrook return s->sspri;
8669ee6e8bbSpbrook case 0x30: /* SAC */
8679ee6e8bbSpbrook return s->sac;
8689ee6e8bbSpbrook default:
869df3692e0SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
870df3692e0SPeter Maydell "stellaris_adc: read at bad offset 0x%x\n", (int)offset);
8719ee6e8bbSpbrook return 0;
8729ee6e8bbSpbrook }
8739ee6e8bbSpbrook }
8749ee6e8bbSpbrook
stellaris_adc_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)875a8170e5eSAvi Kivity static void stellaris_adc_write(void *opaque, hwaddr offset,
87671a2df05SBenoît Canet uint64_t value, unsigned size)
8779ee6e8bbSpbrook {
878d6b109daSPhilippe Mathieu-Daudé StellarisADCState *s = opaque;
8799ee6e8bbSpbrook
8809ee6e8bbSpbrook /* TODO: Implement this. */
8819ee6e8bbSpbrook if (offset >= 0x40 && offset < 0xc0) {
8829ee6e8bbSpbrook int n;
8839ee6e8bbSpbrook n = (offset - 0x40) >> 5;
8849ee6e8bbSpbrook switch (offset & 0x1f) {
8859ee6e8bbSpbrook case 0x00: /* SSMUX */
8869ee6e8bbSpbrook s->ssmux[n] = value & 0x33333333;
8879ee6e8bbSpbrook return;
8889ee6e8bbSpbrook case 0x04: /* SSCTL */
8899ee6e8bbSpbrook if (value != 6) {
890df3692e0SPeter Maydell qemu_log_mask(LOG_UNIMP,
891df3692e0SPeter Maydell "ADC: Unimplemented sequence %" PRIx64 "\n",
8929ee6e8bbSpbrook value);
8939ee6e8bbSpbrook }
8949ee6e8bbSpbrook s->ssctl[n] = value;
8959ee6e8bbSpbrook return;
8969ee6e8bbSpbrook default:
8979ee6e8bbSpbrook break;
8989ee6e8bbSpbrook }
8999ee6e8bbSpbrook }
9009ee6e8bbSpbrook switch (offset) {
9019ee6e8bbSpbrook case 0x00: /* ACTSS */
9029ee6e8bbSpbrook s->actss = value & 0xf;
9039ee6e8bbSpbrook break;
9049ee6e8bbSpbrook case 0x08: /* IM */
9059ee6e8bbSpbrook s->im = value;
9069ee6e8bbSpbrook break;
9079ee6e8bbSpbrook case 0x0c: /* ISC */
9089ee6e8bbSpbrook s->ris &= ~value;
9099ee6e8bbSpbrook break;
9109ee6e8bbSpbrook case 0x10: /* OSTAT */
9119ee6e8bbSpbrook s->ostat &= ~value;
9129ee6e8bbSpbrook break;
9139ee6e8bbSpbrook case 0x14: /* EMUX */
9149ee6e8bbSpbrook s->emux = value;
9159ee6e8bbSpbrook break;
9169ee6e8bbSpbrook case 0x18: /* USTAT */
9179ee6e8bbSpbrook s->ustat &= ~value;
9189ee6e8bbSpbrook break;
9199ee6e8bbSpbrook case 0x20: /* SSPRI */
9209ee6e8bbSpbrook s->sspri = value;
9219ee6e8bbSpbrook break;
9229ee6e8bbSpbrook case 0x28: /* PSSI */
9239492e4b2SPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, "ADC: sample initiate unimplemented\n");
9249ee6e8bbSpbrook break;
9259ee6e8bbSpbrook case 0x30: /* SAC */
9269ee6e8bbSpbrook s->sac = value;
9279ee6e8bbSpbrook break;
9289ee6e8bbSpbrook default:
929df3692e0SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR,
930df3692e0SPeter Maydell "stellaris_adc: write at bad offset 0x%x\n", (int)offset);
9319ee6e8bbSpbrook }
9329ee6e8bbSpbrook stellaris_adc_update(s);
9339ee6e8bbSpbrook }
9349ee6e8bbSpbrook
93571a2df05SBenoît Canet static const MemoryRegionOps stellaris_adc_ops = {
93671a2df05SBenoît Canet .read = stellaris_adc_read,
93771a2df05SBenoît Canet .write = stellaris_adc_write,
93871a2df05SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN,
9399ee6e8bbSpbrook };
9409ee6e8bbSpbrook
941cf1d31dcSJuan Quintela static const VMStateDescription vmstate_stellaris_adc = {
942cf1d31dcSJuan Quintela .name = "stellaris_adc",
943cf1d31dcSJuan Quintela .version_id = 1,
944cf1d31dcSJuan Quintela .minimum_version_id = 1,
945607ef570SRichard Henderson .fields = (const VMStateField[]) {
946d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(actss, StellarisADCState),
947d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ris, StellarisADCState),
948d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(im, StellarisADCState),
949d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(emux, StellarisADCState),
950d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ostat, StellarisADCState),
951d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ustat, StellarisADCState),
952d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(sspri, StellarisADCState),
953d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(sac, StellarisADCState),
954d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(fifo[0].state, StellarisADCState),
955d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32_ARRAY(fifo[0].data, StellarisADCState, 16),
956d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ssmux[0], StellarisADCState),
957d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ssctl[0], StellarisADCState),
958d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(fifo[1].state, StellarisADCState),
959d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32_ARRAY(fifo[1].data, StellarisADCState, 16),
960d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ssmux[1], StellarisADCState),
961d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ssctl[1], StellarisADCState),
962d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(fifo[2].state, StellarisADCState),
963d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32_ARRAY(fifo[2].data, StellarisADCState, 16),
964d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ssmux[2], StellarisADCState),
965d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ssctl[2], StellarisADCState),
966d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(fifo[3].state, StellarisADCState),
967d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32_ARRAY(fifo[3].data, StellarisADCState, 16),
968d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ssmux[3], StellarisADCState),
969d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(ssctl[3], StellarisADCState),
970d6b109daSPhilippe Mathieu-Daudé VMSTATE_UINT32(noise, StellarisADCState),
971cf1d31dcSJuan Quintela VMSTATE_END_OF_LIST()
97223e39294Spbrook }
973cf1d31dcSJuan Quintela };
97423e39294Spbrook
stellaris_adc_init(Object * obj)97515c4fff5Sxiaoqiang.zhao static void stellaris_adc_init(Object *obj)
9769ee6e8bbSpbrook {
97715c4fff5Sxiaoqiang.zhao DeviceState *dev = DEVICE(obj);
978d6b109daSPhilippe Mathieu-Daudé StellarisADCState *s = STELLARIS_ADC(obj);
97915c4fff5Sxiaoqiang.zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
9802c6554bcSPaul Brook int n;
9819ee6e8bbSpbrook
9822c6554bcSPaul Brook for (n = 0; n < 4; n++) {
9837df7f67aSAndreas Färber sysbus_init_irq(sbd, &s->irq[n]);
9842c6554bcSPaul Brook }
9859ee6e8bbSpbrook
98615c4fff5Sxiaoqiang.zhao memory_region_init_io(&s->iomem, obj, &stellaris_adc_ops, s,
98771a2df05SBenoît Canet "adc", 0x1000);
9887df7f67aSAndreas Färber sysbus_init_mmio(sbd, &s->iomem);
9897df7f67aSAndreas Färber qdev_init_gpio_in(dev, stellaris_adc_trigger, 1);
9909ee6e8bbSpbrook }
9919ee6e8bbSpbrook
9929ee6e8bbSpbrook /* Board init. */
99387409ea9SPhilippe Mathieu-Daudé static const stellaris_board_info stellaris_boards[] = {
9949ee6e8bbSpbrook { "LM3S811EVB",
9959ee6e8bbSpbrook 0,
9969ee6e8bbSpbrook 0x0032000e,
9979ee6e8bbSpbrook 0x001f001f, /* dc0 */
9989ee6e8bbSpbrook 0x001132bf,
9999ee6e8bbSpbrook 0x01071013,
10009ee6e8bbSpbrook 0x3f0f01ff,
10019ee6e8bbSpbrook 0x0000001f,
1002cf0dbb21Spbrook BP_OLED_I2C
10039ee6e8bbSpbrook },
10049ee6e8bbSpbrook { "LM3S6965EVB",
10059ee6e8bbSpbrook 0x10010002,
10069ee6e8bbSpbrook 0x1073402e,
10079ee6e8bbSpbrook 0x00ff007f, /* dc0 */
10089ee6e8bbSpbrook 0x001133ff,
10099ee6e8bbSpbrook 0x030f5317,
10109ee6e8bbSpbrook 0x0f0f87ff,
10119ee6e8bbSpbrook 0x5000007f,
1012cf0dbb21Spbrook BP_OLED_SSI | BP_GAMEPAD
10139ee6e8bbSpbrook }
10149ee6e8bbSpbrook };
10159ee6e8bbSpbrook
stellaris_init(MachineState * ms,stellaris_board_info * board)1016ba1ba5ccSIgor Mammedov static void stellaris_init(MachineState *ms, stellaris_board_info *board)
10179ee6e8bbSpbrook {
10187330c1c5SPhilippe Mathieu-Daudé static const int uart_irq[NUM_UART] = {5, 6, 33, 34};
10197330c1c5SPhilippe Mathieu-Daudé static const int timer_irq[NUM_GPTM] = {19, 21, 23, 35};
10207330c1c5SPhilippe Mathieu-Daudé static const uint32_t gpio_addr[NUM_GPIO] =
10219ee6e8bbSpbrook { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
10229ee6e8bbSpbrook 0x40024000, 0x40025000, 0x40026000};
10237330c1c5SPhilippe Mathieu-Daudé static const int gpio_irq[NUM_GPIO] = {0, 1, 2, 3, 4, 30, 31};
10243499f7e3SPhilippe Mathieu-Daudé static const uint32_t i2c_addr[NUM_I2C] = {0x40020000, 0x40021000};
10253499f7e3SPhilippe Mathieu-Daudé static const int i2c_irq[NUM_I2C] = {8, 37};
10269ee6e8bbSpbrook
1027394c8bbfSPeter Maydell /* Memory map of SoC devices, from
1028394c8bbfSPeter Maydell * Stellaris LM3S6965 Microcontroller Data Sheet (rev I)
1029394c8bbfSPeter Maydell * http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
1030394c8bbfSPeter Maydell *
1031566528f8SMichel Heily * 40000000 wdtimer
1032394c8bbfSPeter Maydell * 40004000 GPIO
1033394c8bbfSPeter Maydell * 40005000 GPIO
1034394c8bbfSPeter Maydell * 40006000 GPIO
1035394c8bbfSPeter Maydell * 40007000 GPIO
1036394c8bbfSPeter Maydell * 40008000 SSI
1037394c8bbfSPeter Maydell * 4000c000 UART
1038394c8bbfSPeter Maydell * 4000d000 UART
1039394c8bbfSPeter Maydell * 4000e000 UART
1040394c8bbfSPeter Maydell * 40020000 i2c
1041394c8bbfSPeter Maydell * 40021000 i2c (unimplemented)
1042394c8bbfSPeter Maydell * 40024000 GPIO
1043394c8bbfSPeter Maydell * 40025000 GPIO
1044394c8bbfSPeter Maydell * 40026000 GPIO
1045394c8bbfSPeter Maydell * 40028000 PWM (unimplemented)
1046394c8bbfSPeter Maydell * 4002c000 QEI (unimplemented)
1047394c8bbfSPeter Maydell * 4002d000 QEI (unimplemented)
1048394c8bbfSPeter Maydell * 40030000 gptimer
1049394c8bbfSPeter Maydell * 40031000 gptimer
1050394c8bbfSPeter Maydell * 40032000 gptimer
1051394c8bbfSPeter Maydell * 40033000 gptimer
1052394c8bbfSPeter Maydell * 40038000 ADC
1053394c8bbfSPeter Maydell * 4003c000 analogue comparator (unimplemented)
1054394c8bbfSPeter Maydell * 40048000 ethernet
1055394c8bbfSPeter Maydell * 400fc000 hibernation module (unimplemented)
1056394c8bbfSPeter Maydell * 400fd000 flash memory control (unimplemented)
1057394c8bbfSPeter Maydell * 400fe000 system control
1058394c8bbfSPeter Maydell */
1059394c8bbfSPeter Maydell
1060243b8602SPhilippe Mathieu-Daudé Object *soc_container;
10617330c1c5SPhilippe Mathieu-Daudé DeviceState *gpio_dev[NUM_GPIO], *armv7m, *nvic;
10627330c1c5SPhilippe Mathieu-Daudé qemu_irq gpio_in[NUM_GPIO][8];
10637330c1c5SPhilippe Mathieu-Daudé qemu_irq gpio_out[NUM_GPIO][8];
10649ee6e8bbSpbrook qemu_irq adc;
10659ee6e8bbSpbrook int sram_size;
10669ee6e8bbSpbrook int flash_size;
10673499f7e3SPhilippe Mathieu-Daudé DeviceState *i2c_dev[NUM_I2C] = { };
106840905a6aSPaul Brook DeviceState *dev;
10691e31d8eeSPeter Maydell DeviceState *ssys_dev;
10709ee6e8bbSpbrook int i;
107140905a6aSPaul Brook int j;
107213280845SDavid Woodhouse NICInfo *nd;
107313280845SDavid Woodhouse MACAddr mac;
10749ee6e8bbSpbrook
1075fe6ac447SAlistair Francis MemoryRegion *sram = g_new(MemoryRegion, 1);
1076fe6ac447SAlistair Francis MemoryRegion *flash = g_new(MemoryRegion, 1);
1077fe6ac447SAlistair Francis MemoryRegion *system_memory = get_system_memory();
1078fe6ac447SAlistair Francis
1079fe6ac447SAlistair Francis flash_size = (((board->dc0 & 0xffff) + 1) << 1) * 1024;
1080fe6ac447SAlistair Francis sram_size = ((board->dc0 >> 18) + 1) * 1024;
1081fe6ac447SAlistair Francis
1082e469b331SPeter Xu soc_container = object_new(TYPE_CONTAINER);
1083243b8602SPhilippe Mathieu-Daudé object_property_add_child(OBJECT(ms), "soc", soc_container);
1084243b8602SPhilippe Mathieu-Daudé
1085fe6ac447SAlistair Francis /* Flash programming is done via the SCU, so pretend it is ROM. */
108616260006SPhilippe Mathieu-Daudé memory_region_init_rom(flash, NULL, "stellaris.flash", flash_size,
1087f8ed85acSMarkus Armbruster &error_fatal);
1088fe6ac447SAlistair Francis memory_region_add_subregion(system_memory, 0, flash);
1089fe6ac447SAlistair Francis
109098a99ce0SPeter Maydell memory_region_init_ram(sram, NULL, "stellaris.sram", sram_size,
1091f8ed85acSMarkus Armbruster &error_fatal);
1092fe6ac447SAlistair Francis memory_region_add_subregion(system_memory, 0x20000000, sram);
1093fe6ac447SAlistair Francis
1094a861b3e9SPeter Maydell /*
1095a861b3e9SPeter Maydell * Create the system-registers object early, because we will
1096a861b3e9SPeter Maydell * need its sysclk output.
1097a861b3e9SPeter Maydell */
1098a861b3e9SPeter Maydell ssys_dev = qdev_new(TYPE_STELLARIS_SYS);
1099243b8602SPhilippe Mathieu-Daudé object_property_add_child(soc_container, "sys", OBJECT(ssys_dev));
110013280845SDavid Woodhouse
110113280845SDavid Woodhouse /*
110213280845SDavid Woodhouse * Most devices come preprogrammed with a MAC address in the user data.
110313280845SDavid Woodhouse * Generate a MAC address now, if there isn't a matching -nic for it.
110413280845SDavid Woodhouse */
110513280845SDavid Woodhouse nd = qemu_find_nic_info("stellaris_enet", true, "stellaris");
110613280845SDavid Woodhouse if (nd) {
110713280845SDavid Woodhouse memcpy(mac.a, nd->macaddr.a, sizeof(mac.a));
110813280845SDavid Woodhouse } else {
110913280845SDavid Woodhouse qemu_macaddr_default_if_unset(&mac);
111013280845SDavid Woodhouse }
111113280845SDavid Woodhouse
1112a861b3e9SPeter Maydell qdev_prop_set_uint32(ssys_dev, "user0",
111313280845SDavid Woodhouse mac.a[0] | (mac.a[1] << 8) | (mac.a[2] << 16));
1114a861b3e9SPeter Maydell qdev_prop_set_uint32(ssys_dev, "user1",
111513280845SDavid Woodhouse mac.a[3] | (mac.a[4] << 8) | (mac.a[5] << 16));
1116a861b3e9SPeter Maydell qdev_prop_set_uint32(ssys_dev, "did0", board->did0);
1117a861b3e9SPeter Maydell qdev_prop_set_uint32(ssys_dev, "did1", board->did1);
1118a861b3e9SPeter Maydell qdev_prop_set_uint32(ssys_dev, "dc0", board->dc0);
1119a861b3e9SPeter Maydell qdev_prop_set_uint32(ssys_dev, "dc1", board->dc1);
1120a861b3e9SPeter Maydell qdev_prop_set_uint32(ssys_dev, "dc2", board->dc2);
1121a861b3e9SPeter Maydell qdev_prop_set_uint32(ssys_dev, "dc3", board->dc3);
1122a861b3e9SPeter Maydell qdev_prop_set_uint32(ssys_dev, "dc4", board->dc4);
1123a861b3e9SPeter Maydell sysbus_realize_and_unref(SYS_BUS_DEVICE(ssys_dev), &error_fatal);
1124a861b3e9SPeter Maydell
112519266becSPhilippe Mathieu-Daudé armv7m = qdev_new(TYPE_ARMV7M);
112619266becSPhilippe Mathieu-Daudé object_property_add_child(soc_container, "v7m", OBJECT(armv7m));
112719266becSPhilippe Mathieu-Daudé qdev_prop_set_uint32(armv7m, "num-irq", NUM_IRQ_LINES);
112819266becSPhilippe Mathieu-Daudé qdev_prop_set_uint8(armv7m, "num-prio-bits", NUM_PRIO_BITS);
112919266becSPhilippe Mathieu-Daudé qdev_prop_set_string(armv7m, "cpu-type", ms->cpu_type);
113019266becSPhilippe Mathieu-Daudé qdev_prop_set_bit(armv7m, "enable-bitband", true);
113119266becSPhilippe Mathieu-Daudé qdev_connect_clock_in(armv7m, "cpuclk",
11328ecda75fSPeter Maydell qdev_get_clock_out(ssys_dev, "SYSCLK"));
11338ecda75fSPeter Maydell /* This SoC does not connect the systick reference clock */
113419266becSPhilippe Mathieu-Daudé object_property_set_link(OBJECT(armv7m), "memory",
11355325cc34SMarkus Armbruster OBJECT(get_system_memory()), &error_abort);
1136f04d4465SPeter Maydell /* This will exit with an error if the user passed us a bad cpu_type */
113719266becSPhilippe Mathieu-Daudé sysbus_realize_and_unref(SYS_BUS_DEVICE(armv7m), &error_fatal);
113819266becSPhilippe Mathieu-Daudé nvic = armv7m;
11399ee6e8bbSpbrook
1140a861b3e9SPeter Maydell /* Now we can wire up the IRQ and MMIO of the system registers */
1141a861b3e9SPeter Maydell sysbus_mmio_map(SYS_BUS_DEVICE(ssys_dev), 0, 0x400fe000);
1142a861b3e9SPeter Maydell sysbus_connect_irq(SYS_BUS_DEVICE(ssys_dev), 0, qdev_get_gpio_in(nvic, 28));
1143a861b3e9SPeter Maydell
1144b7c55f59SPhilippe Mathieu-Daudé if (DEV_CAP(1, ADC)) {
11457df7f67aSAndreas Färber dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000,
114620c59c38SMichael Davidsaver qdev_get_gpio_in(nvic, 14),
114720c59c38SMichael Davidsaver qdev_get_gpio_in(nvic, 15),
114820c59c38SMichael Davidsaver qdev_get_gpio_in(nvic, 16),
114920c59c38SMichael Davidsaver qdev_get_gpio_in(nvic, 17),
115020c59c38SMichael Davidsaver NULL);
115140905a6aSPaul Brook adc = qdev_get_gpio_in(dev, 0);
11529ee6e8bbSpbrook } else {
11539ee6e8bbSpbrook adc = NULL;
11549ee6e8bbSpbrook }
11557330c1c5SPhilippe Mathieu-Daudé for (i = 0; i < NUM_GPTM; i++) {
1156b7c55f59SPhilippe Mathieu-Daudé if (DEV_CAP(2, GPTM(i))) {
1157d18fdd69SPeter Maydell SysBusDevice *sbd;
1158d18fdd69SPeter Maydell
1159d18fdd69SPeter Maydell dev = qdev_new(TYPE_STELLARIS_GPTM);
1160d18fdd69SPeter Maydell sbd = SYS_BUS_DEVICE(dev);
1161243b8602SPhilippe Mathieu-Daudé object_property_add_child(soc_container, "gptm[*]", OBJECT(dev));
1162d18fdd69SPeter Maydell qdev_connect_clock_in(dev, "clk",
1163d18fdd69SPeter Maydell qdev_get_clock_out(ssys_dev, "SYSCLK"));
1164d18fdd69SPeter Maydell sysbus_realize_and_unref(sbd, &error_fatal);
1165d18fdd69SPeter Maydell sysbus_mmio_map(sbd, 0, 0x40030000 + i * 0x1000);
1166d18fdd69SPeter Maydell sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
116740905a6aSPaul Brook /* TODO: This is incorrect, but we get away with it because
116840905a6aSPaul Brook the ADC output is only ever pulsed. */
116940905a6aSPaul Brook qdev_connect_gpio_out(dev, 0, adc);
11709ee6e8bbSpbrook }
11719ee6e8bbSpbrook }
11729ee6e8bbSpbrook
1173b7c55f59SPhilippe Mathieu-Daudé if (DEV_CAP(1, WDT)) {
11743e80f690SMarkus Armbruster dev = qdev_new(TYPE_LUMINARY_WATCHDOG);
1175243b8602SPhilippe Mathieu-Daudé object_property_add_child(soc_container, "wdg", OBJECT(dev));
11761e31d8eeSPeter Maydell qdev_connect_clock_in(dev, "WDOGCLK",
11771e31d8eeSPeter Maydell qdev_get_clock_out(ssys_dev, "SYSCLK"));
1178566528f8SMichel Heily
11793c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1180566528f8SMichel Heily sysbus_mmio_map(SYS_BUS_DEVICE(dev),
1181566528f8SMichel Heily 0,
1182566528f8SMichel Heily 0x40000000u);
1183566528f8SMichel Heily sysbus_connect_irq(SYS_BUS_DEVICE(dev),
1184566528f8SMichel Heily 0,
1185566528f8SMichel Heily qdev_get_gpio_in(nvic, 18));
1186566528f8SMichel Heily }
1187566528f8SMichel Heily
1188566528f8SMichel Heily
11897330c1c5SPhilippe Mathieu-Daudé for (i = 0; i < NUM_GPIO; i++) {
1190b7c55f59SPhilippe Mathieu-Daudé if (DEV_CAP(4, GPIO(i))) {
11917063f49fSPeter Maydell gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
119220c59c38SMichael Davidsaver qdev_get_gpio_in(nvic,
119320c59c38SMichael Davidsaver gpio_irq[i]));
119440905a6aSPaul Brook for (j = 0; j < 8; j++) {
119540905a6aSPaul Brook gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
119640905a6aSPaul Brook gpio_out[i][j] = NULL;
119740905a6aSPaul Brook }
11989ee6e8bbSpbrook }
11999ee6e8bbSpbrook }
12009ee6e8bbSpbrook
12013499f7e3SPhilippe Mathieu-Daudé for (i = 0; i < NUM_I2C; i++) {
12023499f7e3SPhilippe Mathieu-Daudé if (DEV_CAP(2, I2C(i))) {
12033499f7e3SPhilippe Mathieu-Daudé i2c_dev[i] = sysbus_create_simple(TYPE_STELLARIS_I2C, i2c_addr[i],
12043499f7e3SPhilippe Mathieu-Daudé qdev_get_gpio_in(nvic,
12053499f7e3SPhilippe Mathieu-Daudé i2c_irq[i]));
12069ee6e8bbSpbrook }
12079ee6e8bbSpbrook }
12083499f7e3SPhilippe Mathieu-Daudé if (board->peripherals & BP_OLED_I2C) {
12093499f7e3SPhilippe Mathieu-Daudé I2CBus *bus = (I2CBus *)qdev_get_child_bus(i2c_dev[0], "i2c");
12103499f7e3SPhilippe Mathieu-Daudé
12113499f7e3SPhilippe Mathieu-Daudé i2c_slave_create_simple(bus, "ssd0303", 0x3d);
12123499f7e3SPhilippe Mathieu-Daudé }
12139ee6e8bbSpbrook
12147330c1c5SPhilippe Mathieu-Daudé for (i = 0; i < NUM_UART; i++) {
1215b7c55f59SPhilippe Mathieu-Daudé if (DEV_CAP(2, UART(i))) {
1216b7f93098SPhilippe Mathieu-Daudé SysBusDevice *sbd;
1217b7f93098SPhilippe Mathieu-Daudé
1218b7f93098SPhilippe Mathieu-Daudé dev = qdev_new("pl011_luminary");
1219243b8602SPhilippe Mathieu-Daudé object_property_add_child(soc_container, "uart[*]", OBJECT(dev));
1220b7f93098SPhilippe Mathieu-Daudé sbd = SYS_BUS_DEVICE(dev);
1221b7f93098SPhilippe Mathieu-Daudé qdev_prop_set_chr(dev, "chardev", serial_hd(i));
1222b7f93098SPhilippe Mathieu-Daudé sysbus_realize_and_unref(sbd, &error_fatal);
1223b7f93098SPhilippe Mathieu-Daudé sysbus_mmio_map(sbd, 0, 0x4000c000 + i * 0x1000);
1224b7f93098SPhilippe Mathieu-Daudé sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(nvic, uart_irq[i]));
12259ee6e8bbSpbrook }
12269ee6e8bbSpbrook }
1227b7c55f59SPhilippe Mathieu-Daudé if (DEV_CAP(2, SSI)) {
122820c59c38SMichael Davidsaver dev = sysbus_create_simple("pl022", 0x40008000,
122920c59c38SMichael Davidsaver qdev_get_gpio_in(nvic, 7));
1230cf0dbb21Spbrook if (board->peripherals & BP_OLED_SSI) {
12315493e33fSPaul Brook void *bus;
12328120e714SPeter A. G. Crosthwaite DeviceState *sddev;
12338120e714SPeter A. G. Crosthwaite DeviceState *ssddev;
123436aa285fSMarkus Armbruster DriveInfo *dinfo;
123536aa285fSMarkus Armbruster DeviceState *carddev;
1236d0a030d8SZongyuan Li DeviceState *gpio_d_splitter;
123736aa285fSMarkus Armbruster BlockBackend *blk;
1238775616c3Spbrook
12395092e014SPeter Maydell /*
12405092e014SPeter Maydell * Some boards have both an OLED controller and SD card connected to
12418120e714SPeter A. G. Crosthwaite * the same SSI port, with the SD card chip select connected to a
12428120e714SPeter A. G. Crosthwaite * GPIO pin. Technically the OLED chip select is connected to the
12438120e714SPeter A. G. Crosthwaite * SSI Fss pin. We do not bother emulating that as both devices
12448120e714SPeter A. G. Crosthwaite * should never be selected simultaneously, and our OLED controller
12458120e714SPeter A. G. Crosthwaite * ignores stray 0xff commands that occur when deselecting the SD
12468120e714SPeter A. G. Crosthwaite * card.
12475092e014SPeter Maydell *
12485092e014SPeter Maydell * The h/w wiring is:
12495092e014SPeter Maydell * - GPIO pin D0 is wired to the active-low SD card chip select
12505092e014SPeter Maydell * - GPIO pin A3 is wired to the active-low OLED chip select
12515092e014SPeter Maydell * - The SoC wiring of the PL061 "auxiliary function" for A3 is
12525092e014SPeter Maydell * SSI0Fss ("frame signal"), which is an output from the SoC's
12535092e014SPeter Maydell * SSI controller. The SSI controller takes SSI0Fss low when it
12545092e014SPeter Maydell * transmits a frame, so it can work as a chip-select signal.
12555092e014SPeter Maydell * - GPIO A4 is aux-function SSI0Rx, and wired to the SD card Tx
12565092e014SPeter Maydell * (the OLED never sends data to the CPU, so no wiring needed)
12575092e014SPeter Maydell * - GPIO A5 is aux-function SSI0Tx, and wired to the SD card Rx
12585092e014SPeter Maydell * and the OLED display-data-in
12595092e014SPeter Maydell * - GPIO A2 is aux-function SSI0Clk, wired to SD card and OLED
12605092e014SPeter Maydell * serial-clock input
12615092e014SPeter Maydell * So a guest that wants to use the OLED can configure the PL061
12625092e014SPeter Maydell * to make pins A2, A3, A5 aux-function, so they are connected
12635092e014SPeter Maydell * directly to the SSI controller. When the SSI controller sends
12645092e014SPeter Maydell * data it asserts SSI0Fss which selects the OLED.
12655092e014SPeter Maydell * A guest that wants to use the SD card configures A2, A4 and A5
12665092e014SPeter Maydell * as aux-function, but leaves A3 as a software-controlled GPIO
12675092e014SPeter Maydell * line. It asserts the SD card chip-select by using the PL061
12685092e014SPeter Maydell * to control pin D0, and lets the SSI controller handle Clk, Tx
12695092e014SPeter Maydell * and Rx. (The SSI controller asserts Fss during tx cycles as
12705092e014SPeter Maydell * usual, but because A3 is not set to aux-function this is not
12715092e014SPeter Maydell * forwarded to the OLED, and so the OLED stays unselected.)
12725092e014SPeter Maydell *
12735092e014SPeter Maydell * The QEMU implementation instead is:
12745092e014SPeter Maydell * - GPIO pin D0 is wired to the active-low SD card chip select,
12755092e014SPeter Maydell * and also to the OLED chip-select which is implemented
12765092e014SPeter Maydell * as *active-high*
12775092e014SPeter Maydell * - SSI controller signals go to the devices regardless of
12785092e014SPeter Maydell * whether the guest programs A2, A4, A5 as aux-function or not
12795092e014SPeter Maydell *
12805092e014SPeter Maydell * The problem with this implementation is if the guest doesn't
12815092e014SPeter Maydell * care about the SD card and only uses the OLED. In that case it
12825092e014SPeter Maydell * may choose never to do anything with D0 (leaving it in its
12835092e014SPeter Maydell * default floating state, which reliably leaves the card disabled
12845092e014SPeter Maydell * because an SD card has a pullup on CS within the card itself),
12855092e014SPeter Maydell * and only set up A2, A3, A5. This for us would mean the OLED
12865092e014SPeter Maydell * never gets the chip-select assert it needs. We work around
12875092e014SPeter Maydell * this with a manual raise of D0 here (despite board creation
12885092e014SPeter Maydell * code being the wrong place to raise IRQ lines) to put the OLED
12895092e014SPeter Maydell * into an initially selected state.
12905092e014SPeter Maydell *
12915092e014SPeter Maydell * In theory the right way to model this would be:
12925092e014SPeter Maydell * - Implement aux-function support in the PL061, with an
12935092e014SPeter Maydell * extra set of AFIN and AFOUT GPIO lines (set up so that
12945092e014SPeter Maydell * if a GPIO line is in auxfn mode the main GPIO in and out
12955092e014SPeter Maydell * track the AFIN and AFOUT lines)
12965092e014SPeter Maydell * - Wire the AFOUT for D0 up to either a line from the
12975092e014SPeter Maydell * SSI controller that's pulled low around every transmit,
12985092e014SPeter Maydell * or at least to an always-0 line here on the board
12995092e014SPeter Maydell * - Make the ssd0323 OLED controller chipselect active-low
13008120e714SPeter A. G. Crosthwaite */
13015493e33fSPaul Brook bus = qdev_get_child_bus(dev, "ssi");
1302ec7e429bSPhilippe Mathieu-Daudé sddev = ssi_create_peripheral(bus, "ssi-sd");
130336aa285fSMarkus Armbruster
130436aa285fSMarkus Armbruster dinfo = drive_get(IF_SD, 0, 0);
130536aa285fSMarkus Armbruster blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
1306c3287c0fSCédric Le Goater carddev = qdev_new(TYPE_SD_CARD_SPI);
130736aa285fSMarkus Armbruster qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
130836aa285fSMarkus Armbruster qdev_realize_and_unref(carddev,
130936aa285fSMarkus Armbruster qdev_get_child_bus(sddev, "sd-bus"),
131036aa285fSMarkus Armbruster &error_fatal);
131136aa285fSMarkus Armbruster
1312a617e65fSCédric Le Goater ssddev = qdev_new("ssd0323");
13137e4a8d9dSPhilippe Mathieu-Daudé object_property_add_child(OBJECT(ms), "oled", OBJECT(ssddev));
1314a617e65fSCédric Le Goater qdev_prop_set_uint8(ssddev, "cs", 1);
1315a617e65fSCédric Le Goater qdev_realize_and_unref(ssddev, bus, &error_fatal);
1316d0a030d8SZongyuan Li
1317d0a030d8SZongyuan Li gpio_d_splitter = qdev_new(TYPE_SPLIT_IRQ);
13187e4a8d9dSPhilippe Mathieu-Daudé object_property_add_child(OBJECT(ms), "splitter",
13197e4a8d9dSPhilippe Mathieu-Daudé OBJECT(gpio_d_splitter));
1320d0a030d8SZongyuan Li qdev_prop_set_uint32(gpio_d_splitter, "num-lines", 2);
1321d0a030d8SZongyuan Li qdev_realize_and_unref(gpio_d_splitter, NULL, &error_fatal);
1322d0a030d8SZongyuan Li qdev_connect_gpio_out(
1323d0a030d8SZongyuan Li gpio_d_splitter, 0,
1324d0a030d8SZongyuan Li qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0));
1325d0a030d8SZongyuan Li qdev_connect_gpio_out(
1326d0a030d8SZongyuan Li gpio_d_splitter, 1,
1327de77914eSPeter Crosthwaite qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0));
1328d0a030d8SZongyuan Li gpio_out[GPIO_D][0] = qdev_get_gpio_in(gpio_d_splitter, 0);
1329d0a030d8SZongyuan Li
1330de77914eSPeter Crosthwaite gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0);
13315493e33fSPaul Brook
1332775616c3Spbrook /* Make sure the select pin is high. */
1333775616c3Spbrook qemu_irq_raise(gpio_out[GPIO_D][0]);
13349ee6e8bbSpbrook }
13359ee6e8bbSpbrook }
1336b7c55f59SPhilippe Mathieu-Daudé if (DEV_CAP(4, EMAC)) {
1337a5580466SPaul Brook DeviceState *enet;
1338a5580466SPaul Brook
13393e80f690SMarkus Armbruster enet = qdev_new("stellaris_enet");
1340243b8602SPhilippe Mathieu-Daudé object_property_add_child(soc_container, "enet", OBJECT(enet));
134113280845SDavid Woodhouse if (nd) {
134213280845SDavid Woodhouse qdev_set_nic_properties(enet, nd);
134313280845SDavid Woodhouse } else {
134413280845SDavid Woodhouse qdev_prop_set_macaddr(enet, "mac", mac.a);
134513280845SDavid Woodhouse }
134613280845SDavid Woodhouse
13473c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(enet), &error_fatal);
13481356b98dSAndreas Färber sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000);
134920c59c38SMichael Davidsaver sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, qdev_get_gpio_in(nvic, 42));
1350a5580466SPaul Brook }
1351cf0dbb21Spbrook if (board->peripherals & BP_GAMEPAD) {
1352a75f336bSPeter Maydell QList *gpad_keycode_list = qlist_new();
13537c76f397SPeter Maydell static const int gpad_keycode[5] = {
13547c76f397SPeter Maydell Q_KEY_CODE_UP, Q_KEY_CODE_DOWN, Q_KEY_CODE_LEFT,
13557c76f397SPeter Maydell Q_KEY_CODE_RIGHT, Q_KEY_CODE_CTRL,
13567c76f397SPeter Maydell };
1357a75f336bSPeter Maydell DeviceState *gpad;
1358cf0dbb21Spbrook
1359a75f336bSPeter Maydell gpad = qdev_new(TYPE_STELLARIS_GAMEPAD);
13607e4a8d9dSPhilippe Mathieu-Daudé object_property_add_child(OBJECT(ms), "gamepad", OBJECT(gpad));
1361a75f336bSPeter Maydell for (i = 0; i < ARRAY_SIZE(gpad_keycode); i++) {
1362a75f336bSPeter Maydell qlist_append_int(gpad_keycode_list, gpad_keycode[i]);
1363a75f336bSPeter Maydell }
1364a75f336bSPeter Maydell qdev_prop_set_array(gpad, "keycodes", gpad_keycode_list);
1365a75f336bSPeter Maydell sysbus_realize_and_unref(SYS_BUS_DEVICE(gpad), &error_fatal);
1366cf0dbb21Spbrook
1367a75f336bSPeter Maydell qdev_connect_gpio_out(gpad, 0,
1368a75f336bSPeter Maydell qemu_irq_invert(gpio_in[GPIO_E][0])); /* up */
1369a75f336bSPeter Maydell qdev_connect_gpio_out(gpad, 1,
1370a75f336bSPeter Maydell qemu_irq_invert(gpio_in[GPIO_E][1])); /* down */
1371a75f336bSPeter Maydell qdev_connect_gpio_out(gpad, 2,
1372a75f336bSPeter Maydell qemu_irq_invert(gpio_in[GPIO_E][2])); /* left */
1373a75f336bSPeter Maydell qdev_connect_gpio_out(gpad, 3,
1374a75f336bSPeter Maydell qemu_irq_invert(gpio_in[GPIO_E][3])); /* right */
1375a75f336bSPeter Maydell qdev_connect_gpio_out(gpad, 4,
1376a75f336bSPeter Maydell qemu_irq_invert(gpio_in[GPIO_F][1])); /* select */
1377cf0dbb21Spbrook }
137840905a6aSPaul Brook for (i = 0; i < 7; i++) {
137940905a6aSPaul Brook if (board->dc4 & (1 << i)) {
138040905a6aSPaul Brook for (j = 0; j < 8; j++) {
138140905a6aSPaul Brook if (gpio_out[i][j]) {
138240905a6aSPaul Brook qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
138340905a6aSPaul Brook }
138440905a6aSPaul Brook }
138540905a6aSPaul Brook }
138640905a6aSPaul Brook }
1387aecfbbc9SPeter Maydell
1388aecfbbc9SPeter Maydell /* Add dummy regions for the devices we don't implement yet,
1389aecfbbc9SPeter Maydell * so guest accesses don't cause unlogged crashes.
1390aecfbbc9SPeter Maydell */
1391aecfbbc9SPeter Maydell create_unimplemented_device("PWM", 0x40028000, 0x1000);
1392aecfbbc9SPeter Maydell create_unimplemented_device("QEI-0", 0x4002c000, 0x1000);
1393aecfbbc9SPeter Maydell create_unimplemented_device("QEI-1", 0x4002d000, 0x1000);
1394aecfbbc9SPeter Maydell create_unimplemented_device("analogue-comparator", 0x4003c000, 0x1000);
1395aecfbbc9SPeter Maydell create_unimplemented_device("hibernation", 0x400fc000, 0x1000);
1396aecfbbc9SPeter Maydell create_unimplemented_device("flash-control", 0x400fd000, 0x1000);
1397f04d4465SPeter Maydell
1398deeb9969SPhilippe Mathieu-Daudé armv7m_load_kernel(ARMV7M(armv7m)->cpu, ms->kernel_filename, 0, flash_size);
13999ee6e8bbSpbrook }
14009ee6e8bbSpbrook
14019ee6e8bbSpbrook /* FIXME: Figure out how to generate these from stellaris_boards. */
lm3s811evb_init(MachineState * machine)14023ef96221SMarcel Apfelbaum static void lm3s811evb_init(MachineState *machine)
14039ee6e8bbSpbrook {
1404ba1ba5ccSIgor Mammedov stellaris_init(machine, &stellaris_boards[0]);
14059ee6e8bbSpbrook }
14069ee6e8bbSpbrook
lm3s6965evb_init(MachineState * machine)14073ef96221SMarcel Apfelbaum static void lm3s6965evb_init(MachineState *machine)
14089ee6e8bbSpbrook {
1409ba1ba5ccSIgor Mammedov stellaris_init(machine, &stellaris_boards[1]);
14109ee6e8bbSpbrook }
14119ee6e8bbSpbrook
141282634b58SPhilippe Mathieu-Daudé /*
141382634b58SPhilippe Mathieu-Daudé * Stellaris LM3S811 Evaluation Board Schematics:
141482634b58SPhilippe Mathieu-Daudé * https://www.ti.com/lit/ug/symlink/spmu030.pdf
141582634b58SPhilippe Mathieu-Daudé */
lm3s811evb_class_init(ObjectClass * oc,const void * data)1416*12d1a768SPhilippe Mathieu-Daudé static void lm3s811evb_class_init(ObjectClass *oc, const void *data)
1417f80f9ec9SAnthony Liguori {
14188a661aeaSAndreas Färber MachineClass *mc = MACHINE_CLASS(oc);
14198a661aeaSAndreas Färber
1420fd8f71b9SPhilippe Mathieu-Daudé mc->desc = "Stellaris LM3S811EVB (Cortex-M3)";
1421e264d29dSEduardo Habkost mc->init = lm3s811evb_init;
14224672cbd7SPeter Maydell mc->ignore_memory_transaction_failures = true;
1423ba1ba5ccSIgor Mammedov mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
1424f80f9ec9SAnthony Liguori }
1425f80f9ec9SAnthony Liguori
14268a661aeaSAndreas Färber static const TypeInfo lm3s811evb_type = {
14278a661aeaSAndreas Färber .name = MACHINE_TYPE_NAME("lm3s811evb"),
14288a661aeaSAndreas Färber .parent = TYPE_MACHINE,
14298a661aeaSAndreas Färber .class_init = lm3s811evb_class_init,
14308a661aeaSAndreas Färber };
1431e264d29dSEduardo Habkost
143282634b58SPhilippe Mathieu-Daudé /*
143382634b58SPhilippe Mathieu-Daudé * Stellaris: LM3S6965 Evaluation Board Schematics:
143482634b58SPhilippe Mathieu-Daudé * https://www.ti.com/lit/ug/symlink/spmu029.pdf
143582634b58SPhilippe Mathieu-Daudé */
lm3s6965evb_class_init(ObjectClass * oc,const void * data)1436*12d1a768SPhilippe Mathieu-Daudé static void lm3s6965evb_class_init(ObjectClass *oc, const void *data)
1437e264d29dSEduardo Habkost {
14388a661aeaSAndreas Färber MachineClass *mc = MACHINE_CLASS(oc);
14398a661aeaSAndreas Färber
1440fd8f71b9SPhilippe Mathieu-Daudé mc->desc = "Stellaris LM3S6965EVB (Cortex-M3)";
1441e264d29dSEduardo Habkost mc->init = lm3s6965evb_init;
14424672cbd7SPeter Maydell mc->ignore_memory_transaction_failures = true;
1443ba1ba5ccSIgor Mammedov mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
1444cdc8d7caSPhilippe Mathieu-Daudé mc->auto_create_sdcard = true;
1445e264d29dSEduardo Habkost }
1446e264d29dSEduardo Habkost
14478a661aeaSAndreas Färber static const TypeInfo lm3s6965evb_type = {
14488a661aeaSAndreas Färber .name = MACHINE_TYPE_NAME("lm3s6965evb"),
14498a661aeaSAndreas Färber .parent = TYPE_MACHINE,
14508a661aeaSAndreas Färber .class_init = lm3s6965evb_class_init,
14518a661aeaSAndreas Färber };
14528a661aeaSAndreas Färber
stellaris_machine_init(void)14538a661aeaSAndreas Färber static void stellaris_machine_init(void)
14548a661aeaSAndreas Färber {
14558a661aeaSAndreas Färber type_register_static(&lm3s811evb_type);
14568a661aeaSAndreas Färber type_register_static(&lm3s6965evb_type);
14578a661aeaSAndreas Färber }
14588a661aeaSAndreas Färber
type_init(stellaris_machine_init)14590e6aac87SEduardo Habkost type_init(stellaris_machine_init)
1460f80f9ec9SAnthony Liguori
1461*12d1a768SPhilippe Mathieu-Daudé static void stellaris_i2c_class_init(ObjectClass *klass, const void *data)
1462999e12bbSAnthony Liguori {
146315c4fff5Sxiaoqiang.zhao DeviceClass *dc = DEVICE_CLASS(klass);
1464cee78fa5SPhilippe Mathieu-Daudé ResettableClass *rc = RESETTABLE_CLASS(klass);
1465999e12bbSAnthony Liguori
1466cee78fa5SPhilippe Mathieu-Daudé rc->phases.enter = stellaris_i2c_reset_enter;
1467cee78fa5SPhilippe Mathieu-Daudé rc->phases.hold = stellaris_i2c_reset_hold;
1468cee78fa5SPhilippe Mathieu-Daudé rc->phases.exit = stellaris_i2c_reset_exit;
146915c4fff5Sxiaoqiang.zhao dc->vmsd = &vmstate_stellaris_i2c;
1470999e12bbSAnthony Liguori }
1471999e12bbSAnthony Liguori
14728c43a6f0SAndreas Färber static const TypeInfo stellaris_i2c_info = {
1473d94a4015SAndreas Färber .name = TYPE_STELLARIS_I2C,
147439bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE,
147539bffca2SAnthony Liguori .instance_size = sizeof(stellaris_i2c_state),
147615c4fff5Sxiaoqiang.zhao .instance_init = stellaris_i2c_init,
1477999e12bbSAnthony Liguori .class_init = stellaris_i2c_class_init,
1478999e12bbSAnthony Liguori };
1479999e12bbSAnthony Liguori
stellaris_adc_class_init(ObjectClass * klass,const void * data)1480*12d1a768SPhilippe Mathieu-Daudé static void stellaris_adc_class_init(ObjectClass *klass, const void *data)
1481999e12bbSAnthony Liguori {
148215c4fff5Sxiaoqiang.zhao DeviceClass *dc = DEVICE_CLASS(klass);
1483bebd89e1SPhilippe Mathieu-Daudé ResettableClass *rc = RESETTABLE_CLASS(klass);
1484999e12bbSAnthony Liguori
1485bebd89e1SPhilippe Mathieu-Daudé rc->phases.hold = stellaris_adc_reset_hold;
148615c4fff5Sxiaoqiang.zhao dc->vmsd = &vmstate_stellaris_adc;
1487999e12bbSAnthony Liguori }
1488999e12bbSAnthony Liguori
14898c43a6f0SAndreas Färber static const TypeInfo stellaris_adc_info = {
14907df7f67aSAndreas Färber .name = TYPE_STELLARIS_ADC,
149139bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE,
1492d6b109daSPhilippe Mathieu-Daudé .instance_size = sizeof(StellarisADCState),
149315c4fff5Sxiaoqiang.zhao .instance_init = stellaris_adc_init,
1494999e12bbSAnthony Liguori .class_init = stellaris_adc_class_init,
1495999e12bbSAnthony Liguori };
1496999e12bbSAnthony Liguori
stellaris_sys_class_init(ObjectClass * klass,const void * data)1497*12d1a768SPhilippe Mathieu-Daudé static void stellaris_sys_class_init(ObjectClass *klass, const void *data)
14984bebb9adSPeter Maydell {
14994bebb9adSPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass);
15004bebb9adSPeter Maydell ResettableClass *rc = RESETTABLE_CLASS(klass);
15014bebb9adSPeter Maydell
15024bebb9adSPeter Maydell dc->vmsd = &vmstate_stellaris_sys;
15034bebb9adSPeter Maydell rc->phases.enter = stellaris_sys_reset_enter;
15044bebb9adSPeter Maydell rc->phases.hold = stellaris_sys_reset_hold;
15054bebb9adSPeter Maydell rc->phases.exit = stellaris_sys_reset_exit;
15064bebb9adSPeter Maydell device_class_set_props(dc, stellaris_sys_properties);
15074bebb9adSPeter Maydell }
15084bebb9adSPeter Maydell
15094bebb9adSPeter Maydell static const TypeInfo stellaris_sys_info = {
15104bebb9adSPeter Maydell .name = TYPE_STELLARIS_SYS,
15114bebb9adSPeter Maydell .parent = TYPE_SYS_BUS_DEVICE,
15124bebb9adSPeter Maydell .instance_size = sizeof(ssys_state),
15134bebb9adSPeter Maydell .instance_init = stellaris_sys_instance_init,
15144bebb9adSPeter Maydell .class_init = stellaris_sys_class_init,
15154bebb9adSPeter Maydell };
15164bebb9adSPeter Maydell
stellaris_register_types(void)151783f7d43aSAndreas Färber static void stellaris_register_types(void)
15181de9610cSPaul Brook {
151939bffca2SAnthony Liguori type_register_static(&stellaris_i2c_info);
152039bffca2SAnthony Liguori type_register_static(&stellaris_adc_info);
15214bebb9adSPeter Maydell type_register_static(&stellaris_sys_info);
15221de9610cSPaul Brook }
15231de9610cSPaul Brook
152483f7d43aSAndreas Färber type_init(stellaris_register_types)
1525