]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/uart/uart_dev_imx.c
MFC 264203, 264204, 264206, 264218:
[FreeBSD/stable/10.git] / sys / dev / uart / uart_dev_imx.c
1 /*-
2  * Copyright (c) 2012 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Oleksandr Rybalko under sponsorship
6  * from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1.   Redistributions of source code must retain the above copyright
12  *      notice, this list of conditions and the following disclaimer.
13  * 2.   Redistributions in binary form must reproduce the above copyright
14  *      notice, this list of conditions and the following disclaimer in the
15  *      documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include "opt_ddb.h"
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/conf.h>
39 #include <sys/kdb.h>
40 #include <machine/bus.h>
41 #include <machine/fdt.h>
42
43 #include <dev/uart/uart.h>
44 #include <dev/uart/uart_cpu.h>
45 #include <dev/uart/uart_bus.h>
46
47 #include <dev/uart/uart_dev_imx5xx.h>
48
49 #include "uart_if.h"
50 /*
51  * Low-level UART interface.
52  */
53 static int imx_uart_probe(struct uart_bas *bas);
54 static void imx_uart_init(struct uart_bas *bas, int, int, int, int);
55 static void imx_uart_term(struct uart_bas *bas);
56 static void imx_uart_putc(struct uart_bas *bas, int);
57 static int imx_uart_rxready(struct uart_bas *bas);
58 static int imx_uart_getc(struct uart_bas *bas, struct mtx *);
59
60 static struct uart_ops uart_imx_uart_ops = {
61         .probe = imx_uart_probe,
62         .init = imx_uart_init,
63         .term = imx_uart_term,
64         .putc = imx_uart_putc,
65         .rxready = imx_uart_rxready,
66         .getc = imx_uart_getc,
67 };
68
69 static int
70 imx_uart_probe(struct uart_bas *bas)
71 {
72
73         return (0);
74 }
75
76 static void
77 imx_uart_init(struct uart_bas *bas, int baudrate, int databits, 
78     int stopbits, int parity)
79 {
80
81 }
82
83 static void
84 imx_uart_term(struct uart_bas *bas)
85 {
86
87 }
88
89 static void
90 imx_uart_putc(struct uart_bas *bas, int c)
91 {
92
93         while (!(IS(bas, USR2, TXFE)))
94                 ;
95         SETREG(bas, REG(UTXD), c);
96 }
97
98 static int
99 imx_uart_rxready(struct uart_bas *bas)
100 {
101
102         return ((IS(bas, USR2, RDR)) ? 1 : 0);
103 }
104
105 static int
106 imx_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
107 {
108         int c;
109
110         uart_lock(hwmtx);
111         while (!(IS(bas, USR2, RDR)))
112                 ;
113
114         c = GETREG(bas, REG(URXD));
115         uart_unlock(hwmtx);
116 #if defined(KDB)
117         if (c & FLD(URXD, BRK)) {
118                 if (kdb_break())
119                         return (0);
120         }
121 #endif
122         return (c & 0xff);
123 }
124
125 /*
126  * High-level UART interface.
127  */
128 struct imx_uart_softc {
129         struct uart_softc base;
130 };
131
132 static int imx_uart_bus_attach(struct uart_softc *);
133 static int imx_uart_bus_detach(struct uart_softc *);
134 static int imx_uart_bus_flush(struct uart_softc *, int);
135 static int imx_uart_bus_getsig(struct uart_softc *);
136 static int imx_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
137 static int imx_uart_bus_ipend(struct uart_softc *);
138 static int imx_uart_bus_param(struct uart_softc *, int, int, int, int);
139 static int imx_uart_bus_probe(struct uart_softc *);
140 static int imx_uart_bus_receive(struct uart_softc *);
141 static int imx_uart_bus_setsig(struct uart_softc *, int);
142 static int imx_uart_bus_transmit(struct uart_softc *);
143 static void imx_uart_bus_grab(struct uart_softc *);
144 static void imx_uart_bus_ungrab(struct uart_softc *);
145
146 static kobj_method_t imx_uart_methods[] = {
147         KOBJMETHOD(uart_attach,         imx_uart_bus_attach),
148         KOBJMETHOD(uart_detach,         imx_uart_bus_detach),
149         KOBJMETHOD(uart_flush,          imx_uart_bus_flush),
150         KOBJMETHOD(uart_getsig,         imx_uart_bus_getsig),
151         KOBJMETHOD(uart_ioctl,          imx_uart_bus_ioctl),
152         KOBJMETHOD(uart_ipend,          imx_uart_bus_ipend),
153         KOBJMETHOD(uart_param,          imx_uart_bus_param),
154         KOBJMETHOD(uart_probe,          imx_uart_bus_probe),
155         KOBJMETHOD(uart_receive,        imx_uart_bus_receive),
156         KOBJMETHOD(uart_setsig,         imx_uart_bus_setsig),
157         KOBJMETHOD(uart_transmit,       imx_uart_bus_transmit),
158         KOBJMETHOD(uart_grab,           imx_uart_bus_grab),
159         KOBJMETHOD(uart_ungrab,         imx_uart_bus_ungrab),
160         { 0, 0 }
161 };
162
163 struct uart_class uart_imx_class = {
164         "imx",
165         imx_uart_methods,
166         sizeof(struct imx_uart_softc),
167         .uc_ops = &uart_imx_uart_ops,
168         .uc_range = 0x100,
169         .uc_rclk = 24000000 /* TODO: get value from CCM */
170 };
171
172 #define SIGCHG(c, i, s, d)                              \
173         if (c) {                                        \
174                 i |= (i & s) ? s : s | d;               \
175         } else {                                        \
176                 i = (i & s) ? (i & ~s) | d : i;         \
177         }
178
179 static int
180 imx_uart_bus_attach(struct uart_softc *sc)
181 {
182         struct uart_bas *bas;
183         struct uart_devinfo *di;
184
185         bas = &sc->sc_bas;
186         if (sc->sc_sysdev != NULL) {
187                 di = sc->sc_sysdev;
188                 imx_uart_init(bas, di->baudrate, di->databits, di->stopbits,
189                     di->parity);
190         } else {
191                 imx_uart_init(bas, 115200, 8, 1, 0);
192         }
193
194         (void)imx_uart_bus_getsig(sc);
195
196         ENA(bas, UCR4, DREN);
197         DIS(bas, UCR1, RRDYEN);
198         DIS(bas, UCR1, IDEN);
199         DIS(bas, UCR3, RXDSEN);
200         DIS(bas, UCR2, ATEN);
201         DIS(bas, UCR1, TXMPTYEN);
202         DIS(bas, UCR1, TRDYEN);
203         DIS(bas, UCR4, TCEN);
204         DIS(bas, UCR4, OREN);
205         ENA(bas, UCR4, BKEN);
206         DIS(bas, UCR4, WKEN);
207         DIS(bas, UCR1, ADEN);
208         DIS(bas, UCR3, ACIEN);
209         DIS(bas, UCR2, ESCI);
210         DIS(bas, UCR4, ENIRI);
211         DIS(bas, UCR3, AIRINTEN);
212         DIS(bas, UCR3, AWAKEN);
213         DIS(bas, UCR3, FRAERREN);
214         DIS(bas, UCR3, PARERREN);
215         DIS(bas, UCR1, RTSDEN);
216         DIS(bas, UCR2, RTSEN);
217         DIS(bas, UCR3, DTREN);
218         DIS(bas, UCR3, RI);
219         DIS(bas, UCR3, DCD);
220         DIS(bas, UCR3, DTRDEN);
221
222         /* ACK all interrupts */
223         SETREG(bas, REG(USR1), 0xffff);
224         SETREG(bas, REG(USR2), 0xffff);
225         return (0);
226 }
227
228 static int
229 imx_uart_bus_detach(struct uart_softc *sc)
230 {
231
232         SETREG(&sc->sc_bas, REG(UCR4), 0);
233
234         return (0);
235 }
236
237 static int
238 imx_uart_bus_flush(struct uart_softc *sc, int what)
239 {
240
241         /* TODO */
242         return (0);
243 }
244
245 static int
246 imx_uart_bus_getsig(struct uart_softc *sc)
247 {
248         uint32_t new, old, sig;
249         uint8_t bes;
250
251         do {
252                 old = sc->sc_hwsig;
253                 sig = old;
254                 uart_lock(sc->sc_hwmtx);
255                 bes = GETREG(&sc->sc_bas, REG(USR2));
256                 uart_unlock(sc->sc_hwmtx);
257                 /* XXX: chip can show delta */
258                 SIGCHG(bes & FLD(USR2, DCDIN), sig, SER_DCD, SER_DDCD);
259                 new = sig & ~SER_MASK_DELTA;
260         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
261
262         return (sig);
263 }
264
265 static int
266 imx_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
267 {
268         struct uart_bas *bas;
269         int error;
270
271         bas = &sc->sc_bas;
272         error = 0;
273         uart_lock(sc->sc_hwmtx);
274         switch (request) {
275         case UART_IOCTL_BREAK:
276                 /* TODO */
277                 break;
278         case UART_IOCTL_BAUD:
279                 /* TODO */
280                 *(int*)data = 115200;
281                 break;
282         default:
283                 error = EINVAL;
284                 break;
285         }
286         uart_unlock(sc->sc_hwmtx);
287
288         return (error);
289 }
290
291 static int
292 imx_uart_bus_ipend(struct uart_softc *sc)
293 {
294         struct uart_bas *bas;
295         int ipend;
296         uint32_t usr1, usr2;
297         uint32_t ucr1, ucr4;
298
299         bas = &sc->sc_bas;
300         ipend = 0;
301
302         uart_lock(sc->sc_hwmtx);
303
304         /* Read pending interrupts */
305         usr1 = GETREG(bas, REG(USR1));
306         usr2 = GETREG(bas, REG(USR2));
307         /* ACK interrupts */
308         SETREG(bas, REG(USR1), usr1);
309         SETREG(bas, REG(USR2), usr2);
310
311         ucr1 = GETREG(bas, REG(UCR1));
312         ucr4 = GETREG(bas, REG(UCR4));
313
314         if ((usr2 & FLD(USR2, TXFE)) && (ucr1 & FLD(UCR1, TXMPTYEN))) {
315                 DIS(bas, UCR1, TXMPTYEN);
316                 /* Continue TXing */
317                 ipend |= SER_INT_TXIDLE;
318         }
319         if ((usr2 & FLD(USR2, RDR)) && (ucr4 & FLD(UCR4, DREN))) {
320                 DIS(bas, UCR4, DREN);
321                 /* Wow, new char on input */
322                 ipend |= SER_INT_RXREADY;
323         }
324         if ((usr2 & FLD(USR2, BRCD)) && (ucr4 & FLD(UCR4, BKEN)))
325                 ipend |= SER_INT_BREAK;
326
327         uart_unlock(sc->sc_hwmtx);
328
329         return (ipend);
330 }
331
332 static int
333 imx_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
334     int stopbits, int parity)
335 {
336
337         uart_lock(sc->sc_hwmtx);
338         imx_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity);
339         uart_unlock(sc->sc_hwmtx);
340         return (0);
341 }
342
343 static int
344 imx_uart_bus_probe(struct uart_softc *sc)
345 {
346         int error;
347
348         error = imx_uart_probe(&sc->sc_bas);
349         if (error)
350                 return (error);
351
352         sc->sc_rxfifosz = 1;
353         sc->sc_txfifosz = 1;
354
355         device_set_desc(sc->sc_dev, "Freescale i.MX UART");
356         return (0);
357 }
358
359 static int
360 imx_uart_bus_receive(struct uart_softc *sc)
361 {
362         struct uart_bas *bas;
363         int xc, out;
364
365         bas = &sc->sc_bas;
366         uart_lock(sc->sc_hwmtx);
367
368         /* Read while we have anything in FIFO */
369         while (IS(bas, USR2, RDR)) {
370                 if (uart_rx_full(sc)) {
371                         /* No space left in input buffer */
372                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
373                         break;
374                 }
375                 out = 0;
376                 xc = GETREG(bas, REG(URXD));
377
378                 /* We have valid char */
379                 if (xc & FLD(URXD, CHARRDY))
380                         out = xc & 0x000000ff;
381
382                 if (xc & FLD(URXD, FRMERR))
383                         out |= UART_STAT_FRAMERR;
384                 if (xc & FLD(URXD, PRERR))
385                         out |= UART_STAT_PARERR;
386                 if (xc & FLD(URXD, OVRRUN))
387                         out |= UART_STAT_OVERRUN;
388                 if (xc & FLD(URXD, BRK))
389                         out |= UART_STAT_BREAK;
390
391                 uart_rx_put(sc, out);
392         }
393         /* Reenable Data Ready interrupt */
394         ENA(bas, UCR4, DREN);
395
396         uart_unlock(sc->sc_hwmtx);
397         return (0);
398 }
399
400 static int
401 imx_uart_bus_setsig(struct uart_softc *sc, int sig)
402 {
403
404         return (0);
405 }
406
407 static int
408 imx_uart_bus_transmit(struct uart_softc *sc)
409 {
410         struct uart_bas *bas = &sc->sc_bas;
411         int i;
412
413         bas = &sc->sc_bas;
414         uart_lock(sc->sc_hwmtx);
415
416         /* Fill TX FIFO */
417         for (i = 0; i < sc->sc_txdatasz; i++) {
418                 SETREG(bas, REG(UTXD), sc->sc_txbuf[i] & 0xff);
419         }
420
421         sc->sc_txbusy = 1;
422         /* Call me when ready */
423         ENA(bas, UCR1, TXMPTYEN);
424
425         uart_unlock(sc->sc_hwmtx);
426
427         return (0);
428 }
429
430 static void
431 imx_uart_bus_grab(struct uart_softc *sc)
432 {
433         struct uart_bas *bas = &sc->sc_bas;
434
435         bas = &sc->sc_bas;
436         uart_lock(sc->sc_hwmtx);
437         DIS(bas, UCR4, DREN);
438         uart_unlock(sc->sc_hwmtx);
439 }
440
441 static void
442 imx_uart_bus_ungrab(struct uart_softc *sc)
443 {
444         struct uart_bas *bas = &sc->sc_bas;
445
446         bas = &sc->sc_bas;
447         uart_lock(sc->sc_hwmtx);
448         ENA(bas, UCR4, DREN);
449         uart_unlock(sc->sc_hwmtx);
450 }