Commit 24859b68ee5178881abf13621477898417c0b6e3

Authored by balrog
1 parent e61b79d6

ARM: Marvell 88w8618 / MusicPal emulation (Jan Kiszka).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4248 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -614,6 +614,7 @@ OBJS+= omap2.o omap_dss.o
614 614 OBJS+= palm.o tsc210x.o
615 615 OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
616 616 OBJS+= mst_fpga.o mainstone.o
  617 +OBJS+= musicpal.o pflash_cfi02.o
617 618 CPPFLAGS += -DHAS_AUDIO
618 619 endif
619 620 ifeq ($(TARGET_BASE_ARCH), sh4)
... ...
hw/boards.h
... ... @@ -106,4 +106,7 @@ extern QEMUMachine dummy_m68k_machine;
106 106 /* mainstone.c */
107 107 extern QEMUMachine mainstone2_machine;
108 108  
  109 +/* musicpal.c */
  110 +extern QEMUMachine musicpal_machine;
  111 +
109 112 #endif
... ...
hw/musicpal.c 0 → 100644
  1 +/*
  2 + * Marvell MV88W8618 / Freecom MusicPal emulation.
  3 + *
  4 + * Copyright (c) 2008 Jan Kiszka
  5 + *
  6 + * This code is licenced under the GNU GPL v2.
  7 + */
  8 +
  9 +#include "hw.h"
  10 +#include "arm-misc.h"
  11 +#include "devices.h"
  12 +#include "net.h"
  13 +#include "sysemu.h"
  14 +#include "boards.h"
  15 +#include "pc.h"
  16 +#include "qemu-timer.h"
  17 +#include "block.h"
  18 +#include "flash.h"
  19 +#include "console.h"
  20 +#include "audio/audio.h"
  21 +#include "i2c.h"
  22 +
  23 +#define MP_ETH_BASE 0x80008000
  24 +#define MP_ETH_SIZE 0x00001000
  25 +
  26 +#define MP_UART1_BASE 0x8000C840
  27 +#define MP_UART2_BASE 0x8000C940
  28 +
  29 +#define MP_FLASHCFG_BASE 0x90006000
  30 +#define MP_FLASHCFG_SIZE 0x00001000
  31 +
  32 +#define MP_AUDIO_BASE 0x90007000
  33 +#define MP_AUDIO_SIZE 0x00001000
  34 +
  35 +#define MP_PIC_BASE 0x90008000
  36 +#define MP_PIC_SIZE 0x00001000
  37 +
  38 +#define MP_PIT_BASE 0x90009000
  39 +#define MP_PIT_SIZE 0x00001000
  40 +
  41 +#define MP_LCD_BASE 0x9000c000
  42 +#define MP_LCD_SIZE 0x00001000
  43 +
  44 +#define MP_SRAM_BASE 0xC0000000
  45 +#define MP_SRAM_SIZE 0x00020000
  46 +
  47 +#define MP_RAM_DEFAULT_SIZE 32*1024*1024
  48 +#define MP_FLASH_SIZE_MAX 32*1024*1024
  49 +
  50 +#define MP_TIMER1_IRQ 4
  51 +/* ... */
  52 +#define MP_TIMER4_IRQ 7
  53 +#define MP_EHCI_IRQ 8
  54 +#define MP_ETH_IRQ 9
  55 +#define MP_UART1_IRQ 11
  56 +#define MP_UART2_IRQ 11
  57 +#define MP_GPIO_IRQ 12
  58 +#define MP_RTC_IRQ 28
  59 +#define MP_AUDIO_IRQ 30
  60 +
  61 +static uint32_t gpio_in_state = 0xffffffff;
  62 +static uint32_t gpio_out_state;
  63 +static ram_addr_t sram_off;
  64 +
  65 +/* Address conversion helpers */
  66 +static void *target2host_addr(uint32_t addr)
  67 +{
  68 + if (addr < MP_SRAM_BASE) {
  69 + if (addr >= MP_RAM_DEFAULT_SIZE)
  70 + return NULL;
  71 + return (void *)(phys_ram_base + addr);
  72 + } else {
  73 + if (addr >= MP_SRAM_BASE + MP_SRAM_SIZE)
  74 + return NULL;
  75 + return (void *)(phys_ram_base + sram_off + addr - MP_SRAM_BASE);
  76 + }
  77 +}
  78 +
  79 +static uint32_t host2target_addr(void *addr)
  80 +{
  81 + if (addr < ((void *)phys_ram_base) + sram_off)
  82 + return (unsigned long)addr - (unsigned long)phys_ram_base;
  83 + else
  84 + return (unsigned long)addr - (unsigned long)phys_ram_base -
  85 + sram_off + MP_SRAM_BASE;
  86 +}
  87 +
  88 +
  89 +typedef enum i2c_state {
  90 + STOPPED = 0,
  91 + INITIALIZING,
  92 + SENDING_BIT7,
  93 + SENDING_BIT6,
  94 + SENDING_BIT5,
  95 + SENDING_BIT4,
  96 + SENDING_BIT3,
  97 + SENDING_BIT2,
  98 + SENDING_BIT1,
  99 + SENDING_BIT0,
  100 + WAITING_FOR_ACK,
  101 + RECEIVING_BIT7,
  102 + RECEIVING_BIT6,
  103 + RECEIVING_BIT5,
  104 + RECEIVING_BIT4,
  105 + RECEIVING_BIT3,
  106 + RECEIVING_BIT2,
  107 + RECEIVING_BIT1,
  108 + RECEIVING_BIT0,
  109 + SENDING_ACK
  110 +} i2c_state;
  111 +
  112 +typedef struct i2c_interface {
  113 + i2c_bus *bus;
  114 + i2c_state state;
  115 + int last_data;
  116 + int last_clock;
  117 + uint8_t buffer;
  118 + int current_addr;
  119 +} i2c_interface;
  120 +
  121 +static void i2c_enter_stop(i2c_interface *i2c)
  122 +{
  123 + if (i2c->current_addr >= 0)
  124 + i2c_end_transfer(i2c->bus);
  125 + i2c->current_addr = -1;
  126 + i2c->state = STOPPED;
  127 +}
  128 +
  129 +static void i2c_state_update(i2c_interface *i2c, int data, int clock)
  130 +{
  131 + if (!i2c)
  132 + return;
  133 +
  134 + switch (i2c->state) {
  135 + case STOPPED:
  136 + if (data == 0 && i2c->last_data == 1 && clock == 1)
  137 + i2c->state = INITIALIZING;
  138 + break;
  139 +
  140 + case INITIALIZING:
  141 + if (clock == 0 && i2c->last_clock == 1 && data == 0)
  142 + i2c->state = SENDING_BIT7;
  143 + else
  144 + i2c_enter_stop(i2c);
  145 + break;
  146 +
  147 + case SENDING_BIT7 ... SENDING_BIT0:
  148 + if (clock == 0 && i2c->last_clock == 1) {
  149 + i2c->buffer = (i2c->buffer << 1) | data;
  150 + i2c->state++; /* will end up in WAITING_FOR_ACK */
  151 + } else if (data == 1 && i2c->last_data == 0 && clock == 1)
  152 + i2c_enter_stop(i2c);
  153 + break;
  154 +
  155 + case WAITING_FOR_ACK:
  156 + if (clock == 0 && i2c->last_clock == 1) {
  157 + if (i2c->current_addr < 0) {
  158 + i2c->current_addr = i2c->buffer;
  159 + i2c_start_transfer(i2c->bus, i2c->current_addr & 0xfe,
  160 + i2c->buffer & 1);
  161 + } else
  162 + i2c_send(i2c->bus, i2c->buffer);
  163 + if (i2c->current_addr & 1) {
  164 + i2c->state = RECEIVING_BIT7;
  165 + i2c->buffer = i2c_recv(i2c->bus);
  166 + } else
  167 + i2c->state = SENDING_BIT7;
  168 + } else if (data == 1 && i2c->last_data == 0 && clock == 1)
  169 + i2c_enter_stop(i2c);
  170 + break;
  171 +
  172 + case RECEIVING_BIT7 ... RECEIVING_BIT0:
  173 + if (clock == 0 && i2c->last_clock == 1) {
  174 + i2c->state++; /* will end up in SENDING_ACK */
  175 + i2c->buffer <<= 1;
  176 + } else if (data == 1 && i2c->last_data == 0 && clock == 1)
  177 + i2c_enter_stop(i2c);
  178 + break;
  179 +
  180 + case SENDING_ACK:
  181 + if (clock == 0 && i2c->last_clock == 1) {
  182 + i2c->state = RECEIVING_BIT7;
  183 + if (data == 0)
  184 + i2c->buffer = i2c_recv(i2c->bus);
  185 + else
  186 + i2c_nack(i2c->bus);
  187 + } else if (data == 1 && i2c->last_data == 0 && clock == 1)
  188 + i2c_enter_stop(i2c);
  189 + break;
  190 + }
  191 +
  192 + i2c->last_data = data;
  193 + i2c->last_clock = clock;
  194 +}
  195 +
  196 +static int i2c_get_data(i2c_interface *i2c)
  197 +{
  198 + if (!i2c)
  199 + return 0;
  200 +
  201 + switch (i2c->state) {
  202 + case RECEIVING_BIT7 ... RECEIVING_BIT0:
  203 + return (i2c->buffer >> 7);
  204 +
  205 + case WAITING_FOR_ACK:
  206 + default:
  207 + return 0;
  208 + }
  209 +}
  210 +
  211 +static i2c_interface *mixer_i2c;
  212 +
  213 +#ifdef HAS_AUDIO
  214 +
  215 +/* Audio register offsets */
  216 +#define MP_AUDIO_PLAYBACK_MODE 0x00
  217 +#define MP_AUDIO_CLOCK_DIV 0x18
  218 +#define MP_AUDIO_IRQ_STATUS 0x20
  219 +#define MP_AUDIO_IRQ_ENABLE 0x24
  220 +#define MP_AUDIO_TX_START_LO 0x28
  221 +#define MP_AUDIO_TX_THRESHOLD 0x2C
  222 +#define MP_AUDIO_TX_STATUS 0x38
  223 +#define MP_AUDIO_TX_START_HI 0x40
  224 +
  225 +/* Status register and IRQ enable bits */
  226 +#define MP_AUDIO_TX_HALF (1 << 6)
  227 +#define MP_AUDIO_TX_FULL (1 << 7)
  228 +
  229 +/* Playback mode bits */
  230 +#define MP_AUDIO_16BIT_SAMPLE (1 << 0)
  231 +#define MP_AUDIO_PLAYBACK_EN (1 << 7)
  232 +#define MP_AUDIO_CLOCK_24MHZ (1 << 9)
  233 +
  234 +/* Wolfson 8750 I2C address */
  235 +#define MP_WM_ADDR 0x34
  236 +
  237 +const char audio_name[] = "mv88w8618";
  238 +
  239 +typedef struct musicpal_audio_state {
  240 + uint32_t base;
  241 + qemu_irq irq;
  242 + uint32_t playback_mode;
  243 + uint32_t status;
  244 + uint32_t irq_enable;
  245 + unsigned long phys_buf;
  246 + void *target_buffer;
  247 + unsigned int threshold;
  248 + unsigned int play_pos;
  249 + unsigned int last_free;
  250 + uint32_t clock_div;
  251 + i2c_slave *wm;
  252 +} musicpal_audio_state;
  253 +
  254 +static void audio_callback(void *opaque, int free_out, int free_in)
  255 +{
  256 + musicpal_audio_state *s = opaque;
  257 + int16_t channel[2];
  258 + int pos, block_size;
  259 +
  260 + if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN))
  261 + return;
  262 +
  263 + if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE)
  264 + free_out <<= 2;
  265 + else
  266 + free_out <<= 1;
  267 +
  268 + block_size = s->threshold/2;
  269 + if (free_out - s->last_free < block_size)
  270 + return;
  271 +
  272 + if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE)
  273 + for (pos = 0; pos < block_size; pos += 4)
  274 + wm8750_dac_dat(s->wm,
  275 + *(uint32_t *)(s->target_buffer + s->play_pos + pos));
  276 + else
  277 + for (pos = 0; pos < block_size; pos += 2) {
  278 + channel[0] = cpu_to_le16(2 *
  279 + *(int8_t *)(s->target_buffer + s->play_pos + pos));
  280 + channel[1] = cpu_to_le16(2 *
  281 + *(int8_t *)(s->target_buffer + s->play_pos + pos + 1));
  282 + wm8750_dac_dat(s->wm, channel[0] | (channel[1] << 16));
  283 + }
  284 +
  285 + s->last_free = free_out - block_size;
  286 +
  287 + if (s->play_pos == 0) {
  288 + s->status |= MP_AUDIO_TX_HALF;
  289 + s->play_pos = block_size;
  290 + } else {
  291 + s->status |= MP_AUDIO_TX_FULL;
  292 + s->play_pos = 0;
  293 + }
  294 +
  295 + if (s->status & s->irq_enable)
  296 + qemu_irq_raise(s->irq);
  297 +}
  298 +
  299 +static uint32_t musicpal_audio_read(void *opaque, target_phys_addr_t offset)
  300 +{
  301 + musicpal_audio_state *s = opaque;
  302 +
  303 + offset -= s->base;
  304 + switch (offset) {
  305 + case MP_AUDIO_PLAYBACK_MODE:
  306 + return s->playback_mode;
  307 +
  308 + case MP_AUDIO_CLOCK_DIV:
  309 + return s->clock_div;
  310 +
  311 + case MP_AUDIO_IRQ_STATUS:
  312 + return s->status;
  313 +
  314 + case MP_AUDIO_IRQ_ENABLE:
  315 + return s->irq_enable;
  316 +
  317 + case MP_AUDIO_TX_STATUS:
  318 + return s->play_pos >> 2;
  319 +
  320 + default:
  321 + return 0;
  322 + }
  323 +}
  324 +
  325 +static void musicpal_audio_write(void *opaque, target_phys_addr_t offset,
  326 + uint32_t value)
  327 +{
  328 + musicpal_audio_state *s = opaque;
  329 +
  330 + offset -= s->base;
  331 + switch (offset) {
  332 + case MP_AUDIO_PLAYBACK_MODE:
  333 + if (value & MP_AUDIO_PLAYBACK_EN &&
  334 + !(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
  335 + s->status = 0;
  336 + s->last_free = 0;
  337 + s->play_pos = 0;
  338 + }
  339 + s->playback_mode = value;
  340 + break;
  341 +
  342 + case MP_AUDIO_CLOCK_DIV:
  343 + s->clock_div = value;
  344 + s->last_free = 0;
  345 + s->play_pos = 0;
  346 + break;
  347 +
  348 + case MP_AUDIO_IRQ_STATUS:
  349 + s->status &= ~value;
  350 + break;
  351 +
  352 + case MP_AUDIO_IRQ_ENABLE:
  353 + s->irq_enable = value;
  354 + if (s->status & s->irq_enable)
  355 + qemu_irq_raise(s->irq);
  356 + break;
  357 +
  358 + case MP_AUDIO_TX_START_LO:
  359 + s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF);
  360 + s->target_buffer = target2host_addr(s->phys_buf);
  361 + s->play_pos = 0;
  362 + s->last_free = 0;
  363 + break;
  364 +
  365 + case MP_AUDIO_TX_THRESHOLD:
  366 + s->threshold = (value + 1) * 4;
  367 + break;
  368 +
  369 + case MP_AUDIO_TX_START_HI:
  370 + s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16);
  371 + s->target_buffer = target2host_addr(s->phys_buf);
  372 + s->play_pos = 0;
  373 + s->last_free = 0;
  374 + break;
  375 + }
  376 +}
  377 +
  378 +static void musicpal_audio_reset(void *opaque)
  379 +{
  380 + musicpal_audio_state *s = opaque;
  381 +
  382 + s->playback_mode = 0;
  383 + s->status = 0;
  384 + s->irq_enable = 0;
  385 +}
  386 +
  387 +static CPUReadMemoryFunc *musicpal_audio_readfn[] = {
  388 + musicpal_audio_read,
  389 + musicpal_audio_read,
  390 + musicpal_audio_read
  391 +};
  392 +
  393 +static CPUWriteMemoryFunc *musicpal_audio_writefn[] = {
  394 + musicpal_audio_write,
  395 + musicpal_audio_write,
  396 + musicpal_audio_write
  397 +};
  398 +
  399 +static i2c_interface *musicpal_audio_init(uint32_t base, qemu_irq irq)
  400 +{
  401 + AudioState *audio;
  402 + musicpal_audio_state *s;
  403 + i2c_interface *i2c;
  404 + int iomemtype;
  405 +
  406 + audio = AUD_init();
  407 + if (!audio) {
  408 + AUD_log(audio_name, "No audio state\n");
  409 + return NULL;
  410 + }
  411 +
  412 + s = qemu_mallocz(sizeof(musicpal_audio_state));
  413 + if (!s)
  414 + return NULL;
  415 + s->base = base;
  416 + s->irq = irq;
  417 +
  418 + i2c = qemu_mallocz(sizeof(i2c_interface));
  419 + if (!i2c)
  420 + return NULL;
  421 + i2c->bus = i2c_init_bus();
  422 + i2c->current_addr = -1;
  423 +
  424 + s->wm = wm8750_init(i2c->bus, audio);
  425 + if (!s->wm)
  426 + return NULL;
  427 + i2c_set_slave_address(s->wm, MP_WM_ADDR);
  428 + wm8750_data_req_set(s->wm, audio_callback, s);
  429 +
  430 + iomemtype = cpu_register_io_memory(0, musicpal_audio_readfn,
  431 + musicpal_audio_writefn, s);
  432 + cpu_register_physical_memory(base, MP_AUDIO_SIZE, iomemtype);
  433 +
  434 + qemu_register_reset(musicpal_audio_reset, s);
  435 +
  436 + return i2c;
  437 +}
  438 +#else /* !HAS_AUDIO */
  439 +static i2c_interface *musicpal_audio_init(uint32_t base, qemu_irq irq)
  440 +{
  441 + return NULL;
  442 +}
  443 +#endif /* !HAS_AUDIO */
  444 +
  445 +/* Ethernet register offsets */
  446 +#define MP_ETH_SMIR 0x010
  447 +#define MP_ETH_PCXR 0x408
  448 +#define MP_ETH_SDCMR 0x448
  449 +#define MP_ETH_ICR 0x450
  450 +#define MP_ETH_IMR 0x458
  451 +#define MP_ETH_FRDP0 0x480
  452 +#define MP_ETH_FRDP1 0x484
  453 +#define MP_ETH_FRDP2 0x488
  454 +#define MP_ETH_FRDP3 0x48C
  455 +#define MP_ETH_CRDP0 0x4A0
  456 +#define MP_ETH_CRDP1 0x4A4
  457 +#define MP_ETH_CRDP2 0x4A8
  458 +#define MP_ETH_CRDP3 0x4AC
  459 +#define MP_ETH_CTDP0 0x4E0
  460 +#define MP_ETH_CTDP1 0x4E4
  461 +#define MP_ETH_CTDP2 0x4E8
  462 +#define MP_ETH_CTDP3 0x4EC
  463 +
  464 +/* MII PHY access */
  465 +#define MP_ETH_SMIR_DATA 0x0000FFFF
  466 +#define MP_ETH_SMIR_ADDR 0x03FF0000
  467 +#define MP_ETH_SMIR_OPCODE (1 << 26) /* Read value */
  468 +#define MP_ETH_SMIR_RDVALID (1 << 27)
  469 +
  470 +/* PHY registers */
  471 +#define MP_ETH_PHY1_BMSR 0x00210000
  472 +#define MP_ETH_PHY1_PHYSID1 0x00410000
  473 +#define MP_ETH_PHY1_PHYSID2 0x00610000
  474 +
  475 +#define MP_PHY_BMSR_LINK 0x0004
  476 +#define MP_PHY_BMSR_AUTONEG 0x0008
  477 +
  478 +#define MP_PHY_88E3015 0x01410E20
  479 +
  480 +/* TX descriptor status */
  481 +#define MP_ETH_TX_OWN (1 << 31)
  482 +
  483 +/* RX descriptor status */
  484 +#define MP_ETH_RX_OWN (1 << 31)
  485 +
  486 +/* Interrupt cause/mask bits */
  487 +#define MP_ETH_IRQ_RX_BIT 0
  488 +#define MP_ETH_IRQ_RX (1 << MP_ETH_IRQ_RX_BIT)
  489 +#define MP_ETH_IRQ_TXHI_BIT 2
  490 +#define MP_ETH_IRQ_TXLO_BIT 3
  491 +
  492 +/* Port config bits */
  493 +#define MP_ETH_PCXR_2BSM_BIT 28 /* 2-byte incoming suffix */
  494 +
  495 +/* SDMA command bits */
  496 +#define MP_ETH_CMD_TXHI (1 << 23)
  497 +#define MP_ETH_CMD_TXLO (1 << 22)
  498 +
  499 +typedef struct mv88w8618_tx_desc {
  500 + uint32_t cmdstat;
  501 + uint16_t res;
  502 + uint16_t bytes;
  503 + uint32_t buffer;
  504 + uint32_t next;
  505 +} mv88w8618_tx_desc;
  506 +
  507 +typedef struct mv88w8618_rx_desc {
  508 + uint32_t cmdstat;
  509 + uint16_t bytes;
  510 + uint16_t buffer_size;
  511 + uint32_t buffer;
  512 + uint32_t next;
  513 +} mv88w8618_rx_desc;
  514 +
  515 +typedef struct mv88w8618_eth_state {
  516 + uint32_t base;
  517 + qemu_irq irq;
  518 + uint32_t smir;
  519 + uint32_t icr;
  520 + uint32_t imr;
  521 + int vlan_header;
  522 + mv88w8618_tx_desc *tx_queue[2];
  523 + mv88w8618_rx_desc *rx_queue[4];
  524 + mv88w8618_rx_desc *frx_queue[4];
  525 + mv88w8618_rx_desc *cur_rx[4];
  526 + VLANClientState *vc;
  527 +} mv88w8618_eth_state;
  528 +
  529 +static int eth_can_receive(void *opaque)
  530 +{
  531 + return 1;
  532 +}
  533 +
  534 +static void eth_receive(void *opaque, const uint8_t *buf, int size)
  535 +{
  536 + mv88w8618_eth_state *s = opaque;
  537 + mv88w8618_rx_desc *desc;
  538 + int i;
  539 +
  540 + for (i = 0; i < 4; i++) {
  541 + desc = s->cur_rx[i];
  542 + if (!desc)
  543 + continue;
  544 + do {
  545 + if (le32_to_cpu(desc->cmdstat) & MP_ETH_RX_OWN &&
  546 + le16_to_cpu(desc->buffer_size) >= size) {
  547 + memcpy(target2host_addr(le32_to_cpu(desc->buffer) +
  548 + s->vlan_header),
  549 + buf, size);
  550 + desc->bytes = cpu_to_le16(size + s->vlan_header);
  551 + desc->cmdstat &= cpu_to_le32(~MP_ETH_RX_OWN);
  552 + s->cur_rx[i] = target2host_addr(le32_to_cpu(desc->next));
  553 +
  554 + s->icr |= MP_ETH_IRQ_RX;
  555 + if (s->icr & s->imr)
  556 + qemu_irq_raise(s->irq);
  557 + return;
  558 + }
  559 + desc = target2host_addr(le32_to_cpu(desc->next));
  560 + } while (desc != s->rx_queue[i]);
  561 + }
  562 +}
  563 +
  564 +static void eth_send(mv88w8618_eth_state *s, int queue_index)
  565 +{
  566 + mv88w8618_tx_desc *desc = s->tx_queue[queue_index];
  567 +
  568 + do {
  569 + if (le32_to_cpu(desc->cmdstat) & MP_ETH_TX_OWN) {
  570 + qemu_send_packet(s->vc,
  571 + target2host_addr(le32_to_cpu(desc->buffer)),
  572 + le16_to_cpu(desc->bytes));
  573 + desc->cmdstat &= cpu_to_le32(~MP_ETH_TX_OWN);
  574 + s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
  575 + }
  576 + desc = target2host_addr(le32_to_cpu(desc->next));
  577 + } while (desc != s->tx_queue[queue_index]);
  578 +}
  579 +
  580 +static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset)
  581 +{
  582 + mv88w8618_eth_state *s = opaque;
  583 +
  584 + offset -= s->base;
  585 + switch (offset) {
  586 + case MP_ETH_SMIR:
  587 + if (s->smir & MP_ETH_SMIR_OPCODE) {
  588 + switch (s->smir & MP_ETH_SMIR_ADDR) {
  589 + case MP_ETH_PHY1_BMSR:
  590 + return MP_PHY_BMSR_LINK | MP_PHY_BMSR_AUTONEG |
  591 + MP_ETH_SMIR_RDVALID;
  592 + case MP_ETH_PHY1_PHYSID1:
  593 + return (MP_PHY_88E3015 >> 16) | MP_ETH_SMIR_RDVALID;
  594 + case MP_ETH_PHY1_PHYSID2:
  595 + return (MP_PHY_88E3015 & 0xFFFF) | MP_ETH_SMIR_RDVALID;
  596 + default:
  597 + return MP_ETH_SMIR_RDVALID;
  598 + }
  599 + }
  600 + return 0;
  601 +
  602 + case MP_ETH_ICR:
  603 + return s->icr;
  604 +
  605 + case MP_ETH_IMR:
  606 + return s->imr;
  607 +
  608 + case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
  609 + return host2target_addr(s->frx_queue[(offset - MP_ETH_FRDP0)/4]);
  610 +
  611 + case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
  612 + return host2target_addr(s->rx_queue[(offset - MP_ETH_CRDP0)/4]);
  613 +
  614 + case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
  615 + return host2target_addr(s->tx_queue[(offset - MP_ETH_CTDP0)/4]);
  616 +
  617 + default:
  618 + return 0;
  619 + }
  620 +}
  621 +
  622 +static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset,
  623 + uint32_t value)
  624 +{
  625 + mv88w8618_eth_state *s = opaque;
  626 +
  627 + offset -= s->base;
  628 + switch (offset) {
  629 + case MP_ETH_SMIR:
  630 + s->smir = value;
  631 + break;
  632 +
  633 + case MP_ETH_PCXR:
  634 + s->vlan_header = ((value >> MP_ETH_PCXR_2BSM_BIT) & 1) * 2;
  635 + break;
  636 +
  637 + case MP_ETH_SDCMR:
  638 + if (value & MP_ETH_CMD_TXHI)
  639 + eth_send(s, 1);
  640 + if (value & MP_ETH_CMD_TXLO)
  641 + eth_send(s, 0);
  642 + if (value & (MP_ETH_CMD_TXHI | MP_ETH_CMD_TXLO) && s->icr & s->imr)
  643 + qemu_irq_raise(s->irq);
  644 + break;
  645 +
  646 + case MP_ETH_ICR:
  647 + s->icr &= value;
  648 + break;
  649 +
  650 + case MP_ETH_IMR:
  651 + s->imr = value;
  652 + if (s->icr & s->imr)
  653 + qemu_irq_raise(s->irq);
  654 + break;
  655 +
  656 + case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
  657 + s->frx_queue[(offset - MP_ETH_FRDP0)/4] = target2host_addr(value);
  658 + break;
  659 +
  660 + case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
  661 + s->rx_queue[(offset - MP_ETH_CRDP0)/4] =
  662 + s->cur_rx[(offset - MP_ETH_CRDP0)/4] = target2host_addr(value);
  663 + break;
  664 +
  665 + case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
  666 + s->tx_queue[(offset - MP_ETH_CTDP0)/4] = target2host_addr(value);
  667 + break;
  668 + }
  669 +}
  670 +
  671 +static CPUReadMemoryFunc *mv88w8618_eth_readfn[] = {
  672 + mv88w8618_eth_read,
  673 + mv88w8618_eth_read,
  674 + mv88w8618_eth_read
  675 +};
  676 +
  677 +static CPUWriteMemoryFunc *mv88w8618_eth_writefn[] = {
  678 + mv88w8618_eth_write,
  679 + mv88w8618_eth_write,
  680 + mv88w8618_eth_write
  681 +};
  682 +
  683 +static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq)
  684 +{
  685 + mv88w8618_eth_state *s;
  686 + int iomemtype;
  687 +
  688 + s = qemu_mallocz(sizeof(mv88w8618_eth_state));
  689 + if (!s)
  690 + return;
  691 + s->base = base;
  692 + s->irq = irq;
  693 + s->vc = qemu_new_vlan_client(nd->vlan, eth_receive, eth_can_receive, s);
  694 + iomemtype = cpu_register_io_memory(0, mv88w8618_eth_readfn,
  695 + mv88w8618_eth_writefn, s);
  696 + cpu_register_physical_memory(base, MP_ETH_SIZE, iomemtype);
  697 +}
  698 +
  699 +/* LCD register offsets */
  700 +#define MP_LCD_IRQCTRL 0x180
  701 +#define MP_LCD_IRQSTAT 0x184
  702 +#define MP_LCD_SPICTRL 0x1ac
  703 +#define MP_LCD_INST 0x1bc
  704 +#define MP_LCD_DATA 0x1c0
  705 +
  706 +/* Mode magics */
  707 +#define MP_LCD_SPI_DATA 0x00100011
  708 +#define MP_LCD_SPI_CMD 0x00104011
  709 +#define MP_LCD_SPI_INVALID 0x00000000
  710 +
  711 +/* Commmands */
  712 +#define MP_LCD_INST_SETPAGE0 0xB0
  713 +/* ... */
  714 +#define MP_LCD_INST_SETPAGE7 0xB7
  715 +
  716 +#define MP_LCD_TEXTCOLOR 0xe0e0ff /* RRGGBB */
  717 +
  718 +typedef struct musicpal_lcd_state {
  719 + uint32_t base;
  720 + uint32_t mode;
  721 + uint32_t irqctrl;
  722 + int page;
  723 + int page_off;
  724 + DisplayState *ds;
  725 + uint8_t video_ram[128*64/8];
  726 +} musicpal_lcd_state;
  727 +
  728 +static uint32_t lcd_brightness;
  729 +
  730 +static uint8_t scale_lcd_color(uint8_t col)
  731 +{
  732 + int tmp = col;
  733 +
  734 + switch (lcd_brightness) {
  735 + case 0x00000007: /* 0 */
  736 + return 0;
  737 +
  738 + case 0x00020000: /* 1 */
  739 + return (tmp * 1) / 7;
  740 +
  741 + case 0x00020001: /* 2 */
  742 + return (tmp * 2) / 7;
  743 +
  744 + case 0x00040000: /* 3 */
  745 + return (tmp * 3) / 7;
  746 +
  747 + case 0x00010006: /* 4 */
  748 + return (tmp * 4) / 7;
  749 +
  750 + case 0x00020005: /* 5 */
  751 + return (tmp * 5) / 7;
  752 +
  753 + case 0x00040003: /* 6 */
  754 + return (tmp * 6) / 7;
  755 +
  756 + case 0x00030004: /* 7 */
  757 + default:
  758 + return col;
  759 + }
  760 +}
  761 +
  762 +static void set_lcd_pixel(musicpal_lcd_state *s, int x, int y, int col)
  763 +{
  764 + int dx, dy;
  765 +
  766 + for (dy = 0; dy < 3; dy++)
  767 + for (dx = 0; dx < 3; dx++) {
  768 + s->ds->data[(x*3 + dx + (y*3 + dy) * 128*3) * 4 + 0] =
  769 + scale_lcd_color(col);
  770 + s->ds->data[(x*3 + dx + (y*3 + dy) * 128*3) * 4 + 1] =
  771 + scale_lcd_color(col >> 8);
  772 + s->ds->data[(x*3 + dx + (y*3 + dy) * 128*3) * 4 + 2] =
  773 + scale_lcd_color(col >> 16);
  774 + }
  775 +}
  776 +
  777 +static void lcd_refresh(void *opaque)
  778 +{
  779 + musicpal_lcd_state *s = opaque;
  780 + int x, y;
  781 +
  782 + for (x = 0; x < 128; x++)
  783 + for (y = 0; y < 64; y++)
  784 + if (s->video_ram[x + (y/8)*128] & (1 << (y % 8)))
  785 + set_lcd_pixel(s, x, y, MP_LCD_TEXTCOLOR);
  786 + else
  787 + set_lcd_pixel(s, x, y, 0);
  788 +
  789 + dpy_update(s->ds, 0, 0, 128*3, 64*3);
  790 +}
  791 +
  792 +static uint32_t musicpal_lcd_read(void *opaque, target_phys_addr_t offset)
  793 +{
  794 + musicpal_lcd_state *s = opaque;
  795 +
  796 + offset -= s->base;
  797 + switch (offset) {
  798 + case MP_LCD_IRQCTRL:
  799 + return s->irqctrl;
  800 +
  801 + default:
  802 + return 0;
  803 + }
  804 +}
  805 +
  806 +static void musicpal_lcd_write(void *opaque, target_phys_addr_t offset,
  807 + uint32_t value)
  808 +{
  809 + musicpal_lcd_state *s = opaque;
  810 +
  811 + offset -= s->base;
  812 + switch (offset) {
  813 + case MP_LCD_IRQCTRL:
  814 + s->irqctrl = value;
  815 + break;
  816 +
  817 + case MP_LCD_SPICTRL:
  818 + if (value == MP_LCD_SPI_DATA || value == MP_LCD_SPI_CMD)
  819 + s->mode = value;
  820 + else
  821 + s->mode = MP_LCD_SPI_INVALID;
  822 + break;
  823 +
  824 + case MP_LCD_INST:
  825 + if (value >= MP_LCD_INST_SETPAGE0 && value <= MP_LCD_INST_SETPAGE7) {
  826 + s->page = value - MP_LCD_INST_SETPAGE0;
  827 + s->page_off = 0;
  828 + }
  829 + break;
  830 +
  831 + case MP_LCD_DATA:
  832 + if (s->mode == MP_LCD_SPI_CMD) {
  833 + if (value >= MP_LCD_INST_SETPAGE0 &&
  834 + value <= MP_LCD_INST_SETPAGE7) {
  835 + s->page = value - MP_LCD_INST_SETPAGE0;
  836 + s->page_off = 0;
  837 + }
  838 + } else if (s->mode == MP_LCD_SPI_DATA) {
  839 + s->video_ram[s->page*128 + s->page_off] = value;
  840 + s->page_off = (s->page_off + 1) & 127;
  841 + }
  842 + break;
  843 + }
  844 +}
  845 +
  846 +static CPUReadMemoryFunc *musicpal_lcd_readfn[] = {
  847 + musicpal_lcd_read,
  848 + musicpal_lcd_read,
  849 + musicpal_lcd_read
  850 +};
  851 +
  852 +static CPUWriteMemoryFunc *musicpal_lcd_writefn[] = {
  853 + musicpal_lcd_write,
  854 + musicpal_lcd_write,
  855 + musicpal_lcd_write
  856 +};
  857 +
  858 +static void musicpal_lcd_init(DisplayState *ds, uint32_t base)
  859 +{
  860 + musicpal_lcd_state *s;
  861 + int iomemtype;
  862 +
  863 + s = qemu_mallocz(sizeof(musicpal_lcd_state));
  864 + if (!s)
  865 + return;
  866 + s->base = base;
  867 + s->ds = ds;
  868 + iomemtype = cpu_register_io_memory(0, musicpal_lcd_readfn,
  869 + musicpal_lcd_writefn, s);
  870 + cpu_register_physical_memory(base, MP_LCD_SIZE, iomemtype);
  871 +
  872 + graphic_console_init(ds, lcd_refresh, NULL, NULL, NULL, s);
  873 + dpy_resize(ds, 128*3, 64*3);
  874 +}
  875 +
  876 +/* PIC register offsets */
  877 +#define MP_PIC_STATUS 0x00
  878 +#define MP_PIC_ENABLE_SET 0x08
  879 +#define MP_PIC_ENABLE_CLR 0x0C
  880 +
  881 +typedef struct mv88w8618_pic_state
  882 +{
  883 + uint32_t base;
  884 + uint32_t level;
  885 + uint32_t enabled;
  886 + qemu_irq parent_irq;
  887 +} mv88w8618_pic_state;
  888 +
  889 +static void mv88w8618_pic_update(mv88w8618_pic_state *s)
  890 +{
  891 + qemu_set_irq(s->parent_irq, (s->level & s->enabled));
  892 +}
  893 +
  894 +static void mv88w8618_pic_set_irq(void *opaque, int irq, int level)
  895 +{
  896 + mv88w8618_pic_state *s = opaque;
  897 +
  898 + if (level)
  899 + s->level |= 1 << irq;
  900 + else
  901 + s->level &= ~(1 << irq);
  902 + mv88w8618_pic_update(s);
  903 +}
  904 +
  905 +static uint32_t mv88w8618_pic_read(void *opaque, target_phys_addr_t offset)
  906 +{
  907 + mv88w8618_pic_state *s = opaque;
  908 +
  909 + offset -= s->base;
  910 + switch (offset) {
  911 + case MP_PIC_STATUS:
  912 + return s->level & s->enabled;
  913 +
  914 + default:
  915 + return 0;
  916 + }
  917 +}
  918 +
  919 +static void mv88w8618_pic_write(void *opaque, target_phys_addr_t offset,
  920 + uint32_t value)
  921 +{
  922 + mv88w8618_pic_state *s = opaque;
  923 +
  924 + offset -= s->base;
  925 + switch (offset) {
  926 + case MP_PIC_ENABLE_SET:
  927 + s->enabled |= value;
  928 + break;
  929 +
  930 + case MP_PIC_ENABLE_CLR:
  931 + s->enabled &= ~value;
  932 + s->level &= ~value;
  933 + break;
  934 + }
  935 + mv88w8618_pic_update(s);
  936 +}
  937 +
  938 +static void mv88w8618_pic_reset(void *opaque)
  939 +{
  940 + mv88w8618_pic_state *s = opaque;
  941 +
  942 + s->level = 0;
  943 + s->enabled = 0;
  944 +}
  945 +
  946 +static CPUReadMemoryFunc *mv88w8618_pic_readfn[] = {
  947 + mv88w8618_pic_read,
  948 + mv88w8618_pic_read,
  949 + mv88w8618_pic_read
  950 +};
  951 +
  952 +static CPUWriteMemoryFunc *mv88w8618_pic_writefn[] = {
  953 + mv88w8618_pic_write,
  954 + mv88w8618_pic_write,
  955 + mv88w8618_pic_write
  956 +};
  957 +
  958 +static qemu_irq *mv88w8618_pic_init(uint32_t base, qemu_irq parent_irq)
  959 +{
  960 + mv88w8618_pic_state *s;
  961 + int iomemtype;
  962 + qemu_irq *qi;
  963 +
  964 + s = qemu_mallocz(sizeof(mv88w8618_pic_state));
  965 + if (!s)
  966 + return NULL;
  967 + qi = qemu_allocate_irqs(mv88w8618_pic_set_irq, s, 32);
  968 + s->base = base;
  969 + s->parent_irq = parent_irq;
  970 + iomemtype = cpu_register_io_memory(0, mv88w8618_pic_readfn,
  971 + mv88w8618_pic_writefn, s);
  972 + cpu_register_physical_memory(base, MP_PIC_SIZE, iomemtype);
  973 +
  974 + qemu_register_reset(mv88w8618_pic_reset, s);
  975 +
  976 + return qi;
  977 +}
  978 +
  979 +/* PIT register offsets */
  980 +#define MP_PIT_TIMER1_LENGTH 0x00
  981 +/* ... */
  982 +#define MP_PIT_TIMER4_LENGTH 0x0C
  983 +#define MP_PIT_CONTROL 0x10
  984 +#define MP_PIT_TIMER1_VALUE 0x14
  985 +/* ... */
  986 +#define MP_PIT_TIMER4_VALUE 0x20
  987 +#define MP_BOARD_RESET 0x34
  988 +
  989 +/* Magic board reset value (probably some watchdog behind it) */
  990 +#define MP_BOARD_RESET_MAGIC 0x10000
  991 +
  992 +typedef struct mv88w8618_timer_state {
  993 + ptimer_state *timer;
  994 + uint32_t limit;
  995 + int freq;
  996 + qemu_irq irq;
  997 +} mv88w8618_timer_state;
  998 +
  999 +typedef struct mv88w8618_pit_state {
  1000 + void *timer[4];
  1001 + uint32_t control;
  1002 + uint32_t base;
  1003 +} mv88w8618_pit_state;
  1004 +
  1005 +static void mv88w8618_timer_tick(void *opaque)
  1006 +{
  1007 + mv88w8618_timer_state *s = opaque;
  1008 +
  1009 + qemu_irq_raise(s->irq);
  1010 +}
  1011 +
  1012 +static void *mv88w8618_timer_init(uint32_t freq, qemu_irq irq)
  1013 +{
  1014 + mv88w8618_timer_state *s;
  1015 + QEMUBH *bh;
  1016 +
  1017 + s = qemu_mallocz(sizeof(mv88w8618_timer_state));
  1018 + s->irq = irq;
  1019 + s->freq = freq;
  1020 +
  1021 + bh = qemu_bh_new(mv88w8618_timer_tick, s);
  1022 + s->timer = ptimer_init(bh);
  1023 +
  1024 + return s;
  1025 +}
  1026 +
  1027 +static uint32_t mv88w8618_pit_read(void *opaque, target_phys_addr_t offset)
  1028 +{
  1029 + mv88w8618_pit_state *s = opaque;
  1030 + mv88w8618_timer_state *t;
  1031 +
  1032 + offset -= s->base;
  1033 + switch (offset) {
  1034 + case MP_PIT_TIMER1_VALUE ... MP_PIT_TIMER4_VALUE:
  1035 + t = s->timer[(offset-MP_PIT_TIMER1_VALUE) >> 2];
  1036 + return ptimer_get_count(t->timer);
  1037 +
  1038 + default:
  1039 + return 0;
  1040 + }
  1041 +}
  1042 +
  1043 +static void mv88w8618_pit_write(void *opaque, target_phys_addr_t offset,
  1044 + uint32_t value)
  1045 +{
  1046 + mv88w8618_pit_state *s = opaque;
  1047 + mv88w8618_timer_state *t;
  1048 + int i;
  1049 +
  1050 + offset -= s->base;
  1051 + switch (offset) {
  1052 + case MP_PIT_TIMER1_LENGTH ... MP_PIT_TIMER4_LENGTH:
  1053 + t = s->timer[offset >> 2];
  1054 + t->limit = value;
  1055 + ptimer_set_limit(t->timer, t->limit, 1);
  1056 + break;
  1057 +
  1058 + case MP_PIT_CONTROL:
  1059 + for (i = 0; i < 4; i++) {
  1060 + if (value & 0xf) {
  1061 + t = s->timer[i];
  1062 + ptimer_set_limit(t->timer, t->limit, 0);
  1063 + ptimer_set_freq(t->timer, t->freq);
  1064 + ptimer_run(t->timer, 0);
  1065 + }
  1066 + value >>= 4;
  1067 + }
  1068 + break;
  1069 +
  1070 + case MP_BOARD_RESET:
  1071 + if (value == MP_BOARD_RESET_MAGIC)
  1072 + qemu_system_reset_request();
  1073 + break;
  1074 + }
  1075 +}
  1076 +
  1077 +static CPUReadMemoryFunc *mv88w8618_pit_readfn[] = {
  1078 + mv88w8618_pit_read,
  1079 + mv88w8618_pit_read,
  1080 + mv88w8618_pit_read
  1081 +};
  1082 +
  1083 +static CPUWriteMemoryFunc *mv88w8618_pit_writefn[] = {
  1084 + mv88w8618_pit_write,
  1085 + mv88w8618_pit_write,
  1086 + mv88w8618_pit_write
  1087 +};
  1088 +
  1089 +static void mv88w8618_pit_init(uint32_t base, qemu_irq *pic, int irq)
  1090 +{
  1091 + int iomemtype;
  1092 + mv88w8618_pit_state *s;
  1093 +
  1094 + s = qemu_mallocz(sizeof(mv88w8618_pit_state));
  1095 + if (!s)
  1096 + return;
  1097 +
  1098 + s->base = base;
  1099 + /* Letting them all run at 1 MHz is likely just a pragmatic
  1100 + * simplification. */
  1101 + s->timer[0] = mv88w8618_timer_init(1000000, pic[irq]);
  1102 + s->timer[1] = mv88w8618_timer_init(1000000, pic[irq + 1]);
  1103 + s->timer[2] = mv88w8618_timer_init(1000000, pic[irq + 2]);
  1104 + s->timer[3] = mv88w8618_timer_init(1000000, pic[irq + 3]);
  1105 +
  1106 + iomemtype = cpu_register_io_memory(0, mv88w8618_pit_readfn,
  1107 + mv88w8618_pit_writefn, s);
  1108 + cpu_register_physical_memory(base, MP_PIT_SIZE, iomemtype);
  1109 +}
  1110 +
  1111 +/* Flash config register offsets */
  1112 +#define MP_FLASHCFG_CFGR0 0x04
  1113 +
  1114 +typedef struct mv88w8618_flashcfg_state {
  1115 + uint32_t base;
  1116 + uint32_t cfgr0;
  1117 +} mv88w8618_flashcfg_state;
  1118 +
  1119 +static uint32_t mv88w8618_flashcfg_read(void *opaque,
  1120 + target_phys_addr_t offset)
  1121 +{
  1122 + mv88w8618_flashcfg_state *s = opaque;
  1123 +
  1124 + offset -= s->base;
  1125 + switch (offset) {
  1126 + case MP_FLASHCFG_CFGR0:
  1127 + return s->cfgr0;
  1128 +
  1129 + default:
  1130 + return 0;
  1131 + }
  1132 +}
  1133 +
  1134 +static void mv88w8618_flashcfg_write(void *opaque, target_phys_addr_t offset,
  1135 + uint32_t value)
  1136 +{
  1137 + mv88w8618_flashcfg_state *s = opaque;
  1138 +
  1139 + offset -= s->base;
  1140 + switch (offset) {
  1141 + case MP_FLASHCFG_CFGR0:
  1142 + s->cfgr0 = value;
  1143 + break;
  1144 + }
  1145 +}
  1146 +
  1147 +static CPUReadMemoryFunc *mv88w8618_flashcfg_readfn[] = {
  1148 + mv88w8618_flashcfg_read,
  1149 + mv88w8618_flashcfg_read,
  1150 + mv88w8618_flashcfg_read
  1151 +};
  1152 +
  1153 +static CPUWriteMemoryFunc *mv88w8618_flashcfg_writefn[] = {
  1154 + mv88w8618_flashcfg_write,
  1155 + mv88w8618_flashcfg_write,
  1156 + mv88w8618_flashcfg_write
  1157 +};
  1158 +
  1159 +static void mv88w8618_flashcfg_init(uint32_t base)
  1160 +{
  1161 + int iomemtype;
  1162 + mv88w8618_flashcfg_state *s;
  1163 +
  1164 + s = qemu_mallocz(sizeof(mv88w8618_flashcfg_state));
  1165 + if (!s)
  1166 + return;
  1167 +
  1168 + s->base = base;
  1169 + s->cfgr0 = 0xfffe4285; /* Default as set by U-Boot for 8 MB flash */
  1170 + iomemtype = cpu_register_io_memory(0, mv88w8618_flashcfg_readfn,
  1171 + mv88w8618_flashcfg_writefn, s);
  1172 + cpu_register_physical_memory(base, MP_FLASHCFG_SIZE, iomemtype);
  1173 +}
  1174 +
  1175 +/* Various registers in the 0x80000000 domain */
  1176 +#define MP_BOARD_REVISION 0x2018
  1177 +
  1178 +#define MP_WLAN_MAGIC1 0xc11c
  1179 +#define MP_WLAN_MAGIC2 0xc124
  1180 +
  1181 +#define MP_GPIO_OE_LO 0xd008
  1182 +#define MP_GPIO_OUT_LO 0xd00c
  1183 +#define MP_GPIO_IN_LO 0xd010
  1184 +#define MP_GPIO_ISR_LO 0xd020
  1185 +#define MP_GPIO_OE_HI 0xd508
  1186 +#define MP_GPIO_OUT_HI 0xd50c
  1187 +#define MP_GPIO_IN_HI 0xd510
  1188 +#define MP_GPIO_ISR_HI 0xd520
  1189 +
  1190 +/* GPIO bits & masks */
  1191 +#define MP_GPIO_WHEEL_VOL (1 << 8)
  1192 +#define MP_GPIO_WHEEL_VOL_INV (1 << 9)
  1193 +#define MP_GPIO_WHEEL_NAV (1 << 10)
  1194 +#define MP_GPIO_WHEEL_NAV_INV (1 << 11)
  1195 +#define MP_GPIO_LCD_BRIGHTNESS 0x00070000
  1196 +#define MP_GPIO_BTN_FAVORITS (1 << 19)
  1197 +#define MP_GPIO_BTN_MENU (1 << 20)
  1198 +#define MP_GPIO_BTN_VOLUME (1 << 21)
  1199 +#define MP_GPIO_BTN_NAVIGATION (1 << 22)
  1200 +#define MP_GPIO_I2C_DATA_BIT 29
  1201 +#define MP_GPIO_I2C_DATA (1 << MP_GPIO_I2C_DATA_BIT)
  1202 +#define MP_GPIO_I2C_CLOCK_BIT 30
  1203 +
  1204 +/* LCD brightness bits in GPIO_OE_HI */
  1205 +#define MP_OE_LCD_BRIGHTNESS 0x0007
  1206 +
  1207 +static uint32_t musicpal_read(void *opaque, target_phys_addr_t offset)
  1208 +{
  1209 + offset -= 0x80000000;
  1210 + switch (offset) {
  1211 + case MP_BOARD_REVISION:
  1212 + return 0x0031;
  1213 +
  1214 + case MP_GPIO_OE_HI: /* used for LCD brightness control */
  1215 + return lcd_brightness & MP_OE_LCD_BRIGHTNESS;
  1216 +
  1217 + case MP_GPIO_OUT_LO:
  1218 + return gpio_out_state & 0xFFFF;
  1219 + case MP_GPIO_OUT_HI:
  1220 + return gpio_out_state >> 16;
  1221 +
  1222 + case MP_GPIO_IN_LO:
  1223 + return gpio_in_state & 0xFFFF;
  1224 + case MP_GPIO_IN_HI:
  1225 + /* Update received I2C data */
  1226 + gpio_in_state = (gpio_in_state & ~MP_GPIO_I2C_DATA) |
  1227 + (i2c_get_data(mixer_i2c) << MP_GPIO_I2C_DATA_BIT);
  1228 + return gpio_in_state >> 16;
  1229 +
  1230 + /* This is a simplification of reality */
  1231 + case MP_GPIO_ISR_LO:
  1232 + return ~gpio_in_state & 0xFFFF;
  1233 + case MP_GPIO_ISR_HI:
  1234 + return ~gpio_in_state >> 16;
  1235 +
  1236 + /* Workaround to allow loading the binary-only wlandrv.ko crap
  1237 + * from the original Freecom firmware. */
  1238 + case MP_WLAN_MAGIC1:
  1239 + return ~3;
  1240 + case MP_WLAN_MAGIC2:
  1241 + return -1;
  1242 +
  1243 + default:
  1244 + return 0;
  1245 + }
  1246 +}
  1247 +
  1248 +static void musicpal_write(void *opaque, target_phys_addr_t offset,
  1249 + uint32_t value)
  1250 +{
  1251 + offset -= 0x80000000;
  1252 + switch (offset) {
  1253 + case MP_GPIO_OE_HI: /* used for LCD brightness control */
  1254 + lcd_brightness = (lcd_brightness & MP_GPIO_LCD_BRIGHTNESS) |
  1255 + (value & MP_OE_LCD_BRIGHTNESS);
  1256 + break;
  1257 +
  1258 + case MP_GPIO_OUT_LO:
  1259 + gpio_out_state = (gpio_out_state & 0xFFFF0000) | (value & 0xFFFF);
  1260 + break;
  1261 + case MP_GPIO_OUT_HI:
  1262 + gpio_out_state = (gpio_out_state & 0xFFFF) | (value << 16);
  1263 + lcd_brightness = (lcd_brightness & 0xFFFF) |
  1264 + (gpio_out_state & MP_GPIO_LCD_BRIGHTNESS);
  1265 + i2c_state_update(mixer_i2c,
  1266 + (gpio_out_state >> MP_GPIO_I2C_DATA_BIT) & 1,
  1267 + (gpio_out_state >> MP_GPIO_I2C_CLOCK_BIT) & 1);
  1268 + break;
  1269 +
  1270 + }
  1271 +}
  1272 +
  1273 +/* Keyboard codes & masks */
  1274 +#define KEY_PRESSED 0x80
  1275 +#define KEY_CODE 0x7f
  1276 +
  1277 +#define KEYCODE_TAB 0x0f
  1278 +#define KEYCODE_ENTER 0x1c
  1279 +#define KEYCODE_F 0x21
  1280 +#define KEYCODE_M 0x32
  1281 +
  1282 +#define KEYCODE_EXTENDED 0xe0
  1283 +#define KEYCODE_UP 0x48
  1284 +#define KEYCODE_DOWN 0x50
  1285 +#define KEYCODE_LEFT 0x4b
  1286 +#define KEYCODE_RIGHT 0x4d
  1287 +
  1288 +static void musicpal_key_event(void *opaque, int keycode)
  1289 +{
  1290 + qemu_irq irq = opaque;
  1291 + uint32_t event = 0;
  1292 + static int kbd_extended;
  1293 +
  1294 + if (keycode == KEYCODE_EXTENDED) {
  1295 + kbd_extended = 1;
  1296 + return;
  1297 + }
  1298 +
  1299 + if (kbd_extended)
  1300 + switch (keycode & KEY_CODE) {
  1301 + case KEYCODE_UP:
  1302 + event = MP_GPIO_WHEEL_NAV | MP_GPIO_WHEEL_NAV_INV;
  1303 + break;
  1304 +
  1305 + case KEYCODE_DOWN:
  1306 + event = MP_GPIO_WHEEL_NAV;
  1307 + break;
  1308 +
  1309 + case KEYCODE_LEFT:
  1310 + event = MP_GPIO_WHEEL_VOL | MP_GPIO_WHEEL_VOL_INV;
  1311 + break;
  1312 +
  1313 + case KEYCODE_RIGHT:
  1314 + event = MP_GPIO_WHEEL_VOL;
  1315 + break;
  1316 + }
  1317 + else
  1318 + switch (keycode & KEY_CODE) {
  1319 + case KEYCODE_F:
  1320 + event = MP_GPIO_BTN_FAVORITS;
  1321 + break;
  1322 +
  1323 + case KEYCODE_TAB:
  1324 + event = MP_GPIO_BTN_VOLUME;
  1325 + break;
  1326 +
  1327 + case KEYCODE_ENTER:
  1328 + event = MP_GPIO_BTN_NAVIGATION;
  1329 + break;
  1330 +
  1331 + case KEYCODE_M:
  1332 + event = MP_GPIO_BTN_MENU;
  1333 + break;
  1334 + }
  1335 +
  1336 + if (keycode & KEY_PRESSED)
  1337 + gpio_in_state |= event;
  1338 + else if (gpio_in_state & event) {
  1339 + gpio_in_state &= ~event;
  1340 + qemu_irq_raise(irq);
  1341 + }
  1342 +
  1343 + kbd_extended = 0;
  1344 +}
  1345 +
  1346 +static CPUReadMemoryFunc *musicpal_readfn[] = {
  1347 + musicpal_read,
  1348 + musicpal_read,
  1349 + musicpal_read,
  1350 +};
  1351 +
  1352 +static CPUWriteMemoryFunc *musicpal_writefn[] = {
  1353 + musicpal_write,
  1354 + musicpal_write,
  1355 + musicpal_write,
  1356 +};
  1357 +
  1358 +static struct arm_boot_info musicpal_binfo = {
  1359 + .loader_start = 0x0,
  1360 + .board_id = 0x20e,
  1361 +};
  1362 +
  1363 +static void musicpal_init(int ram_size, int vga_ram_size,
  1364 + const char *boot_device, DisplayState *ds,
  1365 + const char *kernel_filename, const char *kernel_cmdline,
  1366 + const char *initrd_filename, const char *cpu_model)
  1367 +{
  1368 + CPUState *env;
  1369 + qemu_irq *pic;
  1370 + int index;
  1371 + int iomemtype;
  1372 + unsigned long flash_size;
  1373 +
  1374 + if (!cpu_model)
  1375 + cpu_model = "arm926";
  1376 +
  1377 + env = cpu_init(cpu_model);
  1378 + if (!env) {
  1379 + fprintf(stderr, "Unable to find CPU definition\n");
  1380 + exit(1);
  1381 + }
  1382 + pic = arm_pic_init_cpu(env);
  1383 +
  1384 + /* For now we use a fixed - the original - RAM size */
  1385 + cpu_register_physical_memory(0, MP_RAM_DEFAULT_SIZE,
  1386 + qemu_ram_alloc(MP_RAM_DEFAULT_SIZE));
  1387 +
  1388 + sram_off = qemu_ram_alloc(MP_SRAM_SIZE);
  1389 + cpu_register_physical_memory(MP_SRAM_BASE, MP_SRAM_SIZE, sram_off);
  1390 +
  1391 + /* Catch various stuff not handled by separate subsystems */
  1392 + iomemtype = cpu_register_io_memory(0, musicpal_readfn,
  1393 + musicpal_writefn, first_cpu);
  1394 + cpu_register_physical_memory(0x80000000, 0x10000, iomemtype);
  1395 +
  1396 + pic = mv88w8618_pic_init(MP_PIC_BASE, pic[ARM_PIC_CPU_IRQ]);
  1397 + mv88w8618_pit_init(MP_PIT_BASE, pic, MP_TIMER1_IRQ);
  1398 +
  1399 + if (serial_hds[0])
  1400 + serial_mm_init(MP_UART1_BASE, 2, pic[MP_UART1_IRQ], /*1825000,*/
  1401 + serial_hds[0], 1);
  1402 + if (serial_hds[1])
  1403 + serial_mm_init(MP_UART2_BASE, 2, pic[MP_UART2_IRQ], /*1825000,*/
  1404 + serial_hds[1], 1);
  1405 +
  1406 + /* Register flash */
  1407 + index = drive_get_index(IF_PFLASH, 0, 0);
  1408 + if (index != -1) {
  1409 + flash_size = bdrv_getlength(drives_table[index].bdrv);
  1410 + if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
  1411 + flash_size != 32*1024*1024) {
  1412 + fprintf(stderr, "Invalid flash image size\n");
  1413 + exit(1);
  1414 + }
  1415 +
  1416 + /*
  1417 + * The original U-Boot accesses the flash at 0xFE000000 instead of
  1418 + * 0xFF800000 (if there is 8 MB flash). So remap flash access if the
  1419 + * image is smaller than 32 MB.
  1420 + */
  1421 + pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, qemu_ram_alloc(flash_size),
  1422 + drives_table[index].bdrv, 0x10000,
  1423 + (flash_size + 0xffff) >> 16,
  1424 + MP_FLASH_SIZE_MAX / flash_size,
  1425 + 2, 0x00BF, 0x236D, 0x0000, 0x0000,
  1426 + 0x5555, 0x2AAA);
  1427 + }
  1428 + mv88w8618_flashcfg_init(MP_FLASHCFG_BASE);
  1429 +
  1430 + musicpal_lcd_init(ds, MP_LCD_BASE);
  1431 +
  1432 + qemu_add_kbd_event_handler(musicpal_key_event, pic[MP_GPIO_IRQ]);
  1433 +
  1434 + /*
  1435 + * Wait a bit to catch menu button during U-Boot start-up
  1436 + * (to trigger emergency update).
  1437 + */
  1438 + sleep(1);
  1439 +
  1440 + mv88w8618_eth_init(&nd_table[0], MP_ETH_BASE, pic[MP_ETH_IRQ]);
  1441 +
  1442 + mixer_i2c = musicpal_audio_init(MP_AUDIO_BASE, pic[MP_AUDIO_IRQ]);
  1443 +
  1444 + musicpal_binfo.ram_size = MP_RAM_DEFAULT_SIZE;
  1445 + musicpal_binfo.kernel_filename = kernel_filename;
  1446 + musicpal_binfo.kernel_cmdline = kernel_cmdline;
  1447 + musicpal_binfo.initrd_filename = initrd_filename;
  1448 + arm_load_kernel(first_cpu, &musicpal_binfo);
  1449 +}
  1450 +
  1451 +QEMUMachine musicpal_machine = {
  1452 + "musicpal",
  1453 + "Marvell 88w8618 / MusicPal (ARM926EJ-S)",
  1454 + musicpal_init,
  1455 + MP_RAM_DEFAULT_SIZE + MP_SRAM_SIZE + MP_FLASH_SIZE_MAX + RAMSIZE_FIXED
  1456 +};
... ...
... ... @@ -8057,6 +8057,7 @@ static void register_machines(void)
8057 8057 qemu_register_machine(&connex_machine);
8058 8058 qemu_register_machine(&verdex_machine);
8059 8059 qemu_register_machine(&mainstone2_machine);
  8060 + qemu_register_machine(&musicpal_machine);
8060 8061 #elif defined(TARGET_SH4)
8061 8062 qemu_register_machine(&shix_machine);
8062 8063 qemu_register_machine(&r2d_machine);
... ...