1
-/*
2
- * Marvell MV88W8618 / Freecom MusicPal emulation.
3
- *
4
- * Copyright (c) 2008 Jan Kiszka
5
- *
6
- * This code is licensed under the GNU GPL v2.
7
- *
8
- * Contributions after 2012-01-13 are licensed under the terms of the
9
- * GNU GPL, version 2 or (at your option) any later version.
10
- */
11
-
12
-#include "qemu/osdep.h"
13
-#include "qemu/units.h"
14
-#include "qapi/error.h"
15
-#include "hw/core/sysbus.h"
16
-#include "migration/vmstate.h"
17
-#include "hw/arm/boot.h"
18
-#include "hw/arm/machines-qom.h"
19
-#include "net/net.h"
20
-#include "system/system.h"
21
-#include "hw/core/boards.h"
22
-#include "hw/char/serial-mm.h"
23
-#include "qemu/timer.h"
24
-#include "hw/core/ptimer.h"
25
-#include "hw/core/qdev-properties.h"
26
-#include "hw/block/flash.h"
27
-#include "standard-headers/linux/input-event-codes.h"
28
-#include "ui/console.h"
29
-#include "hw/i2c/i2c.h"
30
-#include "hw/i2c/bitbang_i2c.h"
31
-#include "hw/core/irq.h"
32
-#include "hw/core/or-irq.h"
33
-#include "hw/audio/wm8750.h"
34
-#include "system/block-backend.h"
35
-#include "system/runstate.h"
36
-#include "system/dma.h"
37
-#include "ui/pixel_ops.h"
38
-#include "qemu/cutils.h"
39
-#include "qom/object.h"
40
-#include "hw/net/mv88w8618_eth.h"
41
-#include "qemu/error-report.h"
42
-#include "target/arm/cpu-qom.h"
43
-
44
-#define MP_MISC_BASE 0x80002000
45
-#define MP_MISC_SIZE 0x00001000
46
-
47
-#define MP_ETH_BASE 0x80008000
48
-
49
-#define MP_WLAN_BASE 0x8000C000
50
-#define MP_WLAN_SIZE 0x00000800
51
-
52
-#define MP_UART1_BASE 0x8000C840
53
-#define MP_UART2_BASE 0x8000C940
54
-
55
-#define MP_GPIO_BASE 0x8000D000
56
-#define MP_GPIO_SIZE 0x00001000
57
-
58
-#define MP_FLASHCFG_BASE 0x90006000
59
-#define MP_FLASHCFG_SIZE 0x00001000
60
-
61
-#define MP_AUDIO_BASE 0x90007000
62
-
63
-#define MP_PIC_BASE 0x90008000
64
-#define MP_PIC_SIZE 0x00001000
65
-
66
-#define MP_PIT_BASE 0x90009000
67
-#define MP_PIT_SIZE 0x00001000
68
-
69
-#define MP_LCD_BASE 0x9000c000
70
-#define MP_LCD_SIZE 0x00001000
71
-
72
-#define MP_SRAM_BASE 0xC0000000
73
-#define MP_SRAM_SIZE 0x00020000
74
-
75
-#define MP_RAM_DEFAULT_SIZE 32*1024*1024
76
-#define MP_FLASH_SIZE_MAX 32*1024*1024
77
-
78
-#define MP_TIMER1_IRQ 4
79
-#define MP_TIMER2_IRQ 5
80
-#define MP_TIMER3_IRQ 6
81
-#define MP_TIMER4_IRQ 7
82
-#define MP_EHCI_IRQ 8
83
-#define MP_ETH_IRQ 9
84
-#define MP_UART_SHARED_IRQ 11
85
-#define MP_GPIO_IRQ 12
86
-#define MP_RTC_IRQ 28
87
-#define MP_AUDIO_IRQ 30
88
-
89
-/* Wolfson 8750 I2C address */
90
-#define MP_WM_ADDR 0x1A
91
-
92
-/* LCD register offsets */
93
-#define MP_LCD_IRQCTRL 0x180
94
-#define MP_LCD_IRQSTAT 0x184
95
-#define MP_LCD_SPICTRL 0x1ac
96
-#define MP_LCD_INST 0x1bc
97
-#define MP_LCD_DATA 0x1c0
98
-
99
-/* Mode magics */
100
-#define MP_LCD_SPI_DATA 0x00100011
101
-#define MP_LCD_SPI_CMD 0x00104011
102
-#define MP_LCD_SPI_INVALID 0x00000000
103
-
104
-/* Commands */
105
-#define MP_LCD_INST_SETPAGE0 0xB0
106
-/* ... */
107
-#define MP_LCD_INST_SETPAGE7 0xB7
108
-
109
-#define MP_LCD_TEXTCOLOR 0xe0e0ff /* RRGGBB */
110
-
111
-#define TYPE_MUSICPAL_LCD "musicpal_lcd"
112
-OBJECT_DECLARE_SIMPLE_TYPE(musicpal_lcd_state, MUSICPAL_LCD)
113
-
114
-struct musicpal_lcd_state {
115
- /*< private >*/
116
- SysBusDevice parent_obj;
117
- /*< public >*/
118
-
119
- MemoryRegion iomem;
120
- uint32_t brightness;
121
- uint32_t mode;
122
- uint32_t irqctrl;
123
- uint32_t page;
124
- uint32_t page_off;
125
- QemuConsole *con;
126
- uint8_t video_ram[128*64/8];
127
-};
128
-
129
-static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col)
130
-{
131
- switch (s->brightness) {
132
- case 7:
133
- return col;
134
- case 0:
135
- return 0;
136
- default:
137
- return (col * s->brightness) / 7;
138
- }
139
-}
140
-
141
-static inline void set_lcd_pixel32(musicpal_lcd_state *s,
142
- int x, int y, uint32_t col)
143
-{
144
- int dx, dy;
145
- DisplaySurface *surface = qemu_console_surface(s->con);
146
- uint32_t *pixel =
147
- &((uint32_t *) surface_data(surface))[(y * 128 * 3 + x) * 3];
148
-
149
- for (dy = 0; dy < 3; dy++, pixel += 127 * 3) {
150
- for (dx = 0; dx < 3; dx++, pixel++) {
151
- *pixel = col;
152
- }
153
- }
154
-}
155
-
156
-static bool lcd_refresh(void *opaque)
157
-{
158
- musicpal_lcd_state *s = opaque;
159
- int x, y, col;
160
-
161
- col = rgb_to_pixel32(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff),
162
- scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff),
163
- scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff));
164
- for (x = 0; x < 128; x++) {
165
- for (y = 0; y < 64; y++) {
166
- if (s->video_ram[x + (y / 8) * 128] & (1 << (y % 8))) {
167
- set_lcd_pixel32(s, x, y, col);
168
- } else {
169
- set_lcd_pixel32(s, x, y, 0);
170
- }
171
- }
172
- }
173
-
174
- qemu_console_update(s->con, 0, 0, 128*3, 64*3);
175
- return true;
176
-}
177
-
178
-static void lcd_invalidate(void *opaque)
179
-{
180
-}
181
-
182
-static void musicpal_lcd_gpio_brightness_in(void *opaque, int irq, int level)
183
-{
184
- musicpal_lcd_state *s = opaque;
185
- s->brightness &= ~(1 << irq);
186
- s->brightness |= level << irq;
187
-}
188
-
189
-static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset,
190
- unsigned size)
191
-{
192
- musicpal_lcd_state *s = opaque;
193
-
194
- switch (offset) {
195
- case MP_LCD_IRQCTRL:
196
- return s->irqctrl;
197
-
198
- default:
199
- return 0;
200
- }
201
-}
202
-
203
-static void musicpal_lcd_write(void *opaque, hwaddr offset,
204
- uint64_t value, unsigned size)
205
-{
206
- musicpal_lcd_state *s = opaque;
207
-
208
- switch (offset) {
209
- case MP_LCD_IRQCTRL:
210
- s->irqctrl = value;
211
- break;
212
-
213
- case MP_LCD_SPICTRL:
214
- if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) {
215
- s->mode = value;
216
- } else {
217
- s->mode = MP_LCD_SPI_INVALID;
218
- }
219
- break;
220
-
221
- case MP_LCD_INST:
222
- if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) {
223
- s->page = value - MP_LCD_INST_SETPAGE0;
224
- s->page_off = 0;
225
- }
226
- break;
227
-
228
- case MP_LCD_DATA:
229
- if (s->mode == MP_LCD_SPI_CMD) {
230
- if (value >= MP_LCD_INST_SETPAGE0 &&
231
- value <= MP_LCD_INST_SETPAGE7) {
232
- s->page = value - MP_LCD_INST_SETPAGE0;
233
- s->page_off = 0;
234
- }
235
- } else if (s->mode == MP_LCD_SPI_DATA) {
236
- s->video_ram[s->page*128 + s->page_off] = value;
237
- s->page_off = (s->page_off + 1) & 127;
238
- }
239
- break;
240
- }
241
-}
242
-
243
-static const MemoryRegionOps musicpal_lcd_ops = {
244
- .read = musicpal_lcd_read,
245
- .write = musicpal_lcd_write,
246
- .endianness = DEVICE_NATIVE_ENDIAN,
247
-};
248
-
249
-static const GraphicHwOps musicpal_gfx_ops = {
250
- .invalidate = lcd_invalidate,
251
- .gfx_update = lcd_refresh,
252
-};
253
-
254
-static void musicpal_lcd_realize(DeviceState *dev, Error **errp)
255
-{
256
- musicpal_lcd_state *s = MUSICPAL_LCD(dev);
257
- s->con = qemu_graphic_console_create(dev, 0, &musicpal_gfx_ops, s);
258
- qemu_console_resize(s->con, 128 * 3, 64 * 3);
259
-}
260
-
261
-static void musicpal_lcd_init(Object *obj)
262
-{
263
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
264
- DeviceState *dev = DEVICE(sbd);
265
- musicpal_lcd_state *s = MUSICPAL_LCD(dev);
266
-
267
- s->brightness = 7;
268
-
269
- memory_region_init_io(&s->iomem, obj, &musicpal_lcd_ops, s,
270
- "musicpal-lcd", MP_LCD_SIZE);
271
- sysbus_init_mmio(sbd, &s->iomem);
272
-
273
- qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
274
-}
275
-
276
-static const VMStateDescription musicpal_lcd_vmsd = {
277
- .name = "musicpal_lcd",
278
- .version_id = 1,
279
- .minimum_version_id = 1,
280
- .fields = (const VMStateField[]) {
281
- VMSTATE_UINT32(brightness, musicpal_lcd_state),
282
- VMSTATE_UINT32(mode, musicpal_lcd_state),
283
- VMSTATE_UINT32(irqctrl, musicpal_lcd_state),
284
- VMSTATE_UINT32(page, musicpal_lcd_state),
285
- VMSTATE_UINT32(page_off, musicpal_lcd_state),
286
- VMSTATE_BUFFER(video_ram, musicpal_lcd_state),
287
- VMSTATE_END_OF_LIST()
288
- }
289
-};
290
-
291
-static void musicpal_lcd_class_init(ObjectClass *klass, const void *data)
292
-{
293
- DeviceClass *dc = DEVICE_CLASS(klass);
294
-
295
- dc->vmsd = &musicpal_lcd_vmsd;
296
- dc->realize = musicpal_lcd_realize;
297
-}
298
-
299
-static const TypeInfo musicpal_lcd_info = {
300
- .name = TYPE_MUSICPAL_LCD,
301
- .parent = TYPE_SYS_BUS_DEVICE,
302
- .instance_size = sizeof(musicpal_lcd_state),
303
- .instance_init = musicpal_lcd_init,
304
- .class_init = musicpal_lcd_class_init,
305
-};
306
-
307
-/* PIC register offsets */
308
-#define MP_PIC_STATUS 0x00
309
-#define MP_PIC_ENABLE_SET 0x08
310
-#define MP_PIC_ENABLE_CLR 0x0C
311
-
312
-#define TYPE_MV88W8618_PIC "mv88w8618_pic"
313
-OBJECT_DECLARE_SIMPLE_TYPE(mv88w8618_pic_state, MV88W8618_PIC)
314
-
315
-struct mv88w8618_pic_state {
316
- /*< private >*/
317
- SysBusDevice parent_obj;
318
- /*< public >*/
319
-
320
- MemoryRegion iomem;
321
- uint32_t level;
322
- uint32_t enabled;
323
- qemu_irq parent_irq;
324
-};
325
-
326
-static void mv88w8618_pic_update(mv88w8618_pic_state *s)
327
-{
328
- qemu_set_irq(s->parent_irq, (s->level & s->enabled));
329
-}
330
-
331
-static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
332
-{
333
- mv88w8618_pic_state *s = opaque;
334
-
335
- if (level) {
336
- s->level |= 1 << irq;
337
- } else {
338
- s->level &= ~(1 << irq);
339
- }
340
- mv88w8618_pic_update(s);
341
-}
342
-
343
-static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset,
344
- unsigned size)
345
-{
346
- mv88w8618_pic_state *s = opaque;
347
-
348
- switch (offset) {
349
- case MP_PIC_STATUS:
350
- return s->level & s->enabled;
351
-
352
- default:
353
- return 0;
354
- }
355
-}
356
-
357
-static void mv88w8618_pic_write(void *opaque, hwaddr offset,
358
- uint64_t value, unsigned size)
359
-{
360
- mv88w8618_pic_state *s = opaque;
361
-
362
- switch (offset) {
363
- case MP_PIC_ENABLE_SET:
364
- s->enabled |= value;
365
- break;
366
-
367
- case MP_PIC_ENABLE_CLR:
368
- s->enabled &= ~value;
369
- s->level &= ~value;
370
- break;
371
- }
372
- mv88w8618_pic_update(s);
373
-}
374
-
375
-static void mv88w8618_pic_reset(DeviceState *d)
376
-{
377
- mv88w8618_pic_state *s = MV88W8618_PIC(d);
378
-
379
- s->level = 0;
380
- s->enabled = 0;
381
-}
382
-
383
-static const MemoryRegionOps mv88w8618_pic_ops = {
384
- .read = mv88w8618_pic_read,
385
- .write = mv88w8618_pic_write,
386
- .endianness = DEVICE_NATIVE_ENDIAN,
387
-};
388
-
389
-static void mv88w8618_pic_init(Object *obj)
390
-{
391
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
392
- mv88w8618_pic_state *s = MV88W8618_PIC(dev);
393
-
394
- qdev_init_gpio_in(DEVICE(dev), mv88w8618_pic_set_irq, 32);
395
- sysbus_init_irq(dev, &s->parent_irq);
396
- memory_region_init_io(&s->iomem, obj, &mv88w8618_pic_ops, s,
397
- "musicpal-pic", MP_PIC_SIZE);
398
- sysbus_init_mmio(dev, &s->iomem);
399
-}
400
-
401
-static const VMStateDescription mv88w8618_pic_vmsd = {
402
- .name = "mv88w8618_pic",
403
- .version_id = 1,
404
- .minimum_version_id = 1,
405
- .fields = (const VMStateField[]) {
406
- VMSTATE_UINT32(level, mv88w8618_pic_state),
407
- VMSTATE_UINT32(enabled, mv88w8618_pic_state),
408
- VMSTATE_END_OF_LIST()
409
- }
410
-};
411
-
412
-static void mv88w8618_pic_class_init(ObjectClass *klass, const void *data)
413
-{
414
- DeviceClass *dc = DEVICE_CLASS(klass);
415
-
416
- device_class_set_legacy_reset(dc, mv88w8618_pic_reset);
417
- dc->vmsd = &mv88w8618_pic_vmsd;
418
-}
419
-
420
-static const TypeInfo mv88w8618_pic_info = {
421
- .name = TYPE_MV88W8618_PIC,
422
- .parent = TYPE_SYS_BUS_DEVICE,
423
- .instance_size = sizeof(mv88w8618_pic_state),
424
- .instance_init = mv88w8618_pic_init,
425
- .class_init = mv88w8618_pic_class_init,
426
-};
427
-
428
-/* PIT register offsets */
429
-#define MP_PIT_TIMER1_LENGTH 0x00
430
-/* ... */
431
-#define MP_PIT_TIMER4_LENGTH 0x0C
432
-#define MP_PIT_CONTROL 0x10
433
-#define MP_PIT_TIMER1_VALUE 0x14
434
-/* ... */
435
-#define MP_PIT_TIMER4_VALUE 0x20
436
-#define MP_BOARD_RESET 0x34
437
-
438
-/* Magic board reset value (probably some watchdog behind it) */
439
-#define MP_BOARD_RESET_MAGIC 0x10000
440
-
441
-typedef struct mv88w8618_timer_state {
442
- ptimer_state *ptimer;
443
- uint32_t limit;
444
- int freq;
445
- qemu_irq irq;
446
-} mv88w8618_timer_state;
447
-
448
-#define TYPE_MV88W8618_PIT "mv88w8618_pit"
449
-OBJECT_DECLARE_SIMPLE_TYPE(mv88w8618_pit_state, MV88W8618_PIT)
450
-
451
-struct mv88w8618_pit_state {
452
- /*< private >*/
453
- SysBusDevice parent_obj;
454
- /*< public >*/
455
-
456
- MemoryRegion iomem;
457
- mv88w8618_timer_state timer[4];
458
-};
459
-
460
-static void mv88w8618_timer_tick(void *opaque)
461
-{
462
- mv88w8618_timer_state *s = opaque;
463
-
464
- qemu_irq_raise(s->irq);
465
-}
466
-
467
-static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
468
- uint32_t freq)
469
-{
470
- sysbus_init_irq(dev, &s->irq);
471
- s->freq = freq;
472
-
473
- s->ptimer = ptimer_init(mv88w8618_timer_tick, s, PTIMER_POLICY_LEGACY);
474
-}
475
-
476
-static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset,
477
- unsigned size)
478
-{
479
- mv88w8618_pit_state *s = opaque;
480
- mv88w8618_timer_state *t;
481
-
482
- switch (offset) {
483
- case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:
484
- t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];
485
- return ptimer_get_count(t->ptimer);
486
-
487
- default:
488
- return 0;
489
- }
490
-}
491
-
492
-static void mv88w8618_pit_write(void *opaque, hwaddr offset,
493
- uint64_t value, unsigned size)
494
-{
495
- mv88w8618_pit_state *s = opaque;
496
- mv88w8618_timer_state *t;
497
- int i;
498
-
499
- switch (offset) {
500
- case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
501
- t = &s->timer[offset >> 2];
502
- t->limit = value;
503
- ptimer_transaction_begin(t->ptimer);
504
- if (t->limit > 0) {
505
- ptimer_set_limit(t->ptimer, t->limit, 1);
506
- } else {
507
- ptimer_stop(t->ptimer);
508
- }
509
- ptimer_transaction_commit(t->ptimer);
510
- break;
511
-
512
- case MP_PIT_CONTROL:
513
- for (i = 0; i < 4; i++) {
514
- t = &s->timer[i];
515
- ptimer_transaction_begin(t->ptimer);
516
- if (value & 0xf && t->limit > 0) {
517
- ptimer_set_limit(t->ptimer, t->limit, 0);
518
- ptimer_set_freq(t->ptimer, t->freq);
519
- ptimer_run(t->ptimer, 0);
520
- } else {
521
- ptimer_stop(t->ptimer);
522
- }
523
- ptimer_transaction_commit(t->ptimer);
524
- value >>= 4;
525
- }
526
- break;
527
-
528
- case MP_BOARD_RESET:
529
- if (value == MP_BOARD_RESET_MAGIC) {
530
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
531
- }
532
- break;
533
- }
534
-}
535
-
536
-static void mv88w8618_pit_reset(DeviceState *d)
537
-{
538
- mv88w8618_pit_state *s = MV88W8618_PIT(d);
539
- int i;
540
-
541
- for (i = 0; i < 4; i++) {
542
- mv88w8618_timer_state *t = &s->timer[i];
543
- ptimer_transaction_begin(t->ptimer);
544
- ptimer_stop(t->ptimer);
545
- ptimer_transaction_commit(t->ptimer);
546
- t->limit = 0;
547
- }
548
-}
549
-
550
-static const MemoryRegionOps mv88w8618_pit_ops = {
551
- .read = mv88w8618_pit_read,
552
- .write = mv88w8618_pit_write,
553
- .endianness = DEVICE_NATIVE_ENDIAN,
554
-};
555
-
556
-static void mv88w8618_pit_init(Object *obj)
557
-{
558
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
559
- mv88w8618_pit_state *s = MV88W8618_PIT(dev);
560
- int i;
561
-
562
- /* Letting them all run at 1 MHz is likely just a pragmatic
563
- * simplification. */
564
- for (i = 0; i < 4; i++) {
565
- mv88w8618_timer_init(dev, &s->timer[i], 1000000);
566
- }
567
-
568
- memory_region_init_io(&s->iomem, obj, &mv88w8618_pit_ops, s,
569
- "musicpal-pit", MP_PIT_SIZE);
570
- sysbus_init_mmio(dev, &s->iomem);
571
-}
572
-
573
-static void mv88w8618_pit_finalize(Object *obj)
574
-{
575
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
576
- mv88w8618_pit_state *s = MV88W8618_PIT(dev);
577
- int i;
578
-
579
- for (i = 0; i < 4; i++) {
580
- ptimer_free(s->timer[i].ptimer);
581
- }
582
-}
583
-
584
-static const VMStateDescription mv88w8618_timer_vmsd = {
585
- .name = "timer",
586
- .version_id = 1,
587
- .minimum_version_id = 1,
588
- .fields = (const VMStateField[]) {
589
- VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
590
- VMSTATE_UINT32(limit, mv88w8618_timer_state),
591
- VMSTATE_END_OF_LIST()
592
- }
593
-};
594
-
595
-static const VMStateDescription mv88w8618_pit_vmsd = {
596
- .name = "mv88w8618_pit",
597
- .version_id = 1,
598
- .minimum_version_id = 1,
599
- .fields = (const VMStateField[]) {
600
- VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
601
- mv88w8618_timer_vmsd, mv88w8618_timer_state),
602
- VMSTATE_END_OF_LIST()
603
- }
604
-};
605
-
606
-static void mv88w8618_pit_class_init(ObjectClass *klass, const void *data)
607
-{
608
- DeviceClass *dc = DEVICE_CLASS(klass);
609
-
610
- device_class_set_legacy_reset(dc, mv88w8618_pit_reset);
611
- dc->vmsd = &mv88w8618_pit_vmsd;
612
-}
613
-
614
-static const TypeInfo mv88w8618_pit_info = {
615
- .name = TYPE_MV88W8618_PIT,
616
- .parent = TYPE_SYS_BUS_DEVICE,
617
- .instance_size = sizeof(mv88w8618_pit_state),
618
- .instance_init = mv88w8618_pit_init,
619
- .instance_finalize = mv88w8618_pit_finalize,
620
- .class_init = mv88w8618_pit_class_init,
621
-};
622
-
623
-/* Flash config register offsets */
624
-#define MP_FLASHCFG_CFGR0 0x04
625
-
626
-#define TYPE_MV88W8618_FLASHCFG "mv88w8618_flashcfg"
627
-OBJECT_DECLARE_SIMPLE_TYPE(mv88w8618_flashcfg_state, MV88W8618_FLASHCFG)
628
-
629
-struct mv88w8618_flashcfg_state {
630
- /*< private >*/
631
- SysBusDevice parent_obj;
632
- /*< public >*/
633
-
634
- MemoryRegion iomem;
635
- uint32_t cfgr0;
636
-};
637
-
638
-static uint64_t mv88w8618_flashcfg_read(void *opaque,
639
- hwaddr offset,
640
- unsigned size)
641
-{
642
- mv88w8618_flashcfg_state *s = opaque;
643
-
644
- switch (offset) {
645
- case MP_FLASHCFG_CFGR0:
646
- return s->cfgr0;
647
-
648
- default:
649
- return 0;
650
- }
651
-}
652
-
653
-static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset,
654
- uint64_t value, unsigned size)
655
-{
656
- mv88w8618_flashcfg_state *s = opaque;
657
-
658
- switch (offset) {
659
- case MP_FLASHCFG_CFGR0:
660
- s->cfgr0 = value;
661
- break;
662
- }
663
-}
664
-
665
-static const MemoryRegionOps mv88w8618_flashcfg_ops = {
666
- .read = mv88w8618_flashcfg_read,
667
- .write = mv88w8618_flashcfg_write,
668
- .endianness = DEVICE_NATIVE_ENDIAN,
669
-};
670
-
671
-static void mv88w8618_flashcfg_init(Object *obj)
672
-{
673
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
674
- mv88w8618_flashcfg_state *s = MV88W8618_FLASHCFG(dev);
675
-
676
- s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
677
- memory_region_init_io(&s->iomem, obj, &mv88w8618_flashcfg_ops, s,
678
- "musicpal-flashcfg", MP_FLASHCFG_SIZE);
679
- sysbus_init_mmio(dev, &s->iomem);
680
-}
681
-
682
-static const VMStateDescription mv88w8618_flashcfg_vmsd = {
683
- .name = "mv88w8618_flashcfg",
684
- .version_id = 1,
685
- .minimum_version_id = 1,
686
- .fields = (const VMStateField[]) {
687
- VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
688
- VMSTATE_END_OF_LIST()
689
- }
690
-};
691
-
692
-static void mv88w8618_flashcfg_class_init(ObjectClass *klass, const void *data)
693
-{
694
- DeviceClass *dc = DEVICE_CLASS(klass);
695
-
696
- dc->vmsd = &mv88w8618_flashcfg_vmsd;
697
-}
698
-
699
-static const TypeInfo mv88w8618_flashcfg_info = {
700
- .name = TYPE_MV88W8618_FLASHCFG,
701
- .parent = TYPE_SYS_BUS_DEVICE,
702
- .instance_size = sizeof(mv88w8618_flashcfg_state),
703
- .instance_init = mv88w8618_flashcfg_init,
704
- .class_init = mv88w8618_flashcfg_class_init,
705
-};
706
-
707
-/* Misc register offsets */
708
-#define MP_MISC_BOARD_REVISION 0x18
709
-
710
-#define MP_BOARD_REVISION 0x31
711
-
712
-struct MusicPalMiscState {
713
- SysBusDevice parent_obj;
714
- MemoryRegion iomem;
715
-};
716
-
717
-#define TYPE_MUSICPAL_MISC "musicpal-misc"
718
-OBJECT_DECLARE_SIMPLE_TYPE(MusicPalMiscState, MUSICPAL_MISC)
719
-
720
-static uint64_t musicpal_misc_read(void *opaque, hwaddr offset,
721
- unsigned size)
722
-{
723
- switch (offset) {
724
- case MP_MISC_BOARD_REVISION:
725
- return MP_BOARD_REVISION;
726
-
727
- default:
728
- return 0;
729
- }
730
-}
731
-
732
-static void musicpal_misc_write(void *opaque, hwaddr offset,
733
- uint64_t value, unsigned size)
734
-{
735
-}
736
-
737
-static const MemoryRegionOps musicpal_misc_ops = {
738
- .read = musicpal_misc_read,
739
- .write = musicpal_misc_write,
740
- .endianness = DEVICE_NATIVE_ENDIAN,
741
-};
742
-
743
-static void musicpal_misc_init(Object *obj)
744
-{
745
- SysBusDevice *sd = SYS_BUS_DEVICE(obj);
746
- MusicPalMiscState *s = MUSICPAL_MISC(obj);
747
-
748
- memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_misc_ops, NULL,
749
- "musicpal-misc", MP_MISC_SIZE);
750
- sysbus_init_mmio(sd, &s->iomem);
751
-}
752
-
753
-static const TypeInfo musicpal_misc_info = {
754
- .name = TYPE_MUSICPAL_MISC,
755
- .parent = TYPE_SYS_BUS_DEVICE,
756
- .instance_init = musicpal_misc_init,
757
- .instance_size = sizeof(MusicPalMiscState),
758
-};
759
-
760
-/* WLAN register offsets */
761
-#define MP_WLAN_MAGIC1 0x11c
762
-#define MP_WLAN_MAGIC2 0x124
763
-
764
-static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset,
765
- unsigned size)
766
-{
767
- switch (offset) {
768
- /* Workaround to allow loading the binary-only wlandrv.ko crap
769
- * from the original Freecom firmware. */
770
- case MP_WLAN_MAGIC1:
771
- return ~3;
772
- case MP_WLAN_MAGIC2:
773
- return -1;
774
-
775
- default:
776
- return 0;
777
- }
778
-}
779
-
780
-static void mv88w8618_wlan_write(void *opaque, hwaddr offset,
781
- uint64_t value, unsigned size)
782
-{
783
-}
784
-
785
-static const MemoryRegionOps mv88w8618_wlan_ops = {
786
- .read = mv88w8618_wlan_read,
787
- .write =mv88w8618_wlan_write,
788
- .endianness = DEVICE_NATIVE_ENDIAN,
789
-};
790
-
791
-static void mv88w8618_wlan_realize(DeviceState *dev, Error **errp)
792
-{
793
- MemoryRegion *iomem = g_new(MemoryRegion, 1);
794
-
795
- memory_region_init_io(iomem, OBJECT(dev), &mv88w8618_wlan_ops, NULL,
796
- "musicpal-wlan", MP_WLAN_SIZE);
797
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), iomem);
798
-}
799
-
800
-/* GPIO register offsets */
801
-#define MP_GPIO_OE_LO 0x008
802
-#define MP_GPIO_OUT_LO 0x00c
803
-#define MP_GPIO_IN_LO 0x010
804
-#define MP_GPIO_IER_LO 0x014
805
-#define MP_GPIO_IMR_LO 0x018
806
-#define MP_GPIO_ISR_LO 0x020
807
-#define MP_GPIO_OE_HI 0x508
808
-#define MP_GPIO_OUT_HI 0x50c
809
-#define MP_GPIO_IN_HI 0x510
810
-#define MP_GPIO_IER_HI 0x514
811
-#define MP_GPIO_IMR_HI 0x518
812
-#define MP_GPIO_ISR_HI 0x520
813
-
814
-/* GPIO bits & masks */
815
-#define MP_GPIO_LCD_BRIGHTNESS 0x00070000
816
-#define MP_GPIO_I2C_DATA_BIT 29
817
-#define MP_GPIO_I2C_CLOCK_BIT 30
818
-
819
-/* LCD brightness bits in GPIO_OE_HI */
820
-#define MP_OE_LCD_BRIGHTNESS 0x0007
821
-
822
-#define TYPE_MUSICPAL_GPIO "musicpal_gpio"
823
-OBJECT_DECLARE_SIMPLE_TYPE(musicpal_gpio_state, MUSICPAL_GPIO)
824
-
825
-struct musicpal_gpio_state {
826
- /*< private >*/
827
- SysBusDevice parent_obj;
828
- /*< public >*/
829
-
830
- MemoryRegion iomem;
831
- uint32_t lcd_brightness;
832
- uint32_t out_state;
833
- uint32_t in_state;
834
- uint32_t ier;
835
- uint32_t imr;
836
- uint32_t isr;
837
- qemu_irq irq;
838
- qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */
839
-};
840
-
841
-static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) {
842
- int i;
843
- uint32_t brightness;
844
-
845
- /* compute brightness ratio */
846
- switch (s->lcd_brightness) {
847
- case 0x00000007:
848
- brightness = 0;
849
- break;
850
-
851
- case 0x00020000:
852
- brightness = 1;
853
- break;
854
-
855
- case 0x00020001:
856
- brightness = 2;
857
- break;
858
-
859
- case 0x00040000:
860
- brightness = 3;
861
- break;
862
-
863
- case 0x00010006:
864
- brightness = 4;
865
- break;
866
-
867
- case 0x00020005:
868
- brightness = 5;
869
- break;
870
-
871
- case 0x00040003:
872
- brightness = 6;
873
- break;
874
-
875
- case 0x00030004:
876
- default:
877
- brightness = 7;
878
- }
879
-
880
- /* set lcd brightness GPIOs */
881
- for (i = 0; i <= 2; i++) {
882
- qemu_set_irq(s->out[i], (brightness >> i) & 1);
883
- }
884
-}
885
-
886
-static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
887
-{
888
- musicpal_gpio_state *s = opaque;
889
- uint32_t mask = 1 << pin;
890
- uint32_t delta = level << pin;
891
- uint32_t old = s->in_state & mask;
892
-
893
- s->in_state &= ~mask;
894
- s->in_state |= delta;
895
-
896
- if ((old ^ delta) &&
897
- ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) {
898
- s->isr = mask;
899
- qemu_irq_raise(s->irq);
900
- }
901
-}
902
-
903
-static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset,
904
- unsigned size)
905
-{
906
- musicpal_gpio_state *s = opaque;
907
-
908
- switch (offset) {
909
- case MP_GPIO_OE_HI: /* used for LCD brightness control */
910
- return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS;
911
-
912
- case MP_GPIO_OUT_LO:
913
- return s->out_state & 0xFFFF;
914
- case MP_GPIO_OUT_HI:
915
- return s->out_state >> 16;
916
-
917
- case MP_GPIO_IN_LO:
918
- return s->in_state & 0xFFFF;
919
- case MP_GPIO_IN_HI:
920
- return s->in_state >> 16;
921
-
922
- case MP_GPIO_IER_LO:
923
- return s->ier & 0xFFFF;
924
- case MP_GPIO_IER_HI:
925
- return s->ier >> 16;
926
-
927
- case MP_GPIO_IMR_LO:
928
- return s->imr & 0xFFFF;
929
- case MP_GPIO_IMR_HI:
930
- return s->imr >> 16;
931
-
932
- case MP_GPIO_ISR_LO:
933
- return s->isr & 0xFFFF;
934
- case MP_GPIO_ISR_HI:
935
- return s->isr >> 16;
936
-
937
- default:
938
- return 0;
939
- }
940
-}
941
-
942
-static void musicpal_gpio_write(void *opaque, hwaddr offset,
943
- uint64_t value, unsigned size)
944
-{
945
- musicpal_gpio_state *s = opaque;
946
- switch (offset) {
947
- case MP_GPIO_OE_HI: /* used for LCD brightness control */
948
- s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |
949
- (value & MP_OE_LCD_BRIGHTNESS);
950
- musicpal_gpio_brightness_update(s);
951
- break;
952
-
953
- case MP_GPIO_OUT_LO:
954
- s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF);
955
- break;
956
- case MP_GPIO_OUT_HI:
957
- s->out_state = (s->out_state & 0xFFFF) | (value << 16);
958
- s->lcd_brightness = (s->lcd_brightness & 0xFFFF) |
959
- (s->out_state & MP_GPIO_LCD_BRIGHTNESS);
960
- musicpal_gpio_brightness_update(s);
961
- qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1);
962
- qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);
963
- break;
964
-
965
- case MP_GPIO_IER_LO:
966
- s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF);
967
- break;
968
- case MP_GPIO_IER_HI:
969
- s->ier = (s->ier & 0xFFFF) | (value << 16);
970
- break;
971
-
972
- case MP_GPIO_IMR_LO:
973
- s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF);
974
- break;
975
- case MP_GPIO_IMR_HI:
976
- s->imr = (s->imr & 0xFFFF) | (value << 16);
977
- break;
978
- }
979
-}
980
-
981
-static const MemoryRegionOps musicpal_gpio_ops = {
982
- .read = musicpal_gpio_read,
983
- .write = musicpal_gpio_write,
984
- .endianness = DEVICE_NATIVE_ENDIAN,
985
-};
986
-
987
-static void musicpal_gpio_reset(DeviceState *d)
988
-{
989
- musicpal_gpio_state *s = MUSICPAL_GPIO(d);
990
-
991
- s->lcd_brightness = 0;
992
- s->out_state = 0;
993
- s->in_state = 0xffffffff;
994
- s->ier = 0;
995
- s->imr = 0;
996
- s->isr = 0;
997
-}
998
-
999
-static void musicpal_gpio_init(Object *obj)
1000
-{
1001
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1002
- DeviceState *dev = DEVICE(sbd);
1003
- musicpal_gpio_state *s = MUSICPAL_GPIO(dev);
1004
-
1005
- sysbus_init_irq(sbd, &s->irq);
1006
-
1007
- memory_region_init_io(&s->iomem, obj, &musicpal_gpio_ops, s,
1008
- "musicpal-gpio", MP_GPIO_SIZE);
1009
- sysbus_init_mmio(sbd, &s->iomem);
1010
-
1011
- qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
1012
-
1013
- qdev_init_gpio_in(dev, musicpal_gpio_pin_event, 32);
1014
-}
1015
-
1016
-static const VMStateDescription musicpal_gpio_vmsd = {
1017
- .name = "musicpal_gpio",
1018
- .version_id = 1,
1019
- .minimum_version_id = 1,
1020
- .fields = (const VMStateField[]) {
1021
- VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
1022
- VMSTATE_UINT32(out_state, musicpal_gpio_state),
1023
- VMSTATE_UINT32(in_state, musicpal_gpio_state),
1024
- VMSTATE_UINT32(ier, musicpal_gpio_state),
1025
- VMSTATE_UINT32(imr, musicpal_gpio_state),
1026
- VMSTATE_UINT32(isr, musicpal_gpio_state),
1027
- VMSTATE_END_OF_LIST()
1028
- }
1029
-};
1030
-
1031
-static void musicpal_gpio_class_init(ObjectClass *klass, const void *data)
1032
-{
1033
- DeviceClass *dc = DEVICE_CLASS(klass);
1034
-
1035
- device_class_set_legacy_reset(dc, musicpal_gpio_reset);
1036
- dc->vmsd = &musicpal_gpio_vmsd;
1037
-}
1038
-
1039
-static const TypeInfo musicpal_gpio_info = {
1040
- .name = TYPE_MUSICPAL_GPIO,
1041
- .parent = TYPE_SYS_BUS_DEVICE,
1042
- .instance_size = sizeof(musicpal_gpio_state),
1043
- .instance_init = musicpal_gpio_init,
1044
- .class_init = musicpal_gpio_class_init,
1045
-};
1046
-
1047
-/* Keyboard codes & masks */
1048
-#define MP_KEY_WHEEL_VOL (1 << 0)
1049
-#define MP_KEY_WHEEL_VOL_INV (1 << 1)
1050
-#define MP_KEY_WHEEL_NAV (1 << 2)
1051
-#define MP_KEY_WHEEL_NAV_INV (1 << 3)
1052
-#define MP_KEY_BTN_FAVORITS (1 << 4)
1053
-#define MP_KEY_BTN_MENU (1 << 5)
1054
-#define MP_KEY_BTN_VOLUME (1 << 6)
1055
-#define MP_KEY_BTN_NAVIGATION (1 << 7)
1056
-
1057
-#define TYPE_MUSICPAL_KEY "musicpal_key"
1058
-OBJECT_DECLARE_SIMPLE_TYPE(musicpal_key_state, MUSICPAL_KEY)
1059
-
1060
-struct musicpal_key_state {
1061
- /*< private >*/
1062
- SysBusDevice parent_obj;
1063
- /*< public >*/
1064
-
1065
- QemuInputHandlerState *hs;
1066
- uint32_t pressed_keys;
1067
- qemu_irq out[8];
1068
-};
1069
-
1070
-static void musicpal_key_event(DeviceState *dev, QemuConsole *src,
1071
- QemuInputEvent *evt)
1072
-{
1073
- musicpal_key_state *s = MUSICPAL_KEY(dev);
1074
- uint32_t event = 0;
1075
- int i;
1076
-
1077
- switch (evt->key.key) {
1078
- case KEY_UP:
1079
- event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV;
1080
- break;
1081
-
1082
- case KEY_DOWN:
1083
- event = MP_KEY_WHEEL_NAV;
1084
- break;
1085
-
1086
- case KEY_LEFT:
1087
- event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV;
1088
- break;
1089
-
1090
- case KEY_RIGHT:
1091
- event = MP_KEY_WHEEL_VOL;
1092
- break;
1093
-
1094
- case KEY_F:
1095
- event = MP_KEY_BTN_FAVORITS;
1096
- break;
1097
-
1098
- case KEY_TAB:
1099
- event = MP_KEY_BTN_VOLUME;
1100
- break;
1101
-
1102
- case KEY_ENTER:
1103
- event = MP_KEY_BTN_NAVIGATION;
1104
- break;
1105
-
1106
- case KEY_M:
1107
- event = MP_KEY_BTN_MENU;
1108
- break;
1109
- }
1110
-
1111
- /*
1112
- * We allow repeated wheel-events when the arrow keys are held down,
1113
- * but do not repeat already-pressed buttons for the other key inputs.
1114
- */
1115
- if (!(event & (MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_VOL))) {
1116
- if (evt->key.down && (s->pressed_keys & event)) {
1117
- event = 0;
1118
- }
1119
- }
1120
-
1121
- if (event) {
1122
- /* Raise GPIO pin first if repeating a key */
1123
- if (evt->key.down && (s->pressed_keys & event)) {
1124
- for (i = 0; i <= 7; i++) {
1125
- if (event & (1 << i)) {
1126
- qemu_set_irq(s->out[i], 1);
1127
- }
1128
- }
1129
- }
1130
- for (i = 0; i <= 7; i++) {
1131
- if (event & (1 << i)) {
1132
- qemu_set_irq(s->out[i], !evt->key.down);
1133
- }
1134
- }
1135
- if (evt->key.down) {
1136
- s->pressed_keys |= event;
1137
- } else {
1138
- s->pressed_keys &= ~event;
1139
- }
1140
- }
1141
-}
1142
-
1143
-static void musicpal_key_init(Object *obj)
1144
-{
1145
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1146
- DeviceState *dev = DEVICE(sbd);
1147
- musicpal_key_state *s = MUSICPAL_KEY(dev);
1148
-
1149
- s->pressed_keys = 0;
1150
-
1151
- qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
1152
-}
1153
-
1154
-static const QemuInputHandler musicpal_key_handler = {
1155
- .name = "musicpal_key",
1156
- .mask = INPUT_EVENT_MASK_KEY,
1157
- .event = musicpal_key_event,
1158
-};
1159
-
1160
-static void musicpal_key_realize(DeviceState *dev, Error **errp)
1161
-{
1162
- musicpal_key_state *s = MUSICPAL_KEY(dev);
1163
-
1164
- s->hs = qemu_input_handler_register(dev, &musicpal_key_handler);
1165
-}
1166
-
1167
-static void musicpal_key_unrealize(DeviceState *dev)
1168
-{
1169
- musicpal_key_state *s = MUSICPAL_KEY(dev);
1170
-
1171
- g_clear_pointer(&s->hs, qemu_input_handler_unregister);
1172
-}
1173
-
1174
-static const VMStateDescription musicpal_key_vmsd = {
1175
- .name = "musicpal_key",
1176
- .version_id = 2,
1177
- .minimum_version_id = 2,
1178
- .fields = (const VMStateField[]) {
1179
- VMSTATE_UINT32(pressed_keys, musicpal_key_state),
1180
- VMSTATE_END_OF_LIST()
1181
- }
1182
-};
1183
-
1184
-static void musicpal_key_class_init(ObjectClass *klass, const void *data)
1185
-{
1186
- DeviceClass *dc = DEVICE_CLASS(klass);
1187
-
1188
- dc->vmsd = &musicpal_key_vmsd;
1189
- dc->realize = musicpal_key_realize;
1190
- dc->unrealize = musicpal_key_unrealize;
1191
-}
1192
-
1193
-static const TypeInfo musicpal_key_info = {
1194
- .name = TYPE_MUSICPAL_KEY,
1195
- .parent = TYPE_SYS_BUS_DEVICE,
1196
- .instance_size = sizeof(musicpal_key_state),
1197
- .instance_init = musicpal_key_init,
1198
- .class_init = musicpal_key_class_init,
1199
-};
1200
-
1201
-#define FLASH_SECTOR_SIZE (64 * KiB)
1202
-
1203
-#define TYPE_MUSICPAL_MACHINE MACHINE_TYPE_NAME("musicpal")
1204
-OBJECT_DECLARE_SIMPLE_TYPE(MusicPalMachineState, MUSICPAL_MACHINE)
1205
-
1206
-struct MusicPalMachineState {
1207
- MachineState parent;
1208
-
1209
- struct arm_boot_info bootinfo;
1210
-};
1211
-
1212
-static void musicpal_init(MachineState *machine)
1213
-{
1214
- MusicPalMachineState *mpms = MUSICPAL_MACHINE(machine);
1215
- ARMCPU *cpu;
1216
- DeviceState *dev;
1217
- DeviceState *pic;
1218
- DeviceState *uart_orgate;
1219
- DeviceState *i2c_dev;
1220
- DeviceState *lcd_dev;
1221
- DeviceState *key_dev;
1222
- I2CSlave *wm8750_dev;
1223
- SysBusDevice *s;
1224
- I2CBus *i2c;
1225
- int i;
1226
- unsigned long flash_size;
1227
- DriveInfo *dinfo;
1228
- MachineClass *mc = MACHINE_GET_CLASS(machine);
1229
- MemoryRegion *address_space_mem = get_system_memory();
1230
- MemoryRegion *sram = g_new(MemoryRegion, 1);
1231
-
1232
- /* For now we use a fixed - the original - RAM size */
1233
- if (machine->ram_size != mc->default_ram_size) {
1234
- char *sz = size_to_str(mc->default_ram_size);
1235
- error_report("Invalid RAM size, should be %s", sz);
1236
- g_free(sz);
1237
- exit(EXIT_FAILURE);
1238
- }
1239
-
1240
- cpu = ARM_CPU(cpu_create(machine->cpu_type));
1241
-
1242
- memory_region_add_subregion(address_space_mem, 0, machine->ram);
1243
-
1244
- memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE,
1245
- &error_fatal);
1246
- memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
1247
-
1248
- pic = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE,
1249
- qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
1250
- sysbus_create_varargs(TYPE_MV88W8618_PIT, MP_PIT_BASE,
1251
- qdev_get_gpio_in(pic, MP_TIMER1_IRQ),
1252
- qdev_get_gpio_in(pic, MP_TIMER2_IRQ),
1253
- qdev_get_gpio_in(pic, MP_TIMER3_IRQ),
1254
- qdev_get_gpio_in(pic, MP_TIMER4_IRQ), NULL);
1255
-
1256
- /* Logically OR both UART IRQs together */
1257
- uart_orgate = qdev_new(TYPE_OR_IRQ);
1258
- object_property_set_int(OBJECT(uart_orgate), "num-lines", 2, &error_fatal);
1259
- qdev_realize_and_unref(uart_orgate, NULL, &error_fatal);
1260
- qdev_connect_gpio_out(uart_orgate, 0,
1261
- qdev_get_gpio_in(pic, MP_UART_SHARED_IRQ));
1262
-
1263
- serial_mm_init(address_space_mem, MP_UART1_BASE, 2,
1264
- qdev_get_gpio_in(uart_orgate, 0),
1265
- 1825000, serial_hd(0), DEVICE_NATIVE_ENDIAN);
1266
- serial_mm_init(address_space_mem, MP_UART2_BASE, 2,
1267
- qdev_get_gpio_in(uart_orgate, 1),
1268
- 1825000, serial_hd(1), DEVICE_NATIVE_ENDIAN);
1269
-
1270
- /* Register flash */
1271
- dinfo = drive_get(IF_PFLASH, 0, 0);
1272
- if (dinfo) {
1273
- BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
1274
-
1275
- flash_size = blk_getlength(blk);
1276
- if (flash_size != 8 * MiB && flash_size != 16 * MiB &&
1277
- flash_size != 32 * MiB) {
1278
- error_report("Invalid flash image size");
1279
- exit(1);
1280
- }
1281
-
1282
- /*
1283
- * The original U-Boot accesses the flash at 0xFE000000 instead of
1284
- * 0xFF800000 (if there is 8 MB flash). So remap flash access if the
1285
- * image is smaller than 32 MB.
1286
- */
1287
- pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX,
1288
- "musicpal.flash", flash_size,
1289
- blk, FLASH_SECTOR_SIZE,
1290
- MP_FLASH_SIZE_MAX / flash_size,
1291
- 2, 0x00BF, 0x236D, 0x0000, 0x0000,
1292
- 0x5555, 0x2AAA, 0);
1293
- }
1294
- sysbus_create_simple(TYPE_MV88W8618_FLASHCFG, MP_FLASHCFG_BASE, NULL);
1295
-
1296
- dev = qdev_new(TYPE_MV88W8618_ETH);
1297
- qemu_configure_nic_device(dev, true, "mv88w8618");
1298
- object_property_set_link(OBJECT(dev), "dma-memory",
1299
- OBJECT(get_system_memory()), &error_fatal);
1300
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1301
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE);
1302
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
1303
- qdev_get_gpio_in(pic, MP_ETH_IRQ));
1304
-
1305
- sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
1306
-
1307
- sysbus_create_simple(TYPE_MUSICPAL_MISC, MP_MISC_BASE, NULL);
1308
-
1309
- dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE,
1310
- qdev_get_gpio_in(pic, MP_GPIO_IRQ));
1311
- i2c_dev = sysbus_create_simple(TYPE_GPIO_I2C, -1, NULL);
1312
- i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c");
1313
-
1314
- lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL);
1315
- key_dev = sysbus_create_simple(TYPE_MUSICPAL_KEY, -1, NULL);
1316
-
1317
- /* I2C read data */
1318
- qdev_connect_gpio_out(i2c_dev, 0,
1319
- qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT));
1320
- /* I2C data */
1321
- qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0));
1322
- /* I2C clock */
1323
- qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1));
1324
-
1325
- for (i = 0; i < 3; i++) {
1326
- qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i));
1327
- }
1328
- for (i = 0; i < 4; i++) {
1329
- qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8));
1330
- }
1331
- for (i = 4; i < 8; i++) {
1332
- qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15));
1333
- }
1334
-
1335
- wm8750_dev = i2c_slave_new(TYPE_WM8750, MP_WM_ADDR);
1336
- if (machine->audiodev) {
1337
- qdev_prop_set_string(DEVICE(wm8750_dev), "audiodev", machine->audiodev);
1338
- }
1339
- i2c_slave_realize_and_unref(wm8750_dev, i2c, &error_abort);
1340
-
1341
- dev = qdev_new(TYPE_MV88W8618_AUDIO);
1342
- s = SYS_BUS_DEVICE(dev);
1343
- object_property_set_link(OBJECT(dev), "wm8750", OBJECT(wm8750_dev),
1344
- NULL);
1345
- sysbus_realize_and_unref(s, &error_fatal);
1346
- sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
1347
- sysbus_connect_irq(s, 0, qdev_get_gpio_in(pic, MP_AUDIO_IRQ));
1348
-
1349
- mpms->bootinfo.loader_start = 0x0;
1350
- mpms->bootinfo.board_id = 0x20e;
1351
- mpms->bootinfo.ram_size = MP_RAM_DEFAULT_SIZE;
1352
- arm_load_kernel(cpu, machine, &mpms->bootinfo);
1353
-}
1354
-
1355
-static void musicpal_machine_init(MachineClass *mc)
1356
-{
1357
- mc->desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)";
1358
- mc->init = musicpal_init;
1359
- mc->ignore_memory_transaction_failures = true;
1360
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926");
1361
- mc->default_ram_size = MP_RAM_DEFAULT_SIZE;
1362
- mc->default_ram_id = "musicpal.ram";
1363
-
1364
- machine_add_audiodev_property(mc);
1365
-}
1366
-
1367
-DEFINE_MACHINE_EXTENDED("musicpal", MACHINE, MusicPalMachineState,
1368
- musicpal_machine_init, false,
1369
- arm_machine_interfaces)
1370
-
1371
-static void mv88w8618_wlan_class_init(ObjectClass *klass, const void *data)
1372
-{
1373
- DeviceClass *dc = DEVICE_CLASS(klass);
1374
-
1375
- dc->realize = mv88w8618_wlan_realize;
1376
-}
1377
-
1378
-static const TypeInfo mv88w8618_wlan_info = {
1379
- .name = "mv88w8618_wlan",
1380
- .parent = TYPE_SYS_BUS_DEVICE,
1381
- .instance_size = sizeof(SysBusDevice),
1382
- .class_init = mv88w8618_wlan_class_init,
1383
-};
1384
-
1385
-static void musicpal_register_types(void)
1386
-{
1387
- type_register_static(&mv88w8618_pic_info);
1388
- type_register_static(&mv88w8618_pit_info);
1389
- type_register_static(&mv88w8618_flashcfg_info);
1390
- type_register_static(&mv88w8618_wlan_info);
1391
- type_register_static(&musicpal_lcd_info);
1392
- type_register_static(&musicpal_gpio_info);
1393
- type_register_static(&musicpal_key_info);
1394
- type_register_static(&musicpal_misc_info);
1395
-}
1396
-
1397
-type_init(musicpal_register_types)