]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/kw/uartkw.c
merge
[plan9front.git] / sys / src / 9 / kw / uartkw.c
1 /*
2  * marvell kirkwood uart (supposed to be a 16550)
3  */
4 #include "u.h"
5 #include "../port/lib.h"
6 #include "mem.h"
7 #include "dat.h"
8 #include "fns.h"
9 #include "io.h"
10 #include "../port/error.h"
11 // #include "../port/uart.h"
12
13 enum {
14         UartFREQ =      0, // xxx
15
16         IERrx           = 1<<0,
17         IERtx           = 1<<1,
18
19         IRRintrmask     = (1<<4)-1,
20         IRRnointr       = 1,
21         IRRthrempty     = 2,
22         IRRrxdata       = 4,
23         IRRrxstatus     = 6,
24         IRRtimeout      = 12,
25
26         IRRfifomask     = 3<<6,
27         IRRfifoenable   = 3<<6,
28
29         FCRenable       = 1<<0,
30         FCRrxreset      = 1<<1,
31         FCRtxreset      = 1<<2,
32         /* reserved */
33         FCRrxtriggermask        = 3<<6,
34         FCRrxtrigger1   = 0<<6,
35         FCRrxtrigger4   = 1<<6,
36         FCRrxtrigger8   = 2<<6,
37         FCRrxtrigger14  = 3<<6,
38
39         LCRbpcmask      = 3<<0,
40         LCRbpc5         = 0<<0,
41         LCRbpc6         = 1<<0,
42         LCRbpc7         = 2<<0,
43         LCRbpc8         = 3<<0,
44         LCRstop2b       = 1<<2,
45         LCRparity       = 1<<3,
46         LCRparityeven   = 1<<4,
47         LCRbreak        = 1<<6,
48         LCRdivlatch     = 1<<7,
49
50         LSRrx           = 1<<0,
51         LSRrunerr       = 1<<1,
52         LSRparerr       = 1<<2,
53         LSRframeerr     = 1<<3,
54         LSRbi           = 1<<4,
55         LSRthre         = 1<<5,
56         LSRtxempty      = 1<<6,
57         LSRfifoerr      = 1<<7,
58 };
59
60 extern PhysUart kwphysuart;
61
62 typedef struct UartReg UartReg;
63 struct UartReg
64 {
65         union {
66                 ulong   thr;
67                 ulong   dll;
68                 ulong   rbr;
69         };
70         union {
71                 ulong   ier;
72                 ulong   dlh;
73         };
74         union {
75                 ulong   iir;
76                 ulong   fcr;
77         };
78         ulong   lcr;
79         ulong   mcr;
80         ulong   lsr;
81         ulong   scr;
82 };
83
84 typedef struct Ctlr Ctlr;
85 struct Ctlr {
86         UartReg*regs;
87         int     irq;
88         Lock;
89 };
90
91 static Ctlr kirkwoodctlr[] = {
92 {
93         .regs   = nil,                  /* filled in below */
94         .irq    = IRQ1uart0, },
95 };
96
97 static Uart kirkwooduart[] = {
98 {
99         .regs   = &kirkwoodctlr[0],
100         .name   = "eia0",
101         .freq   = UartFREQ,
102         .phys   = &kwphysuart,
103         .special= 0,
104         .console= 1,
105         .next   = nil, },
106 };
107
108 static void
109 kw_read(Uart *uart)
110 {
111         Ctlr *ctlr = uart->regs;
112         UartReg *regs = ctlr->regs;
113         ulong lsr;
114         char c;
115
116         while ((lsr = regs->lsr) & LSRrx) {
117                 if(lsr&LSRrunerr)
118                         uart->oerr++;
119                 if(lsr&LSRparerr)
120                         uart->perr++;
121                 if(lsr&LSRframeerr)
122                         uart->ferr++;
123                 c = regs->rbr;
124                 if((lsr & (LSRbi|LSRframeerr|LSRparerr)) == 0)
125                         uartrecv(uart, c);
126         }
127 }
128
129 static void
130 kw_intr(Ureg*, void *arg)
131 {
132         Uart *uart = arg;
133         Ctlr *ctlr = uart->regs;
134         UartReg *regs = ctlr->regs;
135         ulong v;
136
137         if(regs == 0) {
138                 kirkwoodctlr[0].regs = (UartReg *)soc.uart[0];
139                 regs = (UartReg *)soc.uart[0];          /* caution */
140                 coherence();
141         }
142         v = regs->iir;
143         if(v & IRRthrempty)
144                 uartkick(uart);
145         if(v & IRRrxdata)
146                 kw_read(uart);
147
148         intrclear(Irqhi, ctlr->irq);
149 }
150
151 static Uart*
152 kw_pnp(void)
153 {
154         kirkwoodctlr[0].regs = (UartReg *)soc.uart[0];
155         coherence();
156         return kirkwooduart;
157 }
158
159 static void
160 kw_enable(Uart* uart, int ie)
161 {
162         Ctlr *ctlr = uart->regs;
163         UartReg *regs = ctlr->regs;
164
165         if(regs == 0) {
166                 kirkwoodctlr[0].regs = (UartReg *)soc.uart[0];
167                 regs = (UartReg *)soc.uart[0];          /* caution */
168                 coherence();
169         }
170         USED(ie);
171         regs->fcr = FCRenable|FCRrxtrigger4;
172         regs->ier = IERrx|IERtx;
173         intrenable(Irqhi, ctlr->irq, kw_intr, uart, uart->name);
174
175         (*uart->phys->dtr)(uart, 1);
176         (*uart->phys->rts)(uart, 1);
177 }
178
179 static void
180 kw_disable(Uart* uart)
181 {
182         Ctlr *ctlr = uart->regs;
183
184         (*uart->phys->dtr)(uart, 0);
185         (*uart->phys->rts)(uart, 0);
186         (*uart->phys->fifo)(uart, 0);
187
188         intrdisable(Irqhi, ctlr->irq, kw_intr, uart, uart->name);
189 }
190
191 static void
192 kw_kick(Uart* uart)
193 {
194         Ctlr *ctlr = uart->regs;
195         UartReg *regs = ctlr->regs;
196         int i;
197
198         if(uart->cts == 0 || uart->blocked)
199                 return;
200
201         for(i = 0; i < 16; i++) {
202                 if((regs->lsr & LSRthre) == 0 ||
203                     uart->op >= uart->oe && uartstageoutput(uart) == 0)
204                         break;
205                 regs->thr = *uart->op++;
206         }
207 }
208
209 static void
210 kw_break(Uart* uart, int ms)
211 {
212         USED(uart, ms);
213 }
214
215 static int
216 kw_baud(Uart* uart, int baud)
217 {
218         USED(uart, baud);
219         return 0;
220 }
221
222 static int
223 kw_bits(Uart* uart, int bits)
224 {
225         USED(uart, bits);
226         return 0;
227 }
228
229 static int
230 kw_stop(Uart* uart, int stop)
231 {
232         USED(uart, stop);
233         return 0;
234 }
235
236 static int
237 kw_parity(Uart* uart, int parity)
238 {
239         USED(uart, parity);
240         return 0;
241 }
242
243 static void
244 kw_modemctl(Uart* uart, int on)
245 {
246         USED(uart, on);
247 }
248
249 static void
250 kw_rts(Uart* uart, int on)
251 {
252         USED(uart, on);
253 }
254
255 static void
256 kw_dtr(Uart* uart, int on)
257 {
258         USED(uart, on);
259 }
260
261 static long
262 kw_status(Uart* uart, void* buf, long n, long offset)
263 {
264         USED(uart, buf, n, offset);
265         return 0;
266 }
267
268 static void
269 kw_fifo(Uart* uart, int level)
270 {
271         USED(uart, level);
272 }
273
274 static int
275 kw_getc(Uart *uart)
276 {
277         Ctlr *ctlr = uart->regs;
278         UartReg *regs = ctlr->regs;
279
280         while((regs->lsr&LSRrx) == 0)
281                 ;
282         return regs->rbr;
283 }
284
285 static void
286 kw_putc(Uart *uart, int c)
287 {
288         Ctlr *ctlr = uart->regs;
289         UartReg *regs = ctlr->regs;
290
291         /* can be called from iprint, among many other places */
292         if(regs == 0) {
293                 kirkwoodctlr[0].regs = (UartReg *)soc.uart[0];
294                 regs = (UartReg *)soc.uart[0];          /* caution */
295                 coherence();
296         }
297         while((regs->lsr&LSRthre) == 0)
298                 ;
299         regs->thr = c;
300         coherence();
301 }
302
303 PhysUart kwphysuart = {
304         .name           = "kirkwood",
305         .pnp            = kw_pnp,
306         .enable         = kw_enable,
307         .disable        = kw_disable,
308         .kick           = kw_kick,
309         .dobreak        = kw_break,
310         .baud           = kw_baud,
311         .bits           = kw_bits,
312         .stop           = kw_stop,
313         .parity         = kw_parity,
314         .modemctl       = kw_modemctl,
315         .rts            = kw_rts,
316         .dtr            = kw_dtr,
317         .status         = kw_status,
318         .fifo           = kw_fifo,
319         .getc           = kw_getc,
320         .putc           = kw_putc,
321 };
322
323 void
324 uartkirkwoodconsole(void)
325 {
326         Uart *uart;
327
328         uart = &kirkwooduart[0];
329         (*uart->phys->enable)(uart, 0);
330         uartctl(uart, "b115200 l8 pn s1 i1");
331         uart->console = 1;
332         consuart = uart;
333 //serialputs("uart0 kirkwood\n", strlen("uart0 kirkwood\n"));
334 }
335
336 void
337 serialputc(int c)
338 {
339         int cnt, s;
340         UartReg *regs = (UartReg *)soc.uart[0];
341
342         s = splhi();
343         cnt = m->cpuhz;
344         if (cnt <= 0)                   /* cpuhz not set yet? */
345                 cnt = 1000000;
346         while((regs->lsr & LSRthre) == 0 && --cnt > 0)
347                 ;
348         regs->thr = c;
349         coherence();
350         delay(1);
351         splx(s);
352 }
353
354 void
355 serialputs(char *p, int len)
356 {
357         while(--len >= 0) {
358                 if(*p == '\n')
359                         serialputc('\r');
360                 serialputc(*p++);
361         }
362 }