1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu/osdep.h"
26#include "hw/sysbus.h"
27#include "sysemu/sysemu.h"
28#include "qemu/log.h"
29#include "include/qemu/error-report.h"
30#include "exec/address-spaces.h"
31
32#include "hw/ssi/aspeed_smc.h"
33
34
35#define R_CONF (0x00 / 4)
36#define CONF_LEGACY_DISABLE (1 << 31)
37#define CONF_ENABLE_W4 20
38#define CONF_ENABLE_W3 19
39#define CONF_ENABLE_W2 18
40#define CONF_ENABLE_W1 17
41#define CONF_ENABLE_W0 16
42#define CONF_FLASH_TYPE4 9
43#define CONF_FLASH_TYPE3 7
44#define CONF_FLASH_TYPE2 5
45#define CONF_FLASH_TYPE1 3
46#define CONF_FLASH_TYPE0 1
47
48
49#define R_CE_CTRL (0x04 / 4)
50#define CTRL_EXTENDED4 4
51#define CTRL_EXTENDED3 3
52#define CTRL_EXTENDED2 2
53#define CTRL_EXTENDED1 1
54#define CTRL_EXTENDED0 0
55
56
57#define R_INTR_CTRL (0x08 / 4)
58#define INTR_CTRL_DMA_STATUS (1 << 11)
59#define INTR_CTRL_CMD_ABORT_STATUS (1 << 10)
60#define INTR_CTRL_WRITE_PROTECT_STATUS (1 << 9)
61#define INTR_CTRL_DMA_EN (1 << 3)
62#define INTR_CTRL_CMD_ABORT_EN (1 << 2)
63#define INTR_CTRL_WRITE_PROTECT_EN (1 << 1)
64
65
66#define R_CTRL0 (0x10 / 4)
67#define CTRL_CMD_SHIFT 16
68#define CTRL_CMD_MASK 0xff
69#define CTRL_CE_STOP_ACTIVE (1 << 2)
70#define CTRL_CMD_MODE_MASK 0x3
71#define CTRL_READMODE 0x0
72#define CTRL_FREADMODE 0x1
73#define CTRL_WRITEMODE 0x2
74#define CTRL_USERMODE 0x3
75#define R_CTRL1 (0x14 / 4)
76#define R_CTRL2 (0x18 / 4)
77#define R_CTRL3 (0x1C / 4)
78#define R_CTRL4 (0x20 / 4)
79
80
81#define R_SEG_ADDR0 (0x30 / 4)
82#define SEG_END_SHIFT 24
83#define SEG_END_MASK 0xff
84#define SEG_START_SHIFT 16
85#define SEG_START_MASK 0xff
86#define R_SEG_ADDR1 (0x34 / 4)
87#define R_SEG_ADDR2 (0x38 / 4)
88#define R_SEG_ADDR3 (0x3C / 4)
89#define R_SEG_ADDR4 (0x40 / 4)
90
91
92#define R_MISC_CTRL1 (0x50 / 4)
93
94
95#define R_MISC_CTRL2 (0x54 / 4)
96
97
98#define R_DMA_CTRL (0x80 / 4)
99#define DMA_CTRL_DELAY_MASK 0xf
100#define DMA_CTRL_DELAY_SHIFT 8
101#define DMA_CTRL_FREQ_MASK 0xf
102#define DMA_CTRL_FREQ_SHIFT 4
103#define DMA_CTRL_MODE (1 << 3)
104#define DMA_CTRL_CKSUM (1 << 2)
105#define DMA_CTRL_DIR (1 << 1)
106#define DMA_CTRL_EN (1 << 0)
107
108
109#define R_DMA_FLASH_ADDR (0x84 / 4)
110
111
112#define R_DMA_DRAM_ADDR (0x88 / 4)
113
114
115#define R_DMA_LEN (0x8C / 4)
116
117
118#define R_DMA_CHECKSUM (0x90 / 4)
119
120
121#define R_TIMINGS (0x94 / 4)
122
123
124#define R_SPI_CONF (0x00 / 4)
125#define SPI_CONF_ENABLE_W0 0
126#define R_SPI_CTRL0 (0x4 / 4)
127#define R_SPI_MISC_CTRL (0x10 / 4)
128#define R_SPI_TIMINGS (0x14 / 4)
129
130#define ASPEED_SOC_SMC_FLASH_BASE 0x10000000
131#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000
132#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000
133#define ASPEED_SOC_SPI2_FLASH_BASE 0x38000000
134
135
136
137
138
139
140static const AspeedSegments aspeed_segments_legacy[] = {
141 { 0x10000000, 32 * 1024 * 1024 },
142};
143
144static const AspeedSegments aspeed_segments_fmc[] = {
145 { 0x20000000, 64 * 1024 * 1024 },
146 { 0x24000000, 32 * 1024 * 1024 },
147 { 0x26000000, 32 * 1024 * 1024 },
148 { 0x28000000, 32 * 1024 * 1024 },
149 { 0x2A000000, 32 * 1024 * 1024 }
150};
151
152static const AspeedSegments aspeed_segments_spi[] = {
153 { 0x30000000, 64 * 1024 * 1024 },
154};
155
156static const AspeedSegments aspeed_segments_ast2500_fmc[] = {
157 { 0x20000000, 128 * 1024 * 1024 },
158 { 0x28000000, 32 * 1024 * 1024 },
159 { 0x2A000000, 32 * 1024 * 1024 },
160};
161
162static const AspeedSegments aspeed_segments_ast2500_spi1[] = {
163 { 0x30000000, 32 * 1024 * 1024 },
164 { 0x32000000, 96 * 1024 * 1024 },
165};
166
167static const AspeedSegments aspeed_segments_ast2500_spi2[] = {
168 { 0x38000000, 32 * 1024 * 1024 },
169 { 0x3A000000, 96 * 1024 * 1024 },
170};
171
172static const AspeedSMCController controllers[] = {
173 { "aspeed.smc.smc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
174 CONF_ENABLE_W0, 5, aspeed_segments_legacy,
175 ASPEED_SOC_SMC_FLASH_BASE, 0x6000000 },
176 { "aspeed.smc.fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
177 CONF_ENABLE_W0, 5, aspeed_segments_fmc,
178 ASPEED_SOC_FMC_FLASH_BASE, 0x10000000 },
179 { "aspeed.smc.spi", R_SPI_CONF, 0xff, R_SPI_CTRL0, R_SPI_TIMINGS,
180 SPI_CONF_ENABLE_W0, 1, aspeed_segments_spi,
181 ASPEED_SOC_SPI_FLASH_BASE, 0x10000000 },
182 { "aspeed.smc.ast2500-fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
183 CONF_ENABLE_W0, 3, aspeed_segments_ast2500_fmc,
184 ASPEED_SOC_FMC_FLASH_BASE, 0x10000000 },
185 { "aspeed.smc.ast2500-spi1", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
186 CONF_ENABLE_W0, 2, aspeed_segments_ast2500_spi1,
187 ASPEED_SOC_SPI_FLASH_BASE, 0x8000000 },
188 { "aspeed.smc.ast2500-spi2", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
189 CONF_ENABLE_W0, 2, aspeed_segments_ast2500_spi2,
190 ASPEED_SOC_SPI2_FLASH_BASE, 0x8000000 },
191};
192
193
194
195
196
197
198
199
200
201
202static inline uint32_t aspeed_smc_segment_to_reg(const AspeedSegments *seg)
203{
204 uint32_t reg = 0;
205 reg |= ((seg->addr >> 23) & SEG_START_MASK) << SEG_START_SHIFT;
206 reg |= (((seg->addr + seg->size) >> 23) & SEG_END_MASK) << SEG_END_SHIFT;
207 return reg;
208}
209
210static inline void aspeed_smc_reg_to_segment(uint32_t reg, AspeedSegments *seg)
211{
212 seg->addr = ((reg >> SEG_START_SHIFT) & SEG_START_MASK) << 23;
213 seg->size = (((reg >> SEG_END_SHIFT) & SEG_END_MASK) << 23) - seg->addr;
214}
215
216static bool aspeed_smc_flash_overlap(const AspeedSMCState *s,
217 const AspeedSegments *new,
218 int cs)
219{
220 AspeedSegments seg;
221 int i;
222
223 for (i = 0; i < s->ctrl->max_slaves; i++) {
224 if (i == cs) {
225 continue;
226 }
227
228 aspeed_smc_reg_to_segment(s->regs[R_SEG_ADDR0 + i], &seg);
229
230 if (new->addr + new->size > seg.addr &&
231 new->addr < seg.addr + seg.size) {
232 qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment CS%d [ 0x%"
233 HWADDR_PRIx" - 0x%"HWADDR_PRIx" ] overlaps with "
234 "CS%d [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n",
235 s->ctrl->name, cs, new->addr, new->addr + new->size,
236 i, seg.addr, seg.addr + seg.size);
237 return true;
238 }
239 }
240 return false;
241}
242
243static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs,
244 uint64_t new)
245{
246 AspeedSMCFlash *fl = &s->flashes[cs];
247 AspeedSegments seg;
248
249 aspeed_smc_reg_to_segment(new, &seg);
250
251
252 if (cs == 0 && seg.addr != s->ctrl->flash_window_base) {
253 qemu_log_mask(LOG_GUEST_ERROR,
254 "%s: Tried to change CS0 start address to 0x%"
255 HWADDR_PRIx "\n", s->ctrl->name, seg.addr);
256 return;
257 }
258
259
260
261
262
263 if ((s->ctrl->segments == aspeed_segments_ast2500_spi1 ||
264 s->ctrl->segments == aspeed_segments_ast2500_spi2) &&
265 cs == s->ctrl->max_slaves &&
266 seg.addr + seg.size != s->ctrl->segments[cs].addr +
267 s->ctrl->segments[cs].size) {
268 qemu_log_mask(LOG_GUEST_ERROR,
269 "%s: Tried to change CS%d end address to 0x%"
270 HWADDR_PRIx "\n", s->ctrl->name, cs, seg.addr);
271 return;
272 }
273
274
275 if (seg.addr + seg.size <= s->ctrl->flash_window_base ||
276 seg.addr > s->ctrl->flash_window_base + s->ctrl->flash_window_size) {
277 qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is invalid : "
278 "[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n",
279 s->ctrl->name, cs, seg.addr, seg.addr + seg.size);
280 return;
281 }
282
283
284 if (seg.addr % seg.size) {
285 qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is not "
286 "aligned : [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n",
287 s->ctrl->name, cs, seg.addr, seg.addr + seg.size);
288 }
289
290
291 if (aspeed_smc_flash_overlap(s, &seg, cs)) {
292 return;
293 }
294
295
296 memory_region_transaction_begin();
297 memory_region_set_size(&fl->mmio, seg.size);
298 memory_region_set_address(&fl->mmio, seg.addr - s->ctrl->flash_window_base);
299 memory_region_set_enabled(&fl->mmio, true);
300 memory_region_transaction_commit();
301
302 s->regs[R_SEG_ADDR0 + cs] = new;
303}
304
305static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr,
306 unsigned size)
307{
308 qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u"
309 PRIx64 "\n", __func__, addr, size);
310 return 0;
311}
312
313static void aspeed_smc_flash_default_write(void *opaque, hwaddr addr,
314 uint64_t data, unsigned size)
315{
316 qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u: 0x%"
317 PRIx64 "\n", __func__, addr, size, data);
318}
319
320static const MemoryRegionOps aspeed_smc_flash_default_ops = {
321 .read = aspeed_smc_flash_default_read,
322 .write = aspeed_smc_flash_default_write,
323 .endianness = DEVICE_LITTLE_ENDIAN,
324 .valid = {
325 .min_access_size = 1,
326 .max_access_size = 4,
327 },
328};
329
330static inline int aspeed_smc_flash_mode(const AspeedSMCState *s, int cs)
331{
332 return s->regs[s->r_ctrl0 + cs] & CTRL_CMD_MODE_MASK;
333}
334
335static inline bool aspeed_smc_is_usermode(const AspeedSMCState *s, int cs)
336{
337 return aspeed_smc_flash_mode(s, cs) == CTRL_USERMODE;
338}
339
340static inline bool aspeed_smc_is_writable(const AspeedSMCState *s, int cs)
341{
342 return s->regs[s->r_conf] & (1 << (s->conf_enable_w0 + cs));
343}
344
345static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
346{
347 AspeedSMCFlash *fl = opaque;
348 const AspeedSMCState *s = fl->controller;
349 uint64_t ret = 0;
350 int i;
351
352 if (aspeed_smc_is_usermode(s, fl->id)) {
353 for (i = 0; i < size; i++) {
354 ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
355 }
356 } else {
357 qemu_log_mask(LOG_UNIMP, "%s: usermode not implemented\n",
358 __func__);
359 ret = -1;
360 }
361
362 return ret;
363}
364
365static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data,
366 unsigned size)
367{
368 AspeedSMCFlash *fl = opaque;
369 const AspeedSMCState *s = fl->controller;
370 int i;
371
372 if (!aspeed_smc_is_writable(s, fl->id)) {
373 qemu_log_mask(LOG_GUEST_ERROR, "%s: flash is not writable at 0x%"
374 HWADDR_PRIx "\n", __func__, addr);
375 return;
376 }
377
378 if (!aspeed_smc_is_usermode(s, fl->id)) {
379 qemu_log_mask(LOG_UNIMP, "%s: usermode not implemented\n",
380 __func__);
381 return;
382 }
383
384 for (i = 0; i < size; i++) {
385 ssi_transfer(s->spi, (data >> (8 * i)) & 0xff);
386 }
387}
388
389static const MemoryRegionOps aspeed_smc_flash_ops = {
390 .read = aspeed_smc_flash_read,
391 .write = aspeed_smc_flash_write,
392 .endianness = DEVICE_LITTLE_ENDIAN,
393 .valid = {
394 .min_access_size = 1,
395 .max_access_size = 4,
396 },
397};
398
399static bool aspeed_smc_is_ce_stop_active(const AspeedSMCState *s, int cs)
400{
401 return s->regs[s->r_ctrl0 + cs] & CTRL_CE_STOP_ACTIVE;
402}
403
404static void aspeed_smc_update_cs(const AspeedSMCState *s)
405{
406 int i;
407
408 for (i = 0; i < s->num_cs; ++i) {
409 qemu_set_irq(s->cs_lines[i], aspeed_smc_is_ce_stop_active(s, i));
410 }
411}
412
413static void aspeed_smc_reset(DeviceState *d)
414{
415 AspeedSMCState *s = ASPEED_SMC(d);
416 int i;
417
418 memset(s->regs, 0, sizeof s->regs);
419
420
421 s->regs[R_INTR_CTRL] = INTR_CTRL_DMA_STATUS;
422
423
424 for (i = 0; i < s->num_cs; ++i) {
425 s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE;
426 }
427
428
429 for (i = 0; i < s->ctrl->max_slaves; ++i) {
430 s->regs[R_SEG_ADDR0 + i] =
431 aspeed_smc_segment_to_reg(&s->ctrl->segments[i]);
432 }
433
434 aspeed_smc_update_cs(s);
435}
436
437static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
438{
439 AspeedSMCState *s = ASPEED_SMC(opaque);
440
441 addr >>= 2;
442
443 if (addr >= ARRAY_SIZE(s->regs)) {
444 qemu_log_mask(LOG_GUEST_ERROR,
445 "%s: Out-of-bounds read at 0x%" HWADDR_PRIx "\n",
446 __func__, addr);
447 return 0;
448 }
449
450 if (addr == s->r_conf ||
451 addr == s->r_timings ||
452 addr == s->r_ce_ctrl ||
453 addr == R_INTR_CTRL ||
454 (addr >= R_SEG_ADDR0 && addr < R_SEG_ADDR0 + s->ctrl->max_slaves) ||
455 (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs)) {
456 return s->regs[addr];
457 } else {
458 qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
459 __func__, addr);
460 return 0;
461 }
462}
463
464static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
465 unsigned int size)
466{
467 AspeedSMCState *s = ASPEED_SMC(opaque);
468 uint32_t value = data;
469
470 addr >>= 2;
471
472 if (addr >= ARRAY_SIZE(s->regs)) {
473 qemu_log_mask(LOG_GUEST_ERROR,
474 "%s: Out-of-bounds write at 0x%" HWADDR_PRIx "\n",
475 __func__, addr);
476 return;
477 }
478
479 if (addr == s->r_conf ||
480 addr == s->r_timings ||
481 addr == s->r_ce_ctrl) {
482 s->regs[addr] = value;
483 } else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) {
484 s->regs[addr] = value;
485 aspeed_smc_update_cs(s);
486 } else if (addr >= R_SEG_ADDR0 &&
487 addr < R_SEG_ADDR0 + s->ctrl->max_slaves) {
488 int cs = addr - R_SEG_ADDR0;
489
490 if (value != s->regs[R_SEG_ADDR0 + cs]) {
491 aspeed_smc_flash_set_segment(s, cs, value);
492 }
493 } else {
494 qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
495 __func__, addr);
496 return;
497 }
498}
499
500static const MemoryRegionOps aspeed_smc_ops = {
501 .read = aspeed_smc_read,
502 .write = aspeed_smc_write,
503 .endianness = DEVICE_LITTLE_ENDIAN,
504 .valid.unaligned = true,
505};
506
507static void aspeed_smc_realize(DeviceState *dev, Error **errp)
508{
509 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
510 AspeedSMCState *s = ASPEED_SMC(dev);
511 AspeedSMCClass *mc = ASPEED_SMC_GET_CLASS(s);
512 int i;
513 char name[32];
514 hwaddr offset = 0;
515
516 s->ctrl = mc->ctrl;
517
518
519 s->r_conf = s->ctrl->r_conf;
520 s->r_ce_ctrl = s->ctrl->r_ce_ctrl;
521 s->r_ctrl0 = s->ctrl->r_ctrl0;
522 s->r_timings = s->ctrl->r_timings;
523 s->conf_enable_w0 = s->ctrl->conf_enable_w0;
524
525
526 if (s->num_cs > s->ctrl->max_slaves) {
527 qemu_log_mask(LOG_GUEST_ERROR, "%s: num_cs cannot exceed: %d\n",
528 __func__, s->ctrl->max_slaves);
529 s->num_cs = s->ctrl->max_slaves;
530 }
531
532 s->spi = ssi_create_bus(dev, "spi");
533
534
535 sysbus_init_irq(sbd, &s->irq);
536 s->cs_lines = g_new0(qemu_irq, s->num_cs);
537 ssi_auto_connect_slaves(dev, s->cs_lines, s->spi);
538
539 for (i = 0; i < s->num_cs; ++i) {
540 sysbus_init_irq(sbd, &s->cs_lines[i]);
541 }
542
543 aspeed_smc_reset(dev);
544
545
546 memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s,
547 s->ctrl->name, ASPEED_SMC_R_MAX * 4);
548 sysbus_init_mmio(sbd, &s->mmio);
549
550
551
552
553
554
555 snprintf(name, sizeof(name), "%s.flash", s->ctrl->name);
556
557 memory_region_init_io(&s->mmio_flash, OBJECT(s),
558 &aspeed_smc_flash_default_ops, s, name,
559 s->ctrl->flash_window_size);
560 sysbus_init_mmio(sbd, &s->mmio_flash);
561
562 s->flashes = g_new0(AspeedSMCFlash, s->ctrl->max_slaves);
563
564
565
566
567
568
569
570
571 for (i = 0; i < s->ctrl->max_slaves; ++i) {
572 AspeedSMCFlash *fl = &s->flashes[i];
573
574 snprintf(name, sizeof(name), "%s.%d", s->ctrl->name, i);
575
576 fl->id = i;
577 fl->controller = s;
578 fl->size = s->ctrl->segments[i].size;
579 memory_region_init_io(&fl->mmio, OBJECT(s), &aspeed_smc_flash_ops,
580 fl, name, fl->size);
581 memory_region_add_subregion(&s->mmio_flash, offset, &fl->mmio);
582 offset += fl->size;
583 }
584}
585
586static const VMStateDescription vmstate_aspeed_smc = {
587 .name = "aspeed.smc",
588 .version_id = 1,
589 .minimum_version_id = 1,
590 .fields = (VMStateField[]) {
591 VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
592 VMSTATE_END_OF_LIST()
593 }
594};
595
596static Property aspeed_smc_properties[] = {
597 DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1),
598 DEFINE_PROP_END_OF_LIST(),
599};
600
601static void aspeed_smc_class_init(ObjectClass *klass, void *data)
602{
603 DeviceClass *dc = DEVICE_CLASS(klass);
604 AspeedSMCClass *mc = ASPEED_SMC_CLASS(klass);
605
606 dc->realize = aspeed_smc_realize;
607 dc->reset = aspeed_smc_reset;
608 dc->props = aspeed_smc_properties;
609 dc->vmsd = &vmstate_aspeed_smc;
610 mc->ctrl = data;
611}
612
613static const TypeInfo aspeed_smc_info = {
614 .name = TYPE_ASPEED_SMC,
615 .parent = TYPE_SYS_BUS_DEVICE,
616 .instance_size = sizeof(AspeedSMCState),
617 .class_size = sizeof(AspeedSMCClass),
618 .abstract = true,
619};
620
621static void aspeed_smc_register_types(void)
622{
623 int i;
624
625 type_register_static(&aspeed_smc_info);
626 for (i = 0; i < ARRAY_SIZE(controllers); ++i) {
627 TypeInfo ti = {
628 .name = controllers[i].name,
629 .parent = TYPE_ASPEED_SMC,
630 .class_init = aspeed_smc_class_init,
631 .class_data = (void *)&controllers[i],
632 };
633 type_register(&ti);
634 }
635}
636
637type_init(aspeed_smc_register_types)
638