qemu/hw/arm/musicpal.c
<<
>>
Prefs
   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 "hw/arm/boot.h"
  17#include "net/net.h"
  18#include "sysemu/sysemu.h"
  19#include "hw/boards.h"
  20#include "hw/char/serial.h"
  21#include "qemu/timer.h"
  22#include "hw/ptimer.h"
  23#include "hw/block/flash.h"
  24#include "ui/console.h"
  25#include "hw/i2c/i2c.h"
  26#include "hw/audio/wm8750.h"
  27#include "sysemu/block-backend.h"
  28#include "exec/address-spaces.h"
  29#include "ui/pixel_ops.h"
  30
  31#define MP_MISC_BASE            0x80002000
  32#define MP_MISC_SIZE            0x00001000
  33
  34#define MP_ETH_BASE             0x80008000
  35#define MP_ETH_SIZE             0x00001000
  36
  37#define MP_WLAN_BASE            0x8000C000
  38#define MP_WLAN_SIZE            0x00000800
  39
  40#define MP_UART1_BASE           0x8000C840
  41#define MP_UART2_BASE           0x8000C940
  42
  43#define MP_GPIO_BASE            0x8000D000
  44#define MP_GPIO_SIZE            0x00001000
  45
  46#define MP_FLASHCFG_BASE        0x90006000
  47#define MP_FLASHCFG_SIZE        0x00001000
  48
  49#define MP_AUDIO_BASE           0x90007000
  50
  51#define MP_PIC_BASE             0x90008000
  52#define MP_PIC_SIZE             0x00001000
  53
  54#define MP_PIT_BASE             0x90009000
  55#define MP_PIT_SIZE             0x00001000
  56
  57#define MP_LCD_BASE             0x9000c000
  58#define MP_LCD_SIZE             0x00001000
  59
  60#define MP_SRAM_BASE            0xC0000000
  61#define MP_SRAM_SIZE            0x00020000
  62
  63#define MP_RAM_DEFAULT_SIZE     32*1024*1024
  64#define MP_FLASH_SIZE_MAX       32*1024*1024
  65
  66#define MP_TIMER1_IRQ           4
  67#define MP_TIMER2_IRQ           5
  68#define MP_TIMER3_IRQ           6
  69#define MP_TIMER4_IRQ           7
  70#define MP_EHCI_IRQ             8
  71#define MP_ETH_IRQ              9
  72#define MP_UART1_IRQ            11
  73#define MP_UART2_IRQ            11
  74#define MP_GPIO_IRQ             12
  75#define MP_RTC_IRQ              28
  76#define MP_AUDIO_IRQ            30
  77
  78/* Wolfson 8750 I2C address */
  79#define MP_WM_ADDR              0x1A
  80
  81/* Ethernet register offsets */
  82#define MP_ETH_SMIR             0x010
  83#define MP_ETH_PCXR             0x408
  84#define MP_ETH_SDCMR            0x448
  85#define MP_ETH_ICR              0x450
  86#define MP_ETH_IMR              0x458
  87#define MP_ETH_FRDP0            0x480
  88#define MP_ETH_FRDP1            0x484
  89#define MP_ETH_FRDP2            0x488
  90#define MP_ETH_FRDP3            0x48C
  91#define MP_ETH_CRDP0            0x4A0
  92#define MP_ETH_CRDP1            0x4A4
  93#define MP_ETH_CRDP2            0x4A8
  94#define MP_ETH_CRDP3            0x4AC
  95#define MP_ETH_CTDP0            0x4E0
  96#define MP_ETH_CTDP1            0x4E4
  97
  98/* MII PHY access */
  99#define MP_ETH_SMIR_DATA        0x0000FFFF
 100#define MP_ETH_SMIR_ADDR        0x03FF0000
 101#define MP_ETH_SMIR_OPCODE      (1 << 26) /* Read value */
 102#define MP_ETH_SMIR_RDVALID     (1 << 27)
 103
 104/* PHY registers */
 105#define MP_ETH_PHY1_BMSR        0x00210000
 106#define MP_ETH_PHY1_PHYSID1     0x00410000
 107#define MP_ETH_PHY1_PHYSID2     0x00610000
 108
 109#define MP_PHY_BMSR_LINK        0x0004
 110#define MP_PHY_BMSR_AUTONEG     0x0008
 111
 112#define MP_PHY_88E3015          0x01410E20
 113
 114/* TX descriptor status */
 115#define MP_ETH_TX_OWN           (1U << 31)
 116
 117/* RX descriptor status */
 118#define MP_ETH_RX_OWN           (1U << 31)
 119
 120/* Interrupt cause/mask bits */
 121#define MP_ETH_IRQ_RX_BIT       0
 122#define MP_ETH_IRQ_RX           (1 << MP_ETH_IRQ_RX_BIT)
 123#define MP_ETH_IRQ_TXHI_BIT     2
 124#define MP_ETH_IRQ_TXLO_BIT     3
 125
 126/* Port config bits */
 127#define MP_ETH_PCXR_2BSM_BIT    28 /* 2-byte incoming suffix */
 128
 129/* SDMA command bits */
 130#define MP_ETH_CMD_TXHI         (1 << 23)
 131#define MP_ETH_CMD_TXLO         (1 << 22)
 132
 133typedef struct mv88w8618_tx_desc {
 134    uint32_t cmdstat;
 135    uint16_t res;
 136    uint16_t bytes;
 137    uint32_t buffer;
 138    uint32_t next;
 139} mv88w8618_tx_desc;
 140
 141typedef struct mv88w8618_rx_desc {
 142    uint32_t cmdstat;
 143    uint16_t bytes;
 144    uint16_t buffer_size;
 145    uint32_t buffer;
 146    uint32_t next;
 147} mv88w8618_rx_desc;
 148
 149#define TYPE_MV88W8618_ETH "mv88w8618_eth"
 150#define MV88W8618_ETH(obj) \
 151    OBJECT_CHECK(mv88w8618_eth_state, (obj), TYPE_MV88W8618_ETH)
 152
 153typedef struct mv88w8618_eth_state {
 154    /*< private >*/
 155    SysBusDevice parent_obj;
 156    /*< public >*/
 157
 158    MemoryRegion iomem;
 159    qemu_irq irq;
 160    uint32_t smir;
 161    uint32_t icr;
 162    uint32_t imr;
 163    int mmio_index;
 164    uint32_t vlan_header;
 165    uint32_t tx_queue[2];
 166    uint32_t rx_queue[4];
 167    uint32_t frx_queue[4];
 168    uint32_t cur_rx[4];
 169    NICState *nic;
 170    NICConf conf;
 171} mv88w8618_eth_state;
 172
 173static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc)
 174{
 175    cpu_to_le32s(&desc->cmdstat);
 176    cpu_to_le16s(&desc->bytes);
 177    cpu_to_le16s(&desc->buffer_size);
 178    cpu_to_le32s(&desc->buffer);
 179    cpu_to_le32s(&desc->next);
 180    cpu_physical_memory_write(addr, desc, sizeof(*desc));
 181}
 182
 183static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
 184{
 185    cpu_physical_memory_read(addr, desc, sizeof(*desc));
 186    le32_to_cpus(&desc->cmdstat);
 187    le16_to_cpus(&desc->bytes);
 188    le16_to_cpus(&desc->buffer_size);
 189    le32_to_cpus(&desc->buffer);
 190    le32_to_cpus(&desc->next);
 191}
 192
 193static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
 194{
 195    mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
 196    uint32_t desc_addr;
 197    mv88w8618_rx_desc desc;
 198    int i;
 199
 200    for (i = 0; i < 4; i++) {
 201        desc_addr = s->cur_rx[i];
 202        if (!desc_addr) {
 203            continue;
 204        }
 205        do {
 206            eth_rx_desc_get(desc_addr, &desc);
 207            if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) {
 208                cpu_physical_memory_write(desc.buffer + s->vlan_header,
 209                                          buf, size);
 210                desc.bytes = size + s->vlan_header;
 211                desc.cmdstat &= ~MP_ETH_RX_OWN;
 212                s->cur_rx[i] = desc.next;
 213
 214                s->icr |= MP_ETH_IRQ_RX;
 215                if (s->icr & s->imr) {
 216                    qemu_irq_raise(s->irq);
 217                }
 218                eth_rx_desc_put(desc_addr, &desc);
 219                return size;
 220            }
 221            desc_addr = desc.next;
 222        } while (desc_addr != s->rx_queue[i]);
 223    }
 224    return size;
 225}
 226
 227static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc)
 228{
 229    cpu_to_le32s(&desc->cmdstat);
 230    cpu_to_le16s(&desc->res);
 231    cpu_to_le16s(&desc->bytes);
 232    cpu_to_le32s(&desc->buffer);
 233    cpu_to_le32s(&desc->next);
 234    cpu_physical_memory_write(addr, desc, sizeof(*desc));
 235}
 236
 237static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc)
 238{
 239    cpu_physical_memory_read(addr, desc, sizeof(*desc));
 240    le32_to_cpus(&desc->cmdstat);
 241    le16_to_cpus(&desc->res);
 242    le16_to_cpus(&desc->bytes);
 243    le32_to_cpus(&desc->buffer);
 244    le32_to_cpus(&desc->next);
 245}
 246
 247static void eth_send(mv88w8618_eth_state *s, int queue_index)
 248{
 249    uint32_t desc_addr = s->tx_queue[queue_index];
 250    mv88w8618_tx_desc desc;
 251    uint32_t next_desc;
 252    uint8_t buf[2048];
 253    int len;
 254
 255    do {
 256        eth_tx_desc_get(desc_addr, &desc);
 257        next_desc = desc.next;
 258        if (desc.cmdstat & MP_ETH_TX_OWN) {
 259            len = desc.bytes;
 260            if (len < 2048) {
 261                cpu_physical_memory_read(desc.buffer, buf, len);
 262                qemu_send_packet(qemu_get_queue(s->nic), buf, len);
 263            }
 264            desc.cmdstat &= ~MP_ETH_TX_OWN;
 265            s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
 266            eth_tx_desc_put(desc_addr, &desc);
 267        }
 268        desc_addr = next_desc;
 269    } while (desc_addr != s->tx_queue[queue_index]);
 270}
 271
 272static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset,
 273                                   unsigned size)
 274{
 275    mv88w8618_eth_state *s = opaque;
 276
 277    switch (offset) {
 278    case MP_ETH_SMIR:
 279        if (s->smir & MP_ETH_SMIR_OPCODE) {
 280            switch (s->smir & MP_ETH_SMIR_ADDR) {
 281            case MP_ETH_PHY1_BMSR:
 282                return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG |
 283                       MP_ETH_SMIR_RDVALID;
 284            case MP_ETH_PHY1_PHYSID1:
 285                return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID;
 286            case MP_ETH_PHY1_PHYSID2:
 287                return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID;
 288            default:
 289                return MP_ETH_SMIR_RDVALID;
 290            }
 291        }
 292        return 0;
 293
 294    case MP_ETH_ICR:
 295        return s->icr;
 296
 297    case MP_ETH_IMR:
 298        return s->imr;
 299
 300    case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
 301        return s->frx_queue[(offset - MP_ETH_FRDP0)/4];
 302
 303    case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
 304        return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
 305
 306    case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
 307        return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
 308
 309    default:
 310        return 0;
 311    }
 312}
 313
 314static void mv88w8618_eth_write(void *opaque, hwaddr offset,
 315                                uint64_t value, unsigned size)
 316{
 317    mv88w8618_eth_state *s = opaque;
 318
 319    switch (offset) {
 320    case MP_ETH_SMIR:
 321        s->smir = value;
 322        break;
 323
 324    case MP_ETH_PCXR:
 325        s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2;
 326        break;
 327
 328    case MP_ETH_SDCMR:
 329        if (value & MP_ETH_CMD_TXHI) {
 330            eth_send(s, 1);
 331        }
 332        if (value & MP_ETH_CMD_TXLO) {
 333            eth_send(s, 0);
 334        }
 335        if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr) {
 336            qemu_irq_raise(s->irq);
 337        }
 338        break;
 339
 340    case MP_ETH_ICR:
 341        s->icr &= value;
 342        break;
 343
 344    case MP_ETH_IMR:
 345        s->imr = value;
 346        if (s->icr & s->imr) {
 347            qemu_irq_raise(s->irq);
 348        }
 349        break;
 350
 351    case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
 352        s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value;
 353        break;
 354
 355    case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
 356        s->rx_queue[(offset - MP_ETH_CRDP0)/4] =
 357            s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
 358        break;
 359
 360    case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
 361        s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
 362        break;
 363    }
 364}
 365
 366static const MemoryRegionOps mv88w8618_eth_ops = {
 367    .read = mv88w8618_eth_read,
 368    .write = mv88w8618_eth_write,
 369    .endianness = DEVICE_NATIVE_ENDIAN,
 370};
 371
 372static void eth_cleanup(NetClientState *nc)
 373{
 374    mv88w8618_eth_state *s = qemu_get_nic_opaque(nc);
 375
 376    s->nic = NULL;
 377}
 378
 379static NetClientInfo net_mv88w8618_info = {
 380    .type = NET_CLIENT_DRIVER_NIC,
 381    .size = sizeof(NICState),
 382    .receive = eth_receive,
 383    .cleanup = eth_cleanup,
 384};
 385
 386static void mv88w8618_eth_init(Object *obj)
 387{
 388    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 389    DeviceState *dev = DEVICE(sbd);
 390    mv88w8618_eth_state *s = MV88W8618_ETH(dev);
 391
 392    sysbus_init_irq(sbd, &s->irq);
 393    memory_region_init_io(&s->iomem, obj, &mv88w8618_eth_ops, s,
 394                          "mv88w8618-eth", MP_ETH_SIZE);
 395    sysbus_init_mmio(sbd, &s->iomem);
 396}
 397
 398static void mv88w8618_eth_realize(DeviceState *dev, Error **errp)
 399{
 400    mv88w8618_eth_state *s = MV88W8618_ETH(dev);
 401
 402    s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
 403                          object_get_typename(OBJECT(dev)), dev->id, s);
 404}
 405
 406static const VMStateDescription mv88w8618_eth_vmsd = {
 407    .name = "mv88w8618_eth",
 408    .version_id = 1,
 409    .minimum_version_id = 1,
 410    .fields = (VMStateField[]) {
 411        VMSTATE_UINT32(smir, mv88w8618_eth_state),
 412        VMSTATE_UINT32(icr, mv88w8618_eth_state),
 413        VMSTATE_UINT32(imr, mv88w8618_eth_state),
 414        VMSTATE_UINT32(vlan_header, mv88w8618_eth_state),
 415        VMSTATE_UINT32_ARRAY(tx_queue, mv88w8618_eth_state, 2),
 416        VMSTATE_UINT32_ARRAY(rx_queue, mv88w8618_eth_state, 4),
 417        VMSTATE_UINT32_ARRAY(frx_queue, mv88w8618_eth_state, 4),
 418        VMSTATE_UINT32_ARRAY(cur_rx, mv88w8618_eth_state, 4),
 419        VMSTATE_END_OF_LIST()
 420    }
 421};
 422
 423static Property mv88w8618_eth_properties[] = {
 424    DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
 425    DEFINE_PROP_END_OF_LIST(),
 426};
 427
 428static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
 429{
 430    DeviceClass *dc = DEVICE_CLASS(klass);
 431
 432    dc->vmsd = &mv88w8618_eth_vmsd;
 433    dc->props = mv88w8618_eth_properties;
 434    dc->realize = mv88w8618_eth_realize;
 435}
 436
 437static const TypeInfo mv88w8618_eth_info = {
 438    .name          = TYPE_MV88W8618_ETH,
 439    .parent        = TYPE_SYS_BUS_DEVICE,
 440    .instance_size = sizeof(mv88w8618_eth_state),
 441    .instance_init = mv88w8618_eth_init,
 442    .class_init    = mv88w8618_eth_class_init,
 443};
 444
 445/* LCD register offsets */
 446#define MP_LCD_IRQCTRL          0x180
 447#define MP_LCD_IRQSTAT          0x184
 448#define MP_LCD_SPICTRL          0x1ac
 449#define MP_LCD_INST             0x1bc
 450#define MP_LCD_DATA             0x1c0
 451
 452/* Mode magics */
 453#define MP_LCD_SPI_DATA         0x00100011
 454#define MP_LCD_SPI_CMD          0x00104011
 455#define MP_LCD_SPI_INVALID      0x00000000
 456
 457/* Commmands */
 458#define MP_LCD_INST_SETPAGE0    0xB0
 459/* ... */
 460#define MP_LCD_INST_SETPAGE7    0xB7
 461
 462#define MP_LCD_TEXTCOLOR        0xe0e0ff /* RRGGBB */
 463
 464#define TYPE_MUSICPAL_LCD "musicpal_lcd"
 465#define MUSICPAL_LCD(obj) \
 466    OBJECT_CHECK(musicpal_lcd_state, (obj), TYPE_MUSICPAL_LCD)
 467
 468typedef struct musicpal_lcd_state {
 469    /*< private >*/
 470    SysBusDevice parent_obj;
 471    /*< public >*/
 472
 473    MemoryRegion iomem;
 474    uint32_t brightness;
 475    uint32_t mode;
 476    uint32_t irqctrl;
 477    uint32_t page;
 478    uint32_t page_off;
 479    QemuConsole *con;
 480    uint8_t video_ram[128*64/8];
 481} musicpal_lcd_state;
 482
 483static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col)
 484{
 485    switch (s->brightness) {
 486    case 7:
 487        return col;
 488    case 0:
 489        return 0;
 490    default:
 491        return (col * s->brightness) / 7;
 492    }
 493}
 494
 495#define SET_LCD_PIXEL(depth, type) \
 496static inline void glue(set_lcd_pixel, depth) \
 497        (musicpal_lcd_state *s, int x, int y, type col) \
 498{ \
 499    int dx, dy; \
 500    DisplaySurface *surface = qemu_console_surface(s->con); \
 501    type *pixel = &((type *) surface_data(surface))[(y * 128 * 3 + x) * 3]; \
 502\
 503    for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \
 504        for (dx = 0; dx < 3; dx++, pixel++) \
 505            *pixel = col; \
 506}
 507SET_LCD_PIXEL(8, uint8_t)
 508SET_LCD_PIXEL(16, uint16_t)
 509SET_LCD_PIXEL(32, uint32_t)
 510
 511static void lcd_refresh(void *opaque)
 512{
 513    musicpal_lcd_state *s = opaque;
 514    DisplaySurface *surface = qemu_console_surface(s->con);
 515    int x, y, col;
 516
 517    switch (surface_bits_per_pixel(surface)) {
 518    case 0:
 519        return;
 520#define LCD_REFRESH(depth, func) \
 521    case depth: \
 522        col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \
 523                   scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \
 524                   scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \
 525        for (x = 0; x < 128; x++) { \
 526            for (y = 0; y < 64; y++) { \
 527                if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \
 528                    glue(set_lcd_pixel, depth)(s, x, y, col); \
 529                } else { \
 530                    glue(set_lcd_pixel, depth)(s, x, y, 0); \
 531                } \
 532            } \
 533        } \
 534        break;
 535    LCD_REFRESH(8, rgb_to_pixel8)
 536    LCD_REFRESH(16, rgb_to_pixel16)
 537    LCD_REFRESH(32, (is_surface_bgr(surface) ?
 538                     rgb_to_pixel32bgr : rgb_to_pixel32))
 539    default:
 540        hw_error("unsupported colour depth %i\n",
 541                 surface_bits_per_pixel(surface));
 542    }
 543
 544    dpy_gfx_update(s->con, 0, 0, 128*3, 64*3);
 545}
 546
 547static void lcd_invalidate(void *opaque)
 548{
 549}
 550
 551static void musicpal_lcd_gpio_brightness_in(void *opaque, int irq, int level)
 552{
 553    musicpal_lcd_state *s = opaque;
 554    s->brightness &= ~(1 << irq);
 555    s->brightness |= level << irq;
 556}
 557
 558static uint64_t musicpal_lcd_read(void *opaque, hwaddr offset,
 559                                  unsigned size)
 560{
 561    musicpal_lcd_state *s = opaque;
 562
 563    switch (offset) {
 564    case MP_LCD_IRQCTRL:
 565        return s->irqctrl;
 566
 567    default:
 568        return 0;
 569    }
 570}
 571
 572static void musicpal_lcd_write(void *opaque, hwaddr offset,
 573                               uint64_t value, unsigned size)
 574{
 575    musicpal_lcd_state *s = opaque;
 576
 577    switch (offset) {
 578    case MP_LCD_IRQCTRL:
 579        s->irqctrl = value;
 580        break;
 581
 582    case MP_LCD_SPICTRL:
 583        if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD) {
 584            s->mode = value;
 585        } else {
 586            s->mode = MP_LCD_SPI_INVALID;
 587        }
 588        break;
 589
 590    case MP_LCD_INST:
 591        if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) {
 592            s->page = value - MP_LCD_INST_SETPAGE0;
 593            s->page_off = 0;
 594        }
 595        break;
 596
 597    case MP_LCD_DATA:
 598        if (s->mode == MP_LCD_SPI_CMD) {
 599            if (value >= MP_LCD_INST_SETPAGE0 &&
 600                value <= MP_LCD_INST_SETPAGE7) {
 601                s->page = value - MP_LCD_INST_SETPAGE0;
 602                s->page_off = 0;
 603            }
 604        } else if (s->mode == MP_LCD_SPI_DATA) {
 605            s->video_ram[s->page*128 + s->page_off] = value;
 606            s->page_off = (s->page_off + 1) & 127;
 607        }
 608        break;
 609    }
 610}
 611
 612static const MemoryRegionOps musicpal_lcd_ops = {
 613    .read = musicpal_lcd_read,
 614    .write = musicpal_lcd_write,
 615    .endianness = DEVICE_NATIVE_ENDIAN,
 616};
 617
 618static const GraphicHwOps musicpal_gfx_ops = {
 619    .invalidate  = lcd_invalidate,
 620    .gfx_update  = lcd_refresh,
 621};
 622
 623static void musicpal_lcd_realize(DeviceState *dev, Error **errp)
 624{
 625    musicpal_lcd_state *s = MUSICPAL_LCD(dev);
 626    s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
 627    qemu_console_resize(s->con, 128 * 3, 64 * 3);
 628}
 629
 630static void musicpal_lcd_init(Object *obj)
 631{
 632    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 633    DeviceState *dev = DEVICE(sbd);
 634    musicpal_lcd_state *s = MUSICPAL_LCD(dev);
 635
 636    s->brightness = 7;
 637
 638    memory_region_init_io(&s->iomem, obj, &musicpal_lcd_ops, s,
 639                          "musicpal-lcd", MP_LCD_SIZE);
 640    sysbus_init_mmio(sbd, &s->iomem);
 641
 642    qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
 643}
 644
 645static const VMStateDescription musicpal_lcd_vmsd = {
 646    .name = "musicpal_lcd",
 647    .version_id = 1,
 648    .minimum_version_id = 1,
 649    .fields = (VMStateField[]) {
 650        VMSTATE_UINT32(brightness, musicpal_lcd_state),
 651        VMSTATE_UINT32(mode, musicpal_lcd_state),
 652        VMSTATE_UINT32(irqctrl, musicpal_lcd_state),
 653        VMSTATE_UINT32(page, musicpal_lcd_state),
 654        VMSTATE_UINT32(page_off, musicpal_lcd_state),
 655        VMSTATE_BUFFER(video_ram, musicpal_lcd_state),
 656        VMSTATE_END_OF_LIST()
 657    }
 658};
 659
 660static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
 661{
 662    DeviceClass *dc = DEVICE_CLASS(klass);
 663
 664    dc->vmsd = &musicpal_lcd_vmsd;
 665    dc->realize = musicpal_lcd_realize;
 666}
 667
 668static const TypeInfo musicpal_lcd_info = {
 669    .name          = TYPE_MUSICPAL_LCD,
 670    .parent        = TYPE_SYS_BUS_DEVICE,
 671    .instance_size = sizeof(musicpal_lcd_state),
 672    .instance_init = musicpal_lcd_init,
 673    .class_init    = musicpal_lcd_class_init,
 674};
 675
 676/* PIC register offsets */
 677#define MP_PIC_STATUS           0x00
 678#define MP_PIC_ENABLE_SET       0x08
 679#define MP_PIC_ENABLE_CLR       0x0C
 680
 681#define TYPE_MV88W8618_PIC "mv88w8618_pic"
 682#define MV88W8618_PIC(obj) \
 683    OBJECT_CHECK(mv88w8618_pic_state, (obj), TYPE_MV88W8618_PIC)
 684
 685typedef struct mv88w8618_pic_state {
 686    /*< private >*/
 687    SysBusDevice parent_obj;
 688    /*< public >*/
 689
 690    MemoryRegion iomem;
 691    uint32_t level;
 692    uint32_t enabled;
 693    qemu_irq parent_irq;
 694} mv88w8618_pic_state;
 695
 696static void mv88w8618_pic_update(mv88w8618_pic_state *s)
 697{
 698    qemu_set_irq(s->parent_irq, (s->level & s->enabled));
 699}
 700
 701static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
 702{
 703    mv88w8618_pic_state *s = opaque;
 704
 705    if (level) {
 706        s->level |= 1 << irq;
 707    } else {
 708        s->level &= ~(1 << irq);
 709    }
 710    mv88w8618_pic_update(s);
 711}
 712
 713static uint64_t mv88w8618_pic_read(void *opaque, hwaddr offset,
 714                                   unsigned size)
 715{
 716    mv88w8618_pic_state *s = opaque;
 717
 718    switch (offset) {
 719    case MP_PIC_STATUS:
 720        return s->level & s->enabled;
 721
 722    default:
 723        return 0;
 724    }
 725}
 726
 727static void mv88w8618_pic_write(void *opaque, hwaddr offset,
 728                                uint64_t value, unsigned size)
 729{
 730    mv88w8618_pic_state *s = opaque;
 731
 732    switch (offset) {
 733    case MP_PIC_ENABLE_SET:
 734        s->enabled |= value;
 735        break;
 736
 737    case MP_PIC_ENABLE_CLR:
 738        s->enabled &= ~value;
 739        s->level &= ~value;
 740        break;
 741    }
 742    mv88w8618_pic_update(s);
 743}
 744
 745static void mv88w8618_pic_reset(DeviceState *d)
 746{
 747    mv88w8618_pic_state *s = MV88W8618_PIC(d);
 748
 749    s->level = 0;
 750    s->enabled = 0;
 751}
 752
 753static const MemoryRegionOps mv88w8618_pic_ops = {
 754    .read = mv88w8618_pic_read,
 755    .write = mv88w8618_pic_write,
 756    .endianness = DEVICE_NATIVE_ENDIAN,
 757};
 758
 759static void mv88w8618_pic_init(Object *obj)
 760{
 761    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 762    mv88w8618_pic_state *s = MV88W8618_PIC(dev);
 763
 764    qdev_init_gpio_in(DEVICE(dev), mv88w8618_pic_set_irq, 32);
 765    sysbus_init_irq(dev, &s->parent_irq);
 766    memory_region_init_io(&s->iomem, obj, &mv88w8618_pic_ops, s,
 767                          "musicpal-pic", MP_PIC_SIZE);
 768    sysbus_init_mmio(dev, &s->iomem);
 769}
 770
 771static const VMStateDescription mv88w8618_pic_vmsd = {
 772    .name = "mv88w8618_pic",
 773    .version_id = 1,
 774    .minimum_version_id = 1,
 775    .fields = (VMStateField[]) {
 776        VMSTATE_UINT32(level, mv88w8618_pic_state),
 777        VMSTATE_UINT32(enabled, mv88w8618_pic_state),
 778        VMSTATE_END_OF_LIST()
 779    }
 780};
 781
 782static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
 783{
 784    DeviceClass *dc = DEVICE_CLASS(klass);
 785
 786    dc->reset = mv88w8618_pic_reset;
 787    dc->vmsd = &mv88w8618_pic_vmsd;
 788}
 789
 790static const TypeInfo mv88w8618_pic_info = {
 791    .name          = TYPE_MV88W8618_PIC,
 792    .parent        = TYPE_SYS_BUS_DEVICE,
 793    .instance_size = sizeof(mv88w8618_pic_state),
 794    .instance_init = mv88w8618_pic_init,
 795    .class_init    = mv88w8618_pic_class_init,
 796};
 797
 798/* PIT register offsets */
 799#define MP_PIT_TIMER1_LENGTH    0x00
 800/* ... */
 801#define MP_PIT_TIMER4_LENGTH    0x0C
 802#define MP_PIT_CONTROL          0x10
 803#define MP_PIT_TIMER1_VALUE     0x14
 804/* ... */
 805#define MP_PIT_TIMER4_VALUE     0x20
 806#define MP_BOARD_RESET          0x34
 807
 808/* Magic board reset value (probably some watchdog behind it) */
 809#define MP_BOARD_RESET_MAGIC    0x10000
 810
 811typedef struct mv88w8618_timer_state {
 812    ptimer_state *ptimer;
 813    uint32_t limit;
 814    int freq;
 815    qemu_irq irq;
 816} mv88w8618_timer_state;
 817
 818#define TYPE_MV88W8618_PIT "mv88w8618_pit"
 819#define MV88W8618_PIT(obj) \
 820    OBJECT_CHECK(mv88w8618_pit_state, (obj), TYPE_MV88W8618_PIT)
 821
 822typedef struct mv88w8618_pit_state {
 823    /*< private >*/
 824    SysBusDevice parent_obj;
 825    /*< public >*/
 826
 827    MemoryRegion iomem;
 828    mv88w8618_timer_state timer[4];
 829} mv88w8618_pit_state;
 830
 831static void mv88w8618_timer_tick(void *opaque)
 832{
 833    mv88w8618_timer_state *s = opaque;
 834
 835    qemu_irq_raise(s->irq);
 836}
 837
 838static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
 839                                 uint32_t freq)
 840{
 841    QEMUBH *bh;
 842
 843    sysbus_init_irq(dev, &s->irq);
 844    s->freq = freq;
 845
 846    bh = qemu_bh_new(mv88w8618_timer_tick, s);
 847    s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
 848}
 849
 850static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset,
 851                                   unsigned size)
 852{
 853    mv88w8618_pit_state *s = opaque;
 854    mv88w8618_timer_state *t;
 855
 856    switch (offset) {
 857    case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:
 858        t = &s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];
 859        return ptimer_get_count(t->ptimer);
 860
 861    default:
 862        return 0;
 863    }
 864}
 865
 866static void mv88w8618_pit_write(void *opaque, hwaddr offset,
 867                                uint64_t value, unsigned size)
 868{
 869    mv88w8618_pit_state *s = opaque;
 870    mv88w8618_timer_state *t;
 871    int i;
 872
 873    switch (offset) {
 874    case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
 875        t = &s->timer[offset >> 2];
 876        t->limit = value;
 877        if (t->limit > 0) {
 878            ptimer_set_limit(t->ptimer, t->limit, 1);
 879        } else {
 880            ptimer_stop(t->ptimer);
 881        }
 882        break;
 883
 884    case MP_PIT_CONTROL:
 885        for (i = 0; i < 4; i++) {
 886            t = &s->timer[i];
 887            if (value & 0xf && t->limit > 0) {
 888                ptimer_set_limit(t->ptimer, t->limit, 0);
 889                ptimer_set_freq(t->ptimer, t->freq);
 890                ptimer_run(t->ptimer, 0);
 891            } else {
 892                ptimer_stop(t->ptimer);
 893            }
 894            value >>= 4;
 895        }
 896        break;
 897
 898    case MP_BOARD_RESET:
 899        if (value == MP_BOARD_RESET_MAGIC) {
 900            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 901        }
 902        break;
 903    }
 904}
 905
 906static void mv88w8618_pit_reset(DeviceState *d)
 907{
 908    mv88w8618_pit_state *s = MV88W8618_PIT(d);
 909    int i;
 910
 911    for (i = 0; i < 4; i++) {
 912        ptimer_stop(s->timer[i].ptimer);
 913        s->timer[i].limit = 0;
 914    }
 915}
 916
 917static const MemoryRegionOps mv88w8618_pit_ops = {
 918    .read = mv88w8618_pit_read,
 919    .write = mv88w8618_pit_write,
 920    .endianness = DEVICE_NATIVE_ENDIAN,
 921};
 922
 923static void mv88w8618_pit_init(Object *obj)
 924{
 925    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 926    mv88w8618_pit_state *s = MV88W8618_PIT(dev);
 927    int i;
 928
 929    /* Letting them all run at 1 MHz is likely just a pragmatic
 930     * simplification. */
 931    for (i = 0; i < 4; i++) {
 932        mv88w8618_timer_init(dev, &s->timer[i], 1000000);
 933    }
 934
 935    memory_region_init_io(&s->iomem, obj, &mv88w8618_pit_ops, s,
 936                          "musicpal-pit", MP_PIT_SIZE);
 937    sysbus_init_mmio(dev, &s->iomem);
 938}
 939
 940static const VMStateDescription mv88w8618_timer_vmsd = {
 941    .name = "timer",
 942    .version_id = 1,
 943    .minimum_version_id = 1,
 944    .fields = (VMStateField[]) {
 945        VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
 946        VMSTATE_UINT32(limit, mv88w8618_timer_state),
 947        VMSTATE_END_OF_LIST()
 948    }
 949};
 950
 951static const VMStateDescription mv88w8618_pit_vmsd = {
 952    .name = "mv88w8618_pit",
 953    .version_id = 1,
 954    .minimum_version_id = 1,
 955    .fields = (VMStateField[]) {
 956        VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
 957                             mv88w8618_timer_vmsd, mv88w8618_timer_state),
 958        VMSTATE_END_OF_LIST()
 959    }
 960};
 961
 962static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
 963{
 964    DeviceClass *dc = DEVICE_CLASS(klass);
 965
 966    dc->reset = mv88w8618_pit_reset;
 967    dc->vmsd = &mv88w8618_pit_vmsd;
 968}
 969
 970static const TypeInfo mv88w8618_pit_info = {
 971    .name          = TYPE_MV88W8618_PIT,
 972    .parent        = TYPE_SYS_BUS_DEVICE,
 973    .instance_size = sizeof(mv88w8618_pit_state),
 974    .instance_init = mv88w8618_pit_init,
 975    .class_init    = mv88w8618_pit_class_init,
 976};
 977
 978/* Flash config register offsets */
 979#define MP_FLASHCFG_CFGR0    0x04
 980
 981#define TYPE_MV88W8618_FLASHCFG "mv88w8618_flashcfg"
 982#define MV88W8618_FLASHCFG(obj) \
 983    OBJECT_CHECK(mv88w8618_flashcfg_state, (obj), TYPE_MV88W8618_FLASHCFG)
 984
 985typedef struct mv88w8618_flashcfg_state {
 986    /*< private >*/
 987    SysBusDevice parent_obj;
 988    /*< public >*/
 989
 990    MemoryRegion iomem;
 991    uint32_t cfgr0;
 992} mv88w8618_flashcfg_state;
 993
 994static uint64_t mv88w8618_flashcfg_read(void *opaque,
 995                                        hwaddr offset,
 996                                        unsigned size)
 997{
 998    mv88w8618_flashcfg_state *s = opaque;
 999
1000    switch (offset) {
1001    case MP_FLASHCFG_CFGR0:
1002        return s->cfgr0;
1003
1004    default:
1005        return 0;
1006    }
1007}
1008
1009static void mv88w8618_flashcfg_write(void *opaque, hwaddr offset,
1010                                     uint64_t value, unsigned size)
1011{
1012    mv88w8618_flashcfg_state *s = opaque;
1013
1014    switch (offset) {
1015    case MP_FLASHCFG_CFGR0:
1016        s->cfgr0 = value;
1017        break;
1018    }
1019}
1020
1021static const MemoryRegionOps mv88w8618_flashcfg_ops = {
1022    .read = mv88w8618_flashcfg_read,
1023    .write = mv88w8618_flashcfg_write,
1024    .endianness = DEVICE_NATIVE_ENDIAN,
1025};
1026
1027static void mv88w8618_flashcfg_init(Object *obj)
1028{
1029    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
1030    mv88w8618_flashcfg_state *s = MV88W8618_FLASHCFG(dev);
1031
1032    s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
1033    memory_region_init_io(&s->iomem, obj, &mv88w8618_flashcfg_ops, s,
1034                          "musicpal-flashcfg", MP_FLASHCFG_SIZE);
1035    sysbus_init_mmio(dev, &s->iomem);
1036}
1037
1038static const VMStateDescription mv88w8618_flashcfg_vmsd = {
1039    .name = "mv88w8618_flashcfg",
1040    .version_id = 1,
1041    .minimum_version_id = 1,
1042    .fields = (VMStateField[]) {
1043        VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
1044        VMSTATE_END_OF_LIST()
1045    }
1046};
1047
1048static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
1049{
1050    DeviceClass *dc = DEVICE_CLASS(klass);
1051
1052    dc->vmsd = &mv88w8618_flashcfg_vmsd;
1053}
1054
1055static const TypeInfo mv88w8618_flashcfg_info = {
1056    .name          = TYPE_MV88W8618_FLASHCFG,
1057    .parent        = TYPE_SYS_BUS_DEVICE,
1058    .instance_size = sizeof(mv88w8618_flashcfg_state),
1059    .instance_init = mv88w8618_flashcfg_init,
1060    .class_init    = mv88w8618_flashcfg_class_init,
1061};
1062
1063/* Misc register offsets */
1064#define MP_MISC_BOARD_REVISION  0x18
1065
1066#define MP_BOARD_REVISION       0x31
1067
1068typedef struct {
1069    SysBusDevice parent_obj;
1070    MemoryRegion iomem;
1071} MusicPalMiscState;
1072
1073#define TYPE_MUSICPAL_MISC "musicpal-misc"
1074#define MUSICPAL_MISC(obj) \
1075     OBJECT_CHECK(MusicPalMiscState, (obj), TYPE_MUSICPAL_MISC)
1076
1077static uint64_t musicpal_misc_read(void *opaque, hwaddr offset,
1078                                   unsigned size)
1079{
1080    switch (offset) {
1081    case MP_MISC_BOARD_REVISION:
1082        return MP_BOARD_REVISION;
1083
1084    default:
1085        return 0;
1086    }
1087}
1088
1089static void musicpal_misc_write(void *opaque, hwaddr offset,
1090                                uint64_t value, unsigned size)
1091{
1092}
1093
1094static const MemoryRegionOps musicpal_misc_ops = {
1095    .read = musicpal_misc_read,
1096    .write = musicpal_misc_write,
1097    .endianness = DEVICE_NATIVE_ENDIAN,
1098};
1099
1100static void musicpal_misc_init(Object *obj)
1101{
1102    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
1103    MusicPalMiscState *s = MUSICPAL_MISC(obj);
1104
1105    memory_region_init_io(&s->iomem, OBJECT(s), &musicpal_misc_ops, NULL,
1106                          "musicpal-misc", MP_MISC_SIZE);
1107    sysbus_init_mmio(sd, &s->iomem);
1108}
1109
1110static const TypeInfo musicpal_misc_info = {
1111    .name = TYPE_MUSICPAL_MISC,
1112    .parent = TYPE_SYS_BUS_DEVICE,
1113    .instance_init = musicpal_misc_init,
1114    .instance_size = sizeof(MusicPalMiscState),
1115};
1116
1117/* WLAN register offsets */
1118#define MP_WLAN_MAGIC1          0x11c
1119#define MP_WLAN_MAGIC2          0x124
1120
1121static uint64_t mv88w8618_wlan_read(void *opaque, hwaddr offset,
1122                                    unsigned size)
1123{
1124    switch (offset) {
1125    /* Workaround to allow loading the binary-only wlandrv.ko crap
1126     * from the original Freecom firmware. */
1127    case MP_WLAN_MAGIC1:
1128        return ~3;
1129    case MP_WLAN_MAGIC2:
1130        return -1;
1131
1132    default:
1133        return 0;
1134    }
1135}
1136
1137static void mv88w8618_wlan_write(void *opaque, hwaddr offset,
1138                                 uint64_t value, unsigned size)
1139{
1140}
1141
1142static const MemoryRegionOps mv88w8618_wlan_ops = {
1143    .read = mv88w8618_wlan_read,
1144    .write =mv88w8618_wlan_write,
1145    .endianness = DEVICE_NATIVE_ENDIAN,
1146};
1147
1148static void mv88w8618_wlan_realize(DeviceState *dev, Error **errp)
1149{
1150    MemoryRegion *iomem = g_new(MemoryRegion, 1);
1151
1152    memory_region_init_io(iomem, OBJECT(dev), &mv88w8618_wlan_ops, NULL,
1153                          "musicpal-wlan", MP_WLAN_SIZE);
1154    sysbus_init_mmio(SYS_BUS_DEVICE(dev), iomem);
1155}
1156
1157/* GPIO register offsets */
1158#define MP_GPIO_OE_LO           0x008
1159#define MP_GPIO_OUT_LO          0x00c
1160#define MP_GPIO_IN_LO           0x010
1161#define MP_GPIO_IER_LO          0x014
1162#define MP_GPIO_IMR_LO          0x018
1163#define MP_GPIO_ISR_LO          0x020
1164#define MP_GPIO_OE_HI           0x508
1165#define MP_GPIO_OUT_HI          0x50c
1166#define MP_GPIO_IN_HI           0x510
1167#define MP_GPIO_IER_HI          0x514
1168#define MP_GPIO_IMR_HI          0x518
1169#define MP_GPIO_ISR_HI          0x520
1170
1171/* GPIO bits & masks */
1172#define MP_GPIO_LCD_BRIGHTNESS  0x00070000
1173#define MP_GPIO_I2C_DATA_BIT    29
1174#define MP_GPIO_I2C_CLOCK_BIT   30
1175
1176/* LCD brightness bits in GPIO_OE_HI */
1177#define MP_OE_LCD_BRIGHTNESS    0x0007
1178
1179#define TYPE_MUSICPAL_GPIO "musicpal_gpio"
1180#define MUSICPAL_GPIO(obj) \
1181    OBJECT_CHECK(musicpal_gpio_state, (obj), TYPE_MUSICPAL_GPIO)
1182
1183typedef struct musicpal_gpio_state {
1184    /*< private >*/
1185    SysBusDevice parent_obj;
1186    /*< public >*/
1187
1188    MemoryRegion iomem;
1189    uint32_t lcd_brightness;
1190    uint32_t out_state;
1191    uint32_t in_state;
1192    uint32_t ier;
1193    uint32_t imr;
1194    uint32_t isr;
1195    qemu_irq irq;
1196    qemu_irq out[5]; /* 3 brightness out + 2 lcd (data and clock ) */
1197} musicpal_gpio_state;
1198
1199static void musicpal_gpio_brightness_update(musicpal_gpio_state *s) {
1200    int i;
1201    uint32_t brightness;
1202
1203    /* compute brightness ratio */
1204    switch (s->lcd_brightness) {
1205    case 0x00000007:
1206        brightness = 0;
1207        break;
1208
1209    case 0x00020000:
1210        brightness = 1;
1211        break;
1212
1213    case 0x00020001:
1214        brightness = 2;
1215        break;
1216
1217    case 0x00040000:
1218        brightness = 3;
1219        break;
1220
1221    case 0x00010006:
1222        brightness = 4;
1223        break;
1224
1225    case 0x00020005:
1226        brightness = 5;
1227        break;
1228
1229    case 0x00040003:
1230        brightness = 6;
1231        break;
1232
1233    case 0x00030004:
1234    default:
1235        brightness = 7;
1236    }
1237
1238    /* set lcd brightness GPIOs  */
1239    for (i = 0; i <= 2; i++) {
1240        qemu_set_irq(s->out[i], (brightness >> i) & 1);
1241    }
1242}
1243
1244static void musicpal_gpio_pin_event(void *opaque, int pin, int level)
1245{
1246    musicpal_gpio_state *s = opaque;
1247    uint32_t mask = 1 << pin;
1248    uint32_t delta = level << pin;
1249    uint32_t old = s->in_state & mask;
1250
1251    s->in_state &= ~mask;
1252    s->in_state |= delta;
1253
1254    if ((old ^ delta) &&
1255        ((level && (s->imr & mask)) || (!level && (s->ier & mask)))) {
1256        s->isr = mask;
1257        qemu_irq_raise(s->irq);
1258    }
1259}
1260
1261static uint64_t musicpal_gpio_read(void *opaque, hwaddr offset,
1262                                   unsigned size)
1263{
1264    musicpal_gpio_state *s = opaque;
1265
1266    switch (offset) {
1267    case MP_GPIO_OE_HI: /* used for LCD brightness control */
1268        return s->lcd_brightness & MP_OE_LCD_BRIGHTNESS;
1269
1270    case MP_GPIO_OUT_LO:
1271        return s->out_state & 0xFFFF;
1272    case MP_GPIO_OUT_HI:
1273        return s->out_state >> 16;
1274
1275    case MP_GPIO_IN_LO:
1276        return s->in_state & 0xFFFF;
1277    case MP_GPIO_IN_HI:
1278        return s->in_state >> 16;
1279
1280    case MP_GPIO_IER_LO:
1281        return s->ier & 0xFFFF;
1282    case MP_GPIO_IER_HI:
1283        return s->ier >> 16;
1284
1285    case MP_GPIO_IMR_LO:
1286        return s->imr & 0xFFFF;
1287    case MP_GPIO_IMR_HI:
1288        return s->imr >> 16;
1289
1290    case MP_GPIO_ISR_LO:
1291        return s->isr & 0xFFFF;
1292    case MP_GPIO_ISR_HI:
1293        return s->isr >> 16;
1294
1295    default:
1296        return 0;
1297    }
1298}
1299
1300static void musicpal_gpio_write(void *opaque, hwaddr offset,
1301                                uint64_t value, unsigned size)
1302{
1303    musicpal_gpio_state *s = opaque;
1304    switch (offset) {
1305    case MP_GPIO_OE_HI: /* used for LCD brightness control */
1306        s->lcd_brightness = (s->lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |
1307                         (value & MP_OE_LCD_BRIGHTNESS);
1308        musicpal_gpio_brightness_update(s);
1309        break;
1310
1311    case MP_GPIO_OUT_LO:
1312        s->out_state = (s->out_state & 0xFFFF0000) | (value & 0xFFFF);
1313        break;
1314    case MP_GPIO_OUT_HI:
1315        s->out_state = (s->out_state & 0xFFFF) | (value << 16);
1316        s->lcd_brightness = (s->lcd_brightness & 0xFFFF) |
1317                            (s->out_state & MP_GPIO_LCD_BRIGHTNESS);
1318        musicpal_gpio_brightness_update(s);
1319        qemu_set_irq(s->out[3], (s->out_state >> MP_GPIO_I2C_DATA_BIT) & 1);
1320        qemu_set_irq(s->out[4], (s->out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);
1321        break;
1322
1323    case MP_GPIO_IER_LO:
1324        s->ier = (s->ier & 0xFFFF0000) | (value & 0xFFFF);
1325        break;
1326    case MP_GPIO_IER_HI:
1327        s->ier = (s->ier & 0xFFFF) | (value << 16);
1328        break;
1329
1330    case MP_GPIO_IMR_LO:
1331        s->imr = (s->imr & 0xFFFF0000) | (value & 0xFFFF);
1332        break;
1333    case MP_GPIO_IMR_HI:
1334        s->imr = (s->imr & 0xFFFF) | (value << 16);
1335        break;
1336    }
1337}
1338
1339static const MemoryRegionOps musicpal_gpio_ops = {
1340    .read = musicpal_gpio_read,
1341    .write = musicpal_gpio_write,
1342    .endianness = DEVICE_NATIVE_ENDIAN,
1343};
1344
1345static void musicpal_gpio_reset(DeviceState *d)
1346{
1347    musicpal_gpio_state *s = MUSICPAL_GPIO(d);
1348
1349    s->lcd_brightness = 0;
1350    s->out_state = 0;
1351    s->in_state = 0xffffffff;
1352    s->ier = 0;
1353    s->imr = 0;
1354    s->isr = 0;
1355}
1356
1357static void musicpal_gpio_init(Object *obj)
1358{
1359    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1360    DeviceState *dev = DEVICE(sbd);
1361    musicpal_gpio_state *s = MUSICPAL_GPIO(dev);
1362
1363    sysbus_init_irq(sbd, &s->irq);
1364
1365    memory_region_init_io(&s->iomem, obj, &musicpal_gpio_ops, s,
1366                          "musicpal-gpio", MP_GPIO_SIZE);
1367    sysbus_init_mmio(sbd, &s->iomem);
1368
1369    qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
1370
1371    qdev_init_gpio_in(dev, musicpal_gpio_pin_event, 32);
1372}
1373
1374static const VMStateDescription musicpal_gpio_vmsd = {
1375    .name = "musicpal_gpio",
1376    .version_id = 1,
1377    .minimum_version_id = 1,
1378    .fields = (VMStateField[]) {
1379        VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
1380        VMSTATE_UINT32(out_state, musicpal_gpio_state),
1381        VMSTATE_UINT32(in_state, musicpal_gpio_state),
1382        VMSTATE_UINT32(ier, musicpal_gpio_state),
1383        VMSTATE_UINT32(imr, musicpal_gpio_state),
1384        VMSTATE_UINT32(isr, musicpal_gpio_state),
1385        VMSTATE_END_OF_LIST()
1386    }
1387};
1388
1389static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
1390{
1391    DeviceClass *dc = DEVICE_CLASS(klass);
1392
1393    dc->reset = musicpal_gpio_reset;
1394    dc->vmsd = &musicpal_gpio_vmsd;
1395}
1396
1397static const TypeInfo musicpal_gpio_info = {
1398    .name          = TYPE_MUSICPAL_GPIO,
1399    .parent        = TYPE_SYS_BUS_DEVICE,
1400    .instance_size = sizeof(musicpal_gpio_state),
1401    .instance_init = musicpal_gpio_init,
1402    .class_init    = musicpal_gpio_class_init,
1403};
1404
1405/* Keyboard codes & masks */
1406#define KEY_RELEASED            0x80
1407#define KEY_CODE                0x7f
1408
1409#define KEYCODE_TAB             0x0f
1410#define KEYCODE_ENTER           0x1c
1411#define KEYCODE_F               0x21
1412#define KEYCODE_M               0x32
1413
1414#define KEYCODE_EXTENDED        0xe0
1415#define KEYCODE_UP              0x48
1416#define KEYCODE_DOWN            0x50
1417#define KEYCODE_LEFT            0x4b
1418#define KEYCODE_RIGHT           0x4d
1419
1420#define MP_KEY_WHEEL_VOL       (1 << 0)
1421#define MP_KEY_WHEEL_VOL_INV   (1 << 1)
1422#define MP_KEY_WHEEL_NAV       (1 << 2)
1423#define MP_KEY_WHEEL_NAV_INV   (1 << 3)
1424#define MP_KEY_BTN_FAVORITS    (1 << 4)
1425#define MP_KEY_BTN_MENU        (1 << 5)
1426#define MP_KEY_BTN_VOLUME      (1 << 6)
1427#define MP_KEY_BTN_NAVIGATION  (1 << 7)
1428
1429#define TYPE_MUSICPAL_KEY "musicpal_key"
1430#define MUSICPAL_KEY(obj) \
1431    OBJECT_CHECK(musicpal_key_state, (obj), TYPE_MUSICPAL_KEY)
1432
1433typedef struct musicpal_key_state {
1434    /*< private >*/
1435    SysBusDevice parent_obj;
1436    /*< public >*/
1437
1438    MemoryRegion iomem;
1439    uint32_t kbd_extended;
1440    uint32_t pressed_keys;
1441    qemu_irq out[8];
1442} musicpal_key_state;
1443
1444static void musicpal_key_event(void *opaque, int keycode)
1445{
1446    musicpal_key_state *s = opaque;
1447    uint32_t event = 0;
1448    int i;
1449
1450    if (keycode == KEYCODE_EXTENDED) {
1451        s->kbd_extended = 1;
1452        return;
1453    }
1454
1455    if (s->kbd_extended) {
1456        switch (keycode & KEY_CODE) {
1457        case KEYCODE_UP:
1458            event = MP_KEY_WHEEL_NAV | MP_KEY_WHEEL_NAV_INV;
1459            break;
1460
1461        case KEYCODE_DOWN:
1462            event = MP_KEY_WHEEL_NAV;
1463            break;
1464
1465        case KEYCODE_LEFT:
1466            event = MP_KEY_WHEEL_VOL | MP_KEY_WHEEL_VOL_INV;
1467            break;
1468
1469        case KEYCODE_RIGHT:
1470            event = MP_KEY_WHEEL_VOL;
1471            break;
1472        }
1473    } else {
1474        switch (keycode & KEY_CODE) {
1475        case KEYCODE_F:
1476            event = MP_KEY_BTN_FAVORITS;
1477            break;
1478
1479        case KEYCODE_TAB:
1480            event = MP_KEY_BTN_VOLUME;
1481            break;
1482
1483        case KEYCODE_ENTER:
1484            event = MP_KEY_BTN_NAVIGATION;
1485            break;
1486
1487        case KEYCODE_M:
1488            event = MP_KEY_BTN_MENU;
1489            break;
1490        }
1491        /* Do not repeat already pressed buttons */
1492        if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
1493            event = 0;
1494        }
1495    }
1496
1497    if (event) {
1498        /* Raise GPIO pin first if repeating a key */
1499        if (!(keycode & KEY_RELEASED) && (s->pressed_keys & event)) {
1500            for (i = 0; i <= 7; i++) {
1501                if (event & (1 << i)) {
1502                    qemu_set_irq(s->out[i], 1);
1503                }
1504            }
1505        }
1506        for (i = 0; i <= 7; i++) {
1507            if (event & (1 << i)) {
1508                qemu_set_irq(s->out[i], !!(keycode & KEY_RELEASED));
1509            }
1510        }
1511        if (keycode & KEY_RELEASED) {
1512            s->pressed_keys &= ~event;
1513        } else {
1514            s->pressed_keys |= event;
1515        }
1516    }
1517
1518    s->kbd_extended = 0;
1519}
1520
1521static void musicpal_key_init(Object *obj)
1522{
1523    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1524    DeviceState *dev = DEVICE(sbd);
1525    musicpal_key_state *s = MUSICPAL_KEY(dev);
1526
1527    memory_region_init(&s->iomem, obj, "dummy", 0);
1528    sysbus_init_mmio(sbd, &s->iomem);
1529
1530    s->kbd_extended = 0;
1531    s->pressed_keys = 0;
1532
1533    qdev_init_gpio_out(dev, s->out, ARRAY_SIZE(s->out));
1534
1535    qemu_add_kbd_event_handler(musicpal_key_event, s);
1536}
1537
1538static const VMStateDescription musicpal_key_vmsd = {
1539    .name = "musicpal_key",
1540    .version_id = 1,
1541    .minimum_version_id = 1,
1542    .fields = (VMStateField[]) {
1543        VMSTATE_UINT32(kbd_extended, musicpal_key_state),
1544        VMSTATE_UINT32(pressed_keys, musicpal_key_state),
1545        VMSTATE_END_OF_LIST()
1546    }
1547};
1548
1549static void musicpal_key_class_init(ObjectClass *klass, void *data)
1550{
1551    DeviceClass *dc = DEVICE_CLASS(klass);
1552
1553    dc->vmsd = &musicpal_key_vmsd;
1554}
1555
1556static const TypeInfo musicpal_key_info = {
1557    .name          = TYPE_MUSICPAL_KEY,
1558    .parent        = TYPE_SYS_BUS_DEVICE,
1559    .instance_size = sizeof(musicpal_key_state),
1560    .instance_init = musicpal_key_init,
1561    .class_init    = musicpal_key_class_init,
1562};
1563
1564static struct arm_boot_info musicpal_binfo = {
1565    .loader_start = 0x0,
1566    .board_id = 0x20e,
1567};
1568
1569static void musicpal_init(MachineState *machine)
1570{
1571    const char *kernel_filename = machine->kernel_filename;
1572    const char *kernel_cmdline = machine->kernel_cmdline;
1573    const char *initrd_filename = machine->initrd_filename;
1574    ARMCPU *cpu;
1575    qemu_irq pic[32];
1576    DeviceState *dev;
1577    DeviceState *i2c_dev;
1578    DeviceState *lcd_dev;
1579    DeviceState *key_dev;
1580    DeviceState *wm8750_dev;
1581    SysBusDevice *s;
1582    I2CBus *i2c;
1583    int i;
1584    unsigned long flash_size;
1585    DriveInfo *dinfo;
1586    MemoryRegion *address_space_mem = get_system_memory();
1587    MemoryRegion *ram = g_new(MemoryRegion, 1);
1588    MemoryRegion *sram = g_new(MemoryRegion, 1);
1589
1590    cpu = ARM_CPU(cpu_create(machine->cpu_type));
1591
1592    /* For now we use a fixed - the original - RAM size */
1593    memory_region_allocate_system_memory(ram, NULL, "musicpal.ram",
1594                                         MP_RAM_DEFAULT_SIZE);
1595    memory_region_add_subregion(address_space_mem, 0, ram);
1596
1597    memory_region_init_ram(sram, NULL, "musicpal.sram", MP_SRAM_SIZE,
1598                           &error_fatal);
1599    memory_region_add_subregion(address_space_mem, MP_SRAM_BASE, sram);
1600
1601    dev = sysbus_create_simple(TYPE_MV88W8618_PIC, MP_PIC_BASE,
1602                               qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ));
1603    for (i = 0; i < 32; i++) {
1604        pic[i] = qdev_get_gpio_in(dev, i);
1605    }
1606    sysbus_create_varargs(TYPE_MV88W8618_PIT, MP_PIT_BASE, pic[MP_TIMER1_IRQ],
1607                          pic[MP_TIMER2_IRQ], pic[MP_TIMER3_IRQ],
1608                          pic[MP_TIMER4_IRQ], NULL);
1609
1610    if (serial_hd(0)) {
1611        serial_mm_init(address_space_mem, MP_UART1_BASE, 2, pic[MP_UART1_IRQ],
1612                       1825000, serial_hd(0), DEVICE_NATIVE_ENDIAN);
1613    }
1614    if (serial_hd(1)) {
1615        serial_mm_init(address_space_mem, MP_UART2_BASE, 2, pic[MP_UART2_IRQ],
1616                       1825000, serial_hd(1), DEVICE_NATIVE_ENDIAN);
1617    }
1618
1619    /* Register flash */
1620    dinfo = drive_get(IF_PFLASH, 0, 0);
1621    if (dinfo) {
1622        BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
1623
1624        flash_size = blk_getlength(blk);
1625        if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
1626            flash_size != 32*1024*1024) {
1627            error_report("Invalid flash image size");
1628            exit(1);
1629        }
1630
1631        /*
1632         * The original U-Boot accesses the flash at 0xFE000000 instead of
1633         * 0xFF800000 (if there is 8 MB flash). So remap flash access if the
1634         * image is smaller than 32 MB.
1635         */
1636#ifdef TARGET_WORDS_BIGENDIAN
1637        pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX,
1638                              "musicpal.flash", flash_size,
1639                              blk, 0x10000,
1640                              MP_FLASH_SIZE_MAX / flash_size,
1641                              2, 0x00BF, 0x236D, 0x0000, 0x0000,
1642                              0x5555, 0x2AAA, 1);
1643#else
1644        pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX,
1645                              "musicpal.flash", flash_size,
1646                              blk, 0x10000,
1647                              MP_FLASH_SIZE_MAX / flash_size,
1648                              2, 0x00BF, 0x236D, 0x0000, 0x0000,
1649                              0x5555, 0x2AAA, 0);
1650#endif
1651
1652    }
1653    sysbus_create_simple(TYPE_MV88W8618_FLASHCFG, MP_FLASHCFG_BASE, NULL);
1654
1655    qemu_check_nic_model(&nd_table[0], "mv88w8618");
1656    dev = qdev_create(NULL, TYPE_MV88W8618_ETH);
1657    qdev_set_nic_properties(dev, &nd_table[0]);
1658    qdev_init_nofail(dev);
1659    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE);
1660    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]);
1661
1662    sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL);
1663
1664    sysbus_create_simple(TYPE_MUSICPAL_MISC, MP_MISC_BASE, NULL);
1665
1666    dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE,
1667                               pic[MP_GPIO_IRQ]);
1668    i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
1669    i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c");
1670
1671    lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL);
1672    key_dev = sysbus_create_simple(TYPE_MUSICPAL_KEY, -1, NULL);
1673
1674    /* I2C read data */
1675    qdev_connect_gpio_out(i2c_dev, 0,
1676                          qdev_get_gpio_in(dev, MP_GPIO_I2C_DATA_BIT));
1677    /* I2C data */
1678    qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(i2c_dev, 0));
1679    /* I2C clock */
1680    qdev_connect_gpio_out(dev, 4, qdev_get_gpio_in(i2c_dev, 1));
1681
1682    for (i = 0; i < 3; i++) {
1683        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(lcd_dev, i));
1684    }
1685    for (i = 0; i < 4; i++) {
1686        qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 8));
1687    }
1688    for (i = 4; i < 8; i++) {
1689        qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15));
1690    }
1691
1692    wm8750_dev = i2c_create_slave(i2c, TYPE_WM8750, MP_WM_ADDR);
1693    dev = qdev_create(NULL, TYPE_MV88W8618_AUDIO);
1694    s = SYS_BUS_DEVICE(dev);
1695    object_property_set_link(OBJECT(dev), OBJECT(wm8750_dev),
1696                             "wm8750", NULL);
1697    qdev_init_nofail(dev);
1698    sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
1699    sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
1700
1701    musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
1702    musicpal_binfo.kernel_filename = kernel_filename;
1703    musicpal_binfo.kernel_cmdline = kernel_cmdline;
1704    musicpal_binfo.initrd_filename = initrd_filename;
1705    arm_load_kernel(cpu, &musicpal_binfo);
1706}
1707
1708static void musicpal_machine_init(MachineClass *mc)
1709{
1710    mc->desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)";
1711    mc->init = musicpal_init;
1712    mc->ignore_memory_transaction_failures = true;
1713    mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm926");
1714}
1715
1716DEFINE_MACHINE("musicpal", musicpal_machine_init)
1717
1718static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
1719{
1720    DeviceClass *dc = DEVICE_CLASS(klass);
1721
1722    dc->realize = mv88w8618_wlan_realize;
1723}
1724
1725static const TypeInfo mv88w8618_wlan_info = {
1726    .name          = "mv88w8618_wlan",
1727    .parent        = TYPE_SYS_BUS_DEVICE,
1728    .instance_size = sizeof(SysBusDevice),
1729    .class_init    = mv88w8618_wlan_class_init,
1730};
1731
1732static void musicpal_register_types(void)
1733{
1734    type_register_static(&mv88w8618_pic_info);
1735    type_register_static(&mv88w8618_pit_info);
1736    type_register_static(&mv88w8618_flashcfg_info);
1737    type_register_static(&mv88w8618_eth_info);
1738    type_register_static(&mv88w8618_wlan_info);
1739    type_register_static(&musicpal_lcd_info);
1740    type_register_static(&musicpal_gpio_info);
1741    type_register_static(&musicpal_key_info);
1742    type_register_static(&musicpal_misc_info);
1743}
1744
1745type_init(musicpal_register_types)
1746