Statistics
| Branch: | Revision:

root / hw / pl022.c @ c9159fe9

History | View | Annotate | Download (8.4 kB)

1
/*
2
 * Arm PrimeCell PL022 Synchronous Serial Port
3
 *
4
 * Copyright (c) 2007 CodeSourcery.
5
 * Written by Paul Brook
6
 *
7
 * This code is licensed under the GPL.
8
 */
9

    
10
#include "sysbus.h"
11
#include "ssi.h"
12

    
13
//#define DEBUG_PL022 1
14

    
15
#ifdef DEBUG_PL022
16
#define DPRINTF(fmt, ...) \
17
do { printf("pl022: " fmt , ## __VA_ARGS__); } while (0)
18
#define BADF(fmt, ...) \
19
do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
20
#else
21
#define DPRINTF(fmt, ...) do {} while(0)
22
#define BADF(fmt, ...) \
23
do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
24
#endif
25

    
26
#define PL022_CR1_LBM 0x01
27
#define PL022_CR1_SSE 0x02
28
#define PL022_CR1_MS  0x04
29
#define PL022_CR1_SDO 0x08
30

    
31
#define PL022_SR_TFE  0x01
32
#define PL022_SR_TNF  0x02
33
#define PL022_SR_RNE  0x04
34
#define PL022_SR_RFF  0x08
35
#define PL022_SR_BSY  0x10
36

    
37
#define PL022_INT_ROR 0x01
38
#define PL022_INT_RT  0x04
39
#define PL022_INT_RX  0x04
40
#define PL022_INT_TX  0x08
41

    
42
typedef struct {
43
    SysBusDevice busdev;
44
    MemoryRegion iomem;
45
    uint32_t cr0;
46
    uint32_t cr1;
47
    uint32_t bitmask;
48
    uint32_t sr;
49
    uint32_t cpsr;
50
    uint32_t is;
51
    uint32_t im;
52
    /* The FIFO head points to the next empty entry.  */
53
    int tx_fifo_head;
54
    int rx_fifo_head;
55
    int tx_fifo_len;
56
    int rx_fifo_len;
57
    uint16_t tx_fifo[8];
58
    uint16_t rx_fifo[8];
59
    qemu_irq irq;
60
    SSIBus *ssi;
61
} pl022_state;
62

    
63
static const unsigned char pl022_id[8] =
64
  { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
65

    
66
static void pl022_update(pl022_state *s)
67
{
68
    s->sr = 0;
69
    if (s->tx_fifo_len == 0)
70
        s->sr |= PL022_SR_TFE;
71
    if (s->tx_fifo_len != 8)
72
        s->sr |= PL022_SR_TNF;
73
    if (s->rx_fifo_len != 0)
74
        s->sr |= PL022_SR_RNE;
75
    if (s->rx_fifo_len == 8)
76
        s->sr |= PL022_SR_RFF;
77
    if (s->tx_fifo_len)
78
        s->sr |= PL022_SR_BSY;
79
    s->is = 0;
80
    if (s->rx_fifo_len >= 4)
81
        s->is |= PL022_INT_RX;
82
    if (s->tx_fifo_len <= 4)
83
        s->is |= PL022_INT_TX;
84

    
85
    qemu_set_irq(s->irq, (s->is & s->im) != 0);
86
}
87

    
88
static void pl022_xfer(pl022_state *s)
89
{
90
    int i;
91
    int o;
92
    int val;
93

    
94
    if ((s->cr1 & PL022_CR1_SSE) == 0) {
95
        pl022_update(s);
96
        DPRINTF("Disabled\n");
97
        return;
98
    }
99

    
100
    DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len);
101
    i = (s->tx_fifo_head - s->tx_fifo_len) & 7;
102
    o = s->rx_fifo_head;
103
    /* ??? We do not emulate the line speed.
104
       This may break some applications.  The are two problematic cases:
105
        (a) A driver feeds data into the TX FIFO until it is full,
106
         and only then drains the RX FIFO.  On real hardware the CPU can
107
         feed data fast enough that the RX fifo never gets chance to overflow.
108
        (b) A driver transmits data, deliberately allowing the RX FIFO to
109
         overflow because it ignores the RX data anyway.
110

111
       We choose to support (a) by stalling the transmit engine if it would
112
       cause the RX FIFO to overflow.  In practice much transmit-only code
113
       falls into (a) because it flushes the RX FIFO to determine when
114
       the transfer has completed.  */
115
    while (s->tx_fifo_len && s->rx_fifo_len < 8) {
116
        DPRINTF("xfer\n");
117
        val = s->tx_fifo[i];
118
        if (s->cr1 & PL022_CR1_LBM) {
119
            /* Loopback mode.  */
120
        } else {
121
            val = ssi_transfer(s->ssi, val);
122
        }
123
        s->rx_fifo[o] = val & s->bitmask;
124
        i = (i + 1) & 7;
125
        o = (o + 1) & 7;
126
        s->tx_fifo_len--;
127
        s->rx_fifo_len++;
128
    }
129
    s->rx_fifo_head = o;
130
    pl022_update(s);
131
}
132

    
133
static uint64_t pl022_read(void *opaque, target_phys_addr_t offset,
134
                           unsigned size)
135
{
136
    pl022_state *s = (pl022_state *)opaque;
137
    int val;
138

    
139
    if (offset >= 0xfe0 && offset < 0x1000) {
140
        return pl022_id[(offset - 0xfe0) >> 2];
141
    }
142
    switch (offset) {
143
    case 0x00: /* CR0 */
144
      return s->cr0;
145
    case 0x04: /* CR1 */
146
      return s->cr1;
147
    case 0x08: /* DR */
148
        if (s->rx_fifo_len) {
149
            val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7];
150
            DPRINTF("RX %02x\n", val);
151
            s->rx_fifo_len--;
152
            pl022_xfer(s);
153
        } else {
154
            val = 0;
155
        }
156
        return val;
157
    case 0x0c: /* SR */
158
        return s->sr;
159
    case 0x10: /* CPSR */
160
        return s->cpsr;
161
    case 0x14: /* IMSC */
162
        return s->im;
163
    case 0x18: /* RIS */
164
        return s->is;
165
    case 0x1c: /* MIS */
166
        return s->im & s->is;
167
    case 0x20: /* DMACR */
168
        /* Not implemented.  */
169
        return 0;
170
    default:
171
        hw_error("pl022_read: Bad offset %x\n", (int)offset);
172
        return 0;
173
    }
174
}
175

    
176
static void pl022_write(void *opaque, target_phys_addr_t offset,
177
                        uint64_t value, unsigned size)
178
{
179
    pl022_state *s = (pl022_state *)opaque;
180

    
181
    switch (offset) {
182
    case 0x00: /* CR0 */
183
        s->cr0 = value;
184
        /* Clock rate and format are ignored.  */
185
        s->bitmask = (1 << ((value & 15) + 1)) - 1;
186
        break;
187
    case 0x04: /* CR1 */
188
        s->cr1 = value;
189
        if ((s->cr1 & (PL022_CR1_MS | PL022_CR1_SSE))
190
                   == (PL022_CR1_MS | PL022_CR1_SSE)) {
191
            BADF("SPI slave mode not implemented\n");
192
        }
193
        pl022_xfer(s);
194
        break;
195
    case 0x08: /* DR */
196
        if (s->tx_fifo_len < 8) {
197
            DPRINTF("TX %02x\n", (unsigned)value);
198
            s->tx_fifo[s->tx_fifo_head] = value & s->bitmask;
199
            s->tx_fifo_head = (s->tx_fifo_head + 1) & 7;
200
            s->tx_fifo_len++;
201
            pl022_xfer(s);
202
        }
203
        break;
204
    case 0x10: /* CPSR */
205
        /* Prescaler.  Ignored.  */
206
        s->cpsr = value & 0xff;
207
        break;
208
    case 0x14: /* IMSC */
209
        s->im = value;
210
        pl022_update(s);
211
        break;
212
    case 0x20: /* DMACR */
213
        if (value) {
214
            hw_error("pl022: DMA not implemented\n");
215
        }
216
        break;
217
    default:
218
        hw_error("pl022_write: Bad offset %x\n", (int)offset);
219
    }
220
}
221

    
222
static void pl022_reset(pl022_state *s)
223
{
224
    s->rx_fifo_len = 0;
225
    s->tx_fifo_len = 0;
226
    s->im = 0;
227
    s->is = PL022_INT_TX;
228
    s->sr = PL022_SR_TFE | PL022_SR_TNF;
229
}
230

    
231
static const MemoryRegionOps pl022_ops = {
232
    .read = pl022_read,
233
    .write = pl022_write,
234
    .endianness = DEVICE_NATIVE_ENDIAN,
235
};
236

    
237
static const VMStateDescription vmstate_pl022 = {
238
    .name = "pl022_ssp",
239
    .version_id = 1,
240
    .minimum_version_id = 1,
241
    .minimum_version_id_old = 1,
242
    .fields      = (VMStateField[]) {
243
        VMSTATE_UINT32(cr0, pl022_state),
244
        VMSTATE_UINT32(cr1, pl022_state),
245
        VMSTATE_UINT32(bitmask, pl022_state),
246
        VMSTATE_UINT32(sr, pl022_state),
247
        VMSTATE_UINT32(cpsr, pl022_state),
248
        VMSTATE_UINT32(is, pl022_state),
249
        VMSTATE_UINT32(im, pl022_state),
250
        VMSTATE_INT32(tx_fifo_head, pl022_state),
251
        VMSTATE_INT32(rx_fifo_head, pl022_state),
252
        VMSTATE_INT32(tx_fifo_len, pl022_state),
253
        VMSTATE_INT32(rx_fifo_len, pl022_state),
254
        VMSTATE_UINT16(tx_fifo[0], pl022_state),
255
        VMSTATE_UINT16(rx_fifo[0], pl022_state),
256
        VMSTATE_UINT16(tx_fifo[1], pl022_state),
257
        VMSTATE_UINT16(rx_fifo[1], pl022_state),
258
        VMSTATE_UINT16(tx_fifo[2], pl022_state),
259
        VMSTATE_UINT16(rx_fifo[2], pl022_state),
260
        VMSTATE_UINT16(tx_fifo[3], pl022_state),
261
        VMSTATE_UINT16(rx_fifo[3], pl022_state),
262
        VMSTATE_UINT16(tx_fifo[4], pl022_state),
263
        VMSTATE_UINT16(rx_fifo[4], pl022_state),
264
        VMSTATE_UINT16(tx_fifo[5], pl022_state),
265
        VMSTATE_UINT16(rx_fifo[5], pl022_state),
266
        VMSTATE_UINT16(tx_fifo[6], pl022_state),
267
        VMSTATE_UINT16(rx_fifo[6], pl022_state),
268
        VMSTATE_UINT16(tx_fifo[7], pl022_state),
269
        VMSTATE_UINT16(rx_fifo[7], pl022_state),
270
        VMSTATE_END_OF_LIST()
271
    }
272
};
273

    
274
static int pl022_init(SysBusDevice *dev)
275
{
276
    pl022_state *s = FROM_SYSBUS(pl022_state, dev);
277

    
278
    memory_region_init_io(&s->iomem, &pl022_ops, s, "pl022", 0x1000);
279
    sysbus_init_mmio(dev, &s->iomem);
280
    sysbus_init_irq(dev, &s->irq);
281
    s->ssi = ssi_create_bus(&dev->qdev, "ssi");
282
    pl022_reset(s);
283
    vmstate_register(&dev->qdev, -1, &vmstate_pl022, s);
284
    return 0;
285
}
286

    
287
static void pl022_class_init(ObjectClass *klass, void *data)
288
{
289
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
290

    
291
    sdc->init = pl022_init;
292
}
293

    
294
static TypeInfo pl022_info = {
295
    .name          = "pl022",
296
    .parent        = TYPE_SYS_BUS_DEVICE,
297
    .instance_size = sizeof(pl022_state),
298
    .class_init    = pl022_class_init,
299
};
300

    
301
static void pl022_register_types(void)
302
{
303
    type_register_static(&pl022_info);
304
}
305

    
306
type_init(pl022_register_types)