Statistics
| Branch: | Revision:

root / hw / pl022.c @ 93148aa5

History | View | Annotate | Download (8.4 kB)

1 9ee6e8bb pbrook
/*
2 9ee6e8bb pbrook
 * Arm PrimeCell PL022 Synchronous Serial Port
3 9ee6e8bb pbrook
 *
4 9ee6e8bb pbrook
 * Copyright (c) 2007 CodeSourcery.
5 9ee6e8bb pbrook
 * Written by Paul Brook
6 9ee6e8bb pbrook
 *
7 8e31bf38 Matthew Fernandez
 * This code is licensed under the GPL.
8 9ee6e8bb pbrook
 */
9 9ee6e8bb pbrook
10 5493e33f Paul Brook
#include "sysbus.h"
11 5493e33f Paul Brook
#include "ssi.h"
12 9ee6e8bb pbrook
13 9ee6e8bb pbrook
//#define DEBUG_PL022 1
14 9ee6e8bb pbrook
15 9ee6e8bb pbrook
#ifdef DEBUG_PL022
16 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) \
17 001faf32 Blue Swirl
do { printf("pl022: " fmt , ## __VA_ARGS__); } while (0)
18 001faf32 Blue Swirl
#define BADF(fmt, ...) \
19 001faf32 Blue Swirl
do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
20 9ee6e8bb pbrook
#else
21 001faf32 Blue Swirl
#define DPRINTF(fmt, ...) do {} while(0)
22 001faf32 Blue Swirl
#define BADF(fmt, ...) \
23 001faf32 Blue Swirl
do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
24 9ee6e8bb pbrook
#endif
25 9ee6e8bb pbrook
26 9ee6e8bb pbrook
#define PL022_CR1_LBM 0x01
27 9ee6e8bb pbrook
#define PL022_CR1_SSE 0x02
28 9ee6e8bb pbrook
#define PL022_CR1_MS  0x04
29 9ee6e8bb pbrook
#define PL022_CR1_SDO 0x08
30 9ee6e8bb pbrook
31 9ee6e8bb pbrook
#define PL022_SR_TFE  0x01
32 9ee6e8bb pbrook
#define PL022_SR_TNF  0x02
33 9ee6e8bb pbrook
#define PL022_SR_RNE  0x04
34 9ee6e8bb pbrook
#define PL022_SR_RFF  0x08
35 9ee6e8bb pbrook
#define PL022_SR_BSY  0x10
36 9ee6e8bb pbrook
37 9ee6e8bb pbrook
#define PL022_INT_ROR 0x01
38 9ee6e8bb pbrook
#define PL022_INT_RT  0x04
39 9ee6e8bb pbrook
#define PL022_INT_RX  0x04
40 9ee6e8bb pbrook
#define PL022_INT_TX  0x08
41 9ee6e8bb pbrook
42 9ee6e8bb pbrook
typedef struct {
43 5493e33f Paul Brook
    SysBusDevice busdev;
44 02a59c37 Avi Kivity
    MemoryRegion iomem;
45 9ee6e8bb pbrook
    uint32_t cr0;
46 9ee6e8bb pbrook
    uint32_t cr1;
47 9ee6e8bb pbrook
    uint32_t bitmask;
48 9ee6e8bb pbrook
    uint32_t sr;
49 9ee6e8bb pbrook
    uint32_t cpsr;
50 9ee6e8bb pbrook
    uint32_t is;
51 9ee6e8bb pbrook
    uint32_t im;
52 9ee6e8bb pbrook
    /* The FIFO head points to the next empty entry.  */
53 9ee6e8bb pbrook
    int tx_fifo_head;
54 9ee6e8bb pbrook
    int rx_fifo_head;
55 9ee6e8bb pbrook
    int tx_fifo_len;
56 9ee6e8bb pbrook
    int rx_fifo_len;
57 9ee6e8bb pbrook
    uint16_t tx_fifo[8];
58 9ee6e8bb pbrook
    uint16_t rx_fifo[8];
59 9ee6e8bb pbrook
    qemu_irq irq;
60 5493e33f Paul Brook
    SSIBus *ssi;
61 9ee6e8bb pbrook
} pl022_state;
62 9ee6e8bb pbrook
63 9ee6e8bb pbrook
static const unsigned char pl022_id[8] =
64 9ee6e8bb pbrook
  { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
65 9ee6e8bb pbrook
66 9ee6e8bb pbrook
static void pl022_update(pl022_state *s)
67 9ee6e8bb pbrook
{
68 9ee6e8bb pbrook
    s->sr = 0;
69 9ee6e8bb pbrook
    if (s->tx_fifo_len == 0)
70 9ee6e8bb pbrook
        s->sr |= PL022_SR_TFE;
71 9ee6e8bb pbrook
    if (s->tx_fifo_len != 8)
72 9ee6e8bb pbrook
        s->sr |= PL022_SR_TNF;
73 9ee6e8bb pbrook
    if (s->rx_fifo_len != 0)
74 9ee6e8bb pbrook
        s->sr |= PL022_SR_RNE;
75 9ee6e8bb pbrook
    if (s->rx_fifo_len == 8)
76 9ee6e8bb pbrook
        s->sr |= PL022_SR_RFF;
77 9ee6e8bb pbrook
    if (s->tx_fifo_len)
78 9ee6e8bb pbrook
        s->sr |= PL022_SR_BSY;
79 9ee6e8bb pbrook
    s->is = 0;
80 9ee6e8bb pbrook
    if (s->rx_fifo_len >= 4)
81 9ee6e8bb pbrook
        s->is |= PL022_INT_RX;
82 9ee6e8bb pbrook
    if (s->tx_fifo_len <= 4)
83 9ee6e8bb pbrook
        s->is |= PL022_INT_TX;
84 9ee6e8bb pbrook
85 9ee6e8bb pbrook
    qemu_set_irq(s->irq, (s->is & s->im) != 0);
86 9ee6e8bb pbrook
}
87 9ee6e8bb pbrook
88 9ee6e8bb pbrook
static void pl022_xfer(pl022_state *s)
89 9ee6e8bb pbrook
{
90 9ee6e8bb pbrook
    int i;
91 9ee6e8bb pbrook
    int o;
92 9ee6e8bb pbrook
    int val;
93 9ee6e8bb pbrook
94 9ee6e8bb pbrook
    if ((s->cr1 & PL022_CR1_SSE) == 0) {
95 9ee6e8bb pbrook
        pl022_update(s);
96 9ee6e8bb pbrook
        DPRINTF("Disabled\n");
97 9ee6e8bb pbrook
        return;
98 9ee6e8bb pbrook
    }
99 9ee6e8bb pbrook
100 9ee6e8bb pbrook
    DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len);
101 9ee6e8bb pbrook
    i = (s->tx_fifo_head - s->tx_fifo_len) & 7;
102 9ee6e8bb pbrook
    o = s->rx_fifo_head;
103 9ee6e8bb pbrook
    /* ??? We do not emulate the line speed.
104 9ee6e8bb pbrook
       This may break some applications.  The are two problematic cases:
105 9ee6e8bb pbrook
        (a) A driver feeds data into the TX FIFO until it is full,
106 9ee6e8bb pbrook
         and only then drains the RX FIFO.  On real hardware the CPU can
107 9ee6e8bb pbrook
         feed data fast enough that the RX fifo never gets chance to overflow.
108 9ee6e8bb pbrook
        (b) A driver transmits data, deliberately allowing the RX FIFO to
109 9ee6e8bb pbrook
         overflow because it ignores the RX data anyway.
110 9ee6e8bb pbrook

111 9ee6e8bb pbrook
       We choose to support (a) by stalling the transmit engine if it would
112 9ee6e8bb pbrook
       cause the RX FIFO to overflow.  In practice much transmit-only code
113 9ee6e8bb pbrook
       falls into (a) because it flushes the RX FIFO to determine when
114 9ee6e8bb pbrook
       the transfer has completed.  */
115 9ee6e8bb pbrook
    while (s->tx_fifo_len && s->rx_fifo_len < 8) {
116 9ee6e8bb pbrook
        DPRINTF("xfer\n");
117 9ee6e8bb pbrook
        val = s->tx_fifo[i];
118 9ee6e8bb pbrook
        if (s->cr1 & PL022_CR1_LBM) {
119 9ee6e8bb pbrook
            /* Loopback mode.  */
120 9ee6e8bb pbrook
        } else {
121 5493e33f Paul Brook
            val = ssi_transfer(s->ssi, val);
122 9ee6e8bb pbrook
        }
123 9ee6e8bb pbrook
        s->rx_fifo[o] = val & s->bitmask;
124 9ee6e8bb pbrook
        i = (i + 1) & 7;
125 9ee6e8bb pbrook
        o = (o + 1) & 7;
126 9ee6e8bb pbrook
        s->tx_fifo_len--;
127 9ee6e8bb pbrook
        s->rx_fifo_len++;
128 9ee6e8bb pbrook
    }
129 9ee6e8bb pbrook
    s->rx_fifo_head = o;
130 9ee6e8bb pbrook
    pl022_update(s);
131 9ee6e8bb pbrook
}
132 9ee6e8bb pbrook
133 02a59c37 Avi Kivity
static uint64_t pl022_read(void *opaque, target_phys_addr_t offset,
134 02a59c37 Avi Kivity
                           unsigned size)
135 9ee6e8bb pbrook
{
136 9ee6e8bb pbrook
    pl022_state *s = (pl022_state *)opaque;
137 9ee6e8bb pbrook
    int val;
138 9ee6e8bb pbrook
139 9ee6e8bb pbrook
    if (offset >= 0xfe0 && offset < 0x1000) {
140 9ee6e8bb pbrook
        return pl022_id[(offset - 0xfe0) >> 2];
141 9ee6e8bb pbrook
    }
142 9ee6e8bb pbrook
    switch (offset) {
143 9ee6e8bb pbrook
    case 0x00: /* CR0 */
144 9ee6e8bb pbrook
      return s->cr0;
145 9ee6e8bb pbrook
    case 0x04: /* CR1 */
146 9ee6e8bb pbrook
      return s->cr1;
147 9ee6e8bb pbrook
    case 0x08: /* DR */
148 9ee6e8bb pbrook
        if (s->rx_fifo_len) {
149 9ee6e8bb pbrook
            val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7];
150 9ee6e8bb pbrook
            DPRINTF("RX %02x\n", val);
151 9ee6e8bb pbrook
            s->rx_fifo_len--;
152 9ee6e8bb pbrook
            pl022_xfer(s);
153 9ee6e8bb pbrook
        } else {
154 9ee6e8bb pbrook
            val = 0;
155 9ee6e8bb pbrook
        }
156 9ee6e8bb pbrook
        return val;
157 9ee6e8bb pbrook
    case 0x0c: /* SR */
158 9ee6e8bb pbrook
        return s->sr;
159 9ee6e8bb pbrook
    case 0x10: /* CPSR */
160 9ee6e8bb pbrook
        return s->cpsr;
161 9ee6e8bb pbrook
    case 0x14: /* IMSC */
162 9ee6e8bb pbrook
        return s->im;
163 9ee6e8bb pbrook
    case 0x18: /* RIS */
164 9ee6e8bb pbrook
        return s->is;
165 9ee6e8bb pbrook
    case 0x1c: /* MIS */
166 9ee6e8bb pbrook
        return s->im & s->is;
167 9ee6e8bb pbrook
    case 0x20: /* DMACR */
168 9ee6e8bb pbrook
        /* Not implemented.  */
169 9ee6e8bb pbrook
        return 0;
170 9ee6e8bb pbrook
    default:
171 2ac71179 Paul Brook
        hw_error("pl022_read: Bad offset %x\n", (int)offset);
172 9ee6e8bb pbrook
        return 0;
173 9ee6e8bb pbrook
    }
174 9ee6e8bb pbrook
}
175 9ee6e8bb pbrook
176 c227f099 Anthony Liguori
static void pl022_write(void *opaque, target_phys_addr_t offset,
177 02a59c37 Avi Kivity
                        uint64_t value, unsigned size)
178 9ee6e8bb pbrook
{
179 9ee6e8bb pbrook
    pl022_state *s = (pl022_state *)opaque;
180 9ee6e8bb pbrook
181 9ee6e8bb pbrook
    switch (offset) {
182 9ee6e8bb pbrook
    case 0x00: /* CR0 */
183 9ee6e8bb pbrook
        s->cr0 = value;
184 9ee6e8bb pbrook
        /* Clock rate and format are ignored.  */
185 9ee6e8bb pbrook
        s->bitmask = (1 << ((value & 15) + 1)) - 1;
186 9ee6e8bb pbrook
        break;
187 9ee6e8bb pbrook
    case 0x04: /* CR1 */
188 9ee6e8bb pbrook
        s->cr1 = value;
189 9ee6e8bb pbrook
        if ((s->cr1 & (PL022_CR1_MS | PL022_CR1_SSE))
190 9ee6e8bb pbrook
                   == (PL022_CR1_MS | PL022_CR1_SSE)) {
191 9ee6e8bb pbrook
            BADF("SPI slave mode not implemented\n");
192 9ee6e8bb pbrook
        }
193 9ee6e8bb pbrook
        pl022_xfer(s);
194 9ee6e8bb pbrook
        break;
195 9ee6e8bb pbrook
    case 0x08: /* DR */
196 9ee6e8bb pbrook
        if (s->tx_fifo_len < 8) {
197 02a59c37 Avi Kivity
            DPRINTF("TX %02x\n", (unsigned)value);
198 9ee6e8bb pbrook
            s->tx_fifo[s->tx_fifo_head] = value & s->bitmask;
199 9ee6e8bb pbrook
            s->tx_fifo_head = (s->tx_fifo_head + 1) & 7;
200 9ee6e8bb pbrook
            s->tx_fifo_len++;
201 9ee6e8bb pbrook
            pl022_xfer(s);
202 9ee6e8bb pbrook
        }
203 9ee6e8bb pbrook
        break;
204 9ee6e8bb pbrook
    case 0x10: /* CPSR */
205 9ee6e8bb pbrook
        /* Prescaler.  Ignored.  */
206 9ee6e8bb pbrook
        s->cpsr = value & 0xff;
207 9ee6e8bb pbrook
        break;
208 9ee6e8bb pbrook
    case 0x14: /* IMSC */
209 9ee6e8bb pbrook
        s->im = value;
210 9ee6e8bb pbrook
        pl022_update(s);
211 9ee6e8bb pbrook
        break;
212 9ee6e8bb pbrook
    case 0x20: /* DMACR */
213 2ac71179 Paul Brook
        if (value) {
214 2ac71179 Paul Brook
            hw_error("pl022: DMA not implemented\n");
215 2ac71179 Paul Brook
        }
216 9ee6e8bb pbrook
        break;
217 9ee6e8bb pbrook
    default:
218 2ac71179 Paul Brook
        hw_error("pl022_write: Bad offset %x\n", (int)offset);
219 9ee6e8bb pbrook
    }
220 9ee6e8bb pbrook
}
221 9ee6e8bb pbrook
222 9ee6e8bb pbrook
static void pl022_reset(pl022_state *s)
223 9ee6e8bb pbrook
{
224 9ee6e8bb pbrook
    s->rx_fifo_len = 0;
225 9ee6e8bb pbrook
    s->tx_fifo_len = 0;
226 9ee6e8bb pbrook
    s->im = 0;
227 9ee6e8bb pbrook
    s->is = PL022_INT_TX;
228 9ee6e8bb pbrook
    s->sr = PL022_SR_TFE | PL022_SR_TNF;
229 9ee6e8bb pbrook
}
230 9ee6e8bb pbrook
231 02a59c37 Avi Kivity
static const MemoryRegionOps pl022_ops = {
232 02a59c37 Avi Kivity
    .read = pl022_read,
233 02a59c37 Avi Kivity
    .write = pl022_write,
234 02a59c37 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
235 9ee6e8bb pbrook
};
236 9ee6e8bb pbrook
237 075790c2 Juan Quintela
static const VMStateDescription vmstate_pl022 = {
238 075790c2 Juan Quintela
    .name = "pl022_ssp",
239 075790c2 Juan Quintela
    .version_id = 1,
240 075790c2 Juan Quintela
    .minimum_version_id = 1,
241 075790c2 Juan Quintela
    .minimum_version_id_old = 1,
242 075790c2 Juan Quintela
    .fields      = (VMStateField[]) {
243 075790c2 Juan Quintela
        VMSTATE_UINT32(cr0, pl022_state),
244 075790c2 Juan Quintela
        VMSTATE_UINT32(cr1, pl022_state),
245 075790c2 Juan Quintela
        VMSTATE_UINT32(bitmask, pl022_state),
246 075790c2 Juan Quintela
        VMSTATE_UINT32(sr, pl022_state),
247 075790c2 Juan Quintela
        VMSTATE_UINT32(cpsr, pl022_state),
248 075790c2 Juan Quintela
        VMSTATE_UINT32(is, pl022_state),
249 075790c2 Juan Quintela
        VMSTATE_UINT32(im, pl022_state),
250 075790c2 Juan Quintela
        VMSTATE_INT32(tx_fifo_head, pl022_state),
251 075790c2 Juan Quintela
        VMSTATE_INT32(rx_fifo_head, pl022_state),
252 075790c2 Juan Quintela
        VMSTATE_INT32(tx_fifo_len, pl022_state),
253 075790c2 Juan Quintela
        VMSTATE_INT32(rx_fifo_len, pl022_state),
254 075790c2 Juan Quintela
        VMSTATE_UINT16(tx_fifo[0], pl022_state),
255 075790c2 Juan Quintela
        VMSTATE_UINT16(rx_fifo[0], pl022_state),
256 075790c2 Juan Quintela
        VMSTATE_UINT16(tx_fifo[1], pl022_state),
257 075790c2 Juan Quintela
        VMSTATE_UINT16(rx_fifo[1], pl022_state),
258 075790c2 Juan Quintela
        VMSTATE_UINT16(tx_fifo[2], pl022_state),
259 075790c2 Juan Quintela
        VMSTATE_UINT16(rx_fifo[2], pl022_state),
260 075790c2 Juan Quintela
        VMSTATE_UINT16(tx_fifo[3], pl022_state),
261 075790c2 Juan Quintela
        VMSTATE_UINT16(rx_fifo[3], pl022_state),
262 075790c2 Juan Quintela
        VMSTATE_UINT16(tx_fifo[4], pl022_state),
263 075790c2 Juan Quintela
        VMSTATE_UINT16(rx_fifo[4], pl022_state),
264 075790c2 Juan Quintela
        VMSTATE_UINT16(tx_fifo[5], pl022_state),
265 075790c2 Juan Quintela
        VMSTATE_UINT16(rx_fifo[5], pl022_state),
266 075790c2 Juan Quintela
        VMSTATE_UINT16(tx_fifo[6], pl022_state),
267 075790c2 Juan Quintela
        VMSTATE_UINT16(rx_fifo[6], pl022_state),
268 075790c2 Juan Quintela
        VMSTATE_UINT16(tx_fifo[7], pl022_state),
269 075790c2 Juan Quintela
        VMSTATE_UINT16(rx_fifo[7], pl022_state),
270 075790c2 Juan Quintela
        VMSTATE_END_OF_LIST()
271 23e39294 pbrook
    }
272 075790c2 Juan Quintela
};
273 23e39294 pbrook
274 81a322d4 Gerd Hoffmann
static int pl022_init(SysBusDevice *dev)
275 9ee6e8bb pbrook
{
276 5493e33f Paul Brook
    pl022_state *s = FROM_SYSBUS(pl022_state, dev);
277 9ee6e8bb pbrook
278 02a59c37 Avi Kivity
    memory_region_init_io(&s->iomem, &pl022_ops, s, "pl022", 0x1000);
279 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
280 5493e33f Paul Brook
    sysbus_init_irq(dev, &s->irq);
281 02e2da45 Paul Brook
    s->ssi = ssi_create_bus(&dev->qdev, "ssi");
282 9ee6e8bb pbrook
    pl022_reset(s);
283 075790c2 Juan Quintela
    vmstate_register(&dev->qdev, -1, &vmstate_pl022, s);
284 81a322d4 Gerd Hoffmann
    return 0;
285 9ee6e8bb pbrook
}
286 5493e33f Paul Brook
287 999e12bb Anthony Liguori
static void pl022_class_init(ObjectClass *klass, void *data)
288 999e12bb Anthony Liguori
{
289 999e12bb Anthony Liguori
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
290 999e12bb Anthony Liguori
291 999e12bb Anthony Liguori
    sdc->init = pl022_init;
292 999e12bb Anthony Liguori
}
293 999e12bb Anthony Liguori
294 39bffca2 Anthony Liguori
static TypeInfo pl022_info = {
295 39bffca2 Anthony Liguori
    .name          = "pl022",
296 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
297 39bffca2 Anthony Liguori
    .instance_size = sizeof(pl022_state),
298 39bffca2 Anthony Liguori
    .class_init    = pl022_class_init,
299 999e12bb Anthony Liguori
};
300 999e12bb Anthony Liguori
301 83f7d43a Andreas Färber
static void pl022_register_types(void)
302 5493e33f Paul Brook
{
303 39bffca2 Anthony Liguori
    type_register_static(&pl022_info);
304 5493e33f Paul Brook
}
305 5493e33f Paul Brook
306 83f7d43a Andreas Färber
type_init(pl022_register_types)