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
kw_read(Uart * uart)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
kw_intr(Ureg *,void * arg)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*
kw_pnp(void)152 kw_pnp(void)
153 {
154 kirkwoodctlr[0].regs = (UartReg *)soc.uart[0];
155 coherence();
156 return kirkwooduart;
157 }
158
159 static void
kw_enable(Uart * uart,int ie)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
kw_disable(Uart * uart)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
kw_kick(Uart * uart)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
kw_break(Uart * uart,int ms)210 kw_break(Uart* uart, int ms)
211 {
212 USED(uart, ms);
213 }
214
215 static int
kw_baud(Uart * uart,int baud)216 kw_baud(Uart* uart, int baud)
217 {
218 USED(uart, baud);
219 return 0;
220 }
221
222 static int
kw_bits(Uart * uart,int bits)223 kw_bits(Uart* uart, int bits)
224 {
225 USED(uart, bits);
226 return 0;
227 }
228
229 static int
kw_stop(Uart * uart,int stop)230 kw_stop(Uart* uart, int stop)
231 {
232 USED(uart, stop);
233 return 0;
234 }
235
236 static int
kw_parity(Uart * uart,int parity)237 kw_parity(Uart* uart, int parity)
238 {
239 USED(uart, parity);
240 return 0;
241 }
242
243 static void
kw_modemctl(Uart * uart,int on)244 kw_modemctl(Uart* uart, int on)
245 {
246 USED(uart, on);
247 }
248
249 static void
kw_rts(Uart * uart,int on)250 kw_rts(Uart* uart, int on)
251 {
252 USED(uart, on);
253 }
254
255 static void
kw_dtr(Uart * uart,int on)256 kw_dtr(Uart* uart, int on)
257 {
258 USED(uart, on);
259 }
260
261 static long
kw_status(Uart * uart,void * buf,long n,long offset)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
kw_fifo(Uart * uart,int level)269 kw_fifo(Uart* uart, int level)
270 {
271 USED(uart, level);
272 }
273
274 static int
kw_getc(Uart * uart)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
kw_putc(Uart * uart,int c)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
uartkirkwoodconsole(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
serialputc(int c)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
serialputs(char * p,int len)355 serialputs(char *p, int len)
356 {
357 while(--len >= 0) {
358 if(*p == '\n')
359 serialputc('\r');
360 serialputc(*p++);
361 }
362 }
363