xref: /openbmc/qemu/hw/arm/musicpal.c (revision d7646f24)
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 "hw/sysbus.h"
13 #include "hw/arm/arm.h"
14 #include "hw/devices.h"
15 #include "net/net.h"
16 #include "sysemu/sysemu.h"
17 #include "hw/boards.h"
18 #include "hw/char/serial.h"
19 #include "qemu/timer.h"
20 #include "hw/ptimer.h"
21 #include "hw/block/flash.h"
22 #include "ui/console.h"
23 #include "hw/i2c/i2c.h"
24 #include "sysemu/block-backend.h"
25 #include "exec/address-spaces.h"
26 #include "ui/pixel_ops.h"
27 
28 #define MP_MISC_BASE            0x80002000
29 #define MP_MISC_SIZE            0x00001000
30 
31 #define MP_ETH_BASE             0x80008000
32 #define MP_ETH_SIZE             0x00001000
33 
34 #define MP_WLAN_BASE            0x8000C000
35 #define MP_WLAN_SIZE            0x00000800
36 
37 #define MP_UART1_BASE           0x8000C840
38 #define MP_UART2_BASE           0x8000C940
39 
40 #define MP_GPIO_BASE            0x8000D000
41 #define MP_GPIO_SIZE            0x00001000
42 
43 #define MP_FLASHCFG_BASE        0x90006000
44 #define MP_FLASHCFG_SIZE        0x00001000
45 
46 #define MP_AUDIO_BASE           0x90007000
47 
48 #define MP_PIC_BASE             0x90008000
49 #define MP_PIC_SIZE             0x00001000
50 
51 #define MP_PIT_BASE             0x90009000
52 #define MP_PIT_SIZE             0x00001000
53 
54 #define MP_LCD_BASE             0x9000c000
55 #define MP_LCD_SIZE             0x00001000
56 
57 #define MP_SRAM_BASE            0xC0000000
58 #define MP_SRAM_SIZE            0x00020000
59 
60 #define MP_RAM_DEFAULT_SIZE     32*1024*1024
61 #define MP_FLASH_SIZE_MAX       32*1024*1024
62 
63 #define MP_TIMER1_IRQ           4
64 #define MP_TIMER2_IRQ           5
65 #define MP_TIMER3_IRQ           6
66 #define MP_TIMER4_IRQ           7
67 #define MP_EHCI_IRQ             8
68 #define MP_ETH_IRQ              9
69 #define MP_UART1_IRQ            11
70 #define MP_UART2_IRQ            11
71 #define MP_GPIO_IRQ             12
72 #define MP_RTC_IRQ              28
73 #define MP_AUDIO_IRQ            30
74 
75 /* Wolfson 8750 I2C address */
76 #define MP_WM_ADDR              0x1A
77 
78 /* Ethernet register offsets */
79 #define MP_ETH_SMIR             0x010
80 #define MP_ETH_PCXR             0x408
81 #define MP_ETH_SDCMR            0x448
82 #define MP_ETH_ICR              0x450
83 #define MP_ETH_IMR              0x458
84 #define MP_ETH_FRDP0            0x480
85 #define MP_ETH_FRDP1            0x484
86 #define MP_ETH_FRDP2            0x488
87 #define MP_ETH_FRDP3            0x48C
88 #define MP_ETH_CRDP0            0x4A0
89 #define MP_ETH_CRDP1            0x4A4
90 #define MP_ETH_CRDP2            0x4A8
91 #define MP_ETH_CRDP3            0x4AC
92 #define MP_ETH_CTDP0            0x4E0
93 #define MP_ETH_CTDP1            0x4E4
94 
95 /* MII PHY access */
96 #define MP_ETH_SMIR_DATA        0x0000FFFF
97 #define MP_ETH_SMIR_ADDR        0x03FF0000
98 #define MP_ETH_SMIR_OPCODE      (1 << 26) /* Read value */
99 #define MP_ETH_SMIR_RDVALID     (1 << 27)
100 
101 /* PHY registers */
102 #define MP_ETH_PHY1_BMSR        0x00210000
103 #define MP_ETH_PHY1_PHYSID1     0x00410000
104 #define MP_ETH_PHY1_PHYSID2     0x00610000
105 
106 #define MP_PHY_BMSR_LINK        0x0004
107 #define MP_PHY_BMSR_AUTONEG     0x0008
108 
109 #define MP_PHY_88E3015          0x01410E20
110 
111 /* TX descriptor status */
112 #define MP_ETH_TX_OWN           (1U << 31)
113 
114 /* RX descriptor status */
115 #define MP_ETH_RX_OWN           (1U << 31)
116 
117 /* Interrupt cause/mask bits */
118 #define MP_ETH_IRQ_RX_BIT       0
119 #define MP_ETH_IRQ_RX           (1 << MP_ETH_IRQ_RX_BIT)
120 #define MP_ETH_IRQ_TXHI_BIT     2
121 #define MP_ETH_IRQ_TXLO_BIT     3
122 
123 /* Port config bits */
124 #define MP_ETH_PCXR_2BSM_BIT    28 /* 2-byte incoming suffix */
125 
126 /* SDMA command bits */
127 #define MP_ETH_CMD_TXHI         (1 << 23)
128 #define MP_ETH_CMD_TXLO         (1 << 22)
129 
130 typedef struct mv88w8618_tx_desc {
131     uint32_t cmdstat;
132     uint16_t res;
133     uint16_t bytes;
134     uint32_t buffer;
135     uint32_t next;
136 } mv88w8618_tx_desc;
137 
138 typedef struct mv88w8618_rx_desc {
139     uint32_t cmdstat;
140     uint16_t bytes;
141     uint16_t buffer_size;
142     uint32_t buffer;
143     uint32_t next;
144 } mv88w8618_rx_desc;
145 
146 #define TYPE_MV88W8618_ETH "mv88w8618_eth"
147 #define MV88W8618_ETH(obj) \
148     OBJECT_CHECK(mv88w8618_eth_state, (obj), TYPE_MV88W8618_ETH)
149 
150 typedef struct mv88w8618_eth_state {
151     /*< private >*/
152     SysBusDevice parent_obj;
153     /*< public >*/
154 
155     MemoryRegion iomem;
156     qemu_irq irq;
157     uint32_t smir;
158     uint32_t icr;
159     uint32_t imr;
160     int mmio_index;
161     uint32_t vlan_header;
162     uint32_t tx_queue[2];
163     uint32_t rx_queue[4];
164     uint32_t frx_queue[4];
165     uint32_t cur_rx[4];
166     NICState *nic;
167     NICConf conf;
168 } mv88w8618_eth_state;
169 
170 static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc)
171 {
172     cpu_to_le32s(&desc->cmdstat);
173     cpu_to_le16s(&desc->bytes);
174     cpu_to_le16s(&desc->buffer_size);
175     cpu_to_le32s(&desc->buffer);
176     cpu_to_le32s(&desc->next);
177     cpu_physical_memory_write(addr, desc, sizeof(*desc));
178 }
179 
180 static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
181 {
182     cpu_physical_memory_read(addr, desc, sizeof(*desc));
183     le32_to_cpus(&desc->cmdstat);
184     le16_to_cpus(&desc->bytes);
185     le16_to_cpus(&desc->buffer_size);
186     le32_to_cpus(&desc->buffer);
187     le32_to_cpus(&desc->next);
188 }
189 
190 static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
191 {
192     mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
193     uint32_t desc_addr;
194     mv88w8618_rx_desc desc;
195     int i;
196 
197     for (i = 0; i < 4; i++) {
198         desc_addr = s->cur_rx[i];
199         if (!desc_addr) {
200             continue;
201         }
202         do {
203             eth_rx_desc_get(desc_addr, &desc);
204             if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) {
205                 cpu_physical_memory_write(desc.buffer + s->vlan_header,
206                                           buf, size);
207                 desc.bytes = size + s->vlan_header;
208                 desc.cmdstat &= ~MP_ETH_RX_OWN;
209                 s->cur_rx[i] = desc.next;
210 
211                 s->icr |= MP_ETH_IRQ_RX;
212                 if (s->icr & s->imr) {
213                     qemu_irq_raise(s->irq);
214                 }
215                 eth_rx_desc_put(desc_addr, &desc);
216                 return size;
217             }
218             desc_addr = desc.next;
219         } while (desc_addr != s->rx_queue[i]);
220     }
221     return size;
222 }
223 
224 static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc)
225 {
226     cpu_to_le32s(&desc->cmdstat);
227     cpu_to_le16s(&desc->res);
228     cpu_to_le16s(&desc->bytes);
229     cpu_to_le32s(&desc->buffer);
230     cpu_to_le32s(&desc->next);
231     cpu_physical_memory_write(addr, desc, sizeof(*desc));
232 }
233 
234 static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc)
235 {
236     cpu_physical_memory_read(addr, desc, sizeof(*desc));
237     le32_to_cpus(&desc->cmdstat);
238     le16_to_cpus(&desc->res);
239     le16_to_cpus(&desc->bytes);
240     le32_to_cpus(&desc->buffer);
241     le32_to_cpus(&desc->next);
242 }
243 
244 static void eth_send(mv88w8618_eth_state *s, int queue_index)
245 {
246     uint32_t desc_addr = s->tx_queue[queue_index];
247     mv88w8618_tx_desc desc;
248     uint32_t next_desc;
249     uint8_t buf[2048];
250     int len;
251 
252     do {
253         eth_tx_desc_get(desc_addr, &desc);
254         next_desc = desc.next;
255         if (desc.cmdstat & MP_ETH_TX_OWN) {
256             len = desc.bytes;
257             if (len < 2048) {
258                 cpu_physical_memory_read(desc.buffer, buf, len);
259                 qemu_send_packet(qemu_get_queue(s->nic), buf, len);
260             }
261             desc.cmdstat &= ~MP_ETH_TX_OWN;
262             s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
263             eth_tx_desc_put(desc_addr, &desc);
264         }
265         desc_addr = next_desc;
266     } while (desc_addr != s->tx_queue[queue_index]);
267 }
268 
269 static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset,
270                                    unsigned size)
271 {
272     mv88w8618_eth_state *s = opaque;
273 
274     switch (offset) {
275     case MP_ETH_SMIR:
276         if (s->smir & MP_ETH_SMIR_OPCODE) {
277             switch (s->smir & MP_ETH_SMIR_ADDR) {
278             case MP_ETH_PHY1_BMSR:
279                 return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG |
280                        MP_ETH_SMIR_RDVALID;
281             case MP_ETH_PHY1_PHYSID1:
282                 return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID;
283             case MP_ETH_PHY1_PHYSID2:
284                 return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID;
285             default:
286                 return MP_ETH_SMIR_RDVALID;
287             }
288         }
289         return 0;
290 
291     case MP_ETH_ICR:
292         return s->icr;
293 
294     case MP_ETH_IMR:
295         return s->imr;
296 
297     case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
298         return s->frx_queue[(offset - MP_ETH_FRDP0)/4];
299 
300     case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
301         return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
302 
303     case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
304         return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
305 
306     default:
307         return 0;
308     }
309 }
310 
311 static void mv88w8618_eth_write(void *opaque, hwaddr offset,
312                                 uint64_t value, unsigned size)
313 {
314     mv88w8618_eth_state *s = opaque;
315 
316     switch (offset) {
317     case MP_ETH_SMIR:
318         s->smir = value;
319         break;
320 
321     case MP_ETH_PCXR:
322         s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2;
323         break;
324 
325     case MP_ETH_SDCMR:
326         if (value & MP_ETH_CMD_TXHI) {
327             eth_send(s, 1);
328         }
329         if (value & MP_ETH_CMD_TXLO) {
330             eth_send(s, 0);
331         }
332         if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) {
333             qemu_irq_raise(s->irq);
334         }
335         break;
336 
337     case MP_ETH_ICR:
338         s->icr &= value;
339         break;
340 
341     case MP_ETH_IMR:
342         s->imr = value;
343         if (s->icr & s->imr) {
344             qemu_irq_raise(s->irq);
345         }
346         break;
347 
348     case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
349         s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value;
350         break;
351 
352     case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
353         s->rx_queue[(offset - MP_ETH_CRDP0)/4] =
354             s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
355         break;
356 
357     case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
358         s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
359         break;
360     }
361 }
362 
363 static const MemoryRegionOps mv88w8618_eth_ops = {
364     .read = mv88w8618_eth_read,
365     .write = mv88w8618_eth_write,
366     .endianness = DEVICE_NATIVE_ENDIAN,
367 };
368 
369 static void eth_cleanup(NetClientState *nc)
370 {
371     mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
372 
373     s->nic = NULL;
374 }
375 
376 static NetClientInfo net_mv88w8618_info = {
377     .type = NET_CLIENT_OPTIONS_KIND_NIC,
378     .size = sizeof(NICState),
379     .receive = eth_receive,
380     .cleanup = eth_cleanup,
381 };
382 
383 static int mv88w8618_eth_init(SysBusDevice *sbd)
384 {
385     DeviceState *dev = DEVICE(sbd);
386     mv88w8618_eth_state *s = MV88W8618_ETH(dev);
387 
388     sysbus_init_irq(sbd, &s->irq);
389     s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
390                           object_get_typename(OBJECT(dev)), dev->id, s);
391     memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_eth_ops, s,
392                           "mv88w8618-eth", MP_ETH_SIZE);
393     sysbus_init_mmio(sbd, &s->iomem);
394     return 0;
395 }
396 
397 static const VMStateDescription mv88w8618_eth_vmsd = {
398     .name = "mv88w8618_eth",
399     .version_id = 1,
400     .minimum_version_id = 1,
401     .fields = (VMStateField[]) {
402         VMSTATE_UINT32(smir, mv88w8618_eth_state),
403         VMSTATE_UINT32(icr, mv88w8618_eth_state),
404         VMSTATE_UINT32(imr, mv88w8618_eth_state),
405         VMSTATE_UINT32(vlan_header, mv88w8618_eth_state),
406         VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2),
407         VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4),
408         VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4),
409         VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4),
410         VMSTATE_END_OF_LIST()
411     }
412 };
413 
414 static Property mv88w8618_eth_properties[] = {
415     DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
416     DEFINE_PROP_END_OF_LIST(),
417 };
418 
419 static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
420 {
421     DeviceClass *dc = DEVICE_CLASS(klass);
422     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
423 
424     k->init = mv88w8618_eth_init;
425     dc->vmsd = &mv88w8618_eth_vmsd;
426     dc->props = mv88w8618_eth_properties;
427 }
428 
429 static const TypeInfo mv88w8618_eth_info = {
430     .name          = TYPE_MV88W8618_ETH,
431     .parent        = TYPE_SYS_BUS_DEVICE,
432     .instance_size = sizeof(mv88w8618_eth_state),
433     .class_init    = mv88w8618_eth_class_init,
434 };
435 
436 /* LCD register offsets */
437 #define MP_LCD_IRQCTRL          0x180
438 #define MP_LCD_IRQSTAT          0x184
439 #define MP_LCD_SPICTRL          0x1ac
440 #define MP_LCD_INST             0x1bc
441 #define MP_LCD_DATA             0x1c0
442 
443 /* Mode magics */
444 #define MP_LCD_SPI_DATA         0x00100011
445 #define MP_LCD_SPI_CMD          0x00104011
446 #define MP_LCD_SPI_INVALID      0x00000000
447 
448 /* Commmands */
449 #define MP_LCD_INST_SETPAGE0    0xB0
450 /* ... */
451 #define MP_LCD_INST_SETPAGE7    0xB7
452 
453 #define MP_LCD_TEXTCOLOR        0xe0e0ff /* RRGGBB */
454 
455 #define TYPE_MUSICPAL_LCD "musicpal_lcd"
456 #define MUSICPAL_LCD(obj) \
457     OBJECT_CHECK(musicpal_lcd_state, (obj), TYPE_MUSICPAL_LCD)
458 
459 typedef struct musicpal_lcd_state {
460     /*< private >*/
461     SysBusDevice parent_obj;
462     /*< public >*/
463 
464     MemoryRegion iomem;
465     uint32_t brightness;
466     uint32_t mode;
467     uint32_t irqctrl;
468     uint32_t page;
469     uint32_t page_off;
470     QemuConsole *con;
471     uint8_t video_ram[128*64/8];
472 } musicpal_lcd_state;
473 
474 static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col)
475 {
476     switch (s->brightness) {
477     case 7:
478         return col;
479     case 0:
480         return 0;
481     default:
482         return (col * s->brightness) / 7;
483     }
484 }
485 
486 #define SET_LCD_PIXEL(depth, type) \
487 static inline void glue(set_lcd_pixel, depth) \
488         (musicpal_lcd_state *s, int x, int y, type col) \
489 { \
490     int dx, dy; \
491     DisplaySurface *surface = qemu_console_surface(s->con); \
492     type *pixel = &((type *) surface_data(surface))[(y * 128 * 3 + x) * 3]; \
493 \
494     for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \
495         for (dx = 0; dx < 3; dx++, pixel++) \
496             *pixel = col; \
497 }
498 SET_LCD_PIXEL(8, uint8_t)
499 SET_LCD_PIXEL(16, uint16_t)
500 SET_LCD_PIXEL(32, uint32_t)
501 
502 static void lcd_refresh(void *opaque)
503 {
504     musicpal_lcd_state *s = opaque;
505     DisplaySurface *surface = qemu_console_surface(s->con);
506     int x, y, col;
507 
508     switch (surface_bits_per_pixel(surface)) {
509     case 0:
510         return;
511 #define LCD_REFRESH(depth, func) \
512     case depth: \
513         col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \
514                    scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \
515                    scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \
516         for (x = 0; x < 128; x++) { \
517             for (y = 0; y < 64; y++) { \
518                 if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \
519                     glue(set_lcd_pixel, depth)(s, x, y, col); \
520                 } else { \
521                     glue(set_lcd_pixel, depth)(s, x, y, 0); \
522                 } \
523             } \
524         } \
525         break;
526     LCD_REFRESH(8, rgb_to_pixel8)
527     LCD_REFRESH(16, rgb_to_pixel16)
528     LCD_REFRESH(32, (is_surface_bgr(surface) ?
529                      rgb_to_pixel32bgr : rgb_to_pixel32))
530     default:
531         hw_error("unsupported colour depth %i\n",
532                  surface_bits_per_pixel(surface));
533     }
534 
535     dpy_gfx_update(s->con, 0, 0, 128*3, 64*3);
536 }
537 
538 static void lcd_invalidate(void *opaque)
539 {
540 }
541 
542 static void musicpal_lcd_gpio_brightness_in(void *opaque, int irq, int level)
543 {
544     musicpal_lcd_state *s = opaque;
545     s->brightness &= ~(1 << irq);
546     s->brightness |= level << irq;
547 }
548 
549 static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset,
550                                   unsigned size)
551 {
552     musicpal_lcd_state *s = opaque;
553 
554     switch (offset) {
555     case MP_LCD_IRQCTRL:
556         return s->irqctrl;
557 
558     default:
559         return 0;
560     }
561 }
562 
563 static void musicpal_lcd_write(void *opaque, hwaddr offset,
564                                uint64_t value, unsigned size)
565 {
566     musicpal_lcd_state *s = opaque;
567 
568     switch (offset) {
569     case MP_LCD_IRQCTRL:
570         s->irqctrl = value;
571         break;
572 
573     case MP_LCD_SPICTRL:
574         if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) {
575             s->mode = value;
576         } else {
577             s->mode = MP_LCD_SPI_INVALID;
578         }
579         break;
580 
581     case MP_LCD_INST:
582         if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) {
583             s->page = value - MP_LCD_INST_SETPAGE0;
584             s->page_off = 0;
585         }
586         break;
587 
588     case MP_LCD_DATA:
589         if (s->mode == MP_LCD_SPI_CMD) {
590             if (value >= MP_LCD_INST_SETPAGE0 &&
591                 value <= MP_LCD_INST_SETPAGE7) {
592                 s->page = value - MP_LCD_INST_SETPAGE0;
593                 s->page_off = 0;
594             }
595         } else if (s->mode == MP_LCD_SPI_DATA) {
596             s->video_ram[s->page*128 + s->page_off] = value;
597             s->page_off = (s->page_off + 1) & 127;
598         }
599         break;
600     }
601 }
602 
603 static const MemoryRegionOps musicpal_lcd_ops = {
604     .read = musicpal_lcd_read,
605     .write = musicpal_lcd_write,
606     .endianness = DEVICE_NATIVE_ENDIAN,
607 };
608 
609 static const GraphicHwOps musicpal_gfx_ops = {
610     .invalidate  = lcd_invalidate,
611     .gfx_update  = lcd_refresh,
612 };
613 
614 static int musicpal_lcd_init(SysBusDevice *sbd)
615 {
616     DeviceState *dev = DEVICE(sbd);
617     musicpal_lcd_state *s = MUSICPAL_LCD(dev);
618 
619     s->brightness = 7;
620 
621     memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_lcd_ops, s,
622                           "musicpal-lcd", MP_LCD_SIZE);
623     sysbus_init_mmio(sbd, &s->iomem);
624 
625     s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
626     qemu_console_resize(s->con, 128*3, 64*3);
627 
628     qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
629 
630     return 0;
631 }
632 
633 static const VMStateDescription musicpal_lcd_vmsd = {
634     .name = "musicpal_lcd",
635     .version_id = 1,
636     .minimum_version_id = 1,
637     .fields = (VMStateField[]) {
638         VMSTATE_UINT32(brightness, musicpal_lcd_state),
639         VMSTATE_UINT32(mode, musicpal_lcd_state),
640         VMSTATE_UINT32(irqctrl, musicpal_lcd_state),
641         VMSTATE_UINT32(page, musicpal_lcd_state),
642         VMSTATE_UINT32(page_off, musicpal_lcd_state),
643         VMSTATE_BUFFER(video_ram, musicpal_lcd_state),
644         VMSTATE_END_OF_LIST()
645     }
646 };
647 
648 static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
649 {
650     DeviceClass *dc = DEVICE_CLASS(klass);
651     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
652 
653     k->init = musicpal_lcd_init;
654     dc->vmsd = &musicpal_lcd_vmsd;
655 }
656 
657 static const TypeInfo musicpal_lcd_info = {
658     .name          = TYPE_MUSICPAL_LCD,
659     .parent        = TYPE_SYS_BUS_DEVICE,
660     .instance_size = sizeof(musicpal_lcd_state),
661     .class_init    = musicpal_lcd_class_init,
662 };
663 
664 /* PIC register offsets */
665 #define MP_PIC_STATUS           0x00
666 #define MP_PIC_ENABLE_SET       0x08
667 #define MP_PIC_ENABLE_CLR       0x0C
668 
669 #define TYPE_MV88W8618_PIC "mv88w8618_pic"
670 #define MV88W8618_PIC(obj) \
671     OBJECT_CHECK(mv88w8618_pic_state, (obj), TYPE_MV88W8618_PIC)
672 
673 typedef struct mv88w8618_pic_state {
674     /*< private >*/
675     SysBusDevice parent_obj;
676     /*< public >*/
677 
678     MemoryRegion iomem;
679     uint32_t level;
680     uint32_t enabled;
681     qemu_irq parent_irq;
682 } mv88w8618_pic_state;
683 
684 static void mv88w8618_pic_update(mv88w8618_pic_state *s)
685 {
686     qemu_set_irq(s->parent_irq, (s->level & s->enabled));
687 }
688 
689 static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
690 {
691     mv88w8618_pic_state *s = opaque;
692 
693     if (level) {
694         s->level |= 1 << irq;
695     } else {
696         s->level &= ~(1 << irq);
697     }
698     mv88w8618_pic_update(s);
699 }
700 
701 static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset,
702                                    unsigned size)
703 {
704     mv88w8618_pic_state *s = opaque;
705 
706     switch (offset) {
707     case MP_PIC_STATUS:
708         return s->level & s->enabled;
709 
710     default:
711         return 0;
712     }
713 }
714 
715 static void mv88w8618_pic_write(void *opaque, hwaddr offset,
716                                 uint64_t value, unsigned size)
717 {
718     mv88w8618_pic_state *s = opaque;
719 
720     switch (offset) {
721     case MP_PIC_ENABLE_SET:
722         s->enabled |= value;
723         break;
724 
725     case MP_PIC_ENABLE_CLR:
726         s->enabled &= ~value;
727         s->level &= ~value;
728         break;
729     }
730     mv88w8618_pic_update(s);
731 }
732 
733 static void mv88w8618_pic_reset(DeviceState *d)
734 {
735     mv88w8618_pic_state *s = MV88W8618_PIC(d);
736 
737     s->level = 0;
738     s->enabled = 0;
739 }
740 
741 static const MemoryRegionOps mv88w8618_pic_ops = {
742     .read = mv88w8618_pic_read,
743     .write = mv88w8618_pic_write,
744     .endianness = DEVICE_NATIVE_ENDIAN,
745 };
746 
747 static int mv88w8618_pic_init(SysBusDevice *dev)
748 {
749     mv88w8618_pic_state *s = MV88W8618_PIC(dev);
750 
751     qdev_init_gpio_in(DEVICE(dev), mv88w8618_pic_set_irq, 32);
752     sysbus_init_irq(dev, &s->parent_irq);
753     memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_pic_ops, s,
754                           "musicpal-pic", MP_PIC_SIZE);
755     sysbus_init_mmio(dev, &s->iomem);
756     return 0;
757 }
758 
759 static const VMStateDescription mv88w8618_pic_vmsd = {
760     .name = "mv88w8618_pic",
761     .version_id = 1,
762     .minimum_version_id = 1,
763     .fields = (VMStateField[]) {
764         VMSTATE_UINT32(level, mv88w8618_pic_state),
765         VMSTATE_UINT32(enabled, mv88w8618_pic_state),
766         VMSTATE_END_OF_LIST()
767     }
768 };
769 
770 static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
771 {
772     DeviceClass *dc = DEVICE_CLASS(klass);
773     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
774 
775     k->init = mv88w8618_pic_init;
776     dc->reset = mv88w8618_pic_reset;
777     dc->vmsd = &mv88w8618_pic_vmsd;
778 }
779 
780 static const TypeInfo mv88w8618_pic_info = {
781     .name          = TYPE_MV88W8618_PIC,
782     .parent        = TYPE_SYS_BUS_DEVICE,
783     .instance_size = sizeof(mv88w8618_pic_state),
784     .class_init    = mv88w8618_pic_class_init,
785 };
786 
787 /* PIT register offsets */
788 #define MP_PIT_TIMER1_LENGTH    0x00
789 /* ... */
790 #define MP_PIT_TIMER4_LENGTH    0x0C
791 #define MP_PIT_CONTROL          0x10
792 #define MP_PIT_TIMER1_VALUE     0x14
793 /* ... */
794 #define MP_PIT_TIMER4_VALUE     0x20
795 #define MP_BOARD_RESET          0x34
796 
797 /* Magic board reset value (probably some watchdog behind it) */
798 #define MP_BOARD_RESET_MAGIC    0x10000
799 
800 typedef struct mv88w8618_timer_state {
801     ptimer_state *ptimer;
802     uint32_t limit;
803     int freq;
804     qemu_irq irq;
805 } mv88w8618_timer_state;
806 
807 #define TYPE_MV88W8618_PIT "mv88w8618_pit"
808 #define MV88W8618_PIT(obj) \
809     OBJECT_CHECK(mv88w8618_pit_state, (obj), TYPE_MV88W8618_PIT)
810 
811 typedef struct mv88w8618_pit_state {
812     /*< private >*/
813     SysBusDevice parent_obj;
814     /*< public >*/
815 
816     MemoryRegion iomem;
817     mv88w8618_timer_state timer[4];
818 } mv88w8618_pit_state;
819 
820 static void mv88w8618_timer_tick(void *opaque)
821 {
822     mv88w8618_timer_state *s = opaque;
823 
824     qemu_irq_raise(s->irq);
825 }
826 
827 static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
828                                  uint32_t freq)
829 {
830     QEMUBH *bh;
831 
832     sysbus_init_irq(dev, &s->irq);
833     s->freq = freq;
834 
835     bh = qemu_bh_new(mv88w8618_timer_tick, s);
836     s->ptimer = ptimer_init(bh);
837 }
838 
839 static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset,
840                                    unsigned size)
841 {
842     mv88w8618_pit_state *s = opaque;
843     mv88w8618_timer_state *t;
844 
845     switch (offset) {
846     case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:
847         t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];
848         return ptimer_get_count(t->ptimer);
849 
850     default:
851         return 0;
852     }
853 }
854 
855 static void mv88w8618_pit_write(void *opaque, hwaddr offset,
856                                 uint64_t value, unsigned size)
857 {
858     mv88w8618_pit_state *s = opaque;
859     mv88w8618_timer_state *t;
860     int i;
861 
862     switch (offset) {
863     case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
864         t = &s->timer[offset >> 2];
865         t->limit = value;
866         if (t->limit > 0) {
867             ptimer_set_limit(t->ptimer, t->limit, 1);
868         } else {
869             ptimer_stop(t->ptimer);
870         }
871         break;
872 
873     case MP_PIT_CONTROL:
874         for (i = 0; i < 4; i++) {
875             t = &s->timer[i];
876             if (value & 0xf && t->limit > 0) {
877                 ptimer_set_limit(t->ptimer, t->limit, 0);
878                 ptimer_set_freq(t->ptimer, t->freq);
879                 ptimer_run(t->ptimer, 0);
880             } else {
881                 ptimer_stop(t->ptimer);
882             }
883             value >>= 4;
884         }
885         break;
886 
887     case MP_BOARD_RESET:
888         if (value == MP_BOARD_RESET_MAGIC) {
889             qemu_system_reset_request();
890         }
891         break;
892     }
893 }
894 
895 static void mv88w8618_pit_reset(DeviceState *d)
896 {
897     mv88w8618_pit_state *s = MV88W8618_PIT(d);
898     int i;
899 
900     for (i = 0; i < 4; i++) {
901         ptimer_stop(s->timer[i].ptimer);
902         s->timer[i].limit = 0;
903     }
904 }
905 
906 static const MemoryRegionOps mv88w8618_pit_ops = {
907     .read = mv88w8618_pit_read,
908     .write = mv88w8618_pit_write,
909     .endianness = DEVICE_NATIVE_ENDIAN,
910 };
911 
912 static int mv88w8618_pit_init(SysBusDevice *dev)
913 {
914     mv88w8618_pit_state *s = MV88W8618_PIT(dev);
915     int i;
916 
917     /* Letting them all run at 1 MHz is likely just a pragmatic
918      * simplification. */
919     for (i = 0; i < 4; i++) {
920         mv88w8618_timer_init(dev, &s->timer[i], 1000000);
921     }
922 
923     memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_pit_ops, s,
924                           "musicpal-pit", MP_PIT_SIZE);
925     sysbus_init_mmio(dev, &s->iomem);
926     return 0;
927 }
928 
929 static const VMStateDescription mv88w8618_timer_vmsd = {
930     .name = "timer",
931     .version_id = 1,
932     .minimum_version_id = 1,
933     .fields = (VMStateField[]) {
934         VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
935         VMSTATE_UINT32(limit, mv88w8618_timer_state),
936         VMSTATE_END_OF_LIST()
937     }
938 };
939 
940 static const VMStateDescription mv88w8618_pit_vmsd = {
941     .name = "mv88w8618_pit",
942     .version_id = 1,
943     .minimum_version_id = 1,
944     .fields = (VMStateField[]) {
945         VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
946                              mv88w8618_timer_vmsd, mv88w8618_timer_state),
947         VMSTATE_END_OF_LIST()
948     }
949 };
950 
951 static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
952 {
953     DeviceClass *dc = DEVICE_CLASS(klass);
954     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
955 
956     k->init = mv88w8618_pit_init;
957     dc->reset = mv88w8618_pit_reset;
958     dc->vmsd = &mv88w8618_pit_vmsd;
959 }
960 
961 static const TypeInfo mv88w8618_pit_info = {
962     .name          = TYPE_MV88W8618_PIT,
963     .parent        = TYPE_SYS_BUS_DEVICE,
964     .instance_size = sizeof(mv88w8618_pit_state),
965     .class_init    = mv88w8618_pit_class_init,
966 };
967 
968 /* Flash config register offsets */
969 #define MP_FLASHCFG_CFGR0    0x04
970 
971 #define TYPE_MV88W8618_FLASHCFG "mv88w8618_flashcfg"
972 #define MV88W8618_FLASHCFG(obj) \
973     OBJECT_CHECK(mv88w8618_flashcfg_state, (obj), TYPE_MV88W8618_FLASHCFG)
974 
975 typedef struct mv88w8618_flashcfg_state {
976     /*< private >*/
977     SysBusDevice parent_obj;
978     /*< public >*/
979 
980     MemoryRegion iomem;
981     uint32_t cfgr0;
982 } mv88w8618_flashcfg_state;
983 
984 static uint64_t mv88w8618_flashcfg_read(void *opaque,
985                                         hwaddr offset,
986                                         unsigned size)
987 {
988     mv88w8618_flashcfg_state *s = opaque;
989 
990     switch (offset) {
991     case MP_FLASHCFG_CFGR0:
992         return s->cfgr0;
993 
994     default:
995         return 0;
996     }
997 }
998 
999 static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset,
1000                                      uint64_t value, unsigned size)
1001 {
1002     mv88w8618_flashcfg_state *s = opaque;
1003 
1004     switch (offset) {
1005     case MP_FLASHCFG_CFGR0:
1006         s->cfgr0 = value;
1007         break;
1008     }
1009 }
1010 
1011 static const MemoryRegionOps mv88w8618_flashcfg_ops = {
1012     .read = mv88w8618_flashcfg_read,
1013     .write = mv88w8618_flashcfg_write,
1014     .endianness = DEVICE_NATIVE_ENDIAN,
1015 };
1016 
1017 static int mv88w8618_flashcfg_init(SysBusDevice *dev)
1018 {
1019     mv88w8618_flashcfg_state *s = MV88W8618_FLASHCFG(dev);
1020 
1021     s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
1022     memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_flashcfg_ops, s,
1023                           "musicpal-flashcfg", MP_FLASHCFG_SIZE);
1024     sysbus_init_mmio(dev, &s->iomem);
1025     return 0;
1026 }
1027 
1028 static const VMStateDescription mv88w8618_flashcfg_vmsd = {
1029     .name = "mv88w8618_flashcfg",
1030     .version_id = 1,
1031     .minimum_version_id = 1,
1032     .fields = (VMStateField[]) {
1033         VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
1034         VMSTATE_END_OF_LIST()
1035     }
1036 };
1037 
1038 static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
1039 {
1040     DeviceClass *dc = DEVICE_CLASS(klass);
1041     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
1042 
1043     k->init = mv88w8618_flashcfg_init;
1044     dc->vmsd = &mv88w8618_flashcfg_vmsd;
1045 }
1046 
1047 static const TypeInfo mv88w8618_flashcfg_info = {
1048     .name          = TYPE_MV88W8618_FLASHCFG,
1049     .parent        = TYPE_SYS_BUS_DEVICE,
1050     .instance_size = sizeof(mv88w8618_flashcfg_state),
1051     .class_init    = mv88w8618_flashcfg_class_init,
1052 };
1053 
1054 /* Misc register offsets */
1055 #define MP_MISC_BOARD_REVISION  0x18
1056 
1057 #define MP_BOARD_REVISION       0x31
1058 
1059 typedef struct {
1060     SysBusDevice parent_obj;
1061     MemoryRegion iomem;
1062 } MusicPalMiscState;
1063 
1064 #define TYPE_MUSICPAL_MISC "musicpal-misc"
1065 #define MUSICPAL_MISC(obj) \
1066      OBJECT_CHECK(MusicPalMiscState, (obj), TYPE_MUSICPAL_MISC)
1067 
1068 static uint64_t musicpal_misc_read(void *opaque, hwaddr offset,
1069                                    unsigned size)
1070 {
1071     switch (offset) {
1072     case MP_MISC_BOARD_REVISION:
1073         return MP_BOARD_REVISION;
1074 
1075     default:
1076         return 0;
1077     }
1078 }
1079 
1080 static void musicpal_misc_write(void *opaque, hwaddr offset,
1081                                 uint64_t value, unsigned size)
1082 {
1083 }
1084 
1085 static const MemoryRegionOps musicpal_misc_ops = {
1086     .read = musicpal_misc_read,
1087     .write = musicpal_misc_write,
1088     .endianness = DEVICE_NATIVE_ENDIAN,
1089 };
1090 
1091 static void musicpal_misc_init(Object *obj)
1092 {
1093     SysBusDevice *sd = SYS_BUS_DEVICE(obj);
1094     MusicPalMiscState *s = MUSICPAL_MISC(obj);
1095 
1096     memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_misc_ops, NULL,
1097                           "musicpal-misc", MP_MISC_SIZE);
1098     sysbus_init_mmio(sd, &s->iomem);
1099 }
1100 
1101 static const TypeInfo musicpal_misc_info = {
1102     .name = TYPE_MUSICPAL_MISC,
1103     .parent = TYPE_SYS_BUS_DEVICE,
1104     .instance_init = musicpal_misc_init,
1105     .instance_size = sizeof(MusicPalMiscState),
1106 };
1107 
1108 /* WLAN register offsets */
1109 #define MP_WLAN_MAGIC1          0x11c
1110 #define MP_WLAN_MAGIC2          0x124
1111 
1112 static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset,
1113                                     unsigned size)
1114 {
1115     switch (offset) {
1116     /* Workaround to allow loading the binary-only wlandrv.ko crap
1117      * from the original Freecom firmware. */
1118     case MP_WLAN_MAGIC1:
1119         return ~3;
1120     case MP_WLAN_MAGIC2:
1121         return -1;
1122 
1123     default:
1124         return 0;
1125     }
1126 }
1127 
1128 static void mv88w8618_wlan_write(void *opaque, hwaddr offset,
1129                                  uint64_t value, unsigned size)
1130 {
1131 }
1132 
1133 static const MemoryRegionOps mv88w8618_wlan_ops = {
1134     .read = mv88w8618_wlan_read,
1135     .write =mv88w8618_wlan_write,
1136     .endianness = DEVICE_NATIVE_ENDIAN,
1137 };
1138 
1139 static int mv88w8618_wlan_init(SysBusDevice *dev)
1140 {
1141     MemoryRegion *iomem = g_new(MemoryRegion, 1);
1142 
1143     memory_region_init_io(iomem, OBJECT(dev), &mv88w8618_wlan_ops, NULL,
1144                           "musicpal-wlan", MP_WLAN_SIZE);
1145     sysbus_init_mmio(dev, iomem);
1146     return 0;
1147 }
1148 
1149 /* GPIO register offsets */
1150 #define MP_GPIO_OE_LO           0x008
1151 #define MP_GPIO_OUT_LO          0x00c
1152 #define MP_GPIO_IN_LO           0x010
1153 #define MP_GPIO_IER_LO          0x014
1154 #define MP_GPIO_IMR_LO          0x018
1155 #define MP_GPIO_ISR_LO          0x020
1156 #define MP_GPIO_OE_HI           0x508
1157 #define MP_GPIO_OUT_HI          0x50c
1158 #define MP_GPIO_IN_HI           0x510
1159 #define MP_GPIO_IER_HI          0x514
1160 #define MP_GPIO_IMR_HI          0x518
1161 #define MP_GPIO_ISR_HI          0x520
1162 
1163 /* GPIO bits & masks */
1164 #define MP_GPIO_LCD_BRIGHTNESS  0x00070000
1165 #define MP_GPIO_I2C_DATA_BIT    29
1166 #define MP_GPIO_I2C_CLOCK_BIT   30
1167 
1168 /* LCD brightness bits in GPIO_OE_HI */
1169 #define MP_OE_LCD_BRIGHTNESS    0x0007
1170 
1171 #define TYPE_MUSICPAL_GPIO "musicpal_gpio"
1172 #define MUSICPAL_GPIO(obj) \
1173     OBJECT_CHECK(musicpal_gpio_state, (obj), TYPE_MUSICPAL_GPIO)
1174 
1175 typedef struct musicpal_gpio_state {
1176     /*< private >*/
1177     SysBusDevice parent_obj;
1178     /*< public >*/
1179 
1180     MemoryRegion iomem;
1181     uint32_t lcd_brightness;
1182     uint32_t out_state;
1183     uint32_t in_state;
1184     uint32_t ier;
1185     uint32_t imr;
1186     uint32_t isr;
1187     qemu_irq irq;
1188     qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */
1189 } musicpal_gpio_state;
1190 
1191 static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) {
1192     int i;
1193     uint32_t brightness;
1194 
1195     /* compute brightness ratio */
1196     switch (s->lcd_brightness) {
1197     case 0x00000007:
1198         brightness = 0;
1199         break;
1200 
1201     case 0x00020000:
1202         brightness = 1;
1203         break;
1204 
1205     case 0x00020001:
1206         brightness = 2;
1207         break;
1208 
1209     case 0x00040000:
1210         brightness = 3;
1211         break;
1212 
1213     case 0x00010006:
1214         brightness = 4;
1215         break;
1216 
1217     case 0x00020005:
1218         brightness = 5;
1219         break;
1220 
1221     case 0x00040003:
1222         brightness = 6;
1223         break;
1224 
1225     case 0x00030004:
1226     default:
1227         brightness = 7;
1228     }
1229 
1230     /* set lcd brightness GPIOs  */
1231     for (i = 0; i <= 2; i++) {
1232         qemu_set_irq(s->out[i], (brightness >> i) & 1);
1233     }
1234 }
1235 
1236 static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
1237 {
1238     musicpal_gpio_state *s = opaque;
1239     uint32_t mask = 1 << pin;
1240     uint32_t delta = level << pin;
1241     uint32_t old = s->in_state & mask;
1242 
1243     s->in_state &= ~mask;
1244     s->in_state |= delta;
1245 
1246     if ((old ^ delta) &&
1247         ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) {
1248         s->isr = mask;
1249         qemu_irq_raise(s->irq);
1250     }
1251 }
1252 
1253 static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset,
1254                                    unsigned size)
1255 {
1256     musicpal_gpio_state *s = opaque;
1257 
1258     switch (offset) {
1259     case MP_GPIO_OE_HI: /* used for LCD brightness control */
1260         return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS;
1261 
1262     case MP_GPIO_OUT_LO:
1263         return s->out_state & 0xFFFF;
1264     case MP_GPIO_OUT_HI:
1265         return s->out_state >> 16;
1266 
1267     case MP_GPIO_IN_LO:
1268         return s->in_state & 0xFFFF;
1269     case MP_GPIO_IN_HI:
1270         return s->in_state >> 16;
1271 
1272     case MP_GPIO_IER_LO:
1273         return s->ier & 0xFFFF;
1274     case MP_GPIO_IER_HI:
1275         return s->ier >> 16;
1276 
1277     case MP_GPIO_IMR_LO:
1278         return s->imr & 0xFFFF;
1279     case MP_GPIO_IMR_HI:
1280         return s->imr >> 16;
1281 
1282     case MP_GPIO_ISR_LO:
1283         return s->isr & 0xFFFF;
1284     case MP_GPIO_ISR_HI:
1285         return s->isr >> 16;
1286 
1287     default:
1288         return 0;
1289     }
1290 }
1291 
1292 static void musicpal_gpio_write(void *opaque, hwaddr offset,
1293                                 uint64_t value, unsigned size)
1294 {
1295     musicpal_gpio_state *s = opaque;
1296     switch (offset) {
1297     case MP_GPIO_OE_HI: /* used for LCD brightness control */
1298         s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |
1299                          (value & MP_OE_LCD_BRIGHTNESS);
1300         musicpal_gpio_brightness_update(s);
1301         break;
1302 
1303     case MP_GPIO_OUT_LO:
1304         s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF);
1305         break;
1306     case MP_GPIO_OUT_HI:
1307         s->out_state = (s->out_state & 0xFFFF) | (value << 16);
1308         s->lcd_brightness = (s->lcd_brightness & 0xFFFF) |
1309                             (s->out_state & MP_GPIO_LCD_BRIGHTNESS);
1310         musicpal_gpio_brightness_update(s);
1311         qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1);
1312         qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);
1313         break;
1314 
1315     case MP_GPIO_IER_LO:
1316         s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF);
1317         break;
1318     case MP_GPIO_IER_HI:
1319         s->ier = (s->ier & 0xFFFF) | (value << 16);
1320         break;
1321 
1322     case MP_GPIO_IMR_LO:
1323         s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF);
1324         break;
1325     case MP_GPIO_IMR_HI:
1326         s->imr = (s->imr & 0xFFFF) | (value << 16);
1327         break;
1328     }
1329 }
1330 
1331 static const MemoryRegionOps musicpal_gpio_ops = {
1332     .read = musicpal_gpio_read,
1333     .write = musicpal_gpio_write,
1334     .endianness = DEVICE_NATIVE_ENDIAN,
1335 };
1336 
1337 static void musicpal_gpio_reset(DeviceState *d)
1338 {
1339     musicpal_gpio_state *s = MUSICPAL_GPIO(d);
1340 
1341     s->lcd_brightness = 0;
1342     s->out_state = 0;
1343     s->in_state = 0xffffffff;
1344     s->ier = 0;
1345     s->imr = 0;
1346     s->isr = 0;
1347 }
1348 
1349 static int musicpal_gpio_init(SysBusDevice *sbd)
1350 {
1351     DeviceState *dev = DEVICE(sbd);
1352     musicpal_gpio_state *s = MUSICPAL_GPIO(dev);
1353 
1354     sysbus_init_irq(sbd, &s->irq);
1355 
1356     memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_gpio_ops, s,
1357                           "musicpal-gpio", MP_GPIO_SIZE);
1358     sysbus_init_mmio(sbd, &s->iomem);
1359 
1360     qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
1361 
1362     qdev_init_gpio_in(dev, musicpal_gpio_pin_event, 32);
1363 
1364     return 0;
1365 }
1366 
1367 static const VMStateDescription musicpal_gpio_vmsd = {
1368     .name = "musicpal_gpio",
1369     .version_id = 1,
1370     .minimum_version_id = 1,
1371     .fields = (VMStateField[]) {
1372         VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
1373         VMSTATE_UINT32(out_state, musicpal_gpio_state),
1374         VMSTATE_UINT32(in_state, musicpal_gpio_state),
1375         VMSTATE_UINT32(ier, musicpal_gpio_state),
1376         VMSTATE_UINT32(imr, musicpal_gpio_state),
1377         VMSTATE_UINT32(isr, musicpal_gpio_state),
1378         VMSTATE_END_OF_LIST()
1379     }
1380 };
1381 
1382 static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
1383 {
1384     DeviceClass *dc = DEVICE_CLASS(klass);
1385     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
1386 
1387     k->init = musicpal_gpio_init;
1388     dc->reset = musicpal_gpio_reset;
1389     dc->vmsd = &musicpal_gpio_vmsd;
1390 }
1391 
1392 static const TypeInfo musicpal_gpio_info = {
1393     .name          = TYPE_MUSICPAL_GPIO,
1394     .parent        = TYPE_SYS_BUS_DEVICE,
1395     .instance_size = sizeof(musicpal_gpio_state),
1396     .class_init    = musicpal_gpio_class_init,
1397 };
1398 
1399 /* Keyboard codes & masks */
1400 #define KEY_RELEASED            0x80
1401 #define KEY_CODE                0x7f
1402 
1403 #define KEYCODE_TAB             0x0f
1404 #define KEYCODE_ENTER           0x1c
1405 #define KEYCODE_F               0x21
1406 #define KEYCODE_M               0x32
1407 
1408 #define KEYCODE_EXTENDED        0xe0
1409 #define KEYCODE_UP              0x48
1410 #define KEYCODE_DOWN            0x50
1411 #define KEYCODE_LEFT            0x4b
1412 #define KEYCODE_RIGHT           0x4d
1413 
1414 #define MP_KEY_WHEEL_VOL       (1 << 0)
1415 #define MP_KEY_WHEEL_VOL_INV   (1 << 1)
1416 #define MP_KEY_WHEEL_NAV       (1 << 2)
1417 #define MP_KEY_WHEEL_NAV_INV   (1 << 3)
1418 #define MP_KEY_BTN_FAVORITS    (1 << 4)
1419 #define MP_KEY_BTN_MENU        (1 << 5)
1420 #define MP_KEY_BTN_VOLUME      (1 << 6)
1421 #define MP_KEY_BTN_NAVIGATION  (1 << 7)
1422 
1423 #define TYPE_MUSICPAL_KEY "musicpal_key"
1424 #define MUSICPAL_KEY(obj) \
1425     OBJECT_CHECK(musicpal_key_state, (obj), TYPE_MUSICPAL_KEY)
1426 
1427 typedef struct musicpal_key_state {
1428     /*< private >*/
1429     SysBusDevice parent_obj;
1430     /*< public >*/
1431 
1432     MemoryRegion iomem;
1433     uint32_t kbd_extended;
1434     uint32_t pressed_keys;
1435     qemu_irq out[8];
1436 } musicpal_key_state;
1437 
1438 static void musicpal_key_event(void *opaque, int keycode)
1439 {
1440     musicpal_key_state *s = opaque;
1441     uint32_t event = 0;
1442     int i;
1443 
1444     if (keycode == KEYCODE_EXTENDED) {
1445         s->kbd_extended = 1;
1446         return;
1447     }
1448 
1449     if (s->kbd_extended) {
1450         switch (keycode & KEY_CODE) {
1451         case KEYCODE_UP:
1452             event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV;
1453             break;
1454 
1455         case KEYCODE_DOWN:
1456             event = MP_KEY_WHEEL_NAV;
1457             break;
1458 
1459         case KEYCODE_LEFT:
1460             event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV;
1461             break;
1462 
1463         case KEYCODE_RIGHT:
1464             event = MP_KEY_WHEEL_VOL;
1465             break;
1466         }
1467     } else {
1468         switch (keycode & KEY_CODE) {
1469         case KEYCODE_F:
1470             event = MP_KEY_BTN_FAVORITS;
1471             break;
1472 
1473         case KEYCODE_TAB:
1474             event = MP_KEY_BTN_VOLUME;
1475             break;
1476 
1477         case KEYCODE_ENTER:
1478             event = MP_KEY_BTN_NAVIGATION;
1479             break;
1480 
1481         case KEYCODE_M:
1482             event = MP_KEY_BTN_MENU;
1483             break;
1484         }
1485         /* Do not repeat already pressed buttons */
1486         if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
1487             event = 0;
1488         }
1489     }
1490 
1491     if (event) {
1492         /* Raise GPIO pin first if repeating a key */
1493         if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
1494             for (i = 0; i <= 7; i++) {
1495                 if (event & (1 << i)) {
1496                     qemu_set_irq(s->out[i], 1);
1497                 }
1498             }
1499         }
1500         for (i = 0; i <= 7; i++) {
1501             if (event & (1 << i)) {
1502                 qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED));
1503             }
1504         }
1505         if (keycode & KEY_RELEASED) {
1506             s->pressed_keys &= ~event;
1507         } else {
1508             s->pressed_keys |= event;
1509         }
1510     }
1511 
1512     s->kbd_extended = 0;
1513 }
1514 
1515 static int musicpal_key_init(SysBusDevice *sbd)
1516 {
1517     DeviceState *dev = DEVICE(sbd);
1518     musicpal_key_state *s = MUSICPAL_KEY(dev);
1519 
1520     memory_region_init(&s->iomem, OBJECT(s), "dummy", 0);
1521     sysbus_init_mmio(sbd, &s->iomem);
1522 
1523     s->kbd_extended = 0;
1524     s->pressed_keys = 0;
1525 
1526     qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
1527 
1528     qemu_add_kbd_event_handler(musicpal_key_event, s);
1529 
1530     return 0;
1531 }
1532 
1533 static const VMStateDescription musicpal_key_vmsd = {
1534     .name = "musicpal_key",
1535     .version_id = 1,
1536     .minimum_version_id = 1,
1537     .fields = (VMStateField[]) {
1538         VMSTATE_UINT32(kbd_extended, musicpal_key_state),
1539         VMSTATE_UINT32(pressed_keys, musicpal_key_state),
1540         VMSTATE_END_OF_LIST()
1541     }
1542 };
1543 
1544 static void musicpal_key_class_init(ObjectClass *klass, void *data)
1545 {
1546     DeviceClass *dc = DEVICE_CLASS(klass);
1547     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
1548 
1549     k->init = musicpal_key_init;
1550     dc->vmsd = &musicpal_key_vmsd;
1551 }
1552 
1553 static const TypeInfo musicpal_key_info = {
1554     .name          = TYPE_MUSICPAL_KEY,
1555     .parent        = TYPE_SYS_BUS_DEVICE,
1556     .instance_size = sizeof(musicpal_key_state),
1557     .class_init    = musicpal_key_class_init,
1558 };
1559 
1560 static struct arm_boot_info musicpal_binfo = {
1561     .loader_start = 0x0,
1562     .board_id = 0x20e,
1563 };
1564 
1565 static void musicpal_init(MachineState *machine)
1566 {
1567     const char *cpu_model = machine->cpu_model;
1568     const char *kernel_filename = machine->kernel_filename;
1569     const char *kernel_cmdline = machine->kernel_cmdline;
1570     const char *initrd_filename = machine->initrd_filename;
1571     ARMCPU *cpu;
1572     qemu_irq pic[32];
1573     DeviceState *dev;
1574     DeviceState *i2c_dev;
1575     DeviceState *lcd_dev;
1576     DeviceState *key_dev;
1577     DeviceState *wm8750_dev;
1578     SysBusDevice *s;
1579     I2CBus *i2c;
1580     int i;
1581     unsigned long flash_size;
1582     DriveInfo *dinfo;
1583     MemoryRegion *address_space_mem = get_system_memory();
1584     MemoryRegion *ram = g_new(MemoryRegion, 1);
1585     MemoryRegion *sram = g_new(MemoryRegion, 1);
1586 
1587     if (!cpu_model) {
1588         cpu_model = "arm926";
1589     }
1590     cpu = cpu_arm_init(cpu_model);
1591     if (!cpu) {
1592         fprintf(stderr, "Unable to find CPU definition\n");
1593         exit(1);
1594     }
1595 
1596     /* For now we use a fixed - the original - RAM size */
1597     memory_region_allocate_system_memory(ram, NULL, "musicpal.ram",
1598                                          MP_RAM_DEFAULT_SIZE);
1599     memory_region_add_subregion(address_space_mem, 0, ram);
1600 
1601     memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE,
1602                            &error_abort);
1603     vmstate_register_ram_global(sram);
1604     memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
1605 
1606     dev = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE,
1607                                qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
1608     for (i = 0; i < 32; i++) {
1609         pic[i] = qdev_get_gpio_in(dev, i);
1610     }
1611     sysbus_create_varargs(TYPE_MV88W8618_PIT, MP_PIT_BASE, pic[MP_TIMER1_IRQ],
1612                           pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ],
1613                           pic[MP_TIMER4_IRQ], NULL);
1614 
1615     if (serial_hds[0]) {
1616         serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ],
1617                        1825000, serial_hds[0], DEVICE_NATIVE_ENDIAN);
1618     }
1619     if (serial_hds[1]) {
1620         serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ],
1621                        1825000, serial_hds[1], DEVICE_NATIVE_ENDIAN);
1622     }
1623 
1624     /* Register flash */
1625     dinfo = drive_get(IF_PFLASH, 0, 0);
1626     if (dinfo) {
1627         BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
1628 
1629         flash_size = blk_getlength(blk);
1630         if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
1631             flash_size != 32*1024*1024) {
1632             fprintf(stderr, "Invalid flash image size\n");
1633             exit(1);
1634         }
1635 
1636         /*
1637          * The original U-Boot accesses the flash at 0xFE000000 instead of
1638          * 0xFF800000 (if there is 8 MB flash). So remap flash access if the
1639          * image is smaller than 32 MB.
1640          */
1641 #ifdef TARGET_WORDS_BIGENDIAN
1642         pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
1643                               "musicpal.flash", flash_size,
1644                               blk, 0x10000, (flash_size + 0xffff) >> 16,
1645                               MP_FLASH_SIZE_MAX / flash_size,
1646                               2, 0x00BF, 0x236D, 0x0000, 0x0000,
1647                               0x5555, 0x2AAA, 1);
1648 #else
1649         pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
1650                               "musicpal.flash", flash_size,
1651                               blk, 0x10000, (flash_size + 0xffff) >> 16,
1652                               MP_FLASH_SIZE_MAX / flash_size,
1653                               2, 0x00BF, 0x236D, 0x0000, 0x0000,
1654                               0x5555, 0x2AAA, 0);
1655 #endif
1656 
1657     }
1658     sysbus_create_simple(TYPE_MV88W8618_FLASHCFG, MP_FLASHCFG_BASE, NULL);
1659 
1660     qemu_check_nic_model(&nd_table[0], "mv88w8618");
1661     dev = qdev_create(NULL, TYPE_MV88W8618_ETH);
1662     qdev_set_nic_properties(dev, &nd_table[0]);
1663     qdev_init_nofail(dev);
1664     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE);
1665     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]);
1666 
1667     sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
1668 
1669     sysbus_create_simple(TYPE_MUSICPAL_MISC, MP_MISC_BASE, NULL);
1670 
1671     dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE,
1672                                pic[MP_GPIO_IRQ]);
1673     i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
1674     i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c");
1675 
1676     lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL);
1677     key_dev = sysbus_create_simple(TYPE_MUSICPAL_KEY, -1, NULL);
1678 
1679     /* I2C read data */
1680     qdev_connect_gpio_out(i2c_dev, 0,
1681                           qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT));
1682     /* I2C data */
1683     qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0));
1684     /* I2C clock */
1685     qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1));
1686 
1687     for (i = 0; i < 3; i++) {
1688         qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i));
1689     }
1690     for (i = 0; i < 4; i++) {
1691         qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8));
1692     }
1693     for (i = 4; i < 8; i++) {
1694         qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15));
1695     }
1696 
1697     wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR);
1698     dev = qdev_create(NULL, "mv88w8618_audio");
1699     s = SYS_BUS_DEVICE(dev);
1700     qdev_prop_set_ptr(dev, "wm8750", wm8750_dev);
1701     qdev_init_nofail(dev);
1702     sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
1703     sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
1704 
1705     musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
1706     musicpal_binfo.kernel_filename = kernel_filename;
1707     musicpal_binfo.kernel_cmdline = kernel_cmdline;
1708     musicpal_binfo.initrd_filename = initrd_filename;
1709     arm_load_kernel(cpu, &musicpal_binfo);
1710 }
1711 
1712 static QEMUMachine musicpal_machine = {
1713     .name = "musicpal",
1714     .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)",
1715     .init = musicpal_init,
1716 };
1717 
1718 static void musicpal_machine_init(void)
1719 {
1720     qemu_register_machine(&musicpal_machine);
1721 }
1722 
1723 machine_init(musicpal_machine_init);
1724 
1725 static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
1726 {
1727     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
1728 
1729     sdc->init = mv88w8618_wlan_init;
1730 }
1731 
1732 static const TypeInfo mv88w8618_wlan_info = {
1733     .name          = "mv88w8618_wlan",
1734     .parent        = TYPE_SYS_BUS_DEVICE,
1735     .instance_size = sizeof(SysBusDevice),
1736     .class_init    = mv88w8618_wlan_class_init,
1737 };
1738 
1739 static void musicpal_register_types(void)
1740 {
1741     type_register_static(&mv88w8618_pic_info);
1742     type_register_static(&mv88w8618_pit_info);
1743     type_register_static(&mv88w8618_flashcfg_info);
1744     type_register_static(&mv88w8618_eth_info);
1745     type_register_static(&mv88w8618_wlan_info);
1746     type_register_static(&musicpal_lcd_info);
1747     type_register_static(&musicpal_gpio_info);
1748     type_register_static(&musicpal_key_info);
1749     type_register_static(&musicpal_misc_info);
1750 }
1751 
1752 type_init(musicpal_register_types)
1753