qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

musicpal.c (38453B)


      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)