Statistics
| Branch: | Revision:

root / hw / musicpal.c @ 9a6ee9fd

History | View | Annotate | Download (46.5 kB)

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