xref: /plan9/sys/src/9/kw/uartkw.c (revision 7365b686ae7154552580a79fd89a0ba5dc9297c4)
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