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