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