blob: d18b1144af5006f4ffb3cffe11db822e9a2d8dc5 [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
Peter Maydell12b16722015-12-07 16:23:45 +000010#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010011#include "qapi/error.h"
Zongyuan Lid0a030d2022-03-25 02:15:55 +080012#include "hw/core/split-irq.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010013#include "hw/sysbus.h"
Markus Armbruster36aa2852021-11-17 17:33:57 +010014#include "hw/sd/sd.h"
Alistair Francis8fd06712016-01-21 14:15:03 +000015#include "hw/ssi/ssi.h"
Peter Maydell12ec8bd2019-05-23 14:47:43 +010016#include "hw/arm/boot.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010017#include "qemu/timer.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010018#include "hw/i2c/i2c.h"
Paolo Bonzini1422e322012-10-24 08:43:34 +020019#include "net/net.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010020#include "hw/boards.h"
Paolo Bonzini03dd0242015-12-15 13:16:16 +010021#include "qemu/log.h"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010022#include "exec/address-spaces.h"
Michael Davidsaverd69ffb52015-11-03 13:49:41 +000023#include "sysemu/sysemu.h"
Peter Maydellf04d4462018-06-15 14:57:13 +010024#include "hw/arm/armv7m.h"
xiaoqiang zhaof0d1d2c2016-06-06 16:59:31 +010025#include "hw/char/pl011.h"
Peter Maydellc45460d2023-10-30 11:47:57 +000026#include "hw/input/stellaris_gamepad.h"
Markus Armbruster64552b62019-08-12 07:23:42 +020027#include "hw/irq.h"
Michel Heily566528f2019-03-05 01:16:22 +020028#include "hw/watchdog/cmsdk-apb-watchdog.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020029#include "migration/vmstate.h"
Peter Maydellaecfbbc2017-02-07 18:30:00 +000030#include "hw/misc/unimp.h"
Peter Maydellf3eb7552021-08-12 10:33:54 +010031#include "hw/timer/stellaris-gptm.h"
Peter Maydell1e31d8e2021-01-28 11:41:37 +000032#include "hw/qdev-clock.h"
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040033#include "qom/object.h"
Peter Maydella75f3362023-10-30 11:48:01 +000034#include "qapi/qmp/qlist.h"
Peter Maydell7c76f392023-10-30 11:48:02 +000035#include "ui/input.h"
pbrook9ee6e8b2007-11-11 00:04:49 +000036
pbrookcf0dbb22007-11-18 14:36:08 +000037#define GPIO_A 0
38#define GPIO_B 1
39#define GPIO_C 2
40#define GPIO_D 3
41#define GPIO_E 4
42#define GPIO_F 5
43#define GPIO_G 6
44
45#define BP_OLED_I2C 0x01
46#define BP_OLED_SSI 0x02
47#define BP_GAMEPAD 0x04
48
Alistair Francis8b47b7d2015-02-05 13:37:21 +000049#define NUM_IRQ_LINES 64
Samuel Tardieu4a046552024-01-06 19:15:03 +010050#define NUM_PRIO_BITS 3
Alistair Francis8b47b7d2015-02-05 13:37:21 +000051
pbrook9ee6e8b2007-11-11 00:04:49 +000052typedef const struct {
53 const char *name;
54 uint32_t did0;
55 uint32_t did1;
56 uint32_t dc0;
57 uint32_t dc1;
58 uint32_t dc2;
59 uint32_t dc3;
60 uint32_t dc4;
pbrookcf0dbb22007-11-18 14:36:08 +000061 uint32_t peripherals;
pbrook9ee6e8b2007-11-11 00:04:49 +000062} stellaris_board_info;
63
pbrook9ee6e8b2007-11-11 00:04:49 +000064/* System controller. */
65
Peter Maydell4bebb9a2021-01-28 11:41:36 +000066#define TYPE_STELLARIS_SYS "stellaris-sys"
67OBJECT_DECLARE_SIMPLE_TYPE(ssys_state, STELLARIS_SYS)
68
69struct ssys_state {
70 SysBusDevice parent_obj;
71
Benoît Canet56993012011-10-17 17:28:29 +020072 MemoryRegion iomem;
pbrook9ee6e8b2007-11-11 00:04:49 +000073 uint32_t pborctl;
74 uint32_t ldopctl;
75 uint32_t int_status;
76 uint32_t int_mask;
77 uint32_t resc;
78 uint32_t rcc;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +010079 uint32_t rcc2;
pbrook9ee6e8b2007-11-11 00:04:49 +000080 uint32_t rcgc[3];
81 uint32_t scgc[3];
82 uint32_t dcgc[3];
83 uint32_t clkvclr;
84 uint32_t ldoarst;
Peter Maydell4bebb9a2021-01-28 11:41:36 +000085 qemu_irq irq;
Peter Maydell1e31d8e2021-01-28 11:41:37 +000086 Clock *sysclk;
Peter Maydell4bebb9a2021-01-28 11:41:36 +000087 /* Properties (all read-only registers) */
pbrookeea589c2007-11-24 03:13:04 +000088 uint32_t user0;
89 uint32_t user1;
Peter Maydell4bebb9a2021-01-28 11:41:36 +000090 uint32_t did0;
91 uint32_t did1;
92 uint32_t dc0;
93 uint32_t dc1;
94 uint32_t dc2;
95 uint32_t dc3;
96 uint32_t dc4;
97};
pbrook9ee6e8b2007-11-11 00:04:49 +000098
99static void ssys_update(ssys_state *s)
100{
101 qemu_set_irq(s->irq, (s->int_status & s->int_mask) != 0);
102}
103
104static uint32_t pllcfg_sandstorm[16] = {
105 0x31c0, /* 1 Mhz */
106 0x1ae0, /* 1.8432 Mhz */
107 0x18c0, /* 2 Mhz */
108 0xd573, /* 2.4576 Mhz */
109 0x37a6, /* 3.57954 Mhz */
110 0x1ae2, /* 3.6864 Mhz */
111 0x0c40, /* 4 Mhz */
112 0x98bc, /* 4.906 Mhz */
113 0x935b, /* 4.9152 Mhz */
114 0x09c0, /* 5 Mhz */
115 0x4dee, /* 5.12 Mhz */
116 0x0c41, /* 6 Mhz */
117 0x75db, /* 6.144 Mhz */
118 0x1ae6, /* 7.3728 Mhz */
119 0x0600, /* 8 Mhz */
120 0x585b /* 8.192 Mhz */
121};
122
123static uint32_t pllcfg_fury[16] = {
124 0x3200, /* 1 Mhz */
125 0x1b20, /* 1.8432 Mhz */
126 0x1900, /* 2 Mhz */
127 0xf42b, /* 2.4576 Mhz */
128 0x37e3, /* 3.57954 Mhz */
129 0x1b21, /* 3.6864 Mhz */
130 0x0c80, /* 4 Mhz */
131 0x98ee, /* 4.906 Mhz */
132 0xd5b4, /* 4.9152 Mhz */
133 0x0a00, /* 5 Mhz */
134 0x4e27, /* 5.12 Mhz */
135 0x1902, /* 6 Mhz */
136 0xec1c, /* 6.144 Mhz */
137 0x1b23, /* 7.3728 Mhz */
138 0x0640, /* 8 Mhz */
139 0xb11c /* 8.192 Mhz */
140};
141
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100142#define DID0_VER_MASK 0x70000000
143#define DID0_VER_0 0x00000000
144#define DID0_VER_1 0x10000000
145
146#define DID0_CLASS_MASK 0x00FF0000
147#define DID0_CLASS_SANDSTORM 0x00000000
148#define DID0_CLASS_FURY 0x00010000
149
150static int ssys_board_class(const ssys_state *s)
151{
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000152 uint32_t did0 = s->did0;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100153 switch (did0 & DID0_VER_MASK) {
154 case DID0_VER_0:
155 return DID0_CLASS_SANDSTORM;
156 case DID0_VER_1:
157 switch (did0 & DID0_CLASS_MASK) {
158 case DID0_CLASS_SANDSTORM:
159 case DID0_CLASS_FURY:
160 return did0 & DID0_CLASS_MASK;
161 }
162 /* for unknown classes, fall through */
163 default:
Peter Maydelldf3692e2017-04-20 17:32:29 +0100164 /* This can only happen if the hardwired constant did0 value
165 * in this board's stellaris_board_info struct is wrong.
166 */
167 g_assert_not_reached();
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100168 }
169}
170
Avi Kivitya8170e52012-10-23 12:30:10 +0200171static uint64_t ssys_read(void *opaque, hwaddr offset,
Benoît Canet56993012011-10-17 17:28:29 +0200172 unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000173{
174 ssys_state *s = (ssys_state *)opaque;
175
pbrook9ee6e8b2007-11-11 00:04:49 +0000176 switch (offset) {
177 case 0x000: /* DID0 */
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000178 return s->did0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000179 case 0x004: /* DID1 */
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000180 return s->did1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000181 case 0x008: /* DC0 */
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000182 return s->dc0;
pbrook9ee6e8b2007-11-11 00:04:49 +0000183 case 0x010: /* DC1 */
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000184 return s->dc1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000185 case 0x014: /* DC2 */
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000186 return s->dc2;
pbrook9ee6e8b2007-11-11 00:04:49 +0000187 case 0x018: /* DC3 */
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000188 return s->dc3;
pbrook9ee6e8b2007-11-11 00:04:49 +0000189 case 0x01c: /* DC4 */
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000190 return s->dc4;
pbrook9ee6e8b2007-11-11 00:04:49 +0000191 case 0x030: /* PBORCTL */
192 return s->pborctl;
193 case 0x034: /* LDOPCTL */
194 return s->ldopctl;
195 case 0x040: /* SRCR0 */
196 return 0;
197 case 0x044: /* SRCR1 */
198 return 0;
199 case 0x048: /* SRCR2 */
200 return 0;
201 case 0x050: /* RIS */
202 return s->int_status;
203 case 0x054: /* IMC */
204 return s->int_mask;
205 case 0x058: /* MISC */
206 return s->int_status & s->int_mask;
207 case 0x05c: /* RESC */
208 return s->resc;
209 case 0x060: /* RCC */
210 return s->rcc;
211 case 0x064: /* PLLCFG */
212 {
213 int xtal;
214 xtal = (s->rcc >> 6) & 0xf;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100215 switch (ssys_board_class(s)) {
216 case DID0_CLASS_FURY:
pbrook9ee6e8b2007-11-11 00:04:49 +0000217 return pllcfg_fury[xtal];
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100218 case DID0_CLASS_SANDSTORM:
pbrook9ee6e8b2007-11-11 00:04:49 +0000219 return pllcfg_sandstorm[xtal];
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100220 default:
Peter Maydelldf3692e2017-04-20 17:32:29 +0100221 g_assert_not_reached();
pbrook9ee6e8b2007-11-11 00:04:49 +0000222 }
223 }
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100224 case 0x070: /* RCC2 */
225 return s->rcc2;
pbrook9ee6e8b2007-11-11 00:04:49 +0000226 case 0x100: /* RCGC0 */
227 return s->rcgc[0];
228 case 0x104: /* RCGC1 */
229 return s->rcgc[1];
230 case 0x108: /* RCGC2 */
231 return s->rcgc[2];
232 case 0x110: /* SCGC0 */
233 return s->scgc[0];
234 case 0x114: /* SCGC1 */
235 return s->scgc[1];
236 case 0x118: /* SCGC2 */
237 return s->scgc[2];
238 case 0x120: /* DCGC0 */
239 return s->dcgc[0];
240 case 0x124: /* DCGC1 */
241 return s->dcgc[1];
242 case 0x128: /* DCGC2 */
243 return s->dcgc[2];
244 case 0x150: /* CLKVCLR */
245 return s->clkvclr;
246 case 0x160: /* LDOARST */
247 return s->ldoarst;
pbrookeea589c2007-11-24 03:13:04 +0000248 case 0x1e0: /* USER0 */
249 return s->user0;
250 case 0x1e4: /* USER1 */
251 return s->user1;
pbrook9ee6e8b2007-11-11 00:04:49 +0000252 default:
Peter Maydelldf3692e2017-04-20 17:32:29 +0100253 qemu_log_mask(LOG_GUEST_ERROR,
254 "SSYS: read at bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000255 return 0;
256 }
257}
258
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100259static bool ssys_use_rcc2(ssys_state *s)
260{
261 return (s->rcc2 >> 31) & 0x1;
262}
263
264/*
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000265 * Calculate the system clock period. We only want to propagate
266 * this change to the rest of the system if we're not being called
267 * from migration post-load.
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100268 */
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000269static void ssys_calculate_system_clock(ssys_state *s, bool propagate_clock)
pbrook23e39292008-07-02 16:48:32 +0000270{
Peter Maydell683754c2021-08-12 10:33:56 +0100271 int period_ns;
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000272 /*
273 * SYSDIV field specifies divisor: 0 == /1, 1 == /2, etc. Input
274 * clock is 200MHz, which is a period of 5 ns. Dividing the clock
275 * frequency by X is the same as multiplying the period by X.
276 */
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100277 if (ssys_use_rcc2(s)) {
Peter Maydell683754c2021-08-12 10:33:56 +0100278 period_ns = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100279 } else {
Peter Maydell683754c2021-08-12 10:33:56 +0100280 period_ns = 5 * (((s->rcc >> 23) & 0xf) + 1);
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100281 }
Peter Maydell683754c2021-08-12 10:33:56 +0100282 clock_set_ns(s->sysclk, period_ns);
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000283 if (propagate_clock) {
284 clock_propagate(s->sysclk);
285 }
pbrook23e39292008-07-02 16:48:32 +0000286}
287
Avi Kivitya8170e52012-10-23 12:30:10 +0200288static void ssys_write(void *opaque, hwaddr offset,
Benoît Canet56993012011-10-17 17:28:29 +0200289 uint64_t value, unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000290{
291 ssys_state *s = (ssys_state *)opaque;
292
pbrook9ee6e8b2007-11-11 00:04:49 +0000293 switch (offset) {
294 case 0x030: /* PBORCTL */
295 s->pborctl = value & 0xffff;
296 break;
297 case 0x034: /* LDOPCTL */
298 s->ldopctl = value & 0x1f;
299 break;
300 case 0x040: /* SRCR0 */
301 case 0x044: /* SRCR1 */
302 case 0x048: /* SRCR2 */
Philippe Mathieu-Daudé91945242018-06-26 17:50:41 +0100303 qemu_log_mask(LOG_UNIMP, "Peripheral reset not implemented\n");
pbrook9ee6e8b2007-11-11 00:04:49 +0000304 break;
305 case 0x054: /* IMC */
306 s->int_mask = value & 0x7f;
307 break;
308 case 0x058: /* MISC */
309 s->int_status &= ~value;
310 break;
311 case 0x05c: /* RESC */
312 s->resc = value & 0x3f;
313 break;
314 case 0x060: /* RCC */
315 if ((s->rcc & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
316 /* PLL enable. */
317 s->int_status |= (1 << 6);
318 }
319 s->rcc = value;
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000320 ssys_calculate_system_clock(s, true);
pbrook9ee6e8b2007-11-11 00:04:49 +0000321 break;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100322 case 0x070: /* RCC2 */
323 if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
324 break;
325 }
326
327 if ((s->rcc2 & (1 << 13)) != 0 && (value & (1 << 13)) == 0) {
328 /* PLL enable. */
329 s->int_status |= (1 << 6);
330 }
331 s->rcc2 = value;
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000332 ssys_calculate_system_clock(s, true);
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100333 break;
pbrook9ee6e8b2007-11-11 00:04:49 +0000334 case 0x100: /* RCGC0 */
335 s->rcgc[0] = value;
336 break;
337 case 0x104: /* RCGC1 */
338 s->rcgc[1] = value;
339 break;
340 case 0x108: /* RCGC2 */
341 s->rcgc[2] = value;
342 break;
343 case 0x110: /* SCGC0 */
344 s->scgc[0] = value;
345 break;
346 case 0x114: /* SCGC1 */
347 s->scgc[1] = value;
348 break;
349 case 0x118: /* SCGC2 */
350 s->scgc[2] = value;
351 break;
352 case 0x120: /* DCGC0 */
353 s->dcgc[0] = value;
354 break;
355 case 0x124: /* DCGC1 */
356 s->dcgc[1] = value;
357 break;
358 case 0x128: /* DCGC2 */
359 s->dcgc[2] = value;
360 break;
361 case 0x150: /* CLKVCLR */
362 s->clkvclr = value;
363 break;
364 case 0x160: /* LDOARST */
365 s->ldoarst = value;
366 break;
367 default:
Peter Maydelldf3692e2017-04-20 17:32:29 +0100368 qemu_log_mask(LOG_GUEST_ERROR,
369 "SSYS: write at bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000370 }
371 ssys_update(s);
372}
373
Benoît Canet56993012011-10-17 17:28:29 +0200374static const MemoryRegionOps ssys_ops = {
375 .read = ssys_read,
376 .write = ssys_write,
377 .endianness = DEVICE_NATIVE_ENDIAN,
pbrook9ee6e8b2007-11-11 00:04:49 +0000378};
379
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000380static void stellaris_sys_reset_enter(Object *obj, ResetType type)
pbrook9ee6e8b2007-11-11 00:04:49 +0000381{
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000382 ssys_state *s = STELLARIS_SYS(obj);
pbrook9ee6e8b2007-11-11 00:04:49 +0000383
384 s->pborctl = 0x7ffd;
385 s->rcc = 0x078e3ac0;
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100386
387 if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
388 s->rcc2 = 0;
389 } else {
390 s->rcc2 = 0x07802810;
391 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000392 s->rcgc[0] = 1;
393 s->scgc[0] = 1;
394 s->dcgc[0] = 1;
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000395}
396
397static void stellaris_sys_reset_hold(Object *obj)
398{
399 ssys_state *s = STELLARIS_SYS(obj);
400
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000401 /* OK to propagate clocks from the hold phase */
402 ssys_calculate_system_clock(s, true);
pbrook9ee6e8b2007-11-11 00:04:49 +0000403}
404
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000405static void stellaris_sys_reset_exit(Object *obj)
406{
407}
408
Juan Quintela293c16a2010-12-02 03:03:11 +0100409static int stellaris_sys_post_load(void *opaque, int version_id)
pbrook23e39292008-07-02 16:48:32 +0000410{
Juan Quintela293c16a2010-12-02 03:03:11 +0100411 ssys_state *s = opaque;
pbrook23e39292008-07-02 16:48:32 +0000412
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000413 ssys_calculate_system_clock(s, false);
pbrook23e39292008-07-02 16:48:32 +0000414
415 return 0;
416}
417
Juan Quintela293c16a2010-12-02 03:03:11 +0100418static const VMStateDescription vmstate_stellaris_sys = {
419 .name = "stellaris_sys",
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100420 .version_id = 2,
Juan Quintela293c16a2010-12-02 03:03:11 +0100421 .minimum_version_id = 1,
Juan Quintela293c16a2010-12-02 03:03:11 +0100422 .post_load = stellaris_sys_post_load,
Richard Henderson607ef572023-12-21 14:15:59 +1100423 .fields = (const VMStateField[]) {
Juan Quintela293c16a2010-12-02 03:03:11 +0100424 VMSTATE_UINT32(pborctl, ssys_state),
425 VMSTATE_UINT32(ldopctl, ssys_state),
426 VMSTATE_UINT32(int_mask, ssys_state),
427 VMSTATE_UINT32(int_status, ssys_state),
428 VMSTATE_UINT32(resc, ssys_state),
429 VMSTATE_UINT32(rcc, ssys_state),
Engin AYDOGANdc804ab2011-08-03 22:15:23 +0100430 VMSTATE_UINT32_V(rcc2, ssys_state, 2),
Juan Quintela293c16a2010-12-02 03:03:11 +0100431 VMSTATE_UINT32_ARRAY(rcgc, ssys_state, 3),
432 VMSTATE_UINT32_ARRAY(scgc, ssys_state, 3),
433 VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
434 VMSTATE_UINT32(clkvclr, ssys_state),
435 VMSTATE_UINT32(ldoarst, ssys_state),
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000436 /* No field for sysclk -- handled in post-load instead */
Juan Quintela293c16a2010-12-02 03:03:11 +0100437 VMSTATE_END_OF_LIST()
438 }
439};
440
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000441static Property stellaris_sys_properties[] = {
442 DEFINE_PROP_UINT32("user0", ssys_state, user0, 0),
443 DEFINE_PROP_UINT32("user1", ssys_state, user1, 0),
444 DEFINE_PROP_UINT32("did0", ssys_state, did0, 0),
445 DEFINE_PROP_UINT32("did1", ssys_state, did1, 0),
446 DEFINE_PROP_UINT32("dc0", ssys_state, dc0, 0),
447 DEFINE_PROP_UINT32("dc1", ssys_state, dc1, 0),
448 DEFINE_PROP_UINT32("dc2", ssys_state, dc2, 0),
449 DEFINE_PROP_UINT32("dc3", ssys_state, dc3, 0),
450 DEFINE_PROP_UINT32("dc4", ssys_state, dc4, 0),
451 DEFINE_PROP_END_OF_LIST()
452};
453
454static void stellaris_sys_instance_init(Object *obj)
455{
456 ssys_state *s = STELLARIS_SYS(obj);
457 SysBusDevice *sbd = SYS_BUS_DEVICE(s);
458
459 memory_region_init_io(&s->iomem, obj, &ssys_ops, s, "ssys", 0x00001000);
460 sysbus_init_mmio(sbd, &s->iomem);
461 sysbus_init_irq(sbd, &s->irq);
Peter Maydell1e31d8e2021-01-28 11:41:37 +0000462 s->sysclk = qdev_init_clock_out(DEVICE(s), "SYSCLK");
Peter Maydell4bebb9a2021-01-28 11:41:36 +0000463}
464
pbrook9ee6e8b2007-11-11 00:04:49 +0000465/* I2C controller. */
466
Andreas Färberd94a4012013-07-24 09:08:23 +0200467#define TYPE_STELLARIS_I2C "stellaris-i2c"
Eduardo Habkost80633962020-09-16 14:25:19 -0400468OBJECT_DECLARE_SIMPLE_TYPE(stellaris_i2c_state, STELLARIS_I2C)
Andreas Färberd94a4012013-07-24 09:08:23 +0200469
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400470struct stellaris_i2c_state {
Andreas Färberd94a4012013-07-24 09:08:23 +0200471 SysBusDevice parent_obj;
472
Andreas Färbera5c82852013-08-03 00:18:51 +0200473 I2CBus *bus;
pbrook9ee6e8b2007-11-11 00:04:49 +0000474 qemu_irq irq;
Benoît Canet8ea72f32011-10-17 17:28:30 +0200475 MemoryRegion iomem;
pbrook9ee6e8b2007-11-11 00:04:49 +0000476 uint32_t msa;
477 uint32_t mcs;
478 uint32_t mdr;
479 uint32_t mtpr;
480 uint32_t mimr;
481 uint32_t mris;
482 uint32_t mcr;
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400483};
pbrook9ee6e8b2007-11-11 00:04:49 +0000484
485#define STELLARIS_I2C_MCS_BUSY 0x01
486#define STELLARIS_I2C_MCS_ERROR 0x02
487#define STELLARIS_I2C_MCS_ADRACK 0x04
488#define STELLARIS_I2C_MCS_DATACK 0x08
489#define STELLARIS_I2C_MCS_ARBLST 0x10
490#define STELLARIS_I2C_MCS_IDLE 0x20
491#define STELLARIS_I2C_MCS_BUSBSY 0x40
492
Avi Kivitya8170e52012-10-23 12:30:10 +0200493static uint64_t stellaris_i2c_read(void *opaque, hwaddr offset,
Benoît Canet8ea72f32011-10-17 17:28:30 +0200494 unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000495{
496 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
497
pbrook9ee6e8b2007-11-11 00:04:49 +0000498 switch (offset) {
499 case 0x00: /* MSA */
500 return s->msa;
501 case 0x04: /* MCS */
502 /* We don't emulate timing, so the controller is never busy. */
503 return s->mcs | STELLARIS_I2C_MCS_IDLE;
504 case 0x08: /* MDR */
505 return s->mdr;
506 case 0x0c: /* MTPR */
507 return s->mtpr;
508 case 0x10: /* MIMR */
509 return s->mimr;
510 case 0x14: /* MRIS */
511 return s->mris;
512 case 0x18: /* MMIS */
513 return s->mris & s->mimr;
514 case 0x20: /* MCR */
515 return s->mcr;
516 default:
Peter Maydelldf3692e2017-04-20 17:32:29 +0100517 qemu_log_mask(LOG_GUEST_ERROR,
518 "stellaris_i2c: read at bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000519 return 0;
520 }
521}
522
523static void stellaris_i2c_update(stellaris_i2c_state *s)
524{
525 int level;
526
527 level = (s->mris & s->mimr) != 0;
528 qemu_set_irq(s->irq, level);
529}
530
Avi Kivitya8170e52012-10-23 12:30:10 +0200531static void stellaris_i2c_write(void *opaque, hwaddr offset,
Benoît Canet8ea72f32011-10-17 17:28:30 +0200532 uint64_t value, unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000533{
534 stellaris_i2c_state *s = (stellaris_i2c_state *)opaque;
535
pbrook9ee6e8b2007-11-11 00:04:49 +0000536 switch (offset) {
537 case 0x00: /* MSA */
538 s->msa = value & 0xff;
539 break;
540 case 0x04: /* MCS */
541 if ((s->mcr & 0x10) == 0) {
542 /* Disabled. Do nothing. */
543 break;
544 }
545 /* Grab the bus if this is starting a transfer. */
546 if ((value & 2) && (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
547 if (i2c_start_transfer(s->bus, s->msa >> 1, s->msa & 1)) {
548 s->mcs |= STELLARIS_I2C_MCS_ARBLST;
549 } else {
550 s->mcs &= ~STELLARIS_I2C_MCS_ARBLST;
551 s->mcs |= STELLARIS_I2C_MCS_BUSBSY;
552 }
553 }
554 /* If we don't have the bus then indicate an error. */
555 if (!i2c_bus_busy(s->bus)
556 || (s->mcs & STELLARIS_I2C_MCS_BUSBSY) == 0) {
557 s->mcs |= STELLARIS_I2C_MCS_ERROR;
558 break;
559 }
560 s->mcs &= ~STELLARIS_I2C_MCS_ERROR;
561 if (value & 1) {
562 /* Transfer a byte. */
563 /* TODO: Handle errors. */
564 if (s->msa & 1) {
565 /* Recv */
Corey Minyard05f9f172018-11-20 11:10:58 -0600566 s->mdr = i2c_recv(s->bus);
pbrook9ee6e8b2007-11-11 00:04:49 +0000567 } else {
568 /* Send */
569 i2c_send(s->bus, s->mdr);
570 }
571 /* Raise an interrupt. */
572 s->mris |= 1;
573 }
574 if (value & 4) {
575 /* Finish transfer. */
576 i2c_end_transfer(s->bus);
577 s->mcs &= ~STELLARIS_I2C_MCS_BUSBSY;
578 }
579 break;
580 case 0x08: /* MDR */
581 s->mdr = value & 0xff;
582 break;
583 case 0x0c: /* MTPR */
584 s->mtpr = value & 0xff;
585 break;
586 case 0x10: /* MIMR */
587 s->mimr = 1;
588 break;
589 case 0x1c: /* MICR */
590 s->mris &= ~value;
591 break;
592 case 0x20: /* MCR */
Peter Maydelldf3692e2017-04-20 17:32:29 +0100593 if (value & 1) {
Philippe Mathieu-Daudé9492e4b2018-06-08 13:15:33 +0100594 qemu_log_mask(LOG_UNIMP,
595 "stellaris_i2c: Loopback not implemented\n");
Peter Maydelldf3692e2017-04-20 17:32:29 +0100596 }
597 if (value & 0x20) {
598 qemu_log_mask(LOG_UNIMP,
Philippe Mathieu-Daudé9492e4b2018-06-08 13:15:33 +0100599 "stellaris_i2c: Slave mode not implemented\n");
Peter Maydelldf3692e2017-04-20 17:32:29 +0100600 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000601 s->mcr = value & 0x31;
602 break;
603 default:
Peter Maydelldf3692e2017-04-20 17:32:29 +0100604 qemu_log_mask(LOG_GUEST_ERROR,
605 "stellaris_i2c: write at bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000606 }
607 stellaris_i2c_update(s);
608}
609
610static void stellaris_i2c_reset(stellaris_i2c_state *s)
611{
612 if (s->mcs & STELLARIS_I2C_MCS_BUSBSY)
613 i2c_end_transfer(s->bus);
614
615 s->msa = 0;
616 s->mcs = 0;
617 s->mdr = 0;
618 s->mtpr = 1;
619 s->mimr = 0;
620 s->mris = 0;
621 s->mcr = 0;
622 stellaris_i2c_update(s);
623}
624
Benoît Canet8ea72f32011-10-17 17:28:30 +0200625static const MemoryRegionOps stellaris_i2c_ops = {
626 .read = stellaris_i2c_read,
627 .write = stellaris_i2c_write,
628 .endianness = DEVICE_NATIVE_ENDIAN,
pbrook9ee6e8b2007-11-11 00:04:49 +0000629};
630
Juan Quintelaff269cd2010-12-02 02:48:43 +0100631static const VMStateDescription vmstate_stellaris_i2c = {
632 .name = "stellaris_i2c",
633 .version_id = 1,
634 .minimum_version_id = 1,
Richard Henderson607ef572023-12-21 14:15:59 +1100635 .fields = (const VMStateField[]) {
Juan Quintelaff269cd2010-12-02 02:48:43 +0100636 VMSTATE_UINT32(msa, stellaris_i2c_state),
637 VMSTATE_UINT32(mcs, stellaris_i2c_state),
638 VMSTATE_UINT32(mdr, stellaris_i2c_state),
639 VMSTATE_UINT32(mtpr, stellaris_i2c_state),
640 VMSTATE_UINT32(mimr, stellaris_i2c_state),
641 VMSTATE_UINT32(mris, stellaris_i2c_state),
642 VMSTATE_UINT32(mcr, stellaris_i2c_state),
643 VMSTATE_END_OF_LIST()
644 }
645};
pbrook23e39292008-07-02 16:48:32 +0000646
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +0800647static void stellaris_i2c_init(Object *obj)
pbrook9ee6e8b2007-11-11 00:04:49 +0000648{
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +0800649 DeviceState *dev = DEVICE(obj);
650 stellaris_i2c_state *s = STELLARIS_I2C(obj);
651 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
Andreas Färbera5c82852013-08-03 00:18:51 +0200652 I2CBus *bus;
pbrook9ee6e8b2007-11-11 00:04:49 +0000653
Andreas Färberd94a4012013-07-24 09:08:23 +0200654 sysbus_init_irq(sbd, &s->irq);
655 bus = i2c_init_bus(dev, "i2c");
pbrook9ee6e8b2007-11-11 00:04:49 +0000656 s->bus = bus;
657
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +0800658 memory_region_init_io(&s->iomem, obj, &stellaris_i2c_ops, s,
Benoît Canet8ea72f32011-10-17 17:28:30 +0200659 "i2c", 0x1000);
Andreas Färberd94a4012013-07-24 09:08:23 +0200660 sysbus_init_mmio(sbd, &s->iomem);
pbrook9ee6e8b2007-11-11 00:04:49 +0000661 /* ??? For now we only implement the master interface. */
662 stellaris_i2c_reset(s);
663}
664
665/* Analogue to Digital Converter. This is only partially implemented,
666 enough for applications that use a combined ADC and timer tick. */
667
668#define STELLARIS_ADC_EM_CONTROLLER 0
669#define STELLARIS_ADC_EM_COMP 1
670#define STELLARIS_ADC_EM_EXTERNAL 4
671#define STELLARIS_ADC_EM_TIMER 5
672#define STELLARIS_ADC_EM_PWM0 6
673#define STELLARIS_ADC_EM_PWM1 7
674#define STELLARIS_ADC_EM_PWM2 8
675
676#define STELLARIS_ADC_FIFO_EMPTY 0x0100
677#define STELLARIS_ADC_FIFO_FULL 0x1000
678
Andreas Färber7df7f672013-07-24 09:13:06 +0200679#define TYPE_STELLARIS_ADC "stellaris-adc"
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100680typedef struct StellarisADCState StellarisADCState;
681DECLARE_INSTANCE_CHECKER(StellarisADCState, STELLARIS_ADC, TYPE_STELLARIS_ADC)
Andreas Färber7df7f672013-07-24 09:13:06 +0200682
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400683struct StellarisADCState {
Andreas Färber7df7f672013-07-24 09:13:06 +0200684 SysBusDevice parent_obj;
685
Benoît Canet71a2df02011-10-17 17:28:31 +0200686 MemoryRegion iomem;
pbrook9ee6e8b2007-11-11 00:04:49 +0000687 uint32_t actss;
688 uint32_t ris;
689 uint32_t im;
690 uint32_t emux;
691 uint32_t ostat;
692 uint32_t ustat;
693 uint32_t sspri;
694 uint32_t sac;
695 struct {
696 uint32_t state;
697 uint32_t data[16];
698 } fifo[4];
699 uint32_t ssmux[4];
700 uint32_t ssctl[4];
pbrook23e39292008-07-02 16:48:32 +0000701 uint32_t noise;
Paul Brook2c6554b2009-06-02 15:30:27 +0100702 qemu_irq irq[4];
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400703};
pbrook9ee6e8b2007-11-11 00:04:49 +0000704
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100705static uint32_t stellaris_adc_fifo_read(StellarisADCState *s, int n)
pbrook9ee6e8b2007-11-11 00:04:49 +0000706{
707 int tail;
708
709 tail = s->fifo[n].state & 0xf;
710 if (s->fifo[n].state & STELLARIS_ADC_FIFO_EMPTY) {
711 s->ustat |= 1 << n;
712 } else {
713 s->fifo[n].state = (s->fifo[n].state & ~0xf) | ((tail + 1) & 0xf);
714 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_FULL;
715 if (tail + 1 == ((s->fifo[n].state >> 4) & 0xf))
716 s->fifo[n].state |= STELLARIS_ADC_FIFO_EMPTY;
717 }
718 return s->fifo[n].data[tail];
719}
720
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100721static void stellaris_adc_fifo_write(StellarisADCState *s, int n,
pbrook9ee6e8b2007-11-11 00:04:49 +0000722 uint32_t value)
723{
724 int head;
725
Paul Brook2c6554b2009-06-02 15:30:27 +0100726 /* TODO: Real hardware has limited size FIFOs. We have a full 16 entry
727 FIFO fir each sequencer. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000728 head = (s->fifo[n].state >> 4) & 0xf;
729 if (s->fifo[n].state & STELLARIS_ADC_FIFO_FULL) {
730 s->ostat |= 1 << n;
731 return;
732 }
733 s->fifo[n].data[head] = value;
734 head = (head + 1) & 0xf;
735 s->fifo[n].state &= ~STELLARIS_ADC_FIFO_EMPTY;
736 s->fifo[n].state = (s->fifo[n].state & ~0xf0) | (head << 4);
737 if ((s->fifo[n].state & 0xf) == head)
738 s->fifo[n].state |= STELLARIS_ADC_FIFO_FULL;
739}
740
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100741static void stellaris_adc_update(StellarisADCState *s)
pbrook9ee6e8b2007-11-11 00:04:49 +0000742{
743 int level;
Paul Brook2c6554b2009-06-02 15:30:27 +0100744 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000745
Paul Brook2c6554b2009-06-02 15:30:27 +0100746 for (n = 0; n < 4; n++) {
747 level = (s->ris & s->im & (1 << n)) != 0;
748 qemu_set_irq(s->irq[n], level);
749 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000750}
751
752static void stellaris_adc_trigger(void *opaque, int irq, int level)
753{
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100754 StellarisADCState *s = opaque;
Paul Brook2c6554b2009-06-02 15:30:27 +0100755 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000756
Paul Brook2c6554b2009-06-02 15:30:27 +0100757 for (n = 0; n < 4; n++) {
758 if ((s->actss & (1 << n)) == 0) {
759 continue;
760 }
761
762 if (((s->emux >> (n * 4)) & 0xff) != 5) {
763 continue;
764 }
765
766 /* Some applications use the ADC as a random number source, so introduce
767 some variation into the signal. */
768 s->noise = s->noise * 314159 + 1;
769 /* ??? actual inputs not implemented. Return an arbitrary value. */
770 stellaris_adc_fifo_write(s, n, 0x200 + ((s->noise >> 16) & 7));
771 s->ris |= (1 << n);
772 stellaris_adc_update(s);
pbrook9ee6e8b2007-11-11 00:04:49 +0000773 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000774}
775
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100776static void stellaris_adc_reset(StellarisADCState *s)
pbrook9ee6e8b2007-11-11 00:04:49 +0000777{
778 int n;
779
780 for (n = 0; n < 4; n++) {
781 s->ssmux[n] = 0;
782 s->ssctl[n] = 0;
783 s->fifo[n].state = STELLARIS_ADC_FIFO_EMPTY;
784 }
785}
786
Avi Kivitya8170e52012-10-23 12:30:10 +0200787static uint64_t stellaris_adc_read(void *opaque, hwaddr offset,
Benoît Canet71a2df02011-10-17 17:28:31 +0200788 unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000789{
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100790 StellarisADCState *s = opaque;
pbrook9ee6e8b2007-11-11 00:04:49 +0000791
792 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000793 if (offset >= 0x40 && offset < 0xc0) {
794 int n;
795 n = (offset - 0x40) >> 5;
796 switch (offset & 0x1f) {
797 case 0x00: /* SSMUX */
798 return s->ssmux[n];
799 case 0x04: /* SSCTL */
800 return s->ssctl[n];
801 case 0x08: /* SSFIFO */
802 return stellaris_adc_fifo_read(s, n);
803 case 0x0c: /* SSFSTAT */
804 return s->fifo[n].state;
805 default:
806 break;
807 }
808 }
809 switch (offset) {
810 case 0x00: /* ACTSS */
811 return s->actss;
812 case 0x04: /* RIS */
813 return s->ris;
814 case 0x08: /* IM */
815 return s->im;
816 case 0x0c: /* ISC */
817 return s->ris & s->im;
818 case 0x10: /* OSTAT */
819 return s->ostat;
820 case 0x14: /* EMUX */
821 return s->emux;
822 case 0x18: /* USTAT */
823 return s->ustat;
824 case 0x20: /* SSPRI */
825 return s->sspri;
826 case 0x30: /* SAC */
827 return s->sac;
828 default:
Peter Maydelldf3692e2017-04-20 17:32:29 +0100829 qemu_log_mask(LOG_GUEST_ERROR,
830 "stellaris_adc: read at bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000831 return 0;
832 }
833}
834
Avi Kivitya8170e52012-10-23 12:30:10 +0200835static void stellaris_adc_write(void *opaque, hwaddr offset,
Benoît Canet71a2df02011-10-17 17:28:31 +0200836 uint64_t value, unsigned size)
pbrook9ee6e8b2007-11-11 00:04:49 +0000837{
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100838 StellarisADCState *s = opaque;
pbrook9ee6e8b2007-11-11 00:04:49 +0000839
840 /* TODO: Implement this. */
pbrook9ee6e8b2007-11-11 00:04:49 +0000841 if (offset >= 0x40 && offset < 0xc0) {
842 int n;
843 n = (offset - 0x40) >> 5;
844 switch (offset & 0x1f) {
845 case 0x00: /* SSMUX */
846 s->ssmux[n] = value & 0x33333333;
847 return;
848 case 0x04: /* SSCTL */
849 if (value != 6) {
Peter Maydelldf3692e2017-04-20 17:32:29 +0100850 qemu_log_mask(LOG_UNIMP,
851 "ADC: Unimplemented sequence %" PRIx64 "\n",
852 value);
pbrook9ee6e8b2007-11-11 00:04:49 +0000853 }
854 s->ssctl[n] = value;
855 return;
856 default:
857 break;
858 }
859 }
860 switch (offset) {
861 case 0x00: /* ACTSS */
862 s->actss = value & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +0000863 break;
864 case 0x08: /* IM */
865 s->im = value;
866 break;
867 case 0x0c: /* ISC */
868 s->ris &= ~value;
869 break;
870 case 0x10: /* OSTAT */
871 s->ostat &= ~value;
872 break;
873 case 0x14: /* EMUX */
874 s->emux = value;
875 break;
876 case 0x18: /* USTAT */
877 s->ustat &= ~value;
878 break;
879 case 0x20: /* SSPRI */
880 s->sspri = value;
881 break;
882 case 0x28: /* PSSI */
Philippe Mathieu-Daudé9492e4b2018-06-08 13:15:33 +0100883 qemu_log_mask(LOG_UNIMP, "ADC: sample initiate unimplemented\n");
pbrook9ee6e8b2007-11-11 00:04:49 +0000884 break;
885 case 0x30: /* SAC */
886 s->sac = value;
887 break;
888 default:
Peter Maydelldf3692e2017-04-20 17:32:29 +0100889 qemu_log_mask(LOG_GUEST_ERROR,
890 "stellaris_adc: write at bad offset 0x%x\n", (int)offset);
pbrook9ee6e8b2007-11-11 00:04:49 +0000891 }
892 stellaris_adc_update(s);
893}
894
Benoît Canet71a2df02011-10-17 17:28:31 +0200895static const MemoryRegionOps stellaris_adc_ops = {
896 .read = stellaris_adc_read,
897 .write = stellaris_adc_write,
898 .endianness = DEVICE_NATIVE_ENDIAN,
pbrook9ee6e8b2007-11-11 00:04:49 +0000899};
900
Juan Quintelacf1d31d2010-12-03 01:27:58 +0100901static const VMStateDescription vmstate_stellaris_adc = {
902 .name = "stellaris_adc",
903 .version_id = 1,
904 .minimum_version_id = 1,
Richard Henderson607ef572023-12-21 14:15:59 +1100905 .fields = (const VMStateField[]) {
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100906 VMSTATE_UINT32(actss, StellarisADCState),
907 VMSTATE_UINT32(ris, StellarisADCState),
908 VMSTATE_UINT32(im, StellarisADCState),
909 VMSTATE_UINT32(emux, StellarisADCState),
910 VMSTATE_UINT32(ostat, StellarisADCState),
911 VMSTATE_UINT32(ustat, StellarisADCState),
912 VMSTATE_UINT32(sspri, StellarisADCState),
913 VMSTATE_UINT32(sac, StellarisADCState),
914 VMSTATE_UINT32(fifo[0].state, StellarisADCState),
915 VMSTATE_UINT32_ARRAY(fifo[0].data, StellarisADCState, 16),
916 VMSTATE_UINT32(ssmux[0], StellarisADCState),
917 VMSTATE_UINT32(ssctl[0], StellarisADCState),
918 VMSTATE_UINT32(fifo[1].state, StellarisADCState),
919 VMSTATE_UINT32_ARRAY(fifo[1].data, StellarisADCState, 16),
920 VMSTATE_UINT32(ssmux[1], StellarisADCState),
921 VMSTATE_UINT32(ssctl[1], StellarisADCState),
922 VMSTATE_UINT32(fifo[2].state, StellarisADCState),
923 VMSTATE_UINT32_ARRAY(fifo[2].data, StellarisADCState, 16),
924 VMSTATE_UINT32(ssmux[2], StellarisADCState),
925 VMSTATE_UINT32(ssctl[2], StellarisADCState),
926 VMSTATE_UINT32(fifo[3].state, StellarisADCState),
927 VMSTATE_UINT32_ARRAY(fifo[3].data, StellarisADCState, 16),
928 VMSTATE_UINT32(ssmux[3], StellarisADCState),
929 VMSTATE_UINT32(ssctl[3], StellarisADCState),
930 VMSTATE_UINT32(noise, StellarisADCState),
Juan Quintelacf1d31d2010-12-03 01:27:58 +0100931 VMSTATE_END_OF_LIST()
pbrook23e39292008-07-02 16:48:32 +0000932 }
Juan Quintelacf1d31d2010-12-03 01:27:58 +0100933};
pbrook23e39292008-07-02 16:48:32 +0000934
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +0800935static void stellaris_adc_init(Object *obj)
pbrook9ee6e8b2007-11-11 00:04:49 +0000936{
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +0800937 DeviceState *dev = DEVICE(obj);
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +0100938 StellarisADCState *s = STELLARIS_ADC(obj);
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +0800939 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
Paul Brook2c6554b2009-06-02 15:30:27 +0100940 int n;
pbrook9ee6e8b2007-11-11 00:04:49 +0000941
Paul Brook2c6554b2009-06-02 15:30:27 +0100942 for (n = 0; n < 4; n++) {
Andreas Färber7df7f672013-07-24 09:13:06 +0200943 sysbus_init_irq(sbd, &s->irq[n]);
Paul Brook2c6554b2009-06-02 15:30:27 +0100944 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000945
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +0800946 memory_region_init_io(&s->iomem, obj, &stellaris_adc_ops, s,
Benoît Canet71a2df02011-10-17 17:28:31 +0200947 "adc", 0x1000);
Andreas Färber7df7f672013-07-24 09:13:06 +0200948 sysbus_init_mmio(sbd, &s->iomem);
pbrook9ee6e8b2007-11-11 00:04:49 +0000949 stellaris_adc_reset(s);
Andreas Färber7df7f672013-07-24 09:13:06 +0200950 qdev_init_gpio_in(dev, stellaris_adc_trigger, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +0000951}
952
953/* Board init. */
954static stellaris_board_info stellaris_boards[] = {
955 { "LM3S811EVB",
956 0,
957 0x0032000e,
958 0x001f001f, /* dc0 */
959 0x001132bf,
960 0x01071013,
961 0x3f0f01ff,
962 0x0000001f,
pbrookcf0dbb22007-11-18 14:36:08 +0000963 BP_OLED_I2C
pbrook9ee6e8b2007-11-11 00:04:49 +0000964 },
965 { "LM3S6965EVB",
966 0x10010002,
967 0x1073402e,
968 0x00ff007f, /* dc0 */
969 0x001133ff,
970 0x030f5317,
971 0x0f0f87ff,
972 0x5000007f,
pbrookcf0dbb22007-11-18 14:36:08 +0000973 BP_OLED_SSI | BP_GAMEPAD
pbrook9ee6e8b2007-11-11 00:04:49 +0000974 }
975};
976
Igor Mammedovba1ba5c2017-09-13 18:04:57 +0200977static void stellaris_init(MachineState *ms, stellaris_board_info *board)
pbrook9ee6e8b2007-11-11 00:04:49 +0000978{
979 static const int uart_irq[] = {5, 6, 33, 34};
980 static const int timer_irq[] = {19, 21, 23, 35};
981 static const uint32_t gpio_addr[7] =
982 { 0x40004000, 0x40005000, 0x40006000, 0x40007000,
983 0x40024000, 0x40025000, 0x40026000};
984 static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
985
Peter Maydell394c8bb2017-02-07 18:30:00 +0000986 /* Memory map of SoC devices, from
987 * Stellaris LM3S6965 Microcontroller Data Sheet (rev I)
988 * http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
989 *
Michel Heily566528f2019-03-05 01:16:22 +0200990 * 40000000 wdtimer
Peter Maydell394c8bb2017-02-07 18:30:00 +0000991 * 40002000 i2c (unimplemented)
992 * 40004000 GPIO
993 * 40005000 GPIO
994 * 40006000 GPIO
995 * 40007000 GPIO
996 * 40008000 SSI
997 * 4000c000 UART
998 * 4000d000 UART
999 * 4000e000 UART
1000 * 40020000 i2c
1001 * 40021000 i2c (unimplemented)
1002 * 40024000 GPIO
1003 * 40025000 GPIO
1004 * 40026000 GPIO
1005 * 40028000 PWM (unimplemented)
1006 * 4002c000 QEI (unimplemented)
1007 * 4002d000 QEI (unimplemented)
1008 * 40030000 gptimer
1009 * 40031000 gptimer
1010 * 40032000 gptimer
1011 * 40033000 gptimer
1012 * 40038000 ADC
1013 * 4003c000 analogue comparator (unimplemented)
1014 * 40048000 ethernet
1015 * 400fc000 hibernation module (unimplemented)
1016 * 400fd000 flash memory control (unimplemented)
1017 * 400fe000 system control
1018 */
1019
Michael Davidsaver20c59c32015-11-03 13:49:41 +00001020 DeviceState *gpio_dev[7], *nvic;
Paul Brook40905a62009-06-03 15:16:49 +01001021 qemu_irq gpio_in[7][8];
1022 qemu_irq gpio_out[7][8];
pbrook9ee6e8b2007-11-11 00:04:49 +00001023 qemu_irq adc;
1024 int sram_size;
1025 int flash_size;
Andreas Färbera5c82852013-08-03 00:18:51 +02001026 I2CBus *i2c;
Paul Brook40905a62009-06-03 15:16:49 +01001027 DeviceState *dev;
Peter Maydell1e31d8e2021-01-28 11:41:37 +00001028 DeviceState *ssys_dev;
pbrook9ee6e8b2007-11-11 00:04:49 +00001029 int i;
Paul Brook40905a62009-06-03 15:16:49 +01001030 int j;
Peter Maydell8ecda752021-08-12 10:33:48 +01001031 const uint8_t *macaddr;
pbrook9ee6e8b2007-11-11 00:04:49 +00001032
Alistair Francisfe6ac442015-02-05 13:37:21 +00001033 MemoryRegion *sram = g_new(MemoryRegion, 1);
1034 MemoryRegion *flash = g_new(MemoryRegion, 1);
1035 MemoryRegion *system_memory = get_system_memory();
1036
1037 flash_size = (((board->dc0 & 0xffff) + 1) << 1) * 1024;
1038 sram_size = ((board->dc0 >> 18) + 1) * 1024;
1039
1040 /* Flash programming is done via the SCU, so pretend it is ROM. */
Philippe Mathieu-Daudé16260002020-02-24 19:50:18 +01001041 memory_region_init_rom(flash, NULL, "stellaris.flash", flash_size,
Markus Armbrusterf8ed85a2015-09-11 16:51:43 +02001042 &error_fatal);
Alistair Francisfe6ac442015-02-05 13:37:21 +00001043 memory_region_add_subregion(system_memory, 0, flash);
1044
Peter Maydell98a99ce2017-07-07 15:42:53 +01001045 memory_region_init_ram(sram, NULL, "stellaris.sram", sram_size,
Markus Armbrusterf8ed85a2015-09-11 16:51:43 +02001046 &error_fatal);
Alistair Francisfe6ac442015-02-05 13:37:21 +00001047 memory_region_add_subregion(system_memory, 0x20000000, sram);
1048
Peter Maydella861b3e2021-08-12 10:33:47 +01001049 /*
1050 * Create the system-registers object early, because we will
1051 * need its sysclk output.
1052 */
1053 ssys_dev = qdev_new(TYPE_STELLARIS_SYS);
1054 /* Most devices come preprogrammed with a MAC address in the user data. */
1055 macaddr = nd_table[0].macaddr.a;
1056 qdev_prop_set_uint32(ssys_dev, "user0",
1057 macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16));
1058 qdev_prop_set_uint32(ssys_dev, "user1",
1059 macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16));
1060 qdev_prop_set_uint32(ssys_dev, "did0", board->did0);
1061 qdev_prop_set_uint32(ssys_dev, "did1", board->did1);
1062 qdev_prop_set_uint32(ssys_dev, "dc0", board->dc0);
1063 qdev_prop_set_uint32(ssys_dev, "dc1", board->dc1);
1064 qdev_prop_set_uint32(ssys_dev, "dc2", board->dc2);
1065 qdev_prop_set_uint32(ssys_dev, "dc3", board->dc3);
1066 qdev_prop_set_uint32(ssys_dev, "dc4", board->dc4);
1067 sysbus_realize_and_unref(SYS_BUS_DEVICE(ssys_dev), &error_fatal);
1068
Markus Armbruster3e80f692020-06-10 07:31:58 +02001069 nvic = qdev_new(TYPE_ARMV7M);
Peter Maydellf04d4462018-06-15 14:57:13 +01001070 qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES);
Samuel Tardieu4a046552024-01-06 19:15:03 +01001071 qdev_prop_set_uint8(nvic, "num-prio-bits", NUM_PRIO_BITS);
Peter Maydellf04d4462018-06-15 14:57:13 +01001072 qdev_prop_set_string(nvic, "cpu-type", ms->cpu_type);
Stefan Hajnoczia1c5a062018-08-16 14:05:28 +01001073 qdev_prop_set_bit(nvic, "enable-bitband", true);
Peter Maydell8ecda752021-08-12 10:33:48 +01001074 qdev_connect_clock_in(nvic, "cpuclk",
1075 qdev_get_clock_out(ssys_dev, "SYSCLK"));
1076 /* This SoC does not connect the systick reference clock */
Markus Armbruster5325cc32020-07-07 18:05:54 +02001077 object_property_set_link(OBJECT(nvic), "memory",
1078 OBJECT(get_system_memory()), &error_abort);
Peter Maydellf04d4462018-06-15 14:57:13 +01001079 /* This will exit with an error if the user passed us a bad cpu_type */
Markus Armbruster3c6ef472020-06-10 07:32:34 +02001080 sysbus_realize_and_unref(SYS_BUS_DEVICE(nvic), &error_fatal);
pbrook9ee6e8b2007-11-11 00:04:49 +00001081
Peter Maydella861b3e2021-08-12 10:33:47 +01001082 /* Now we can wire up the IRQ and MMIO of the system registers */
1083 sysbus_mmio_map(SYS_BUS_DEVICE(ssys_dev), 0, 0x400fe000);
1084 sysbus_connect_irq(SYS_BUS_DEVICE(ssys_dev), 0, qdev_get_gpio_in(nvic, 28));
1085
pbrook9ee6e8b2007-11-11 00:04:49 +00001086 if (board->dc1 & (1 << 16)) {
Andreas Färber7df7f672013-07-24 09:13:06 +02001087 dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000,
Michael Davidsaver20c59c32015-11-03 13:49:41 +00001088 qdev_get_gpio_in(nvic, 14),
1089 qdev_get_gpio_in(nvic, 15),
1090 qdev_get_gpio_in(nvic, 16),
1091 qdev_get_gpio_in(nvic, 17),
1092 NULL);
Paul Brook40905a62009-06-03 15:16:49 +01001093 adc = qdev_get_gpio_in(dev, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00001094 } else {
1095 adc = NULL;
1096 }
1097 for (i = 0; i < 4; i++) {
1098 if (board->dc2 & (0x10000 << i)) {
Peter Maydelld18fdd62021-08-12 10:33:55 +01001099 SysBusDevice *sbd;
1100
1101 dev = qdev_new(TYPE_STELLARIS_GPTM);
1102 sbd = SYS_BUS_DEVICE(dev);
1103 qdev_connect_clock_in(dev, "clk",
1104 qdev_get_clock_out(ssys_dev, "SYSCLK"));
1105 sysbus_realize_and_unref(sbd, &error_fatal);
1106 sysbus_mmio_map(sbd, 0, 0x40030000 + i * 0x1000);
1107 sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
Paul Brook40905a62009-06-03 15:16:49 +01001108 /* TODO: This is incorrect, but we get away with it because
1109 the ADC output is only ever pulsed. */
1110 qdev_connect_gpio_out(dev, 0, adc);
pbrook9ee6e8b2007-11-11 00:04:49 +00001111 }
1112 }
1113
Michel Heily566528f2019-03-05 01:16:22 +02001114 if (board->dc1 & (1 << 3)) { /* watchdog present */
Markus Armbruster3e80f692020-06-10 07:31:58 +02001115 dev = qdev_new(TYPE_LUMINARY_WATCHDOG);
Michel Heily566528f2019-03-05 01:16:22 +02001116
Peter Maydell1e31d8e2021-01-28 11:41:37 +00001117 qdev_connect_clock_in(dev, "WDOGCLK",
1118 qdev_get_clock_out(ssys_dev, "SYSCLK"));
Michel Heily566528f2019-03-05 01:16:22 +02001119
Markus Armbruster3c6ef472020-06-10 07:32:34 +02001120 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
Michel Heily566528f2019-03-05 01:16:22 +02001121 sysbus_mmio_map(SYS_BUS_DEVICE(dev),
1122 0,
1123 0x40000000u);
1124 sysbus_connect_irq(SYS_BUS_DEVICE(dev),
1125 0,
1126 qdev_get_gpio_in(nvic, 18));
1127 }
1128
1129
pbrook9ee6e8b2007-11-11 00:04:49 +00001130 for (i = 0; i < 7; i++) {
1131 if (board->dc4 & (1 << i)) {
Peter Maydell7063f492011-02-21 20:57:51 +00001132 gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
Michael Davidsaver20c59c32015-11-03 13:49:41 +00001133 qdev_get_gpio_in(nvic,
1134 gpio_irq[i]));
Paul Brook40905a62009-06-03 15:16:49 +01001135 for (j = 0; j < 8; j++) {
1136 gpio_in[i][j] = qdev_get_gpio_in(gpio_dev[i], j);
1137 gpio_out[i][j] = NULL;
1138 }
pbrook9ee6e8b2007-11-11 00:04:49 +00001139 }
1140 }
1141
1142 if (board->dc2 & (1 << 12)) {
Michael Davidsaver20c59c32015-11-03 13:49:41 +00001143 dev = sysbus_create_simple(TYPE_STELLARIS_I2C, 0x40020000,
1144 qdev_get_gpio_in(nvic, 8));
Andreas Färbera5c82852013-08-03 00:18:51 +02001145 i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
pbrookcf0dbb22007-11-18 14:36:08 +00001146 if (board->peripherals & BP_OLED_I2C) {
Philippe Mathieu-Daudé1373b152020-07-06 00:41:53 +02001147 i2c_slave_create_simple(i2c, "ssd0303", 0x3d);
pbrook9ee6e8b2007-11-11 00:04:49 +00001148 }
1149 }
1150
1151 for (i = 0; i < 4; i++) {
1152 if (board->dc2 & (1 << i)) {
Philippe Mathieu-Daudéb7f93092023-02-20 12:51:09 +01001153 SysBusDevice *sbd;
1154
1155 dev = qdev_new("pl011_luminary");
1156 sbd = SYS_BUS_DEVICE(dev);
1157 qdev_prop_set_chr(dev, "chardev", serial_hd(i));
1158 sysbus_realize_and_unref(sbd, &error_fatal);
1159 sysbus_mmio_map(sbd, 0, 0x4000c000 + i * 0x1000);
1160 sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(nvic, uart_irq[i]));
pbrook9ee6e8b2007-11-11 00:04:49 +00001161 }
1162 }
1163 if (board->dc2 & (1 << 4)) {
Michael Davidsaver20c59c32015-11-03 13:49:41 +00001164 dev = sysbus_create_simple("pl022", 0x40008000,
1165 qdev_get_gpio_in(nvic, 7));
pbrookcf0dbb22007-11-18 14:36:08 +00001166 if (board->peripherals & BP_OLED_SSI) {
Paul Brook5493e332009-05-14 22:35:09 +01001167 void *bus;
Peter A. G. Crosthwaite8120e712012-07-31 16:42:04 +10001168 DeviceState *sddev;
1169 DeviceState *ssddev;
Markus Armbruster36aa2852021-11-17 17:33:57 +01001170 DriveInfo *dinfo;
1171 DeviceState *carddev;
Zongyuan Lid0a030d2022-03-25 02:15:55 +08001172 DeviceState *gpio_d_splitter;
Markus Armbruster36aa2852021-11-17 17:33:57 +01001173 BlockBackend *blk;
pbrook775616c2007-11-24 23:35:08 +00001174
Peter Maydell5092e012021-07-02 11:40:18 +01001175 /*
1176 * Some boards have both an OLED controller and SD card connected to
Peter A. G. Crosthwaite8120e712012-07-31 16:42:04 +10001177 * the same SSI port, with the SD card chip select connected to a
1178 * GPIO pin. Technically the OLED chip select is connected to the
1179 * SSI Fss pin. We do not bother emulating that as both devices
1180 * should never be selected simultaneously, and our OLED controller
1181 * ignores stray 0xff commands that occur when deselecting the SD
1182 * card.
Peter Maydell5092e012021-07-02 11:40:18 +01001183 *
1184 * The h/w wiring is:
1185 * - GPIO pin D0 is wired to the active-low SD card chip select
1186 * - GPIO pin A3 is wired to the active-low OLED chip select
1187 * - The SoC wiring of the PL061 "auxiliary function" for A3 is
1188 * SSI0Fss ("frame signal"), which is an output from the SoC's
1189 * SSI controller. The SSI controller takes SSI0Fss low when it
1190 * transmits a frame, so it can work as a chip-select signal.
1191 * - GPIO A4 is aux-function SSI0Rx, and wired to the SD card Tx
1192 * (the OLED never sends data to the CPU, so no wiring needed)
1193 * - GPIO A5 is aux-function SSI0Tx, and wired to the SD card Rx
1194 * and the OLED display-data-in
1195 * - GPIO A2 is aux-function SSI0Clk, wired to SD card and OLED
1196 * serial-clock input
1197 * So a guest that wants to use the OLED can configure the PL061
1198 * to make pins A2, A3, A5 aux-function, so they are connected
1199 * directly to the SSI controller. When the SSI controller sends
1200 * data it asserts SSI0Fss which selects the OLED.
1201 * A guest that wants to use the SD card configures A2, A4 and A5
1202 * as aux-function, but leaves A3 as a software-controlled GPIO
1203 * line. It asserts the SD card chip-select by using the PL061
1204 * to control pin D0, and lets the SSI controller handle Clk, Tx
1205 * and Rx. (The SSI controller asserts Fss during tx cycles as
1206 * usual, but because A3 is not set to aux-function this is not
1207 * forwarded to the OLED, and so the OLED stays unselected.)
1208 *
1209 * The QEMU implementation instead is:
1210 * - GPIO pin D0 is wired to the active-low SD card chip select,
1211 * and also to the OLED chip-select which is implemented
1212 * as *active-high*
1213 * - SSI controller signals go to the devices regardless of
1214 * whether the guest programs A2, A4, A5 as aux-function or not
1215 *
1216 * The problem with this implementation is if the guest doesn't
1217 * care about the SD card and only uses the OLED. In that case it
1218 * may choose never to do anything with D0 (leaving it in its
1219 * default floating state, which reliably leaves the card disabled
1220 * because an SD card has a pullup on CS within the card itself),
1221 * and only set up A2, A3, A5. This for us would mean the OLED
1222 * never gets the chip-select assert it needs. We work around
1223 * this with a manual raise of D0 here (despite board creation
1224 * code being the wrong place to raise IRQ lines) to put the OLED
1225 * into an initially selected state.
1226 *
1227 * In theory the right way to model this would be:
1228 * - Implement aux-function support in the PL061, with an
1229 * extra set of AFIN and AFOUT GPIO lines (set up so that
1230 * if a GPIO line is in auxfn mode the main GPIO in and out
1231 * track the AFIN and AFOUT lines)
1232 * - Wire the AFOUT for D0 up to either a line from the
1233 * SSI controller that's pulled low around every transmit,
1234 * or at least to an always-0 line here on the board
1235 * - Make the ssd0323 OLED controller chipselect active-low
Peter A. G. Crosthwaite8120e712012-07-31 16:42:04 +10001236 */
Paul Brook5493e332009-05-14 22:35:09 +01001237 bus = qdev_get_child_bus(dev, "ssi");
Philippe Mathieu-Daudéec7e4292020-10-12 14:49:55 +02001238 sddev = ssi_create_peripheral(bus, "ssi-sd");
Markus Armbruster36aa2852021-11-17 17:33:57 +01001239
1240 dinfo = drive_get(IF_SD, 0, 0);
1241 blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
Cédric Le Goaterc3287c02023-07-03 08:00:08 +02001242 carddev = qdev_new(TYPE_SD_CARD_SPI);
Markus Armbruster36aa2852021-11-17 17:33:57 +01001243 qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
Markus Armbruster36aa2852021-11-17 17:33:57 +01001244 qdev_realize_and_unref(carddev,
1245 qdev_get_child_bus(sddev, "sd-bus"),
1246 &error_fatal);
1247
Cédric Le Goatera617e652023-06-07 06:39:38 +02001248 ssddev = qdev_new("ssd0323");
1249 qdev_prop_set_uint8(ssddev, "cs", 1);
1250 qdev_realize_and_unref(ssddev, bus, &error_fatal);
Zongyuan Lid0a030d2022-03-25 02:15:55 +08001251
1252 gpio_d_splitter = qdev_new(TYPE_SPLIT_IRQ);
1253 qdev_prop_set_uint32(gpio_d_splitter, "num-lines", 2);
1254 qdev_realize_and_unref(gpio_d_splitter, NULL, &error_fatal);
1255 qdev_connect_gpio_out(
1256 gpio_d_splitter, 0,
1257 qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0));
1258 qdev_connect_gpio_out(
1259 gpio_d_splitter, 1,
Peter Crosthwaitede779142014-05-19 23:31:33 -07001260 qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0));
Zongyuan Lid0a030d2022-03-25 02:15:55 +08001261 gpio_out[GPIO_D][0] = qdev_get_gpio_in(gpio_d_splitter, 0);
1262
Peter Crosthwaitede779142014-05-19 23:31:33 -07001263 gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0);
Paul Brook5493e332009-05-14 22:35:09 +01001264
pbrook775616c2007-11-24 23:35:08 +00001265 /* Make sure the select pin is high. */
1266 qemu_irq_raise(gpio_out[GPIO_D][0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001267 }
1268 }
Paul Brooka5580462009-05-14 22:35:07 +01001269 if (board->dc4 & (1 << 28)) {
1270 DeviceState *enet;
1271
1272 qemu_check_nic_model(&nd_table[0], "stellaris");
1273
Markus Armbruster3e80f692020-06-10 07:31:58 +02001274 enet = qdev_new("stellaris_enet");
Gerd Hoffmann540f0062009-10-21 15:25:39 +02001275 qdev_set_nic_properties(enet, &nd_table[0]);
Markus Armbruster3c6ef472020-06-10 07:32:34 +02001276 sysbus_realize_and_unref(SYS_BUS_DEVICE(enet), &error_fatal);
Andreas Färber1356b982013-01-20 02:47:33 +01001277 sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000);
Michael Davidsaver20c59c32015-11-03 13:49:41 +00001278 sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, qdev_get_gpio_in(nvic, 42));
Paul Brooka5580462009-05-14 22:35:07 +01001279 }
pbrookcf0dbb22007-11-18 14:36:08 +00001280 if (board->peripherals & BP_GAMEPAD) {
Peter Maydella75f3362023-10-30 11:48:01 +00001281 QList *gpad_keycode_list = qlist_new();
Peter Maydell7c76f392023-10-30 11:48:02 +00001282 static const int gpad_keycode[5] = {
1283 Q_KEY_CODE_UP, Q_KEY_CODE_DOWN, Q_KEY_CODE_LEFT,
1284 Q_KEY_CODE_RIGHT, Q_KEY_CODE_CTRL,
1285 };
Peter Maydella75f3362023-10-30 11:48:01 +00001286 DeviceState *gpad;
pbrookcf0dbb22007-11-18 14:36:08 +00001287
Peter Maydella75f3362023-10-30 11:48:01 +00001288 gpad = qdev_new(TYPE_STELLARIS_GAMEPAD);
1289 for (i = 0; i < ARRAY_SIZE(gpad_keycode); i++) {
1290 qlist_append_int(gpad_keycode_list, gpad_keycode[i]);
1291 }
1292 qdev_prop_set_array(gpad, "keycodes", gpad_keycode_list);
1293 sysbus_realize_and_unref(SYS_BUS_DEVICE(gpad), &error_fatal);
pbrookcf0dbb22007-11-18 14:36:08 +00001294
Peter Maydella75f3362023-10-30 11:48:01 +00001295 qdev_connect_gpio_out(gpad, 0,
1296 qemu_irq_invert(gpio_in[GPIO_E][0])); /* up */
1297 qdev_connect_gpio_out(gpad, 1,
1298 qemu_irq_invert(gpio_in[GPIO_E][1])); /* down */
1299 qdev_connect_gpio_out(gpad, 2,
1300 qemu_irq_invert(gpio_in[GPIO_E][2])); /* left */
1301 qdev_connect_gpio_out(gpad, 3,
1302 qemu_irq_invert(gpio_in[GPIO_E][3])); /* right */
1303 qdev_connect_gpio_out(gpad, 4,
1304 qemu_irq_invert(gpio_in[GPIO_F][1])); /* select */
pbrookcf0dbb22007-11-18 14:36:08 +00001305 }
Paul Brook40905a62009-06-03 15:16:49 +01001306 for (i = 0; i < 7; i++) {
1307 if (board->dc4 & (1 << i)) {
1308 for (j = 0; j < 8; j++) {
1309 if (gpio_out[i][j]) {
1310 qdev_connect_gpio_out(gpio_dev[i], j, gpio_out[i][j]);
1311 }
1312 }
1313 }
1314 }
Peter Maydellaecfbbc2017-02-07 18:30:00 +00001315
1316 /* Add dummy regions for the devices we don't implement yet,
1317 * so guest accesses don't cause unlogged crashes.
1318 */
Peter Maydellaecfbbc2017-02-07 18:30:00 +00001319 create_unimplemented_device("i2c-0", 0x40002000, 0x1000);
1320 create_unimplemented_device("i2c-2", 0x40021000, 0x1000);
1321 create_unimplemented_device("PWM", 0x40028000, 0x1000);
1322 create_unimplemented_device("QEI-0", 0x4002c000, 0x1000);
1323 create_unimplemented_device("QEI-1", 0x4002d000, 0x1000);
1324 create_unimplemented_device("analogue-comparator", 0x4003c000, 0x1000);
1325 create_unimplemented_device("hibernation", 0x400fc000, 0x1000);
1326 create_unimplemented_device("flash-control", 0x400fd000, 0x1000);
Peter Maydellf04d4462018-06-15 14:57:13 +01001327
Peter Maydell761c5322022-08-23 17:04:17 +01001328 armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, 0, flash_size);
pbrook9ee6e8b2007-11-11 00:04:49 +00001329}
1330
1331/* FIXME: Figure out how to generate these from stellaris_boards. */
Marcel Apfelbaum3ef96222014-05-07 17:42:57 +03001332static void lm3s811evb_init(MachineState *machine)
pbrook9ee6e8b2007-11-11 00:04:49 +00001333{
Igor Mammedovba1ba5c2017-09-13 18:04:57 +02001334 stellaris_init(machine, &stellaris_boards[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001335}
1336
Marcel Apfelbaum3ef96222014-05-07 17:42:57 +03001337static void lm3s6965evb_init(MachineState *machine)
pbrook9ee6e8b2007-11-11 00:04:49 +00001338{
Igor Mammedovba1ba5c2017-09-13 18:04:57 +02001339 stellaris_init(machine, &stellaris_boards[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00001340}
1341
Andreas Färber8a661ae2015-09-19 10:49:44 +02001342static void lm3s811evb_class_init(ObjectClass *oc, void *data)
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001343{
Andreas Färber8a661ae2015-09-19 10:49:44 +02001344 MachineClass *mc = MACHINE_CLASS(oc);
1345
Philippe Mathieu-Daudéfd8f71b2021-01-31 19:44:49 +01001346 mc->desc = "Stellaris LM3S811EVB (Cortex-M3)";
Eduardo Habkoste264d292015-09-04 15:37:08 -03001347 mc->init = lm3s811evb_init;
Peter Maydell4672cbd2017-09-07 13:54:54 +01001348 mc->ignore_memory_transaction_failures = true;
Igor Mammedovba1ba5c2017-09-13 18:04:57 +02001349 mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001350}
1351
Andreas Färber8a661ae2015-09-19 10:49:44 +02001352static const TypeInfo lm3s811evb_type = {
1353 .name = MACHINE_TYPE_NAME("lm3s811evb"),
1354 .parent = TYPE_MACHINE,
1355 .class_init = lm3s811evb_class_init,
1356};
Eduardo Habkoste264d292015-09-04 15:37:08 -03001357
Andreas Färber8a661ae2015-09-19 10:49:44 +02001358static void lm3s6965evb_class_init(ObjectClass *oc, void *data)
Eduardo Habkoste264d292015-09-04 15:37:08 -03001359{
Andreas Färber8a661ae2015-09-19 10:49:44 +02001360 MachineClass *mc = MACHINE_CLASS(oc);
1361
Philippe Mathieu-Daudéfd8f71b2021-01-31 19:44:49 +01001362 mc->desc = "Stellaris LM3S6965EVB (Cortex-M3)";
Eduardo Habkoste264d292015-09-04 15:37:08 -03001363 mc->init = lm3s6965evb_init;
Peter Maydell4672cbd2017-09-07 13:54:54 +01001364 mc->ignore_memory_transaction_failures = true;
Igor Mammedovba1ba5c2017-09-13 18:04:57 +02001365 mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
Eduardo Habkoste264d292015-09-04 15:37:08 -03001366}
1367
Andreas Färber8a661ae2015-09-19 10:49:44 +02001368static const TypeInfo lm3s6965evb_type = {
1369 .name = MACHINE_TYPE_NAME("lm3s6965evb"),
1370 .parent = TYPE_MACHINE,
1371 .class_init = lm3s6965evb_class_init,
1372};
1373
1374static void stellaris_machine_init(void)
1375{
1376 type_register_static(&lm3s811evb_type);
1377 type_register_static(&lm3s6965evb_type);
1378}
1379
Eduardo Habkost0e6aac82016-02-16 18:59:04 -02001380type_init(stellaris_machine_init)
Anthony Liguorif80f9ec2009-05-20 18:38:09 -05001381
Anthony Liguori999e12b2012-01-24 13:12:29 -06001382static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
1383{
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +08001384 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -06001385
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +08001386 dc->vmsd = &vmstate_stellaris_i2c;
Anthony Liguori999e12b2012-01-24 13:12:29 -06001387}
1388
Andreas Färber8c43a6f2013-01-10 16:19:07 +01001389static const TypeInfo stellaris_i2c_info = {
Andreas Färberd94a4012013-07-24 09:08:23 +02001390 .name = TYPE_STELLARIS_I2C,
Anthony Liguori39bffca2011-12-07 21:34:16 -06001391 .parent = TYPE_SYS_BUS_DEVICE,
1392 .instance_size = sizeof(stellaris_i2c_state),
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +08001393 .instance_init = stellaris_i2c_init,
Anthony Liguori39bffca2011-12-07 21:34:16 -06001394 .class_init = stellaris_i2c_class_init,
Anthony Liguori999e12b2012-01-24 13:12:29 -06001395};
1396
Anthony Liguori999e12b2012-01-24 13:12:29 -06001397static void stellaris_adc_class_init(ObjectClass *klass, void *data)
1398{
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +08001399 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -06001400
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +08001401 dc->vmsd = &vmstate_stellaris_adc;
Anthony Liguori999e12b2012-01-24 13:12:29 -06001402}
1403
Andreas Färber8c43a6f2013-01-10 16:19:07 +01001404static const TypeInfo stellaris_adc_info = {
Andreas Färber7df7f672013-07-24 09:13:06 +02001405 .name = TYPE_STELLARIS_ADC,
Anthony Liguori39bffca2011-12-07 21:34:16 -06001406 .parent = TYPE_SYS_BUS_DEVICE,
Philippe Mathieu-Daudéd6b109d2023-01-09 15:03:00 +01001407 .instance_size = sizeof(StellarisADCState),
xiaoqiang.zhao15c4fff2016-03-07 15:05:48 +08001408 .instance_init = stellaris_adc_init,
Anthony Liguori39bffca2011-12-07 21:34:16 -06001409 .class_init = stellaris_adc_class_init,
Anthony Liguori999e12b2012-01-24 13:12:29 -06001410};
1411
Peter Maydell4bebb9a2021-01-28 11:41:36 +00001412static void stellaris_sys_class_init(ObjectClass *klass, void *data)
1413{
1414 DeviceClass *dc = DEVICE_CLASS(klass);
1415 ResettableClass *rc = RESETTABLE_CLASS(klass);
1416
1417 dc->vmsd = &vmstate_stellaris_sys;
1418 rc->phases.enter = stellaris_sys_reset_enter;
1419 rc->phases.hold = stellaris_sys_reset_hold;
1420 rc->phases.exit = stellaris_sys_reset_exit;
1421 device_class_set_props(dc, stellaris_sys_properties);
1422}
1423
1424static const TypeInfo stellaris_sys_info = {
1425 .name = TYPE_STELLARIS_SYS,
1426 .parent = TYPE_SYS_BUS_DEVICE,
1427 .instance_size = sizeof(ssys_state),
1428 .instance_init = stellaris_sys_instance_init,
1429 .class_init = stellaris_sys_class_init,
1430};
1431
Andreas Färber83f7d432012-02-09 15:20:55 +01001432static void stellaris_register_types(void)
Paul Brook1de96102009-05-14 22:35:09 +01001433{
Anthony Liguori39bffca2011-12-07 21:34:16 -06001434 type_register_static(&stellaris_i2c_info);
Anthony Liguori39bffca2011-12-07 21:34:16 -06001435 type_register_static(&stellaris_adc_info);
Peter Maydell4bebb9a2021-01-28 11:41:36 +00001436 type_register_static(&stellaris_sys_info);
Paul Brook1de96102009-05-14 22:35:09 +01001437}
1438
Andreas Färber83f7d432012-02-09 15:20:55 +01001439type_init(stellaris_register_types)