find -type f | xargs sed -i 's/[\t ]*$//g' # Yes, again. Note the star in the regex.
[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 "vl.h"
11
12 typedef struct {
13     uint32_t base;
14     uint32_t readbuff;
15     uint32_t flags;
16     uint32_t lcr;
17     uint32_t cr;
18     uint32_t dmacr;
19     uint32_t int_enabled;
20     uint32_t int_level;
21     uint32_t read_fifo[16];
22     uint32_t ilpr;
23     uint32_t ibrd;
24     uint32_t fbrd;
25     uint32_t ifl;
26     int read_pos;
27     int read_count;
28     int read_trigger;
29     CharDriverState *chr;
30     qemu_irq irq;
31 } pl011_state;
32
33 #define PL011_INT_TX 0x20
34 #define PL011_INT_RX 0x10
35
36 #define PL011_FLAG_TXFE 0x80
37 #define PL011_FLAG_RXFF 0x40
38 #define PL011_FLAG_TXFF 0x20
39 #define PL011_FLAG_RXFE 0x10
40
41 static const unsigned char pl011_id[] =
42 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
43
44 static void pl011_update(pl011_state *s)
45 {
46     uint32_t flags;
47
48     flags = s->int_level & s->int_enabled;
49     qemu_set_irq(s->irq, flags != 0);
50 }
51
52 static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
53 {
54     pl011_state *s = (pl011_state *)opaque;
55     uint32_t c;
56
57     offset -= s->base;
58     if (offset >= 0xfe0 && offset < 0x1000) {
59         return pl011_id[(offset - 0xfe0) >> 2];
60     }
61     switch (offset >> 2) {
62     case 0: /* UARTDR */
63         s->flags &= ~PL011_FLAG_RXFF;
64         c = s->read_fifo[s->read_pos];
65         if (s->read_count > 0) {
66             s->read_count--;
67             if (++s->read_pos == 16)
68                 s->read_pos = 0;
69         }
70         if (s->read_count == 0) {
71             s->flags |= PL011_FLAG_RXFE;
72         }
73         if (s->read_count == s->read_trigger - 1)
74             s->int_level &= ~ PL011_INT_RX;
75         pl011_update(s);
76         return c;
77     case 1: /* UARTCR */
78         return 0;
79     case 6: /* UARTFR */
80         return s->flags;
81     case 8: /* UARTILPR */
82         return s->ilpr;
83     case 9: /* UARTIBRD */
84         return s->ibrd;
85     case 10: /* UARTFBRD */
86         return s->fbrd;
87     case 11: /* UARTLCR_H */
88         return s->lcr;
89     case 12: /* UARTCR */
90         return s->cr;
91     case 13: /* UARTIFLS */
92         return s->ifl;
93     case 14: /* UARTIMSC */
94         return s->int_enabled;
95     case 15: /* UARTRIS */
96         return s->int_level;
97     case 16: /* UARTMIS */
98         return s->int_level & s->int_enabled;
99     case 18: /* UARTDMACR */
100         return s->dmacr;
101     default:
102         cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);
103         return 0;
104     }
105 }
106
107 static void pl011_set_read_trigger(pl011_state *s)
108 {
109 #if 0
110     /* The docs say the RX interrupt is triggered when the FIFO exceeds
111        the threshold.  However linux only reads the FIFO in response to an
112        interrupt.  Triggering the interrupt when the FIFO is non-empty seems
113        to make things work.  */
114     if (s->lcr & 0x10)
115         s->read_trigger = (s->ifl >> 1) & 0x1c;
116     else
117 #endif
118         s->read_trigger = 1;
119 }
120
121 static void pl011_write(void *opaque, target_phys_addr_t offset,
122                           uint32_t value)
123 {
124     pl011_state *s = (pl011_state *)opaque;
125     unsigned char ch;
126
127     offset -= s->base;
128     switch (offset >> 2) {
129     case 0: /* UARTDR */
130         /* ??? Check if transmitter is enabled.  */
131         ch = value;
132         if (s->chr)
133             qemu_chr_write(s->chr, &ch, 1);
134         s->int_level |= PL011_INT_TX;
135         pl011_update(s);
136         break;
137     case 1: /* UARTCR */
138         s->cr = value;
139         break;
140     case 8: /* UARTUARTILPR */
141         s->ilpr = value;
142         break;
143     case 9: /* UARTIBRD */
144         s->ibrd = value;
145         break;
146     case 10: /* UARTFBRD */
147         s->fbrd = value;
148         break;
149     case 11: /* UARTLCR_H */
150         s->lcr = value;
151         pl011_set_read_trigger(s);
152         break;
153     case 12: /* UARTCR */
154         /* ??? Need to implement the enable and loopback bits.  */
155         s->cr = value;
156         break;
157     case 13: /* UARTIFS */
158         s->ifl = value;
159         pl011_set_read_trigger(s);
160         break;
161     case 14: /* UARTIMSC */
162         s->int_enabled = value;
163         pl011_update(s);
164         break;
165     case 17: /* UARTICR */
166         s->int_level &= ~value;
167         pl011_update(s);
168         break;
169     case 18: /* UARTDMACR */
170         s->dmacr = value;
171         if (value & 3)
172             cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
173         break;
174     default:
175         cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);
176     }
177 }
178
179 static int pl011_can_receive(void *opaque)
180 {
181     pl011_state *s = (pl011_state *)opaque;
182
183     if (s->lcr & 0x10)
184         return s->read_count < 16;
185     else
186         return s->read_count < 1;
187 }
188
189 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
190 {
191     pl011_state *s = (pl011_state *)opaque;
192     int slot;
193
194     slot = s->read_pos + s->read_count;
195     if (slot >= 16)
196         slot -= 16;
197     s->read_fifo[slot] = *buf;
198     s->read_count++;
199     s->flags &= ~PL011_FLAG_RXFE;
200     if (s->cr & 0x10 || s->read_count == 16) {
201         s->flags |= PL011_FLAG_RXFF;
202     }
203     if (s->read_count == s->read_trigger) {
204         s->int_level |= PL011_INT_RX;
205         pl011_update(s);
206     }
207 }
208
209 static void pl011_event(void *opaque, int event)
210 {
211     /* ??? Should probably implement break.  */
212 }
213
214 static CPUReadMemoryFunc *pl011_readfn[] = {
215    pl011_read,
216    pl011_read,
217    pl011_read
218 };
219
220 static CPUWriteMemoryFunc *pl011_writefn[] = {
221    pl011_write,
222    pl011_write,
223    pl011_write
224 };
225
226 void pl011_init(uint32_t base, qemu_irq irq,
227                 CharDriverState *chr)
228 {
229     int iomemtype;
230     pl011_state *s;
231
232     s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
233     iomemtype = cpu_register_io_memory(0, pl011_readfn,
234                                        pl011_writefn, s);
235     cpu_register_physical_memory(base, 0x00001000, iomemtype);
236     s->base = base;
237     s->irq = irq;
238     s->chr = chr;
239     s->read_trigger = 1;
240     s->ifl = 0x12;
241     s->cr = 0x300;
242     s->flags = 0x90;
243     if (chr){
244         qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive,
245                               pl011_event, s);
246     }
247     /* ??? Save/restore.  */
248 }
249