Save/restore for stellaris boards.
[qemu] / hw / pl011.c
1 /*
2  * Arm PrimeCell PL011 UART
3  *
4  * Copyright (c) 2006 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licenced under the GPL.
8  */
9
10 #include "hw.h"
11 #include "qemu-char.h"
12 #include "primecell.h"
13
14 typedef struct {
15     uint32_t base;
16     uint32_t readbuff;
17     uint32_t flags;
18     uint32_t lcr;
19     uint32_t cr;
20     uint32_t dmacr;
21     uint32_t int_enabled;
22     uint32_t int_level;
23     uint32_t read_fifo[16];
24     uint32_t ilpr;
25     uint32_t ibrd;
26     uint32_t fbrd;
27     uint32_t ifl;
28     int read_pos;
29     int read_count;
30     int read_trigger;
31     CharDriverState *chr;
32     qemu_irq irq;
33     enum pl011_type type;
34 } pl011_state;
35
36 #define PL011_INT_TX 0x20
37 #define PL011_INT_RX 0x10
38
39 #define PL011_FLAG_TXFE 0x80
40 #define PL011_FLAG_RXFF 0x40
41 #define PL011_FLAG_TXFF 0x20
42 #define PL011_FLAG_RXFE 0x10
43
44 static const unsigned char pl011_id[2][8] = {
45   { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }, /* PL011_ARM */
46   { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }, /* PL011_LUMINARY */
47 };
48
49 static void pl011_update(pl011_state *s)
50 {
51     uint32_t flags;
52
53     flags = s->int_level & s->int_enabled;
54     qemu_set_irq(s->irq, flags != 0);
55 }
56
57 static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
58 {
59     pl011_state *s = (pl011_state *)opaque;
60     uint32_t c;
61
62     offset -= s->base;
63     if (offset >= 0xfe0 && offset < 0x1000) {
64         return pl011_id[s->type][(offset - 0xfe0) >> 2];
65     }
66     switch (offset >> 2) {
67     case 0: /* UARTDR */
68         s->flags &= ~PL011_FLAG_RXFF;
69         c = s->read_fifo[s->read_pos];
70         if (s->read_count > 0) {
71             s->read_count--;
72             if (++s->read_pos == 16)
73                 s->read_pos = 0;
74         }
75         if (s->read_count == 0) {
76             s->flags |= PL011_FLAG_RXFE;
77         }
78         if (s->read_count == s->read_trigger - 1)
79             s->int_level &= ~ PL011_INT_RX;
80         pl011_update(s);
81         qemu_chr_accept_input(s->chr);
82         return c;
83     case 1: /* UARTCR */
84         return 0;
85     case 6: /* UARTFR */
86         return s->flags;
87     case 8: /* UARTILPR */
88         return s->ilpr;
89     case 9: /* UARTIBRD */
90         return s->ibrd;
91     case 10: /* UARTFBRD */
92         return s->fbrd;
93     case 11: /* UARTLCR_H */
94         return s->lcr;
95     case 12: /* UARTCR */
96         return s->cr;
97     case 13: /* UARTIFLS */
98         return s->ifl;
99     case 14: /* UARTIMSC */
100         return s->int_enabled;
101     case 15: /* UARTRIS */
102         return s->int_level;
103     case 16: /* UARTMIS */
104         return s->int_level & s->int_enabled;
105     case 18: /* UARTDMACR */
106         return s->dmacr;
107     default:
108         cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", (int)offset);
109         return 0;
110     }
111 }
112
113 static void pl011_set_read_trigger(pl011_state *s)
114 {
115 #if 0
116     /* The docs say the RX interrupt is triggered when the FIFO exceeds
117        the threshold.  However linux only reads the FIFO in response to an
118        interrupt.  Triggering the interrupt when the FIFO is non-empty seems
119        to make things work.  */
120     if (s->lcr & 0x10)
121         s->read_trigger = (s->ifl >> 1) & 0x1c;
122     else
123 #endif
124         s->read_trigger = 1;
125 }
126
127 static void pl011_write(void *opaque, target_phys_addr_t offset,
128                           uint32_t value)
129 {
130     pl011_state *s = (pl011_state *)opaque;
131     unsigned char ch;
132
133     offset -= s->base;
134     switch (offset >> 2) {
135     case 0: /* UARTDR */
136         /* ??? Check if transmitter is enabled.  */
137         ch = value;
138         if (s->chr)
139             qemu_chr_write(s->chr, &ch, 1);
140         s->int_level |= PL011_INT_TX;
141         pl011_update(s);
142         break;
143     case 1: /* UARTCR */
144         s->cr = value;
145         break;
146     case 6: /* UARTFR */
147         /* Writes to Flag register are ignored.  */
148         break;
149     case 8: /* UARTUARTILPR */
150         s->ilpr = value;
151         break;
152     case 9: /* UARTIBRD */
153         s->ibrd = value;
154         break;
155     case 10: /* UARTFBRD */
156         s->fbrd = value;
157         break;
158     case 11: /* UARTLCR_H */
159         s->lcr = value;
160         pl011_set_read_trigger(s);
161         break;
162     case 12: /* UARTCR */
163         /* ??? Need to implement the enable and loopback bits.  */
164         s->cr = value;
165         break;
166     case 13: /* UARTIFS */
167         s->ifl = value;
168         pl011_set_read_trigger(s);
169         break;
170     case 14: /* UARTIMSC */
171         s->int_enabled = value;
172         pl011_update(s);
173         break;
174     case 17: /* UARTICR */
175         s->int_level &= ~value;
176         pl011_update(s);
177         break;
178     case 18: /* UARTDMACR */
179         s->dmacr = value;
180         if (value & 3)
181             cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
182         break;
183     default:
184         cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", (int)offset);
185     }
186 }
187
188 static int pl011_can_receive(void *opaque)
189 {
190     pl011_state *s = (pl011_state *)opaque;
191
192     if (s->lcr & 0x10)
193         return s->read_count < 16;
194     else
195         return s->read_count < 1;
196 }
197
198 static void pl011_put_fifo(void *opaque, uint32_t value)
199 {
200     pl011_state *s = (pl011_state *)opaque;
201     int slot;
202
203     slot = s->read_pos + s->read_count;
204     if (slot >= 16)
205         slot -= 16;
206     s->read_fifo[slot] = value;
207     s->read_count++;
208     s->flags &= ~PL011_FLAG_RXFE;
209     if (s->cr & 0x10 || s->read_count == 16) {
210         s->flags |= PL011_FLAG_RXFF;
211     }
212     if (s->read_count == s->read_trigger) {
213         s->int_level |= PL011_INT_RX;
214         pl011_update(s);
215     }
216 }
217
218 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
219 {
220     pl011_put_fifo(opaque, *buf);
221 }
222
223 static void pl011_event(void *opaque, int event)
224 {
225     if (event == CHR_EVENT_BREAK)
226         pl011_put_fifo(opaque, 0x400);
227 }
228
229 static CPUReadMemoryFunc *pl011_readfn[] = {
230    pl011_read,
231    pl011_read,
232    pl011_read
233 };
234
235 static CPUWriteMemoryFunc *pl011_writefn[] = {
236    pl011_write,
237    pl011_write,
238    pl011_write
239 };
240
241 static void pl011_save(QEMUFile *f, void *opaque)
242 {
243     pl011_state *s = (pl011_state *)opaque;
244     int i;
245
246     qemu_put_be32(f, s->readbuff);
247     qemu_put_be32(f, s->flags);
248     qemu_put_be32(f, s->lcr);
249     qemu_put_be32(f, s->cr);
250     qemu_put_be32(f, s->dmacr);
251     qemu_put_be32(f, s->int_enabled);
252     qemu_put_be32(f, s->int_level);
253     for (i = 0; i < 16; i++)
254         qemu_put_be32(f, s->read_fifo[i]);
255     qemu_put_be32(f, s->ilpr);
256     qemu_put_be32(f, s->ibrd);
257     qemu_put_be32(f, s->fbrd);
258     qemu_put_be32(f, s->ifl);
259     qemu_put_be32(f, s->read_pos);
260     qemu_put_be32(f, s->read_count);
261     qemu_put_be32(f, s->read_trigger);
262 }
263
264 static int pl011_load(QEMUFile *f, void *opaque, int version_id)
265 {
266     pl011_state *s = (pl011_state *)opaque;
267     int i;
268
269     if (version_id != 1)
270         return -EINVAL;
271
272     s->readbuff = qemu_get_be32(f);
273     s->flags = qemu_get_be32(f);
274     s->lcr = qemu_get_be32(f);
275     s->cr = qemu_get_be32(f);
276     s->dmacr = qemu_get_be32(f);
277     s->int_enabled = qemu_get_be32(f);
278     s->int_level = qemu_get_be32(f);
279     for (i = 0; i < 16; i++)
280         s->read_fifo[i] = qemu_get_be32(f);
281     s->ilpr = qemu_get_be32(f);
282     s->ibrd = qemu_get_be32(f);
283     s->fbrd = qemu_get_be32(f);
284     s->ifl = qemu_get_be32(f);
285     s->read_pos = qemu_get_be32(f);
286     s->read_count = qemu_get_be32(f);
287     s->read_trigger = qemu_get_be32(f);
288
289     return 0;
290 }
291
292 void pl011_init(uint32_t base, qemu_irq irq,
293                 CharDriverState *chr, enum pl011_type type)
294 {
295     int iomemtype;
296     pl011_state *s;
297
298     s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
299     iomemtype = cpu_register_io_memory(0, pl011_readfn,
300                                        pl011_writefn, s);
301     cpu_register_physical_memory(base, 0x00001000, iomemtype);
302     s->base = base;
303     s->irq = irq;
304     s->type = type;
305     s->chr = chr;
306     s->read_trigger = 1;
307     s->ifl = 0x12;
308     s->cr = 0x300;
309     s->flags = 0x90;
310     if (chr){
311         qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive,
312                               pl011_event, s);
313     }
314     register_savevm("pl011_uart", -1, 1, pl011_save, pl011_load, s);
315 }
316