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