1 /*
2 * xen/drivers/char/pl011.c
3 *
4 * Driver for ARM PrimeCell PL011 UART.
5 *
6 * Tim Deegan <tim@xen.org>
7 * Copyright (c) 2011 Citrix Systems.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20 #include <xen/console.h>
21 #include <xen/serial.h>
22 #include <xen/init.h>
23 #include <xen/irq.h>
24 #include <xen/device_tree.h>
25 #include <xen/errno.h>
26 #include <asm/device.h>
27 #include <xen/mm.h>
28 #include <xen/vmap.h>
29 #include <asm/pl011-uart.h>
30 #include <asm/io.h>
31
32 static struct pl011 {
33 unsigned int data_bits, parity, stop_bits;
34 unsigned int irq;
35 void __iomem *regs;
36 /* UART with IRQ line: interrupt-driven I/O. */
37 struct irqaction irqaction;
38 struct vuart_info vuart;
39 /* /\* UART with no IRQ line: periodically-polled I/O. *\/ */
40 /* struct timer timer; */
41 /* unsigned int timeout_ms; */
42 /* bool_t probing, intr_works; */
43 bool sbsa; /* ARM SBSA generic interface */
44 } pl011_com = {0};
45
46 /* These parity settings can be ORed directly into the LCR. */
47 #define PARITY_NONE (0)
48 #define PARITY_ODD (PEN)
49 #define PARITY_EVEN (PEN|EPS)
50 #define PARITY_MARK (PEN|SPS)
51 #define PARITY_SPACE (PEN|EPS|SPS)
52
53 /* SBSA v2.x document requires, all reads/writes must be 32-bit accesses */
54 #define pl011_read(uart, off) readl((uart)->regs + (off))
55 #define pl011_write(uart, off,val) writel((val), (uart)->regs + (off))
56
pl011_intr_status(struct pl011 * uart)57 static unsigned int pl011_intr_status(struct pl011 *uart)
58 {
59 /* UARTMIS is not documented in SBSA v2.x, so use UARTRIS/UARTIMSC. */
60 return (pl011_read(uart, RIS) & pl011_read(uart, IMSC));
61 }
62
pl011_interrupt(int irq,void * data,struct cpu_user_regs * regs)63 static void pl011_interrupt(int irq, void *data, struct cpu_user_regs *regs)
64 {
65 struct serial_port *port = data;
66 struct pl011 *uart = port->uart;
67 unsigned int status = pl011_intr_status(uart);
68
69 if ( status )
70 {
71 do
72 {
73 pl011_write(uart, ICR, status & ~(TXI|RTI|RXI));
74
75 if ( status & (RTI|RXI) )
76 serial_rx_interrupt(port, regs);
77
78 /* TODO
79 if ( status & (DSRMI|DCDMI|CTSMI|RIMI) )
80 ...
81 */
82
83 if ( status & (TXI) )
84 serial_tx_interrupt(port, regs);
85
86 status = pl011_intr_status(uart);
87 } while (status != 0);
88 }
89 }
90
pl011_init_preirq(struct serial_port * port)91 static void __init pl011_init_preirq(struct serial_port *port)
92 {
93 struct pl011 *uart = port->uart;
94 unsigned int cr;
95
96 /* No interrupts, please. */
97 pl011_write(uart, IMSC, 0);
98
99 if ( !uart->sbsa )
100 {
101 /* Definitely no DMA */
102 pl011_write(uart, DMACR, 0x0);
103
104 /* This write must follow FBRD and IBRD writes. */
105 pl011_write(uart, LCR_H, (uart->data_bits - 5) << 5
106 | FEN
107 | ((uart->stop_bits - 1) << 3)
108 | uart->parity);
109 }
110 /* Clear errors */
111 pl011_write(uart, RSR, 0);
112
113 /* Mask and clear the interrupts */
114 pl011_write(uart, IMSC, 0);
115 pl011_write(uart, ICR, ALLI);
116
117 if ( !uart->sbsa )
118 {
119 /* Enable the UART for RX and TX; keep RTS and DTR */
120 cr = pl011_read(uart, CR);
121 cr &= RTS | DTR;
122 pl011_write(uart, CR, cr | RXE | TXE | UARTEN);
123 }
124 }
125
pl011_init_postirq(struct serial_port * port)126 static void __init pl011_init_postirq(struct serial_port *port)
127 {
128 struct pl011 *uart = port->uart;
129 int rc;
130
131 if ( uart->irq > 0 )
132 {
133 uart->irqaction.handler = pl011_interrupt;
134 uart->irqaction.name = "pl011";
135 uart->irqaction.dev_id = port;
136 if ( (rc = setup_irq(uart->irq, 0, &uart->irqaction)) != 0 )
137 printk("ERROR: Failed to allocate pl011 IRQ %d\n", uart->irq);
138 }
139
140 /* Clear pending error interrupts */
141 pl011_write(uart, ICR, OEI|BEI|PEI|FEI);
142
143 /* Unmask interrupts */
144 pl011_write(uart, IMSC, RTI|OEI|BEI|PEI|FEI|TXI|RXI);
145 }
146
pl011_suspend(struct serial_port * port)147 static void pl011_suspend(struct serial_port *port)
148 {
149 BUG(); // XXX
150 }
151
pl011_resume(struct serial_port * port)152 static void pl011_resume(struct serial_port *port)
153 {
154 BUG(); // XXX
155 }
156
pl011_tx_ready(struct serial_port * port)157 static int pl011_tx_ready(struct serial_port *port)
158 {
159 struct pl011 *uart = port->uart;
160
161 return ((pl011_read(uart, FR) & TXFE) ? 16 : 0);
162 }
163
pl011_putc(struct serial_port * port,char c)164 static void pl011_putc(struct serial_port *port, char c)
165 {
166 struct pl011 *uart = port->uart;
167
168 pl011_write(uart, DR, (uint32_t)(unsigned char)c);
169 }
170
pl011_getc(struct serial_port * port,char * pc)171 static int pl011_getc(struct serial_port *port, char *pc)
172 {
173 struct pl011 *uart = port->uart;
174
175 if ( pl011_read(uart, FR) & RXFE )
176 return 0;
177
178 *pc = pl011_read(uart, DR) & 0xff;
179 return 1;
180 }
181
pl011_irq(struct serial_port * port)182 static int __init pl011_irq(struct serial_port *port)
183 {
184 struct pl011 *uart = port->uart;
185
186 return ((uart->irq > 0) ? uart->irq : -1);
187 }
188
pl011_vuart(struct serial_port * port)189 static const struct vuart_info *pl011_vuart(struct serial_port *port)
190 {
191 struct pl011 *uart = port->uart;
192
193 return &uart->vuart;
194 }
195
pl011_tx_stop(struct serial_port * port)196 static void pl011_tx_stop(struct serial_port *port)
197 {
198 struct pl011 *uart = port->uart;
199
200 pl011_write(uart, IMSC, pl011_read(uart, IMSC) & ~(TXI));
201 }
202
pl011_tx_start(struct serial_port * port)203 static void pl011_tx_start(struct serial_port *port)
204 {
205 struct pl011 *uart = port->uart;
206
207 pl011_write(uart, IMSC, pl011_read(uart, IMSC) | (TXI));
208 }
209
210 static struct uart_driver __read_mostly pl011_driver = {
211 .init_preirq = pl011_init_preirq,
212 .init_postirq = pl011_init_postirq,
213 .endboot = NULL,
214 .suspend = pl011_suspend,
215 .resume = pl011_resume,
216 .tx_ready = pl011_tx_ready,
217 .putc = pl011_putc,
218 .getc = pl011_getc,
219 .irq = pl011_irq,
220 .start_tx = pl011_tx_start,
221 .stop_tx = pl011_tx_stop,
222 .vuart_info = pl011_vuart,
223 };
224
pl011_uart_init(int irq,u64 addr,u64 size,bool sbsa)225 static int __init pl011_uart_init(int irq, u64 addr, u64 size, bool sbsa)
226 {
227 struct pl011 *uart;
228
229 uart = &pl011_com;
230 uart->irq = irq;
231 uart->data_bits = 8;
232 uart->parity = PARITY_NONE;
233 uart->stop_bits = 1;
234 uart->sbsa = sbsa;
235
236 uart->regs = ioremap_nocache(addr, size);
237 if ( !uart->regs )
238 {
239 printk("pl011: Unable to map the UART memory\n");
240 return -ENOMEM;
241 }
242
243 uart->vuart.base_addr = addr;
244 uart->vuart.size = size;
245 uart->vuart.data_off = DR;
246 uart->vuart.status_off = FR;
247 uart->vuart.status = 0;
248
249 /* Register with generic serial driver. */
250 serial_register_uart(SERHND_DTUART, &pl011_driver, uart);
251
252 return 0;
253 }
254
255 /* TODO: Parse UART config from the command line */
pl011_dt_uart_init(struct dt_device_node * dev,const void * data)256 static int __init pl011_dt_uart_init(struct dt_device_node *dev,
257 const void *data)
258 {
259 const char *config = data;
260 int res;
261 u64 addr, size;
262
263 if ( strcmp(config, "") )
264 {
265 printk("WARNING: UART configuration is not supported\n");
266 }
267
268 res = dt_device_get_address(dev, 0, &addr, &size);
269 if ( res )
270 {
271 printk("pl011: Unable to retrieve the base"
272 " address of the UART\n");
273 return res;
274 }
275
276 res = platform_get_irq(dev, 0);
277 if ( res < 0 )
278 {
279 printk("pl011: Unable to retrieve the IRQ\n");
280 return -EINVAL;
281 }
282
283 res = pl011_uart_init(res, addr, size, false);
284 if ( res < 0 )
285 {
286 printk("pl011: Unable to initialize\n");
287 return res;
288 }
289
290 dt_device_set_used_by(dev, DOMID_XEN);
291
292 return 0;
293 }
294
295 static const struct dt_device_match pl011_dt_match[] __initconst =
296 {
297 DT_MATCH_COMPATIBLE("arm,pl011"),
298 { /* sentinel */ },
299 };
300
301 DT_DEVICE_START(pl011, "PL011 UART", DEVICE_SERIAL)
302 .dt_match = pl011_dt_match,
303 .init = pl011_dt_uart_init,
304 DT_DEVICE_END
305
306 #ifdef CONFIG_ACPI
307 #include <xen/acpi.h>
308
309 static int __init pl011_acpi_uart_init(const void *data)
310 {
311 acpi_status status;
312 struct acpi_table_spcr *spcr = NULL;
313 int res;
314 bool sbsa;
315
316 status = acpi_get_table(ACPI_SIG_SPCR, 0,
317 (struct acpi_table_header **)&spcr);
318
319 if ( ACPI_FAILURE(status) )
320 {
321 printk("pl011: Failed to get SPCR table\n");
322 return -EINVAL;
323 }
324
325 sbsa = (spcr->interface_type == ACPI_DBG2_SBSA ||
326 spcr->interface_type == ACPI_DBG2_SBSA_32);
327
328 /* trigger/polarity information is not available in spcr */
329 irq_set_type(spcr->interrupt, IRQ_TYPE_LEVEL_HIGH);
330
331 res = pl011_uart_init(spcr->interrupt, spcr->serial_port.address,
332 PAGE_SIZE, sbsa);
333 if ( res < 0 )
334 {
335 printk("pl011: Unable to initialize\n");
336 return res;
337 }
338
339 return 0;
340 }
341
342 ACPI_DEVICE_START(apl011, "PL011 UART", DEVICE_SERIAL)
343 .class_type = ACPI_DBG2_PL011,
344 .init = pl011_acpi_uart_init,
345 ACPI_DEVICE_END
346
347 ACPI_DEVICE_START(asbsa_uart, "SBSA UART", DEVICE_SERIAL)
348 .class_type = ACPI_DBG2_SBSA,
349 .init = pl011_acpi_uart_init,
350 ACPI_DEVICE_END
351
352 ACPI_DEVICE_START(asbsa32_uart, "SBSA32 UART", DEVICE_SERIAL)
353 .class_type = ACPI_DBG2_SBSA_32,
354 .init = pl011_acpi_uart_init,
355 ACPI_DEVICE_END
356
357 #endif
358
359 /*
360 * Local variables:
361 * mode: C
362 * c-file-style: "BSD"
363 * c-basic-offset: 4
364 * indent-tabs-mode: nil
365 * End:
366 */
367