add roms/pcbios
[armpft.git] / hw / musicpal.c
blob0d21f1778f3b66d890c85a2edcb21208edb5408a
1 /*
2 * Marvell MV88W8618 / Freecom MusicPal emulation.
4 * Copyright (c) 2008 Jan Kiszka
6 * This code is licenced under the GNU GPL v2.
7 */
9 #include "sysbus.h"
10 #include "arm-misc.h"
11 #include "devices.h"
12 #include "net.h"
13 #include "sysemu.h"
14 #include "boards.h"
15 #include "pc.h"
16 #include "qemu-timer.h"
17 #include "block.h"
18 #include "flash.h"
19 #include "console.h"
20 #include "i2c.h"
22 #define MP_MISC_BASE 0x80002000
23 #define MP_MISC_SIZE 0x00001000
25 #define MP_ETH_BASE 0x80008000
26 #define MP_ETH_SIZE 0x00001000
28 #define MP_WLAN_BASE 0x8000C000
29 #define MP_WLAN_SIZE 0x00000800
31 #define MP_UART1_BASE 0x8000C840
32 #define MP_UART2_BASE 0x8000C940
34 #define MP_GPIO_BASE 0x8000D000
35 #define MP_GPIO_SIZE 0x00001000
37 #define MP_FLASHCFG_BASE 0x90006000
38 #define MP_FLASHCFG_SIZE 0x00001000
40 #define MP_AUDIO_BASE 0x90007000
42 #define MP_PIC_BASE 0x90008000
43 #define MP_PIC_SIZE 0x00001000
45 #define MP_PIT_BASE 0x90009000
46 #define MP_PIT_SIZE 0x00001000
48 #define MP_LCD_BASE 0x9000c000
49 #define MP_LCD_SIZE 0x00001000
51 #define MP_SRAM_BASE 0xC0000000
52 #define MP_SRAM_SIZE 0x00020000
54 #define MP_RAM_DEFAULT_SIZE 32*1024*1024
55 #define MP_FLASH_SIZE_MAX 32*1024*1024
57 #define MP_TIMER1_IRQ 4
58 #define MP_TIMER2_IRQ 5
59 #define MP_TIMER3_IRQ 6
60 #define MP_TIMER4_IRQ 7
61 #define MP_EHCI_IRQ 8
62 #define MP_ETH_IRQ 9
63 #define MP_UART1_IRQ 11
64 #define MP_UART2_IRQ 11
65 #define MP_GPIO_IRQ 12
66 #define MP_RTC_IRQ 28
67 #define MP_AUDIO_IRQ 30
69 /* Wolfson 8750 I2C address */
70 #define MP_WM_ADDR 0x34
72 /* Ethernet register offsets */
73 #define MP_ETH_SMIR 0x010
74 #define MP_ETH_PCXR 0x408
75 #define MP_ETH_SDCMR 0x448
76 #define MP_ETH_ICR 0x450
77 #define MP_ETH_IMR 0x458
78 #define MP_ETH_FRDP0 0x480
79 #define MP_ETH_FRDP1 0x484
80 #define MP_ETH_FRDP2 0x488
81 #define MP_ETH_FRDP3 0x48C
82 #define MP_ETH_CRDP0 0x4A0
83 #define MP_ETH_CRDP1 0x4A4
84 #define MP_ETH_CRDP2 0x4A8
85 #define MP_ETH_CRDP3 0x4AC
86 #define MP_ETH_CTDP0 0x4E0
87 #define MP_ETH_CTDP1 0x4E4
88 #define MP_ETH_CTDP2 0x4E8
89 #define MP_ETH_CTDP3 0x4EC
91 /* MII PHY access */
92 #define MP_ETH_SMIR_DATA 0x0000FFFF
93 #define MP_ETH_SMIR_ADDR 0x03FF0000
94 #define MP_ETH_SMIR_OPCODE (1 << 26) /* Read value */
95 #define MP_ETH_SMIR_RDVALID (1 << 27)
97 /* PHY registers */
98 #define MP_ETH_PHY1_BMSR 0x00210000
99 #define MP_ETH_PHY1_PHYSID1 0x00410000
100 #define MP_ETH_PHY1_PHYSID2 0x00610000
102 #define MP_PHY_BMSR_LINK 0x0004
103 #define MP_PHY_BMSR_AUTONEG 0x0008
105 #define MP_PHY_88E3015 0x01410E20
107 /* TX descriptor status */
108 #define MP_ETH_TX_OWN (1 << 31)
110 /* RX descriptor status */
111 #define MP_ETH_RX_OWN (1 << 31)
113 /* Interrupt cause/mask bits */
114 #define MP_ETH_IRQ_RX_BIT 0
115 #define MP_ETH_IRQ_RX (1 << MP_ETH_IRQ_RX_BIT)
116 #define MP_ETH_IRQ_TXHI_BIT 2
117 #define MP_ETH_IRQ_TXLO_BIT 3
119 /* Port config bits */
120 #define MP_ETH_PCXR_2BSM_BIT 28 /* 2-byte incoming suffix */
122 /* SDMA command bits */
123 #define MP_ETH_CMD_TXHI (1 << 23)
124 #define MP_ETH_CMD_TXLO (1 << 22)
126 typedef struct mv88w8618_tx_desc {
127 uint32_t cmdstat;
128 uint16_t res;
129 uint16_t bytes;
130 uint32_t buffer;
131 uint32_t next;
132 } mv88w8618_tx_desc;
134 typedef struct mv88w8618_rx_desc {
135 uint32_t cmdstat;
136 uint16_t bytes;
137 uint16_t buffer_size;
138 uint32_t buffer;
139 uint32_t next;
140 } mv88w8618_rx_desc;
142 typedef struct mv88w8618_eth_state {
143 SysBusDevice busdev;
144 qemu_irq irq;
145 uint32_t smir;
146 uint32_t icr;
147 uint32_t imr;
148 int mmio_index;
149 uint32_t vlan_header;
150 uint32_t tx_queue[2];
151 uint32_t rx_queue[4];
152 uint32_t frx_queue[4];
153 uint32_t cur_rx[4];
154 VLANClientState *vc;
155 NICConf conf;
156 } mv88w8618_eth_state;
158 static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc)
160 cpu_to_le32s(&desc->cmdstat);
161 cpu_to_le16s(&desc->bytes);
162 cpu_to_le16s(&desc->buffer_size);
163 cpu_to_le32s(&desc->buffer);
164 cpu_to_le32s(&desc->next);
165 cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
168 static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
170 cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
171 le32_to_cpus(&desc->cmdstat);
172 le16_to_cpus(&desc->bytes);
173 le16_to_cpus(&desc->buffer_size);
174 le32_to_cpus(&desc->buffer);
175 le32_to_cpus(&desc->next);
178 static int eth_can_receive(VLANClientState *vc)
180 return 1;
183 static ssize_t eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
185 mv88w8618_eth_state *s = vc->opaque;
186 uint32_t desc_addr;
187 mv88w8618_rx_desc desc;
188 int i;
190 for (i = 0; i < 4; i++) {
191 desc_addr = s->cur_rx[i];
192 if (!desc_addr) {
193 continue;
195 do {
196 eth_rx_desc_get(desc_addr, &desc);
197 if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) {
198 cpu_physical_memory_write(desc.buffer + s->vlan_header,
199 buf, size);
200 desc.bytes = size + s->vlan_header;
201 desc.cmdstat &= ~MP_ETH_RX_OWN;
202 s->cur_rx[i] = desc.next;
204 s->icr |= MP_ETH_IRQ_RX;
205 if (s->icr & s->imr) {
206 qemu_irq_raise(s->irq);
208 eth_rx_desc_put(desc_addr, &desc);
209 return size;
211 desc_addr = desc.next;
212 } while (desc_addr != s->rx_queue[i]);
214 return size;
217 static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc)
219 cpu_to_le32s(&desc->cmdstat);
220 cpu_to_le16s(&desc->res);
221 cpu_to_le16s(&desc->bytes);
222 cpu_to_le32s(&desc->buffer);
223 cpu_to_le32s(&desc->next);
224 cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
227 static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc)
229 cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
230 le32_to_cpus(&desc->cmdstat);
231 le16_to_cpus(&desc->res);
232 le16_to_cpus(&desc->bytes);
233 le32_to_cpus(&desc->buffer);
234 le32_to_cpus(&desc->next);
237 static void eth_send(mv88w8618_eth_state *s, int queue_index)
239 uint32_t desc_addr = s->tx_queue[queue_index];
240 mv88w8618_tx_desc desc;
241 uint8_t buf[2048];
242 int len;
244 if (!desc_addr) {
245 return;
247 do {
248 eth_tx_desc_get(desc_addr, &desc);
249 if (desc.cmdstat & MP_ETH_TX_OWN) {
250 len = desc.bytes;
251 if (len < 2048) {
252 cpu_physical_memory_read(desc.buffer, buf, len);
253 qemu_send_packet(s->vc, buf, len);
255 desc.cmdstat &= ~MP_ETH_TX_OWN;
256 s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
257 eth_tx_desc_put(desc_addr, &desc);
259 desc_addr = desc.next;
260 } while (desc_addr != s->tx_queue[queue_index]);
263 static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset)
265 mv88w8618_eth_state *s = opaque;
267 switch (offset) {
268 case MP_ETH_SMIR:
269 if (s->smir & MP_ETH_SMIR_OPCODE) {
270 switch (s->smir & MP_ETH_SMIR_ADDR) {
271 case MP_ETH_PHY1_BMSR:
272 return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG |
273 MP_ETH_SMIR_RDVALID;
274 case MP_ETH_PHY1_PHYSID1:
275 return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID;
276 case MP_ETH_PHY1_PHYSID2:
277 return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID;
278 default:
279 return MP_ETH_SMIR_RDVALID;
282 return 0;
284 case MP_ETH_ICR:
285 return s->icr;
287 case MP_ETH_IMR:
288 return s->imr;
290 case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
291 return s->frx_queue[(offset - MP_ETH_FRDP0)/4];
293 case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
294 return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
296 case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
297 return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
299 default:
300 return 0;
304 static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset,
305 uint32_t value)
307 mv88w8618_eth_state *s = opaque;
309 switch (offset) {
310 case MP_ETH_SMIR:
311 s->smir = value;
312 break;
314 case MP_ETH_PCXR:
315 s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2;
316 break;
318 case MP_ETH_SDCMR:
319 if (value & MP_ETH_CMD_TXHI) {
320 eth_send(s, 1);
322 if (value & MP_ETH_CMD_TXLO) {
323 eth_send(s, 0);
325 if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) {
326 qemu_irq_raise(s->irq);
328 break;
330 case MP_ETH_ICR:
331 s->icr &= value;
332 break;
334 case MP_ETH_IMR:
335 s->imr = value;
336 if (s->icr & s->imr) {
337 qemu_irq_raise(s->irq);
339 break;
341 case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
342 s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value;
343 break;
345 case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
346 s->rx_queue[(offset - MP_ETH_CRDP0)/4] =
347 s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
348 break;
350 case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
351 s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
352 break;
356 static CPUReadMemoryFunc * const mv88w8618_eth_readfn[] = {
357 mv88w8618_eth_read,
358 mv88w8618_eth_read,
359 mv88w8618_eth_read
362 static CPUWriteMemoryFunc * const mv88w8618_eth_writefn[] = {
363 mv88w8618_eth_write,
364 mv88w8618_eth_write,
365 mv88w8618_eth_write
368 static void eth_cleanup(VLANClientState *vc)
370 mv88w8618_eth_state *s = vc->opaque;
372 s->vc = NULL;
375 static int mv88w8618_eth_init(SysBusDevice *dev)
377 mv88w8618_eth_state *s = FROM_SYSBUS(mv88w8618_eth_state, dev);
379 sysbus_init_irq(dev, &s->irq);
380 s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
381 s->conf.vlan, s->conf.peer,
382 dev->qdev.info->name, dev->qdev.id,
383 eth_can_receive, eth_receive, NULL,
384 NULL, eth_cleanup, s);
385 s->mmio_index = cpu_register_io_memory(mv88w8618_eth_readfn,
386 mv88w8618_eth_writefn, s);
387 sysbus_init_mmio(dev, MP_ETH_SIZE, s->mmio_index);
388 return 0;
391 static const VMStateDescription mv88w8618_eth_vmsd = {
392 .name = "mv88w8618_eth",
393 .version_id = 1,
394 .minimum_version_id = 1,
395 .minimum_version_id_old = 1,
396 .fields = (VMStateField[]) {
397 VMSTATE_UINT32(smir, mv88w8618_eth_state),
398 VMSTATE_UINT32(icr, mv88w8618_eth_state),
399 VMSTATE_UINT32(imr, mv88w8618_eth_state),
400 VMSTATE_UINT32(vlan_header, mv88w8618_eth_state),
401 VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2),
402 VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4),
403 VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4),
404 VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4),
405 VMSTATE_END_OF_LIST()
409 static SysBusDeviceInfo mv88w8618_eth_info = {
410 .init = mv88w8618_eth_init,
411 .qdev.name = "mv88w8618_eth",
412 .qdev.size = sizeof(mv88w8618_eth_state),
413 .qdev.vmsd = &mv88w8618_eth_vmsd,
414 .qdev.props = (Property[]) {
415 DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
416 DEFINE_PROP_END_OF_LIST(),
420 /* LCD register offsets */
421 #define MP_LCD_IRQCTRL 0x180
422 #define MP_LCD_IRQSTAT 0x184
423 #define MP_LCD_SPICTRL 0x1ac
424 #define MP_LCD_INST 0x1bc
425 #define MP_LCD_DATA 0x1c0
427 /* Mode magics */
428 #define MP_LCD_SPI_DATA 0x00100011
429 #define MP_LCD_SPI_CMD 0x00104011
430 #define MP_LCD_SPI_INVALID 0x00000000
432 /* Commmands */
433 #define MP_LCD_INST_SETPAGE0 0xB0
434 /* ... */
435 #define MP_LCD_INST_SETPAGE7 0xB7
437 #define MP_LCD_TEXTCOLOR 0xe0e0ff /* RRGGBB */
439 typedef struct musicpal_lcd_state {
440 SysBusDevice busdev;
441 uint32_t brightness;
442 uint32_t mode;
443 uint32_t irqctrl;
444 uint32_t page;
445 uint32_t page_off;
446 DisplayState *ds;
447 uint8_t video_ram[128*64/8];
448 } musicpal_lcd_state;
450 static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col)
452 switch (s->brightness) {
453 case 7:
454 return col;
455 case 0:
456 return 0;
457 default:
458 return (col * s->brightness) / 7;
462 #define SET_LCD_PIXEL(depth, type) \
463 static inline void glue(set_lcd_pixel, depth) \
464 (musicpal_lcd_state *s, int x, int y, type col) \
466 int dx, dy; \
467 type *pixel = &((type *) ds_get_data(s->ds))[(y * 128 * 3 + x) * 3]; \
469 for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \
470 for (dx = 0; dx < 3; dx++, pixel++) \
471 *pixel = col; \
473 SET_LCD_PIXEL(8, uint8_t)
474 SET_LCD_PIXEL(16, uint16_t)
475 SET_LCD_PIXEL(32, uint32_t)
477 #include "pixel_ops.h"
479 static void lcd_refresh(void *opaque)
481 musicpal_lcd_state *s = opaque;
482 int x, y, col;
484 switch (ds_get_bits_per_pixel(s->ds)) {
485 case 0:
486 return;
487 #define LCD_REFRESH(depth, func) \
488 case depth: \
489 col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \
490 scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \
491 scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \
492 for (x = 0; x < 128; x++) { \
493 for (y = 0; y < 64; y++) { \
494 if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \
495 glue(set_lcd_pixel, depth)(s, x, y, col); \
496 } else { \
497 glue(set_lcd_pixel, depth)(s, x, y, 0); \
501 break;
502 LCD_REFRESH(8, rgb_to_pixel8)
503 LCD_REFRESH(16, rgb_to_pixel16)
504 LCD_REFRESH(32, (is_surface_bgr(s->ds->surface) ?
505 rgb_to_pixel32bgr : rgb_to_pixel32))
506 default:
507 hw_error("unsupported colour depth %i\n",
508 ds_get_bits_per_pixel(s->ds));
511 dpy_update(s->ds, 0, 0, 128*3, 64*3);
514 static void lcd_invalidate(void *opaque)
518 static void musicpal_lcd_gpio_brigthness_in(void *opaque, int irq, int level)
520 musicpal_lcd_state *s = opaque;
521 s->brightness &= ~(1 << irq);
522 s->brightness |= level << irq;
525 static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset)
527 musicpal_lcd_state *s = opaque;
529 switch (offset) {
530 case MP_LCD_IRQCTRL:
531 return s->irqctrl;
533 default:
534 return 0;
538 static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset,
539 uint32_t value)
541 musicpal_lcd_state *s = opaque;
543 switch (offset) {
544 case MP_LCD_IRQCTRL:
545 s->irqctrl = value;
546 break;
548 case MP_LCD_SPICTRL:
549 if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) {
550 s->mode = value;
551 } else {
552 s->mode = MP_LCD_SPI_INVALID;
554 break;
556 case MP_LCD_INST:
557 if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) {
558 s->page = value - MP_LCD_INST_SETPAGE0;
559 s->page_off = 0;
561 break;
563 case MP_LCD_DATA:
564 if (s->mode == MP_LCD_SPI_CMD) {
565 if (value >= MP_LCD_INST_SETPAGE0 &&
566 value <= MP_LCD_INST_SETPAGE7) {
567 s->page = value - MP_LCD_INST_SETPAGE0;
568 s->page_off = 0;
570 } else if (s->mode == MP_LCD_SPI_DATA) {
571 s->video_ram[s->page*128 + s->page_off] = value;
572 s->page_off = (s->page_off + 1) & 127;
574 break;
578 static CPUReadMemoryFunc * const musicpal_lcd_readfn[] = {
579 musicpal_lcd_read,
580 musicpal_lcd_read,
581 musicpal_lcd_read
584 static CPUWriteMemoryFunc * const musicpal_lcd_writefn[] = {
585 musicpal_lcd_write,
586 musicpal_lcd_write,
587 musicpal_lcd_write
590 static int musicpal_lcd_init(SysBusDevice *dev)
592 musicpal_lcd_state *s = FROM_SYSBUS(musicpal_lcd_state, dev);
593 int iomemtype;
595 s->brightness = 7;
597 iomemtype = cpu_register_io_memory(musicpal_lcd_readfn,
598 musicpal_lcd_writefn, s);
599 sysbus_init_mmio(dev, MP_LCD_SIZE, iomemtype);
601 s->ds = graphic_console_init(lcd_refresh, lcd_invalidate,
602 NULL, NULL, s);
603 qemu_console_resize(s->ds, 128*3, 64*3);
605 qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3);
607 return 0;
610 static const VMStateDescription musicpal_lcd_vmsd = {
611 .name = "musicpal_lcd",
612 .version_id = 1,
613 .minimum_version_id = 1,
614 .minimum_version_id_old = 1,
615 .fields = (VMStateField[]) {
616 VMSTATE_UINT32(brightness, musicpal_lcd_state),
617 VMSTATE_UINT32(mode, musicpal_lcd_state),
618 VMSTATE_UINT32(irqctrl, musicpal_lcd_state),
619 VMSTATE_UINT32(page, musicpal_lcd_state),
620 VMSTATE_UINT32(page_off, musicpal_lcd_state),
621 VMSTATE_BUFFER(video_ram, musicpal_lcd_state),
622 VMSTATE_END_OF_LIST()
626 static SysBusDeviceInfo musicpal_lcd_info = {
627 .init = musicpal_lcd_init,
628 .qdev.name = "musicpal_lcd",
629 .qdev.size = sizeof(musicpal_lcd_state),
630 .qdev.vmsd = &musicpal_lcd_vmsd,
633 /* PIC register offsets */
634 #define MP_PIC_STATUS 0x00
635 #define MP_PIC_ENABLE_SET 0x08
636 #define MP_PIC_ENABLE_CLR 0x0C
638 typedef struct mv88w8618_pic_state
640 SysBusDevice busdev;
641 uint32_t level;
642 uint32_t enabled;
643 qemu_irq parent_irq;
644 } mv88w8618_pic_state;
646 static void mv88w8618_pic_update(mv88w8618_pic_state *s)
648 qemu_set_irq(s->parent_irq, (s->level & s->enabled));
651 static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
653 mv88w8618_pic_state *s = opaque;
655 if (level) {
656 s->level |= 1 << irq;
657 } else {
658 s->level &= ~(1 << irq);
660 mv88w8618_pic_update(s);
663 static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset)
665 mv88w8618_pic_state *s = opaque;
667 switch (offset) {
668 case MP_PIC_STATUS:
669 return s->level & s->enabled;
671 default:
672 return 0;
676 static void mv88w8618_pic_write(void *opaque, target_phys_addr_t offset,
677 uint32_t value)
679 mv88w8618_pic_state *s = opaque;
681 switch (offset) {
682 case MP_PIC_ENABLE_SET:
683 s->enabled |= value;
684 break;
686 case MP_PIC_ENABLE_CLR:
687 s->enabled &= ~value;
688 s->level &= ~value;
689 break;
691 mv88w8618_pic_update(s);
694 static void mv88w8618_pic_reset(DeviceState *d)
696 mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state,
697 sysbus_from_qdev(d));
699 s->level = 0;
700 s->enabled = 0;
703 static CPUReadMemoryFunc * const mv88w8618_pic_readfn[] = {
704 mv88w8618_pic_read,
705 mv88w8618_pic_read,
706 mv88w8618_pic_read
709 static CPUWriteMemoryFunc * const mv88w8618_pic_writefn[] = {
710 mv88w8618_pic_write,
711 mv88w8618_pic_write,
712 mv88w8618_pic_write
715 static int mv88w8618_pic_init(SysBusDevice *dev)
717 mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, dev);
718 int iomemtype;
720 qdev_init_gpio_in(&dev->qdev, mv88w8618_pic_set_irq, 32);
721 sysbus_init_irq(dev, &s->parent_irq);
722 iomemtype = cpu_register_io_memory(mv88w8618_pic_readfn,
723 mv88w8618_pic_writefn, s);
724 sysbus_init_mmio(dev, MP_PIC_SIZE, iomemtype);
725 return 0;
728 static const VMStateDescription mv88w8618_pic_vmsd = {
729 .name = "mv88w8618_pic",
730 .version_id = 1,
731 .minimum_version_id = 1,
732 .minimum_version_id_old = 1,
733 .fields = (VMStateField[]) {
734 VMSTATE_UINT32(level, mv88w8618_pic_state),
735 VMSTATE_UINT32(enabled, mv88w8618_pic_state),
736 VMSTATE_END_OF_LIST()
740 static SysBusDeviceInfo mv88w8618_pic_info = {
741 .init = mv88w8618_pic_init,
742 .qdev.name = "mv88w8618_pic",
743 .qdev.size = sizeof(mv88w8618_pic_state),
744 .qdev.reset = mv88w8618_pic_reset,
745 .qdev.vmsd = &mv88w8618_pic_vmsd,
748 /* PIT register offsets */
749 #define MP_PIT_TIMER1_LENGTH 0x00
750 /* ... */
751 #define MP_PIT_TIMER4_LENGTH 0x0C
752 #define MP_PIT_CONTROL 0x10
753 #define MP_PIT_TIMER1_VALUE 0x14
754 /* ... */
755 #define MP_PIT_TIMER4_VALUE 0x20
756 #define MP_BOARD_RESET 0x34
758 /* Magic board reset value (probably some watchdog behind it) */
759 #define MP_BOARD_RESET_MAGIC 0x10000
761 typedef struct mv88w8618_timer_state {
762 ptimer_state *ptimer;
763 uint32_t limit;
764 int freq;
765 qemu_irq irq;
766 } mv88w8618_timer_state;
768 typedef struct mv88w8618_pit_state {
769 SysBusDevice busdev;
770 mv88w8618_timer_state timer[4];
771 } mv88w8618_pit_state;
773 static void mv88w8618_timer_tick(void *opaque)
775 mv88w8618_timer_state *s = opaque;
777 qemu_irq_raise(s->irq);
780 static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
781 uint32_t freq)
783 QEMUBH *bh;
785 sysbus_init_irq(dev, &s->irq);
786 s->freq = freq;
788 bh = qemu_bh_new(mv88w8618_timer_tick, s);
789 s->ptimer = ptimer_init(bh);
792 static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset)
794 mv88w8618_pit_state *s = opaque;
795 mv88w8618_timer_state *t;
797 switch (offset) {
798 case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:
799 t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];
800 return ptimer_get_count(t->ptimer);
802 default:
803 return 0;
807 static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset,
808 uint32_t value)
810 mv88w8618_pit_state *s = opaque;
811 mv88w8618_timer_state *t;
812 int i;
814 switch (offset) {
815 case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
816 t = &s->timer[offset >> 2];
817 t->limit = value;
818 if (t->limit > 0) {
819 ptimer_set_limit(t->ptimer, t->limit, 1);
820 } else {
821 ptimer_stop(t->ptimer);
823 break;
825 case MP_PIT_CONTROL:
826 for (i = 0; i < 4; i++) {
827 t = &s->timer[i];
828 if (value & 0xf && t->limit > 0) {
829 ptimer_set_limit(t->ptimer, t->limit, 0);
830 ptimer_set_freq(t->ptimer, t->freq);
831 ptimer_run(t->ptimer, 0);
832 } else {
833 ptimer_stop(t->ptimer);
835 value >>= 4;
837 break;
839 case MP_BOARD_RESET:
840 if (value == MP_BOARD_RESET_MAGIC) {
841 qemu_system_reset_request();
843 break;
847 static void mv88w8618_pit_reset(DeviceState *d)
849 mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state,
850 sysbus_from_qdev(d));
851 int i;
853 for (i = 0; i < 4; i++) {
854 ptimer_stop(s->timer[i].ptimer);
855 s->timer[i].limit = 0;
859 static CPUReadMemoryFunc * const mv88w8618_pit_readfn[] = {
860 mv88w8618_pit_read,
861 mv88w8618_pit_read,
862 mv88w8618_pit_read
865 static CPUWriteMemoryFunc * const mv88w8618_pit_writefn[] = {
866 mv88w8618_pit_write,
867 mv88w8618_pit_write,
868 mv88w8618_pit_write
871 static int mv88w8618_pit_init(SysBusDevice *dev)
873 int iomemtype;
874 mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, dev);
875 int i;
877 /* Letting them all run at 1 MHz is likely just a pragmatic
878 * simplification. */
879 for (i = 0; i < 4; i++) {
880 mv88w8618_timer_init(dev, &s->timer[i], 1000000);
883 iomemtype = cpu_register_io_memory(mv88w8618_pit_readfn,
884 mv88w8618_pit_writefn, s);
885 sysbus_init_mmio(dev, MP_PIT_SIZE, iomemtype);
886 return 0;
889 static const VMStateDescription mv88w8618_timer_vmsd = {
890 .name = "timer",
891 .version_id = 1,
892 .minimum_version_id = 1,
893 .minimum_version_id_old = 1,
894 .fields = (VMStateField[]) {
895 VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
896 VMSTATE_UINT32(limit, mv88w8618_timer_state),
897 VMSTATE_END_OF_LIST()
901 static const VMStateDescription mv88w8618_pit_vmsd = {
902 .name = "mv88w8618_pit",
903 .version_id = 1,
904 .minimum_version_id = 1,
905 .minimum_version_id_old = 1,
906 .fields = (VMStateField[]) {
907 VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
908 mv88w8618_timer_vmsd, mv88w8618_timer_state),
909 VMSTATE_END_OF_LIST()
913 static SysBusDeviceInfo mv88w8618_pit_info = {
914 .init = mv88w8618_pit_init,
915 .qdev.name = "mv88w8618_pit",
916 .qdev.size = sizeof(mv88w8618_pit_state),
917 .qdev.reset = mv88w8618_pit_reset,
918 .qdev.vmsd = &mv88w8618_pit_vmsd,
921 /* Flash config register offsets */
922 #define MP_FLASHCFG_CFGR0 0x04
924 typedef struct mv88w8618_flashcfg_state {
925 SysBusDevice busdev;
926 uint32_t cfgr0;
927 } mv88w8618_flashcfg_state;
929 static uint32_t mv88w8618_flashcfg_read(void *opaque,
930 target_phys_addr_t offset)
932 mv88w8618_flashcfg_state *s = opaque;
934 switch (offset) {
935 case MP_FLASHCFG_CFGR0:
936 return s->cfgr0;
938 default:
939 return 0;
943 static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset,
944 uint32_t value)
946 mv88w8618_flashcfg_state *s = opaque;
948 switch (offset) {
949 case MP_FLASHCFG_CFGR0:
950 s->cfgr0 = value;
951 break;
955 static CPUReadMemoryFunc * const mv88w8618_flashcfg_readfn[] = {
956 mv88w8618_flashcfg_read,
957 mv88w8618_flashcfg_read,
958 mv88w8618_flashcfg_read
961 static CPUWriteMemoryFunc * const mv88w8618_flashcfg_writefn[] = {
962 mv88w8618_flashcfg_write,
963 mv88w8618_flashcfg_write,
964 mv88w8618_flashcfg_write
967 static int mv88w8618_flashcfg_init(SysBusDevice *dev)
969 int iomemtype;
970 mv88w8618_flashcfg_state *s = FROM_SYSBUS(mv88w8618_flashcfg_state, dev);
972 s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
973 iomemtype = cpu_register_io_memory(mv88w8618_flashcfg_readfn,
974 mv88w8618_flashcfg_writefn, s);
975 sysbus_init_mmio(dev, MP_FLASHCFG_SIZE, iomemtype);
976 return 0;
979 static const VMStateDescription mv88w8618_flashcfg_vmsd = {
980 .name = "mv88w8618_flashcfg",
981 .version_id = 1,
982 .minimum_version_id = 1,
983 .minimum_version_id_old = 1,
984 .fields = (VMStateField[]) {
985 VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
986 VMSTATE_END_OF_LIST()
990 static SysBusDeviceInfo mv88w8618_flashcfg_info = {
991 .init = mv88w8618_flashcfg_init,
992 .qdev.name = "mv88w8618_flashcfg",
993 .qdev.size = sizeof(mv88w8618_flashcfg_state),
994 .qdev.vmsd = &mv88w8618_flashcfg_vmsd,
997 /* Misc register offsets */
998 #define MP_MISC_BOARD_REVISION 0x18
1000 #define MP_BOARD_REVISION 0x31
1002 static uint32_t musicpal_misc_read(void *opaque, target_phys_addr_t offset)
1004 switch (offset) {
1005 case MP_MISC_BOARD_REVISION:
1006 return MP_BOARD_REVISION;
1008 default:
1009 return 0;
1013 static void musicpal_misc_write(void *opaque, target_phys_addr_t offset,
1014 uint32_t value)
1018 static CPUReadMemoryFunc * const musicpal_misc_readfn[] = {
1019 musicpal_misc_read,
1020 musicpal_misc_read,
1021 musicpal_misc_read,
1024 static CPUWriteMemoryFunc * const musicpal_misc_writefn[] = {
1025 musicpal_misc_write,
1026 musicpal_misc_write,
1027 musicpal_misc_write,
1030 static void musicpal_misc_init(void)
1032 int iomemtype;
1034 iomemtype = cpu_register_io_memory(musicpal_misc_readfn,
1035 musicpal_misc_writefn, NULL);
1036 cpu_register_physical_memory(MP_MISC_BASE, MP_MISC_SIZE, iomemtype);
1039 /* WLAN register offsets */
1040 #define MP_WLAN_MAGIC1 0x11c
1041 #define MP_WLAN_MAGIC2 0x124
1043 static uint32_t mv88w8618_wlan_read(void *opaque, target_phys_addr_t offset)
1045 switch (offset) {
1046 /* Workaround to allow loading the binary-only wlandrv.ko crap
1047 * from the original Freecom firmware. */
1048 case MP_WLAN_MAGIC1:
1049 return ~3;
1050 case MP_WLAN_MAGIC2:
1051 return -1;
1053 default:
1054 return 0;
1058 static void mv88w8618_wlan_write(void *opaque, target_phys_addr_t offset,
1059 uint32_t value)
1063 static CPUReadMemoryFunc * const mv88w8618_wlan_readfn[] = {
1064 mv88w8618_wlan_read,
1065 mv88w8618_wlan_read,
1066 mv88w8618_wlan_read,
1069 static CPUWriteMemoryFunc * const mv88w8618_wlan_writefn[] = {
1070 mv88w8618_wlan_write,
1071 mv88w8618_wlan_write,
1072 mv88w8618_wlan_write,
1075 static int mv88w8618_wlan_init(SysBusDevice *dev)
1077 int iomemtype;
1079 iomemtype = cpu_register_io_memory(mv88w8618_wlan_readfn,
1080 mv88w8618_wlan_writefn, NULL);
1081 sysbus_init_mmio(dev, MP_WLAN_SIZE, iomemtype);
1082 return 0;
1085 /* GPIO register offsets */
1086 #define MP_GPIO_OE_LO 0x008
1087 #define MP_GPIO_OUT_LO 0x00c
1088 #define MP_GPIO_IN_LO 0x010
1089 #define MP_GPIO_IER_LO 0x014
1090 #define MP_GPIO_IMR_LO 0x018
1091 #define MP_GPIO_ISR_LO 0x020
1092 #define MP_GPIO_OE_HI 0x508
1093 #define MP_GPIO_OUT_HI 0x50c
1094 #define MP_GPIO_IN_HI 0x510
1095 #define MP_GPIO_IER_HI 0x514
1096 #define MP_GPIO_IMR_HI 0x518
1097 #define MP_GPIO_ISR_HI 0x520
1099 /* GPIO bits & masks */
1100 #define MP_GPIO_LCD_BRIGHTNESS 0x00070000
1101 #define MP_GPIO_I2C_DATA_BIT 29
1102 #define MP_GPIO_I2C_CLOCK_BIT 30
1104 /* LCD brightness bits in GPIO_OE_HI */
1105 #define MP_OE_LCD_BRIGHTNESS 0x0007
1107 typedef struct musicpal_gpio_state {
1108 SysBusDevice busdev;
1109 uint32_t lcd_brightness;
1110 uint32_t out_state;
1111 uint32_t in_state;
1112 uint32_t ier;
1113 uint32_t imr;
1114 uint32_t isr;
1115 qemu_irq irq;
1116 qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */
1117 } musicpal_gpio_state;
1119 static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) {
1120 int i;
1121 uint32_t brightness;
1123 /* compute brightness ratio */
1124 switch (s->lcd_brightness) {
1125 case 0x00000007:
1126 brightness = 0;
1127 break;
1129 case 0x00020000:
1130 brightness = 1;
1131 break;
1133 case 0x00020001:
1134 brightness = 2;
1135 break;
1137 case 0x00040000:
1138 brightness = 3;
1139 break;
1141 case 0x00010006:
1142 brightness = 4;
1143 break;
1145 case 0x00020005:
1146 brightness = 5;
1147 break;
1149 case 0x00040003:
1150 brightness = 6;
1151 break;
1153 case 0x00030004:
1154 default:
1155 brightness = 7;
1158 /* set lcd brightness GPIOs */
1159 for (i = 0; i <= 2; i++) {
1160 qemu_set_irq(s->out[i], (brightness >> i) & 1);
1164 static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
1166 musicpal_gpio_state *s = opaque;
1167 uint32_t mask = 1 << pin;
1168 uint32_t delta = level << pin;
1169 uint32_t old = s->in_state & mask;
1171 s->in_state &= ~mask;
1172 s->in_state |= delta;
1174 if ((old ^ delta) &&
1175 ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) {
1176 s->isr = mask;
1177 qemu_irq_raise(s->irq);
1181 static uint32_t musicpal_gpio_read(void *opaque, target_phys_addr_t offset)
1183 musicpal_gpio_state *s = opaque;
1185 switch (offset) {
1186 case MP_GPIO_OE_HI: /* used for LCD brightness control */
1187 return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS;
1189 case MP_GPIO_OUT_LO:
1190 return s->out_state & 0xFFFF;
1191 case MP_GPIO_OUT_HI:
1192 return s->out_state >> 16;
1194 case MP_GPIO_IN_LO:
1195 return s->in_state & 0xFFFF;
1196 case MP_GPIO_IN_HI:
1197 return s->in_state >> 16;
1199 case MP_GPIO_IER_LO:
1200 return s->ier & 0xFFFF;
1201 case MP_GPIO_IER_HI:
1202 return s->ier >> 16;
1204 case MP_GPIO_IMR_LO:
1205 return s->imr & 0xFFFF;
1206 case MP_GPIO_IMR_HI:
1207 return s->imr >> 16;
1209 case MP_GPIO_ISR_LO:
1210 return s->isr & 0xFFFF;
1211 case MP_GPIO_ISR_HI:
1212 return s->isr >> 16;
1214 default:
1215 return 0;
1219 static void musicpal_gpio_write(void *opaque, target_phys_addr_t offset,
1220 uint32_t value)
1222 musicpal_gpio_state *s = opaque;
1223 switch (offset) {
1224 case MP_GPIO_OE_HI: /* used for LCD brightness control */
1225 s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |
1226 (value & MP_OE_LCD_BRIGHTNESS);
1227 musicpal_gpio_brightness_update(s);
1228 break;
1230 case MP_GPIO_OUT_LO:
1231 s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF);
1232 break;
1233 case MP_GPIO_OUT_HI:
1234 s->out_state = (s->out_state & 0xFFFF) | (value << 16);
1235 s->lcd_brightness = (s->lcd_brightness & 0xFFFF) |
1236 (s->out_state & MP_GPIO_LCD_BRIGHTNESS);
1237 musicpal_gpio_brightness_update(s);
1238 qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1);
1239 qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);
1240 break;
1242 case MP_GPIO_IER_LO:
1243 s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF);
1244 break;
1245 case MP_GPIO_IER_HI:
1246 s->ier = (s->ier & 0xFFFF) | (value << 16);
1247 break;
1249 case MP_GPIO_IMR_LO:
1250 s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF);
1251 break;
1252 case MP_GPIO_IMR_HI:
1253 s->imr = (s->imr & 0xFFFF) | (value << 16);
1254 break;
1258 static CPUReadMemoryFunc * const musicpal_gpio_readfn[] = {
1259 musicpal_gpio_read,
1260 musicpal_gpio_read,
1261 musicpal_gpio_read,
1264 static CPUWriteMemoryFunc * const musicpal_gpio_writefn[] = {
1265 musicpal_gpio_write,
1266 musicpal_gpio_write,
1267 musicpal_gpio_write,
1270 static void musicpal_gpio_reset(DeviceState *d)
1272 musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state,
1273 sysbus_from_qdev(d));
1275 s->lcd_brightness = 0;
1276 s->out_state = 0;
1277 s->in_state = 0xffffffff;
1278 s->ier = 0;
1279 s->imr = 0;
1280 s->isr = 0;
1283 static int musicpal_gpio_init(SysBusDevice *dev)
1285 musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, dev);
1286 int iomemtype;
1288 sysbus_init_irq(dev, &s->irq);
1290 iomemtype = cpu_register_io_memory(musicpal_gpio_readfn,
1291 musicpal_gpio_writefn, s);
1292 sysbus_init_mmio(dev, MP_GPIO_SIZE, iomemtype);
1294 musicpal_gpio_reset(&dev->qdev);
1296 qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
1298 qdev_init_gpio_in(&dev->qdev, musicpal_gpio_pin_event, 32);
1300 return 0;
1303 static const VMStateDescription musicpal_gpio_vmsd = {
1304 .name = "musicpal_gpio",
1305 .version_id = 1,
1306 .minimum_version_id = 1,
1307 .minimum_version_id_old = 1,
1308 .fields = (VMStateField[]) {
1309 VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
1310 VMSTATE_UINT32(out_state, musicpal_gpio_state),
1311 VMSTATE_UINT32(in_state, musicpal_gpio_state),
1312 VMSTATE_UINT32(ier, musicpal_gpio_state),
1313 VMSTATE_UINT32(imr, musicpal_gpio_state),
1314 VMSTATE_UINT32(isr, musicpal_gpio_state),
1315 VMSTATE_END_OF_LIST()
1319 static SysBusDeviceInfo musicpal_gpio_info = {
1320 .init = musicpal_gpio_init,
1321 .qdev.name = "musicpal_gpio",
1322 .qdev.size = sizeof(musicpal_gpio_state),
1323 .qdev.reset = musicpal_gpio_reset,
1324 .qdev.vmsd = &musicpal_gpio_vmsd,
1327 /* Keyboard codes & masks */
1328 #define KEY_RELEASED 0x80
1329 #define KEY_CODE 0x7f
1331 #define KEYCODE_TAB 0x0f
1332 #define KEYCODE_ENTER 0x1c
1333 #define KEYCODE_F 0x21
1334 #define KEYCODE_M 0x32
1336 #define KEYCODE_EXTENDED 0xe0
1337 #define KEYCODE_UP 0x48
1338 #define KEYCODE_DOWN 0x50
1339 #define KEYCODE_LEFT 0x4b
1340 #define KEYCODE_RIGHT 0x4d
1342 #define MP_KEY_WHEEL_VOL (1 << 0)
1343 #define MP_KEY_WHEEL_VOL_INV (1 << 1)
1344 #define MP_KEY_WHEEL_NAV (1 << 2)
1345 #define MP_KEY_WHEEL_NAV_INV (1 << 3)
1346 #define MP_KEY_BTN_FAVORITS (1 << 4)
1347 #define MP_KEY_BTN_MENU (1 << 5)
1348 #define MP_KEY_BTN_VOLUME (1 << 6)
1349 #define MP_KEY_BTN_NAVIGATION (1 << 7)
1351 typedef struct musicpal_key_state {
1352 SysBusDevice busdev;
1353 uint32_t kbd_extended;
1354 uint32_t pressed_keys;
1355 qemu_irq out[8];
1356 } musicpal_key_state;
1358 static void musicpal_key_event(void *opaque, int keycode)
1360 musicpal_key_state *s = opaque;
1361 uint32_t event = 0;
1362 int i;
1364 if (keycode == KEYCODE_EXTENDED) {
1365 s->kbd_extended = 1;
1366 return;
1369 if (s->kbd_extended) {
1370 switch (keycode & KEY_CODE) {
1371 case KEYCODE_UP:
1372 event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV;
1373 break;
1375 case KEYCODE_DOWN:
1376 event = MP_KEY_WHEEL_NAV;
1377 break;
1379 case KEYCODE_LEFT:
1380 event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV;
1381 break;
1383 case KEYCODE_RIGHT:
1384 event = MP_KEY_WHEEL_VOL;
1385 break;
1387 } else {
1388 switch (keycode & KEY_CODE) {
1389 case KEYCODE_F:
1390 event = MP_KEY_BTN_FAVORITS;
1391 break;
1393 case KEYCODE_TAB:
1394 event = MP_KEY_BTN_VOLUME;
1395 break;
1397 case KEYCODE_ENTER:
1398 event = MP_KEY_BTN_NAVIGATION;
1399 break;
1401 case KEYCODE_M:
1402 event = MP_KEY_BTN_MENU;
1403 break;
1405 /* Do not repeat already pressed buttons */
1406 if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
1407 event = 0;
1411 if (event) {
1412 /* Raise GPIO pin first if repeating a key */
1413 if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
1414 for (i = 0; i <= 7; i++) {
1415 if (event & (1 << i)) {
1416 qemu_set_irq(s->out[i], 1);
1420 for (i = 0; i <= 7; i++) {
1421 if (event & (1 << i)) {
1422 qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED));
1425 if (keycode & KEY_RELEASED) {
1426 s->pressed_keys &= ~event;
1427 } else {
1428 s->pressed_keys |= event;
1432 s->kbd_extended = 0;
1435 static int musicpal_key_init(SysBusDevice *dev)
1437 musicpal_key_state *s = FROM_SYSBUS(musicpal_key_state, dev);
1439 sysbus_init_mmio(dev, 0x0, 0);
1441 s->kbd_extended = 0;
1442 s->pressed_keys = 0;
1444 qdev_init_gpio_out(&dev->qdev, s->out, ARRAY_SIZE(s->out));
1446 qemu_add_kbd_event_handler(musicpal_key_event, s);
1448 return 0;
1451 static const VMStateDescription musicpal_key_vmsd = {
1452 .name = "musicpal_key",
1453 .version_id = 1,
1454 .minimum_version_id = 1,
1455 .minimum_version_id_old = 1,
1456 .fields = (VMStateField[]) {
1457 VMSTATE_UINT32(kbd_extended, musicpal_key_state),
1458 VMSTATE_UINT32(pressed_keys, musicpal_key_state),
1459 VMSTATE_END_OF_LIST()
1463 static SysBusDeviceInfo musicpal_key_info = {
1464 .init = musicpal_key_init,
1465 .qdev.name = "musicpal_key",
1466 .qdev.size = sizeof(musicpal_key_state),
1467 .qdev.vmsd = &musicpal_key_vmsd,
1470 static struct arm_boot_info musicpal_binfo = {
1471 .loader_start = 0x0,
1472 .board_id = 0x20e,
1475 static void musicpal_init(ram_addr_t ram_size,
1476 const char *boot_device,
1477 const char *kernel_filename, const char *kernel_cmdline,
1478 const char *initrd_filename, const char *cpu_model)
1480 CPUState *env;
1481 qemu_irq *cpu_pic;
1482 qemu_irq pic[32];
1483 DeviceState *dev;
1484 DeviceState *i2c_dev;
1485 DeviceState *lcd_dev;
1486 DeviceState *key_dev;
1487 #ifdef HAS_AUDIO
1488 DeviceState *wm8750_dev;
1489 SysBusDevice *s;
1490 #endif
1491 i2c_bus *i2c;
1492 int i;
1493 unsigned long flash_size;
1494 DriveInfo *dinfo;
1495 ram_addr_t sram_off;
1497 if (!cpu_model) {
1498 cpu_model = "arm926";
1500 env = cpu_init(cpu_model);
1501 if (!env) {
1502 fprintf(stderr, "Unable to find CPU definition\n");
1503 exit(1);
1505 cpu_pic = arm_pic_init_cpu(env);
1507 /* For now we use a fixed - the original - RAM size */
1508 cpu_register_physical_memory(0, MP_RAM_DEFAULT_SIZE,
1509 qemu_ram_alloc(MP_RAM_DEFAULT_SIZE));
1511 sram_off = qemu_ram_alloc(MP_SRAM_SIZE);
1512 cpu_register_physical_memory(MP_SRAM_BASE, MP_SRAM_SIZE, sram_off);
1514 dev = sysbus_create_simple("mv88w8618_pic", MP_PIC_BASE,
1515 cpu_pic[ARM_PIC_CPU_IRQ]);
1516 for (i = 0; i < 32; i++) {
1517 pic[i] = qdev_get_gpio_in(dev, i);
1519 sysbus_create_varargs("mv88w8618_pit", MP_PIT_BASE, pic[MP_TIMER1_IRQ],
1520 pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ],
1521 pic[MP_TIMER4_IRQ], NULL);
1523 if (serial_hds[0]) {
1524 serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], 1825000,
1525 serial_hds[0], 1);
1527 if (serial_hds[1]) {
1528 serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], 1825000,
1529 serial_hds[1], 1);
1532 /* Register flash */
1533 dinfo = drive_get(IF_PFLASH, 0, 0);
1534 if (dinfo) {
1535 flash_size = bdrv_getlength(dinfo->bdrv);
1536 if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
1537 flash_size != 32*1024*1024) {
1538 fprintf(stderr, "Invalid flash image size\n");
1539 exit(1);
1543 * The original U-Boot accesses the flash at 0xFE000000 instead of
1544 * 0xFF800000 (if there is 8 MB flash). So remap flash access if the
1545 * image is smaller than 32 MB.
1547 pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(flash_size),
1548 dinfo->bdrv, 0x10000,
1549 (flash_size + 0xffff) >> 16,
1550 MP_FLASH_SIZE_MAX / flash_size,
1551 2, 0x00BF, 0x236D, 0x0000, 0x0000,
1552 0x5555, 0x2AAA);
1554 sysbus_create_simple("mv88w8618_flashcfg", MP_FLASHCFG_BASE, NULL);
1556 qemu_check_nic_model(&nd_table[0], "mv88w8618");
1557 dev = qdev_create(NULL, "mv88w8618_eth");
1558 qdev_set_nic_properties(dev, &nd_table[0]);
1559 qdev_init_nofail(dev);
1560 sysbus_mmio_map(sysbus_from_qdev(dev), 0, MP_ETH_BASE);
1561 sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[MP_ETH_IRQ]);
1563 sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
1565 musicpal_misc_init();
1567 dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]);
1568 i2c_dev = sysbus_create_simple("bitbang_i2c", 0, NULL);
1569 i2c = (i2c_bus *)qdev_get_child_bus(i2c_dev, "i2c");
1571 lcd_dev = sysbus_create_simple("musicpal_lcd", MP_LCD_BASE, NULL);
1572 key_dev = sysbus_create_simple("musicpal_key", 0, NULL);
1574 /* I2C read data */
1575 qdev_connect_gpio_out(i2c_dev, 0,
1576 qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT));
1577 /* I2C data */
1578 qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0));
1579 /* I2C clock */
1580 qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1));
1582 for (i = 0; i < 3; i++) {
1583 qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i));
1585 for (i = 0; i < 4; i++) {
1586 qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8));
1588 for (i = 4; i < 8; i++) {
1589 qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15));
1592 #ifdef HAS_AUDIO
1593 wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR);
1594 dev = qdev_create(NULL, "mv88w8618_audio");
1595 s = sysbus_from_qdev(dev);
1596 qdev_prop_set_ptr(dev, "wm8750", wm8750_dev);
1597 qdev_init_nofail(dev);
1598 sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
1599 sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
1600 #endif
1602 musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
1603 musicpal_binfo.kernel_filename = kernel_filename;
1604 musicpal_binfo.kernel_cmdline = kernel_cmdline;
1605 musicpal_binfo.initrd_filename = initrd_filename;
1606 arm_load_kernel(env, &musicpal_binfo);
1609 static QEMUMachine musicpal_machine = {
1610 .name = "musicpal",
1611 .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)",
1612 .init = musicpal_init,
1615 static void musicpal_machine_init(void)
1617 qemu_register_machine(&musicpal_machine);
1620 machine_init(musicpal_machine_init);
1622 static void musicpal_register_devices(void)
1624 sysbus_register_withprop(&mv88w8618_pic_info);
1625 sysbus_register_withprop(&mv88w8618_pit_info);
1626 sysbus_register_withprop(&mv88w8618_flashcfg_info);
1627 sysbus_register_withprop(&mv88w8618_eth_info);
1628 sysbus_register_dev("mv88w8618_wlan", sizeof(SysBusDevice),
1629 mv88w8618_wlan_init);
1630 sysbus_register_withprop(&musicpal_lcd_info);
1631 sysbus_register_withprop(&musicpal_gpio_info);
1632 sysbus_register_withprop(&musicpal_key_info);
1635 device_init(musicpal_register_devices)