xref: /plan9/sys/src/9/kw/uartkw.c (revision ff579efb6d9c16f03df7f0fbdbd7810dcb61813e)
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 #define UART0REG	((UartReg*)AddrUart0)
63 
64 typedef struct UartReg UartReg;
65 struct UartReg
66 {
67 	union {
68 		ulong	thr;
69 		ulong	dll;
70 		ulong	rbr;
71 	};
72 	union {
73 		ulong	ier;
74 		ulong	dlh;
75 	};
76 	union {
77 		ulong	iir;
78 		ulong	fcr;
79 	};
80 	ulong	lcr;
81 	ulong	mcr;
82 	ulong	lsr;
83 	ulong	scr;
84 };
85 
86 typedef struct Ctlr Ctlr;
87 struct Ctlr {
88 	UartReg*regs;
89 	int	irq;
90 	Lock;
91 };
92 
93 static Ctlr kirkwoodctlr[] = {
94 {
95 	.regs   = UART0REG,
96 	.irq    = IRQ1uart0, },
97 };
98 
99 static Uart kirkwooduart[] = {
100 {
101 	.regs	= &kirkwoodctlr[0],
102 	.name	= "eia0",
103 	.freq	= UartFREQ,
104 	.phys	= &kwphysuart,
105 	.special= 0,
106 	.console= 1,
107 	.next	= nil, },
108 };
109 
110 static void
111 kw_read(Uart *uart)
112 {
113 	Ctlr *ctlr = uart->regs;
114 	UartReg *regs = ctlr->regs;
115 	ulong lsr;
116 	char c;
117 
118 	while ((lsr = regs->lsr) & LSRrx) {
119 		if(lsr&LSRrunerr)
120 			uart->oerr++;
121 		if(lsr&LSRparerr)
122 			uart->perr++;
123 		if(lsr&LSRframeerr)
124 			uart->ferr++;
125 		c = regs->rbr;
126 		if((lsr & (LSRbi|LSRframeerr|LSRparerr)) == 0)
127 			uartrecv(uart, c);
128 	}
129 }
130 
131 static void
132 kw_intr(Ureg*, void *arg)
133 {
134 	Uart *uart = arg;
135 	Ctlr *ctlr = uart->regs;
136 	UartReg *regs = ctlr->regs;
137 	ulong v;
138 
139 	v = regs->iir;
140 	if(v & IRRthrempty)
141 		uartkick(uart);
142 	if(v & IRRrxdata)
143 		kw_read(uart);
144 
145 	intrclear(Irqhi, ctlr->irq);
146 }
147 
148 static Uart*
149 kw_pnp(void)
150 {
151 	return kirkwooduart;
152 }
153 
154 static void
155 kw_enable(Uart* uart, int ie)
156 {
157 	Ctlr *ctlr = uart->regs;
158 	UartReg *regs = ctlr->regs;
159 
160 	USED(ie);
161 	regs->fcr = FCRenable|FCRrxtrigger4;
162 	regs->ier = IERrx|IERtx;
163 	intrenable(Irqhi, ctlr->irq, kw_intr, uart, uart->name);
164 
165 	(*uart->phys->dtr)(uart, 1);
166 	(*uart->phys->rts)(uart, 1);
167 }
168 
169 static void
170 kw_disable(Uart* uart)
171 {
172 	Ctlr *ctlr = uart->regs;
173 
174 	(*uart->phys->dtr)(uart, 0);
175 	(*uart->phys->rts)(uart, 0);
176 	(*uart->phys->fifo)(uart, 0);
177 
178 	intrdisable(Irqhi, ctlr->irq, kw_intr, uart, uart->name);
179 }
180 
181 static void
182 kw_kick(Uart* uart)
183 {
184 	Ctlr *ctlr = uart->regs;
185 	UartReg *regs = ctlr->regs;
186 	int i;
187 
188 	if(uart->cts == 0 || uart->blocked)
189 		return;
190 
191 	for(i = 0; i < 16; i++) {
192 		if((regs->lsr & LSRthre) == 0 ||
193 		    uart->op >= uart->oe && uartstageoutput(uart) == 0)
194 			break;
195 		regs->thr = *uart->op++;
196 	}
197 }
198 
199 static void
200 kw_break(Uart* uart, int ms)
201 {
202 	USED(uart, ms);
203 }
204 
205 static int
206 kw_baud(Uart* uart, int baud)
207 {
208 	USED(uart, baud);
209 	return 0;
210 }
211 
212 static int
213 kw_bits(Uart* uart, int bits)
214 {
215 	USED(uart, bits);
216 	return 0;
217 }
218 
219 static int
220 kw_stop(Uart* uart, int stop)
221 {
222 	USED(uart, stop);
223 	return 0;
224 }
225 
226 static int
227 kw_parity(Uart* uart, int parity)
228 {
229 	USED(uart, parity);
230 	return 0;
231 }
232 
233 static void
234 kw_modemctl(Uart* uart, int on)
235 {
236 	USED(uart, on);
237 }
238 
239 static void
240 kw_rts(Uart* uart, int on)
241 {
242 	USED(uart, on);
243 }
244 
245 static void
246 kw_dtr(Uart* uart, int on)
247 {
248 	USED(uart, on);
249 }
250 
251 static long
252 kw_status(Uart* uart, void* buf, long n, long offset)
253 {
254 	USED(uart, buf, n, offset);
255 	return 0;
256 }
257 
258 static void
259 kw_fifo(Uart* uart, int level)
260 {
261 	USED(uart, level);
262 }
263 
264 static int
265 kw_getc(Uart *uart)
266 {
267 	Ctlr *ctlr = uart->regs;
268 	UartReg *regs = ctlr->regs;
269 
270 	while((regs->lsr&LSRrx) == 0)
271 		;
272 	return regs->rbr;
273 }
274 
275 static void
276 kw_putc(Uart *uart, int c)
277 {
278 	Ctlr *ctlr = uart->regs;
279 	UartReg *regs = ctlr->regs;
280 
281 	while((regs->lsr&LSRthre) == 0)
282 		;
283 	regs->thr = c;
284 }
285 
286 PhysUart kwphysuart = {
287 	.name		= "kirkwood",
288 	.pnp		= kw_pnp,
289 	.enable		= kw_enable,
290 	.disable	= kw_disable,
291 	.kick		= kw_kick,
292 	.dobreak	= kw_break,
293 	.baud		= kw_baud,
294 	.bits		= kw_bits,
295 	.stop		= kw_stop,
296 	.parity		= kw_parity,
297 	.modemctl	= kw_modemctl,
298 	.rts		= kw_rts,
299 	.dtr		= kw_dtr,
300 	.status		= kw_status,
301 	.fifo		= kw_fifo,
302 	.getc		= kw_getc,
303 	.putc		= kw_putc,
304 };
305 
306 void
307 uartkirkwoodconsole(void)
308 {
309 	Uart *uart;
310 
311 	uart = &kirkwooduart[0];
312 	(*uart->phys->enable)(uart, 0);
313 	uartctl(uart, "b115200 l8 pn s1 i1");
314 	uart->console = 1;
315 	consuart = uart;
316 //serialputs("uart0 kirkwood\n", strlen("uart0 kirkwood\n"));
317 }
318 
319 void
320 serialputc(int c)
321 {
322 	int cnt, s;
323 
324 	s = splhi();
325 	cnt = m->cpuhz;
326 	if (cnt <= 0)			/* cpuhz not set yet? */
327 		cnt = 1000000;
328 	while((UART0REG->lsr & LSRthre) == 0 && --cnt > 0)
329 		;
330 	UART0REG->thr = c;
331 	delay(1);
332 	splx(s);
333 }
334 
335 void
336 serialputs(char *p, int len)
337 {
338 	while(--len >= 0) {
339 		if(*p == '\n')
340 			serialputc('\r');
341 		serialputc(*p++);
342 	}
343 }
344