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