]> git.proxmox.com Git - mirror_qemu.git/blame - hw/ssi/pl022.c
Include qemu/module.h where needed, drop it from qemu-common.h
[mirror_qemu.git] / hw / ssi / pl022.c
CommitLineData
9ee6e8bb
PB
1/*
2 * Arm PrimeCell PL022 Synchronous Serial Port
3 *
4 * Copyright (c) 2007 CodeSourcery.
5 * Written by Paul Brook
6 *
8e31bf38 7 * This code is licensed under the GPL.
9ee6e8bb
PB
8 */
9
17b7f2db 10#include "qemu/osdep.h"
83c9f4ca 11#include "hw/sysbus.h"
1d52866f 12#include "hw/ssi/pl022.h"
8fd06719 13#include "hw/ssi/ssi.h"
03dd024f 14#include "qemu/log.h"
0b8fa32f 15#include "qemu/module.h"
9ee6e8bb
PB
16
17//#define DEBUG_PL022 1
18
19#ifdef DEBUG_PL022
001faf32
BS
20#define DPRINTF(fmt, ...) \
21do { printf("pl022: " fmt , ## __VA_ARGS__); } while (0)
22#define BADF(fmt, ...) \
23do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
9ee6e8bb 24#else
001faf32
BS
25#define DPRINTF(fmt, ...) do {} while(0)
26#define BADF(fmt, ...) \
27do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
9ee6e8bb
PB
28#endif
29
30#define PL022_CR1_LBM 0x01
31#define PL022_CR1_SSE 0x02
32#define PL022_CR1_MS 0x04
33#define PL022_CR1_SDO 0x08
34
35#define PL022_SR_TFE 0x01
36#define PL022_SR_TNF 0x02
37#define PL022_SR_RNE 0x04
38#define PL022_SR_RFF 0x08
39#define PL022_SR_BSY 0x10
40
41#define PL022_INT_ROR 0x01
139d941e 42#define PL022_INT_RT 0x02
9ee6e8bb
PB
43#define PL022_INT_RX 0x04
44#define PL022_INT_TX 0x08
45
9ee6e8bb
PB
46static const unsigned char pl022_id[8] =
47 { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
48
ce556e0b 49static void pl022_update(PL022State *s)
9ee6e8bb
PB
50{
51 s->sr = 0;
52 if (s->tx_fifo_len == 0)
53 s->sr |= PL022_SR_TFE;
54 if (s->tx_fifo_len != 8)
55 s->sr |= PL022_SR_TNF;
56 if (s->rx_fifo_len != 0)
57 s->sr |= PL022_SR_RNE;
58 if (s->rx_fifo_len == 8)
59 s->sr |= PL022_SR_RFF;
60 if (s->tx_fifo_len)
61 s->sr |= PL022_SR_BSY;
62 s->is = 0;
63 if (s->rx_fifo_len >= 4)
64 s->is |= PL022_INT_RX;
65 if (s->tx_fifo_len <= 4)
66 s->is |= PL022_INT_TX;
67
68 qemu_set_irq(s->irq, (s->is & s->im) != 0);
69}
70
ce556e0b 71static void pl022_xfer(PL022State *s)
9ee6e8bb
PB
72{
73 int i;
74 int o;
75 int val;
76
77 if ((s->cr1 & PL022_CR1_SSE) == 0) {
78 pl022_update(s);
79 DPRINTF("Disabled\n");
80 return;
81 }
82
83 DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len);
84 i = (s->tx_fifo_head - s->tx_fifo_len) & 7;
85 o = s->rx_fifo_head;
86 /* ??? We do not emulate the line speed.
87 This may break some applications. The are two problematic cases:
88 (a) A driver feeds data into the TX FIFO until it is full,
89 and only then drains the RX FIFO. On real hardware the CPU can
90 feed data fast enough that the RX fifo never gets chance to overflow.
91 (b) A driver transmits data, deliberately allowing the RX FIFO to
92 overflow because it ignores the RX data anyway.
93
94 We choose to support (a) by stalling the transmit engine if it would
95 cause the RX FIFO to overflow. In practice much transmit-only code
96 falls into (a) because it flushes the RX FIFO to determine when
97 the transfer has completed. */
98 while (s->tx_fifo_len && s->rx_fifo_len < 8) {
99 DPRINTF("xfer\n");
100 val = s->tx_fifo[i];
101 if (s->cr1 & PL022_CR1_LBM) {
102 /* Loopback mode. */
9ee6e8bb 103 } else {
5493e33f 104 val = ssi_transfer(s->ssi, val);
9ee6e8bb
PB
105 }
106 s->rx_fifo[o] = val & s->bitmask;
107 i = (i + 1) & 7;
108 o = (o + 1) & 7;
109 s->tx_fifo_len--;
110 s->rx_fifo_len++;
111 }
112 s->rx_fifo_head = o;
113 pl022_update(s);
114}
115
a8170e5e 116static uint64_t pl022_read(void *opaque, hwaddr offset,
02a59c37 117 unsigned size)
9ee6e8bb 118{
ce556e0b 119 PL022State *s = (PL022State *)opaque;
9ee6e8bb
PB
120 int val;
121
9ee6e8bb
PB
122 if (offset >= 0xfe0 && offset < 0x1000) {
123 return pl022_id[(offset - 0xfe0) >> 2];
124 }
125 switch (offset) {
126 case 0x00: /* CR0 */
127 return s->cr0;
128 case 0x04: /* CR1 */
129 return s->cr1;
130 case 0x08: /* DR */
131 if (s->rx_fifo_len) {
132 val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7];
133 DPRINTF("RX %02x\n", val);
134 s->rx_fifo_len--;
135 pl022_xfer(s);
136 } else {
137 val = 0;
138 }
139 return val;
140 case 0x0c: /* SR */
141 return s->sr;
142 case 0x10: /* CPSR */
143 return s->cpsr;
144 case 0x14: /* IMSC */
145 return s->im;
146 case 0x18: /* RIS */
147 return s->is;
148 case 0x1c: /* MIS */
149 return s->im & s->is;
7d3912f5 150 case 0x24: /* DMACR */
9ee6e8bb
PB
151 /* Not implemented. */
152 return 0;
153 default:
af83c32b
PM
154 qemu_log_mask(LOG_GUEST_ERROR,
155 "pl022_read: Bad offset %x\n", (int)offset);
9ee6e8bb
PB
156 return 0;
157 }
158}
159
a8170e5e 160static void pl022_write(void *opaque, hwaddr offset,
02a59c37 161 uint64_t value, unsigned size)
9ee6e8bb 162{
ce556e0b 163 PL022State *s = (PL022State *)opaque;
9ee6e8bb 164
9ee6e8bb
PB
165 switch (offset) {
166 case 0x00: /* CR0 */
167 s->cr0 = value;
168 /* Clock rate and format are ignored. */
169 s->bitmask = (1 << ((value & 15) + 1)) - 1;
170 break;
171 case 0x04: /* CR1 */
172 s->cr1 = value;
173 if ((s->cr1 & (PL022_CR1_MS | PL022_CR1_SSE))
174 == (PL022_CR1_MS | PL022_CR1_SSE)) {
175 BADF("SPI slave mode not implemented\n");
176 }
177 pl022_xfer(s);
178 break;
179 case 0x08: /* DR */
180 if (s->tx_fifo_len < 8) {
02a59c37 181 DPRINTF("TX %02x\n", (unsigned)value);
9ee6e8bb
PB
182 s->tx_fifo[s->tx_fifo_head] = value & s->bitmask;
183 s->tx_fifo_head = (s->tx_fifo_head + 1) & 7;
184 s->tx_fifo_len++;
185 pl022_xfer(s);
186 }
187 break;
188 case 0x10: /* CPSR */
189 /* Prescaler. Ignored. */
190 s->cpsr = value & 0xff;
191 break;
192 case 0x14: /* IMSC */
193 s->im = value;
194 pl022_update(s);
195 break;
7d3912f5
PM
196 case 0x20: /* ICR */
197 /*
198 * write-1-to-clear: bit 0 clears ROR, bit 1 clears RT;
199 * RX and TX interrupts cannot be cleared this way.
200 */
201 value &= PL022_INT_ROR | PL022_INT_RT;
202 s->is &= ~value;
203 break;
204 case 0x24: /* DMACR */
2ac71179 205 if (value) {
af83c32b 206 qemu_log_mask(LOG_UNIMP, "pl022: DMA not implemented\n");
2ac71179 207 }
9ee6e8bb
PB
208 break;
209 default:
af83c32b
PM
210 qemu_log_mask(LOG_GUEST_ERROR,
211 "pl022_write: Bad offset %x\n", (int)offset);
9ee6e8bb
PB
212 }
213}
214
66d9aa79 215static void pl022_reset(DeviceState *dev)
9ee6e8bb 216{
66d9aa79
PM
217 PL022State *s = PL022(dev);
218
9ee6e8bb
PB
219 s->rx_fifo_len = 0;
220 s->tx_fifo_len = 0;
221 s->im = 0;
222 s->is = PL022_INT_TX;
223 s->sr = PL022_SR_TFE | PL022_SR_TNF;
224}
225
02a59c37
AK
226static const MemoryRegionOps pl022_ops = {
227 .read = pl022_read,
228 .write = pl022_write,
229 .endianness = DEVICE_NATIVE_ENDIAN,
9ee6e8bb
PB
230};
231
d8d0a0bc
MT
232static int pl022_post_load(void *opaque, int version_id)
233{
234 PL022State *s = opaque;
235
236 if (s->tx_fifo_head < 0 ||
237 s->tx_fifo_head >= ARRAY_SIZE(s->tx_fifo) ||
238 s->rx_fifo_head < 0 ||
239 s->rx_fifo_head >= ARRAY_SIZE(s->rx_fifo)) {
240 return -1;
241 }
242 return 0;
243}
244
075790c2
JQ
245static const VMStateDescription vmstate_pl022 = {
246 .name = "pl022_ssp",
247 .version_id = 1,
248 .minimum_version_id = 1,
d8d0a0bc 249 .post_load = pl022_post_load,
8f1e884b 250 .fields = (VMStateField[]) {
ce556e0b
AF
251 VMSTATE_UINT32(cr0, PL022State),
252 VMSTATE_UINT32(cr1, PL022State),
253 VMSTATE_UINT32(bitmask, PL022State),
254 VMSTATE_UINT32(sr, PL022State),
255 VMSTATE_UINT32(cpsr, PL022State),
256 VMSTATE_UINT32(is, PL022State),
257 VMSTATE_UINT32(im, PL022State),
258 VMSTATE_INT32(tx_fifo_head, PL022State),
259 VMSTATE_INT32(rx_fifo_head, PL022State),
260 VMSTATE_INT32(tx_fifo_len, PL022State),
261 VMSTATE_INT32(rx_fifo_len, PL022State),
262 VMSTATE_UINT16(tx_fifo[0], PL022State),
263 VMSTATE_UINT16(rx_fifo[0], PL022State),
264 VMSTATE_UINT16(tx_fifo[1], PL022State),
265 VMSTATE_UINT16(rx_fifo[1], PL022State),
266 VMSTATE_UINT16(tx_fifo[2], PL022State),
267 VMSTATE_UINT16(rx_fifo[2], PL022State),
268 VMSTATE_UINT16(tx_fifo[3], PL022State),
269 VMSTATE_UINT16(rx_fifo[3], PL022State),
270 VMSTATE_UINT16(tx_fifo[4], PL022State),
271 VMSTATE_UINT16(rx_fifo[4], PL022State),
272 VMSTATE_UINT16(tx_fifo[5], PL022State),
273 VMSTATE_UINT16(rx_fifo[5], PL022State),
274 VMSTATE_UINT16(tx_fifo[6], PL022State),
275 VMSTATE_UINT16(rx_fifo[6], PL022State),
276 VMSTATE_UINT16(tx_fifo[7], PL022State),
277 VMSTATE_UINT16(rx_fifo[7], PL022State),
075790c2 278 VMSTATE_END_OF_LIST()
23e39294 279 }
075790c2 280};
23e39294 281
13391a56 282static void pl022_realize(DeviceState *dev, Error **errp)
9ee6e8bb 283{
13391a56 284 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
3d29bcee 285 PL022State *s = PL022(dev);
9ee6e8bb 286
29776739 287 memory_region_init_io(&s->iomem, OBJECT(s), &pl022_ops, s, "pl022", 0x1000);
3d29bcee
AF
288 sysbus_init_mmio(sbd, &s->iomem);
289 sysbus_init_irq(sbd, &s->irq);
290 s->ssi = ssi_create_bus(dev, "ssi");
9ee6e8bb 291}
5493e33f 292
999e12bb
AL
293static void pl022_class_init(ObjectClass *klass, void *data)
294{
66d9aa79 295 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb 296
66d9aa79 297 dc->reset = pl022_reset;
275ff67f 298 dc->vmsd = &vmstate_pl022;
13391a56 299 dc->realize = pl022_realize;
999e12bb
AL
300}
301
8c43a6f0 302static const TypeInfo pl022_info = {
3d29bcee 303 .name = TYPE_PL022,
39bffca2 304 .parent = TYPE_SYS_BUS_DEVICE,
ce556e0b 305 .instance_size = sizeof(PL022State),
39bffca2 306 .class_init = pl022_class_init,
999e12bb
AL
307};
308
83f7d43a 309static void pl022_register_types(void)
5493e33f 310{
39bffca2 311 type_register_static(&pl022_info);
5493e33f
PB
312}
313
83f7d43a 314type_init(pl022_register_types)