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