1 /*
2 * xen/drivers/char/scif-uart.c
3 *
4 * Driver for SCIF (Serial communication interface with FIFO)
5 * compatible UART.
6 *
7 * Oleksandr Tyshchenko <oleksandr.tyshchenko@globallogic.com>
8 * Copyright (C) 2014, Globallogic.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 */
20
21 #include <xen/console.h>
22 #include <xen/errno.h>
23 #include <xen/serial.h>
24 #include <xen/init.h>
25 #include <xen/irq.h>
26 #include <xen/mm.h>
27 #include <xen/delay.h>
28 #include <asm/device.h>
29 #include <asm/scif-uart.h>
30 #include <asm/io.h>
31
32 #define PARITY_NONE 0
33 #define PARITY_EVEN 1
34 #define PARITY_ODD 2
35
36 #define scif_readb(uart, off) readb((uart)->regs + (off))
37 #define scif_writeb(uart, off, val) writeb((val), (uart)->regs + (off))
38
39 #define scif_readw(uart, off) readw((uart)->regs + (off))
40 #define scif_writew(uart, off, val) writew((val), (uart)->regs + (off))
41
42 static struct scif_uart {
43 unsigned int irq;
44 char __iomem *regs;
45 struct irqaction irqaction;
46 struct vuart_info vuart;
47 } scif_com = {0};
48
scif_uart_interrupt(int irq,void * data,struct cpu_user_regs * regs)49 static void scif_uart_interrupt(int irq, void *data, struct cpu_user_regs *regs)
50 {
51 struct serial_port *port = data;
52 struct scif_uart *uart = port->uart;
53 uint16_t status, ctrl;
54
55 ctrl = scif_readw(uart, SCIF_SCSCR);
56 status = scif_readw(uart, SCIF_SCFSR) & ~SCFSR_TEND;
57 /* Ignore next flag if TX Interrupt is disabled */
58 if ( !(ctrl & SCSCR_TIE) )
59 status &= ~SCFSR_TDFE;
60
61 while ( status != 0 )
62 {
63 /* TX Interrupt */
64 if ( status & SCFSR_TDFE )
65 serial_tx_interrupt(port, regs);
66
67 /* RX Interrupt */
68 if ( status & (SCFSR_RDF | SCFSR_DR) )
69 serial_rx_interrupt(port, regs);
70
71 /* Error Interrupt */
72 if ( status & SCIF_ERRORS )
73 scif_writew(uart, SCIF_SCFSR, ~SCIF_ERRORS);
74 if ( scif_readw(uart, SCIF_SCLSR) & SCLSR_ORER )
75 scif_writew(uart, SCIF_SCLSR, 0);
76
77 ctrl = scif_readw(uart, SCIF_SCSCR);
78 status = scif_readw(uart, SCIF_SCFSR) & ~SCFSR_TEND;
79 /* Ignore next flag if TX Interrupt is disabled */
80 if ( !(ctrl & SCSCR_TIE) )
81 status &= ~SCFSR_TDFE;
82 }
83 }
84
scif_uart_init_preirq(struct serial_port * port)85 static void __init scif_uart_init_preirq(struct serial_port *port)
86 {
87 struct scif_uart *uart = port->uart;
88
89 /*
90 * Wait until last bit has been transmitted. This is needed for a smooth
91 * transition when we come from early printk
92 */
93 while ( !(scif_readw(uart, SCIF_SCFSR) & SCFSR_TEND) );
94
95 /* Disable TX/RX parts and all interrupts */
96 scif_writew(uart, SCIF_SCSCR, 0);
97
98 /* Reset TX/RX FIFOs */
99 scif_writew(uart, SCIF_SCFCR, SCFCR_RFRST | SCFCR_TFRST);
100
101 /* Clear all errors and flags */
102 scif_readw(uart, SCIF_SCFSR);
103 scif_writew(uart, SCIF_SCFSR, 0);
104 scif_readw(uart, SCIF_SCLSR);
105 scif_writew(uart, SCIF_SCLSR, 0);
106
107 /* Setup trigger level for TX/RX FIFOs */
108 scif_writew(uart, SCIF_SCFCR, SCFCR_RTRG11 | SCFCR_TTRG11);
109
110 /* Enable TX/RX parts */
111 scif_writew(uart, SCIF_SCSCR, scif_readw(uart, SCIF_SCSCR) |
112 SCSCR_TE | SCSCR_RE);
113 }
114
scif_uart_init_postirq(struct serial_port * port)115 static void __init scif_uart_init_postirq(struct serial_port *port)
116 {
117 struct scif_uart *uart = port->uart;
118 int rc;
119
120 uart->irqaction.handler = scif_uart_interrupt;
121 uart->irqaction.name = "scif_uart";
122 uart->irqaction.dev_id = port;
123
124 if ( (rc = setup_irq(uart->irq, 0, &uart->irqaction)) != 0 )
125 dprintk(XENLOG_ERR, "Failed to allocated scif_uart IRQ %d\n",
126 uart->irq);
127
128 /* Clear all errors */
129 if ( scif_readw(uart, SCIF_SCFSR) & SCIF_ERRORS )
130 scif_writew(uart, SCIF_SCFSR, ~SCIF_ERRORS);
131 if ( scif_readw(uart, SCIF_SCLSR) & SCLSR_ORER )
132 scif_writew(uart, SCIF_SCLSR, 0);
133
134 /* Enable TX/RX and Error Interrupts */
135 scif_writew(uart, SCIF_SCSCR, scif_readw(uart, SCIF_SCSCR) |
136 SCSCR_TIE | SCSCR_RIE | SCSCR_REIE);
137 }
138
scif_uart_suspend(struct serial_port * port)139 static void scif_uart_suspend(struct serial_port *port)
140 {
141 BUG();
142 }
143
scif_uart_resume(struct serial_port * port)144 static void scif_uart_resume(struct serial_port *port)
145 {
146 BUG();
147 }
148
scif_uart_tx_ready(struct serial_port * port)149 static int scif_uart_tx_ready(struct serial_port *port)
150 {
151 struct scif_uart *uart = port->uart;
152 uint16_t cnt;
153
154 /* Check for empty space in TX FIFO */
155 if ( !(scif_readw(uart, SCIF_SCFSR) & SCFSR_TDFE) )
156 return 0;
157
158 /* Check number of data bytes stored in TX FIFO */
159 cnt = scif_readw(uart, SCIF_SCFDR) >> 8;
160 ASSERT( cnt >= 0 && cnt <= SCIF_FIFO_MAX_SIZE );
161
162 return (SCIF_FIFO_MAX_SIZE - cnt);
163 }
164
scif_uart_putc(struct serial_port * port,char c)165 static void scif_uart_putc(struct serial_port *port, char c)
166 {
167 struct scif_uart *uart = port->uart;
168
169 scif_writeb(uart, SCIF_SCFTDR, c);
170 /* Clear required TX flags */
171 scif_writew(uart, SCIF_SCFSR, scif_readw(uart, SCIF_SCFSR) &
172 ~(SCFSR_TEND | SCFSR_TDFE));
173 }
174
scif_uart_getc(struct serial_port * port,char * pc)175 static int scif_uart_getc(struct serial_port *port, char *pc)
176 {
177 struct scif_uart *uart = port->uart;
178
179 /* Check for available data bytes in RX FIFO */
180 if ( !(scif_readw(uart, SCIF_SCFSR) & (SCFSR_RDF | SCFSR_DR)) )
181 return 0;
182
183 *pc = scif_readb(uart, SCIF_SCFRDR);
184
185 /* dummy read */
186 scif_readw(uart, SCIF_SCFSR);
187 /* Clear required RX flags */
188 scif_writew(uart, SCIF_SCFSR, ~(SCFSR_RDF | SCFSR_DR));
189
190 return 1;
191 }
192
scif_uart_irq(struct serial_port * port)193 static int __init scif_uart_irq(struct serial_port *port)
194 {
195 struct scif_uart *uart = port->uart;
196
197 return ((uart->irq > 0) ? uart->irq : -1);
198 }
199
scif_vuart_info(struct serial_port * port)200 static const struct vuart_info *scif_vuart_info(struct serial_port *port)
201 {
202 struct scif_uart *uart = port->uart;
203
204 return &uart->vuart;
205 }
206
scif_uart_start_tx(struct serial_port * port)207 static void scif_uart_start_tx(struct serial_port *port)
208 {
209 struct scif_uart *uart = port->uart;
210
211 scif_writew(uart, SCIF_SCSCR, scif_readw(uart, SCIF_SCSCR) | SCSCR_TIE);
212 }
213
scif_uart_stop_tx(struct serial_port * port)214 static void scif_uart_stop_tx(struct serial_port *port)
215 {
216 struct scif_uart *uart = port->uart;
217
218 scif_writew(uart, SCIF_SCSCR, scif_readw(uart, SCIF_SCSCR) & ~SCSCR_TIE);
219 }
220
221 static struct uart_driver __read_mostly scif_uart_driver = {
222 .init_preirq = scif_uart_init_preirq,
223 .init_postirq = scif_uart_init_postirq,
224 .endboot = NULL,
225 .suspend = scif_uart_suspend,
226 .resume = scif_uart_resume,
227 .tx_ready = scif_uart_tx_ready,
228 .putc = scif_uart_putc,
229 .getc = scif_uart_getc,
230 .irq = scif_uart_irq,
231 .start_tx = scif_uart_start_tx,
232 .stop_tx = scif_uart_stop_tx,
233 .vuart_info = scif_vuart_info,
234 };
235
scif_uart_init(struct dt_device_node * dev,const void * data)236 static int __init scif_uart_init(struct dt_device_node *dev,
237 const void *data)
238 {
239 const char *config = data;
240 struct scif_uart *uart;
241 int res;
242 u64 addr, size;
243
244 if ( strcmp(config, "") )
245 printk("WARNING: UART configuration is not supported\n");
246
247 uart = &scif_com;
248
249 res = dt_device_get_address(dev, 0, &addr, &size);
250 if ( res )
251 {
252 printk("scif-uart: Unable to retrieve the base"
253 " address of the UART\n");
254 return res;
255 }
256
257 res = platform_get_irq(dev, 0);
258 if ( res < 0 )
259 {
260 printk("scif-uart: Unable to retrieve the IRQ\n");
261 return res;
262 }
263 uart->irq = res;
264
265 uart->regs = ioremap_nocache(addr, size);
266 if ( !uart->regs )
267 {
268 printk("scif-uart: Unable to map the UART memory\n");
269 return -ENOMEM;
270 }
271
272 uart->vuart.base_addr = addr;
273 uart->vuart.size = size;
274 uart->vuart.data_off = SCIF_SCFTDR;
275 uart->vuart.status_off = SCIF_SCFSR;
276 uart->vuart.status = SCFSR_TDFE;
277
278 /* Register with generic serial driver */
279 serial_register_uart(SERHND_DTUART, &scif_uart_driver, uart);
280
281 dt_device_set_used_by(dev, DOMID_XEN);
282
283 return 0;
284 }
285
286 static const struct dt_device_match scif_uart_dt_match[] __initconst =
287 {
288 DT_MATCH_COMPATIBLE("renesas,scif"),
289 { /* sentinel */ },
290 };
291
292 DT_DEVICE_START(scif_uart, "SCIF UART", DEVICE_SERIAL)
293 .dt_match = scif_uart_dt_match,
294 .init = scif_uart_init,
295 DT_DEVICE_END
296
297 /*
298 * Local variables:
299 * mode: C
300 * c-file-style: "BSD"
301 * c-basic-offset: 4
302 * indent-tabs-mode: nil
303 * End:
304 */
305