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 "cpu.h" 16 #include "hw/sysbus.h" 17 #include "migration/vmstate.h" 18 #include "hw/arm/boot.h" 19 #include "net/net.h" 20 #include "sysemu/sysemu.h" 21 #include "hw/boards.h" 22 #include "hw/char/serial.h" 23 #include "qemu/timer.h" 24 #include "hw/ptimer.h" 25 #include "hw/qdev-properties.h" 26 #include "hw/block/flash.h" 27 #include "ui/console.h" 28 #include "hw/i2c/i2c.h" 29 #include "hw/i2c/bitbang_i2c.h" 30 #include "hw/irq.h" 31 #include "hw/or-irq.h" 32 #include "hw/audio/wm8750.h" 33 #include "sysemu/block-backend.h" 34 #include "sysemu/runstate.h" 35 #include "sysemu/dma.h" 36 #include "ui/pixel_ops.h" 37 #include "qemu/cutils.h" 38 #include "qom/object.h" 39 #include "hw/net/mv88w8618_eth.h" 40 #include "qemu/error-report.h" 41 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 = (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 = (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 = (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 = (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 = (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 = (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 KEY_RELEASED 0x80 1047 #define KEY_CODE 0x7f 1048 1049 #define KEYCODE_TAB 0x0f 1050 #define KEYCODE_ENTER 0x1c 1051 #define KEYCODE_F 0x21 1052 #define KEYCODE_M 0x32 1053 1054 #define KEYCODE_EXTENDED 0xe0 1055 #define KEYCODE_UP 0x48 1056 #define KEYCODE_DOWN 0x50 1057 #define KEYCODE_LEFT 0x4b 1058 #define KEYCODE_RIGHT 0x4d 1059 1060 #define MP_KEY_WHEEL_VOL (1 << 0) 1061 #define MP_KEY_WHEEL_VOL_INV (1 << 1) 1062 #define MP_KEY_WHEEL_NAV (1 << 2) 1063 #define MP_KEY_WHEEL_NAV_INV (1 << 3) 1064 #define MP_KEY_BTN_FAVORITS (1 << 4) 1065 #define MP_KEY_BTN_MENU (1 << 5) 1066 #define MP_KEY_BTN_VOLUME (1 << 6) 1067 #define MP_KEY_BTN_NAVIGATION (1 << 7) 1068 1069 #define TYPE_MUSICPAL_KEY "musicpal_key" 1070 OBJECT_DECLARE_SIMPLE_TYPE(musicpal_key_state, MUSICPAL_KEY) 1071 1072 struct musicpal_key_state { 1073 /*< private >*/ 1074 SysBusDevice parent_obj; 1075 /*< public >*/ 1076 1077 uint32_t kbd_extended; 1078 uint32_t pressed_keys; 1079 qemu_irq out[8]; 1080 }; 1081 1082 static void musicpal_key_event(void *opaque, int keycode) 1083 { 1084 musicpal_key_state *s = opaque; 1085 uint32_t event = 0; 1086 int i; 1087 1088 if (keycode == KEYCODE_EXTENDED) { 1089 s->kbd_extended = 1; 1090 return; 1091 } 1092 1093 if (s->kbd_extended) { 1094 switch (keycode & KEY_CODE) { 1095 case KEYCODE_UP: 1096 event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV; 1097 break; 1098 1099 case KEYCODE_DOWN: 1100 event = MP_KEY_WHEEL_NAV; 1101 break; 1102 1103 case KEYCODE_LEFT: 1104 event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV; 1105 break; 1106 1107 case KEYCODE_RIGHT: 1108 event = MP_KEY_WHEEL_VOL; 1109 break; 1110 } 1111 } else { 1112 switch (keycode & KEY_CODE) { 1113 case KEYCODE_F: 1114 event = MP_KEY_BTN_FAVORITS; 1115 break; 1116 1117 case KEYCODE_TAB: 1118 event = MP_KEY_BTN_VOLUME; 1119 break; 1120 1121 case KEYCODE_ENTER: 1122 event = MP_KEY_BTN_NAVIGATION; 1123 break; 1124 1125 case KEYCODE_M: 1126 event = MP_KEY_BTN_MENU; 1127 break; 1128 } 1129 /* Do not repeat already pressed buttons */ 1130 if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { 1131 event = 0; 1132 } 1133 } 1134 1135 if (event) { 1136 /* Raise GPIO pin first if repeating a key */ 1137 if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) { 1138 for (i = 0; i <= 7; i++) { 1139 if (event & (1 << i)) { 1140 qemu_set_irq(s->out[i], 1); 1141 } 1142 } 1143 } 1144 for (i = 0; i <= 7; i++) { 1145 if (event & (1 << i)) { 1146 qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED)); 1147 } 1148 } 1149 if (keycode & KEY_RELEASED) { 1150 s->pressed_keys &= ~event; 1151 } else { 1152 s->pressed_keys |= event; 1153 } 1154 } 1155 1156 s->kbd_extended = 0; 1157 } 1158 1159 static void musicpal_key_init(Object *obj) 1160 { 1161 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 1162 DeviceState *dev = DEVICE(sbd); 1163 musicpal_key_state *s = MUSICPAL_KEY(dev); 1164 1165 s->kbd_extended = 0; 1166 s->pressed_keys = 0; 1167 1168 qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out)); 1169 1170 qemu_add_kbd_event_handler(musicpal_key_event, s); 1171 } 1172 1173 static const VMStateDescription musicpal_key_vmsd = { 1174 .name = "musicpal_key", 1175 .version_id = 1, 1176 .minimum_version_id = 1, 1177 .fields = (VMStateField[]) { 1178 VMSTATE_UINT32(kbd_extended, musicpal_key_state), 1179 VMSTATE_UINT32(pressed_keys, musicpal_key_state), 1180 VMSTATE_END_OF_LIST() 1181 } 1182 }; 1183 1184 static void musicpal_key_class_init(ObjectClass *klass, void *data) 1185 { 1186 DeviceClass *dc = DEVICE_CLASS(klass); 1187 1188 dc->vmsd = &musicpal_key_vmsd; 1189 } 1190 1191 static const TypeInfo musicpal_key_info = { 1192 .name = TYPE_MUSICPAL_KEY, 1193 .parent = TYPE_SYS_BUS_DEVICE, 1194 .instance_size = sizeof(musicpal_key_state), 1195 .instance_init = musicpal_key_init, 1196 .class_init = musicpal_key_class_init, 1197 }; 1198 1199 #define FLASH_SECTOR_SIZE (64 * KiB) 1200 1201 static struct arm_boot_info musicpal_binfo = { 1202 .loader_start = 0x0, 1203 .board_id = 0x20e, 1204 }; 1205 1206 static void musicpal_init(MachineState *machine) 1207 { 1208 ARMCPU *cpu; 1209 DeviceState *dev; 1210 DeviceState *pic; 1211 DeviceState *uart_orgate; 1212 DeviceState *i2c_dev; 1213 DeviceState *lcd_dev; 1214 DeviceState *key_dev; 1215 I2CSlave *wm8750_dev; 1216 SysBusDevice *s; 1217 I2CBus *i2c; 1218 int i; 1219 unsigned long flash_size; 1220 DriveInfo *dinfo; 1221 MachineClass *mc = MACHINE_GET_CLASS(machine); 1222 MemoryRegion *address_space_mem = get_system_memory(); 1223 MemoryRegion *sram = g_new(MemoryRegion, 1); 1224 1225 /* For now we use a fixed - the original - RAM size */ 1226 if (machine->ram_size != mc->default_ram_size) { 1227 char *sz = size_to_str(mc->default_ram_size); 1228 error_report("Invalid RAM size, should be %s", sz); 1229 g_free(sz); 1230 exit(EXIT_FAILURE); 1231 } 1232 1233 cpu = ARM_CPU(cpu_create(machine->cpu_type)); 1234 1235 memory_region_add_subregion(address_space_mem, 0, machine->ram); 1236 1237 memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE, 1238 &error_fatal); 1239 memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram); 1240 1241 pic = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE, 1242 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ)); 1243 sysbus_create_varargs(TYPE_MV88W8618_PIT, MP_PIT_BASE, 1244 qdev_get_gpio_in(pic, MP_TIMER1_IRQ), 1245 qdev_get_gpio_in(pic, MP_TIMER2_IRQ), 1246 qdev_get_gpio_in(pic, MP_TIMER3_IRQ), 1247 qdev_get_gpio_in(pic, MP_TIMER4_IRQ), NULL); 1248 1249 /* Logically OR both UART IRQs together */ 1250 uart_orgate = DEVICE(object_new(TYPE_OR_IRQ)); 1251 object_property_set_int(OBJECT(uart_orgate), "num-lines", 2, &error_fatal); 1252 qdev_realize_and_unref(uart_orgate, NULL, &error_fatal); 1253 qdev_connect_gpio_out(DEVICE(uart_orgate), 0, 1254 qdev_get_gpio_in(pic, MP_UART_SHARED_IRQ)); 1255 1256 serial_mm_init(address_space_mem, MP_UART1_BASE, 2, 1257 qdev_get_gpio_in(uart_orgate, 0), 1258 1825000, serial_hd(0), DEVICE_NATIVE_ENDIAN); 1259 serial_mm_init(address_space_mem, MP_UART2_BASE, 2, 1260 qdev_get_gpio_in(uart_orgate, 1), 1261 1825000, serial_hd(1), DEVICE_NATIVE_ENDIAN); 1262 1263 /* Register flash */ 1264 dinfo = drive_get(IF_PFLASH, 0, 0); 1265 if (dinfo) { 1266 BlockBackend *blk = blk_by_legacy_dinfo(dinfo); 1267 1268 flash_size = blk_getlength(blk); 1269 if (flash_size != 8 * MiB && flash_size != 16 * MiB && 1270 flash_size != 32 * MiB) { 1271 error_report("Invalid flash image size"); 1272 exit(1); 1273 } 1274 1275 /* 1276 * The original U-Boot accesses the flash at 0xFE000000 instead of 1277 * 0xFF800000 (if there is 8 MB flash). So remap flash access if the 1278 * image is smaller than 32 MB. 1279 */ 1280 pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX, 1281 "musicpal.flash", flash_size, 1282 blk, FLASH_SECTOR_SIZE, 1283 MP_FLASH_SIZE_MAX / flash_size, 1284 2, 0x00BF, 0x236D, 0x0000, 0x0000, 1285 0x5555, 0x2AAA, 0); 1286 } 1287 sysbus_create_simple(TYPE_MV88W8618_FLASHCFG, MP_FLASHCFG_BASE, NULL); 1288 1289 qemu_check_nic_model(&nd_table[0], "mv88w8618"); 1290 dev = qdev_new(TYPE_MV88W8618_ETH); 1291 qdev_set_nic_properties(dev, &nd_table[0]); 1292 object_property_set_link(OBJECT(dev), "dma-memory", 1293 OBJECT(get_system_memory()), &error_fatal); 1294 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 1295 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE); 1296 sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, 1297 qdev_get_gpio_in(pic, MP_ETH_IRQ)); 1298 1299 sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL); 1300 1301 sysbus_create_simple(TYPE_MUSICPAL_MISC, MP_MISC_BASE, NULL); 1302 1303 dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE, 1304 qdev_get_gpio_in(pic, MP_GPIO_IRQ)); 1305 i2c_dev = sysbus_create_simple(TYPE_GPIO_I2C, -1, NULL); 1306 i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c"); 1307 1308 lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL); 1309 key_dev = sysbus_create_simple(TYPE_MUSICPAL_KEY, -1, NULL); 1310 1311 /* I2C read data */ 1312 qdev_connect_gpio_out(i2c_dev, 0, 1313 qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT)); 1314 /* I2C data */ 1315 qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0)); 1316 /* I2C clock */ 1317 qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1)); 1318 1319 for (i = 0; i < 3; i++) { 1320 qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i)); 1321 } 1322 for (i = 0; i < 4; i++) { 1323 qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8)); 1324 } 1325 for (i = 4; i < 8; i++) { 1326 qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15)); 1327 } 1328 1329 wm8750_dev = i2c_slave_create_simple(i2c, TYPE_WM8750, MP_WM_ADDR); 1330 dev = qdev_new(TYPE_MV88W8618_AUDIO); 1331 s = SYS_BUS_DEVICE(dev); 1332 object_property_set_link(OBJECT(dev), "wm8750", OBJECT(wm8750_dev), 1333 NULL); 1334 sysbus_realize_and_unref(s, &error_fatal); 1335 sysbus_mmio_map(s, 0, MP_AUDIO_BASE); 1336 sysbus_connect_irq(s, 0, qdev_get_gpio_in(pic, MP_AUDIO_IRQ)); 1337 1338 musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE; 1339 arm_load_kernel(cpu, machine, &musicpal_binfo); 1340 } 1341 1342 static void musicpal_machine_init(MachineClass *mc) 1343 { 1344 mc->desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)"; 1345 mc->init = musicpal_init; 1346 mc->ignore_memory_transaction_failures = true; 1347 mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926"); 1348 mc->default_ram_size = MP_RAM_DEFAULT_SIZE; 1349 mc->default_ram_id = "musicpal.ram"; 1350 } 1351 1352 DEFINE_MACHINE("musicpal", musicpal_machine_init) 1353 1354 static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data) 1355 { 1356 DeviceClass *dc = DEVICE_CLASS(klass); 1357 1358 dc->realize = mv88w8618_wlan_realize; 1359 } 1360 1361 static const TypeInfo mv88w8618_wlan_info = { 1362 .name = "mv88w8618_wlan", 1363 .parent = TYPE_SYS_BUS_DEVICE, 1364 .instance_size = sizeof(SysBusDevice), 1365 .class_init = mv88w8618_wlan_class_init, 1366 }; 1367 1368 static void musicpal_register_types(void) 1369 { 1370 type_register_static(&mv88w8618_pic_info); 1371 type_register_static(&mv88w8618_pit_info); 1372 type_register_static(&mv88w8618_flashcfg_info); 1373 type_register_static(&mv88w8618_wlan_info); 1374 type_register_static(&musicpal_lcd_info); 1375 type_register_static(&musicpal_gpio_info); 1376 type_register_static(&musicpal_key_info); 1377 type_register_static(&musicpal_misc_info); 1378 } 1379 1380 type_init(musicpal_register_types) 1381