xref: /plan9/sys/src/9/kw/uartkw.c (revision 7365b686ae7154552580a79fd89a0ba5dc9297c4)
1154abd99SDavid du Colombier /*
2154abd99SDavid du Colombier  * marvell kirkwood uart (supposed to be a 16550)
3154abd99SDavid du Colombier  */
4154abd99SDavid du Colombier #include "u.h"
5154abd99SDavid du Colombier #include "../port/lib.h"
6154abd99SDavid du Colombier #include "mem.h"
7154abd99SDavid du Colombier #include "dat.h"
8154abd99SDavid du Colombier #include "fns.h"
9154abd99SDavid du Colombier #include "io.h"
10154abd99SDavid du Colombier #include "../port/error.h"
11154abd99SDavid du Colombier // #include "../port/uart.h"
12154abd99SDavid du Colombier 
13154abd99SDavid du Colombier enum {
14154abd99SDavid du Colombier 	UartFREQ =	0, // xxx
15154abd99SDavid du Colombier 
16154abd99SDavid du Colombier 	IERrx		= 1<<0,
17154abd99SDavid du Colombier 	IERtx		= 1<<1,
18154abd99SDavid du Colombier 
19154abd99SDavid du Colombier 	IRRintrmask	= (1<<4)-1,
20154abd99SDavid du Colombier 	IRRnointr	= 1,
21154abd99SDavid du Colombier 	IRRthrempty	= 2,
22154abd99SDavid du Colombier 	IRRrxdata	= 4,
23154abd99SDavid du Colombier 	IRRrxstatus	= 6,
24154abd99SDavid du Colombier 	IRRtimeout	= 12,
25154abd99SDavid du Colombier 
26154abd99SDavid du Colombier 	IRRfifomask	= 3<<6,
27154abd99SDavid du Colombier 	IRRfifoenable	= 3<<6,
28154abd99SDavid du Colombier 
29154abd99SDavid du Colombier 	FCRenable	= 1<<0,
30154abd99SDavid du Colombier 	FCRrxreset	= 1<<1,
31154abd99SDavid du Colombier 	FCRtxreset	= 1<<2,
32154abd99SDavid du Colombier 	/* reserved */
33154abd99SDavid du Colombier 	FCRrxtriggermask	= 3<<6,
34154abd99SDavid du Colombier 	FCRrxtrigger1	= 0<<6,
35154abd99SDavid du Colombier 	FCRrxtrigger4	= 1<<6,
36154abd99SDavid du Colombier 	FCRrxtrigger8	= 2<<6,
37154abd99SDavid du Colombier 	FCRrxtrigger14	= 3<<6,
38154abd99SDavid du Colombier 
39154abd99SDavid du Colombier 	LCRbpcmask	= 3<<0,
40154abd99SDavid du Colombier 	LCRbpc5		= 0<<0,
41154abd99SDavid du Colombier 	LCRbpc6		= 1<<0,
42154abd99SDavid du Colombier 	LCRbpc7		= 2<<0,
43154abd99SDavid du Colombier 	LCRbpc8		= 3<<0,
44154abd99SDavid du Colombier 	LCRstop2b	= 1<<2,
45154abd99SDavid du Colombier 	LCRparity	= 1<<3,
46154abd99SDavid du Colombier 	LCRparityeven	= 1<<4,
47154abd99SDavid du Colombier 	LCRbreak	= 1<<6,
48154abd99SDavid du Colombier 	LCRdivlatch	= 1<<7,
49154abd99SDavid du Colombier 
50154abd99SDavid du Colombier 	LSRrx		= 1<<0,
51154abd99SDavid du Colombier 	LSRrunerr	= 1<<1,
52154abd99SDavid du Colombier 	LSRparerr	= 1<<2,
53154abd99SDavid du Colombier 	LSRframeerr	= 1<<3,
54154abd99SDavid du Colombier 	LSRbi		= 1<<4,
55154abd99SDavid du Colombier 	LSRthre		= 1<<5,
56154abd99SDavid du Colombier 	LSRtxempty	= 1<<6,
57154abd99SDavid du Colombier 	LSRfifoerr	= 1<<7,
58154abd99SDavid du Colombier };
59154abd99SDavid du Colombier 
60154abd99SDavid du Colombier extern PhysUart kwphysuart;
61154abd99SDavid du Colombier 
62154abd99SDavid du Colombier typedef struct UartReg UartReg;
63154abd99SDavid du Colombier struct UartReg
64154abd99SDavid du Colombier {
65154abd99SDavid du Colombier 	union {
66154abd99SDavid du Colombier 		ulong	thr;
67154abd99SDavid du Colombier 		ulong	dll;
68154abd99SDavid du Colombier 		ulong	rbr;
69154abd99SDavid du Colombier 	};
70154abd99SDavid du Colombier 	union {
71154abd99SDavid du Colombier 		ulong	ier;
72154abd99SDavid du Colombier 		ulong	dlh;
73154abd99SDavid du Colombier 	};
74154abd99SDavid du Colombier 	union {
75154abd99SDavid du Colombier 		ulong	iir;
76154abd99SDavid du Colombier 		ulong	fcr;
77154abd99SDavid du Colombier 	};
78154abd99SDavid du Colombier 	ulong	lcr;
79154abd99SDavid du Colombier 	ulong	mcr;
80154abd99SDavid du Colombier 	ulong	lsr;
81154abd99SDavid du Colombier 	ulong	scr;
82154abd99SDavid du Colombier };
83154abd99SDavid du Colombier 
84154abd99SDavid du Colombier typedef struct Ctlr Ctlr;
85154abd99SDavid du Colombier struct Ctlr {
86154abd99SDavid du Colombier 	UartReg*regs;
87154abd99SDavid du Colombier 	int	irq;
88154abd99SDavid du Colombier 	Lock;
89154abd99SDavid du Colombier };
90154abd99SDavid du Colombier 
91154abd99SDavid du Colombier static Ctlr kirkwoodctlr[] = {
92154abd99SDavid du Colombier {
93*7365b686SDavid du Colombier 	.regs   = nil,			/* filled in below */
94154abd99SDavid du Colombier 	.irq    = IRQ1uart0, },
95154abd99SDavid du Colombier };
96154abd99SDavid du Colombier 
97154abd99SDavid du Colombier static Uart kirkwooduart[] = {
98154abd99SDavid du Colombier {
99154abd99SDavid du Colombier 	.regs	= &kirkwoodctlr[0],
100154abd99SDavid du Colombier 	.name	= "eia0",
101154abd99SDavid du Colombier 	.freq	= UartFREQ,
102154abd99SDavid du Colombier 	.phys	= &kwphysuart,
103154abd99SDavid du Colombier 	.special= 0,
104154abd99SDavid du Colombier 	.console= 1,
105154abd99SDavid du Colombier 	.next	= nil, },
106154abd99SDavid du Colombier };
107154abd99SDavid du Colombier 
108154abd99SDavid du Colombier static void
kw_read(Uart * uart)109154abd99SDavid du Colombier kw_read(Uart *uart)
110154abd99SDavid du Colombier {
111154abd99SDavid du Colombier 	Ctlr *ctlr = uart->regs;
112154abd99SDavid du Colombier 	UartReg *regs = ctlr->regs;
113154abd99SDavid du Colombier 	ulong lsr;
114154abd99SDavid du Colombier 	char c;
115154abd99SDavid du Colombier 
116154abd99SDavid du Colombier 	while ((lsr = regs->lsr) & LSRrx) {
117154abd99SDavid du Colombier 		if(lsr&LSRrunerr)
118154abd99SDavid du Colombier 			uart->oerr++;
119154abd99SDavid du Colombier 		if(lsr&LSRparerr)
120154abd99SDavid du Colombier 			uart->perr++;
121154abd99SDavid du Colombier 		if(lsr&LSRframeerr)
122154abd99SDavid du Colombier 			uart->ferr++;
123154abd99SDavid du Colombier 		c = regs->rbr;
124154abd99SDavid du Colombier 		if((lsr & (LSRbi|LSRframeerr|LSRparerr)) == 0)
125154abd99SDavid du Colombier 			uartrecv(uart, c);
126154abd99SDavid du Colombier 	}
127154abd99SDavid du Colombier }
128154abd99SDavid du Colombier 
129154abd99SDavid du Colombier static void
kw_intr(Ureg *,void * arg)130154abd99SDavid du Colombier kw_intr(Ureg*, void *arg)
131154abd99SDavid du Colombier {
132154abd99SDavid du Colombier 	Uart *uart = arg;
133154abd99SDavid du Colombier 	Ctlr *ctlr = uart->regs;
134154abd99SDavid du Colombier 	UartReg *regs = ctlr->regs;
135154abd99SDavid du Colombier 	ulong v;
136154abd99SDavid du Colombier 
137*7365b686SDavid du Colombier 	if(regs == 0) {
138*7365b686SDavid du Colombier 		kirkwoodctlr[0].regs = (UartReg *)soc.uart[0];
139*7365b686SDavid du Colombier 		regs = (UartReg *)soc.uart[0];		/* caution */
140*7365b686SDavid du Colombier 		coherence();
141*7365b686SDavid du Colombier 	}
142154abd99SDavid du Colombier 	v = regs->iir;
143154abd99SDavid du Colombier 	if(v & IRRthrempty)
144154abd99SDavid du Colombier 		uartkick(uart);
145154abd99SDavid du Colombier 	if(v & IRRrxdata)
146154abd99SDavid du Colombier 		kw_read(uart);
147154abd99SDavid du Colombier 
148154abd99SDavid du Colombier 	intrclear(Irqhi, ctlr->irq);
149154abd99SDavid du Colombier }
150154abd99SDavid du Colombier 
151154abd99SDavid du Colombier static Uart*
kw_pnp(void)152154abd99SDavid du Colombier kw_pnp(void)
153154abd99SDavid du Colombier {
154*7365b686SDavid du Colombier 	kirkwoodctlr[0].regs = (UartReg *)soc.uart[0];
155*7365b686SDavid du Colombier 	coherence();
156154abd99SDavid du Colombier 	return kirkwooduart;
157154abd99SDavid du Colombier }
158154abd99SDavid du Colombier 
159154abd99SDavid du Colombier static void
kw_enable(Uart * uart,int ie)160154abd99SDavid du Colombier kw_enable(Uart* uart, int ie)
161154abd99SDavid du Colombier {
162154abd99SDavid du Colombier 	Ctlr *ctlr = uart->regs;
163154abd99SDavid du Colombier 	UartReg *regs = ctlr->regs;
164154abd99SDavid du Colombier 
165*7365b686SDavid du Colombier 	if(regs == 0) {
166*7365b686SDavid du Colombier 		kirkwoodctlr[0].regs = (UartReg *)soc.uart[0];
167*7365b686SDavid du Colombier 		regs = (UartReg *)soc.uart[0];		/* caution */
168*7365b686SDavid du Colombier 		coherence();
169*7365b686SDavid du Colombier 	}
170154abd99SDavid du Colombier 	USED(ie);
171154abd99SDavid du Colombier 	regs->fcr = FCRenable|FCRrxtrigger4;
172154abd99SDavid du Colombier 	regs->ier = IERrx|IERtx;
173154abd99SDavid du Colombier 	intrenable(Irqhi, ctlr->irq, kw_intr, uart, uart->name);
174154abd99SDavid du Colombier 
175154abd99SDavid du Colombier 	(*uart->phys->dtr)(uart, 1);
176154abd99SDavid du Colombier 	(*uart->phys->rts)(uart, 1);
177154abd99SDavid du Colombier }
178154abd99SDavid du Colombier 
179154abd99SDavid du Colombier static void
kw_disable(Uart * uart)180154abd99SDavid du Colombier kw_disable(Uart* uart)
181154abd99SDavid du Colombier {
182154abd99SDavid du Colombier 	Ctlr *ctlr = uart->regs;
183154abd99SDavid du Colombier 
184154abd99SDavid du Colombier 	(*uart->phys->dtr)(uart, 0);
185154abd99SDavid du Colombier 	(*uart->phys->rts)(uart, 0);
186154abd99SDavid du Colombier 	(*uart->phys->fifo)(uart, 0);
187154abd99SDavid du Colombier 
188154abd99SDavid du Colombier 	intrdisable(Irqhi, ctlr->irq, kw_intr, uart, uart->name);
189154abd99SDavid du Colombier }
190154abd99SDavid du Colombier 
191154abd99SDavid du Colombier static void
kw_kick(Uart * uart)192154abd99SDavid du Colombier kw_kick(Uart* uart)
193154abd99SDavid du Colombier {
194154abd99SDavid du Colombier 	Ctlr *ctlr = uart->regs;
195154abd99SDavid du Colombier 	UartReg *regs = ctlr->regs;
196154abd99SDavid du Colombier 	int i;
197154abd99SDavid du Colombier 
198154abd99SDavid du Colombier 	if(uart->cts == 0 || uart->blocked)
199154abd99SDavid du Colombier 		return;
200154abd99SDavid du Colombier 
201154abd99SDavid du Colombier 	for(i = 0; i < 16; i++) {
202154abd99SDavid du Colombier 		if((regs->lsr & LSRthre) == 0 ||
203154abd99SDavid du Colombier 		    uart->op >= uart->oe && uartstageoutput(uart) == 0)
204154abd99SDavid du Colombier 			break;
205154abd99SDavid du Colombier 		regs->thr = *uart->op++;
206154abd99SDavid du Colombier 	}
207154abd99SDavid du Colombier }
208154abd99SDavid du Colombier 
209154abd99SDavid du Colombier static void
kw_break(Uart * uart,int ms)210154abd99SDavid du Colombier kw_break(Uart* uart, int ms)
211154abd99SDavid du Colombier {
212154abd99SDavid du Colombier 	USED(uart, ms);
213154abd99SDavid du Colombier }
214154abd99SDavid du Colombier 
215154abd99SDavid du Colombier static int
kw_baud(Uart * uart,int baud)216154abd99SDavid du Colombier kw_baud(Uart* uart, int baud)
217154abd99SDavid du Colombier {
218154abd99SDavid du Colombier 	USED(uart, baud);
219154abd99SDavid du Colombier 	return 0;
220154abd99SDavid du Colombier }
221154abd99SDavid du Colombier 
222154abd99SDavid du Colombier static int
kw_bits(Uart * uart,int bits)223154abd99SDavid du Colombier kw_bits(Uart* uart, int bits)
224154abd99SDavid du Colombier {
225154abd99SDavid du Colombier 	USED(uart, bits);
226154abd99SDavid du Colombier 	return 0;
227154abd99SDavid du Colombier }
228154abd99SDavid du Colombier 
229154abd99SDavid du Colombier static int
kw_stop(Uart * uart,int stop)230154abd99SDavid du Colombier kw_stop(Uart* uart, int stop)
231154abd99SDavid du Colombier {
232154abd99SDavid du Colombier 	USED(uart, stop);
233154abd99SDavid du Colombier 	return 0;
234154abd99SDavid du Colombier }
235154abd99SDavid du Colombier 
236154abd99SDavid du Colombier static int
kw_parity(Uart * uart,int parity)237154abd99SDavid du Colombier kw_parity(Uart* uart, int parity)
238154abd99SDavid du Colombier {
239154abd99SDavid du Colombier 	USED(uart, parity);
240154abd99SDavid du Colombier 	return 0;
241154abd99SDavid du Colombier }
242154abd99SDavid du Colombier 
243154abd99SDavid du Colombier static void
kw_modemctl(Uart * uart,int on)244154abd99SDavid du Colombier kw_modemctl(Uart* uart, int on)
245154abd99SDavid du Colombier {
246154abd99SDavid du Colombier 	USED(uart, on);
247154abd99SDavid du Colombier }
248154abd99SDavid du Colombier 
249154abd99SDavid du Colombier static void
kw_rts(Uart * uart,int on)250154abd99SDavid du Colombier kw_rts(Uart* uart, int on)
251154abd99SDavid du Colombier {
252154abd99SDavid du Colombier 	USED(uart, on);
253154abd99SDavid du Colombier }
254154abd99SDavid du Colombier 
255154abd99SDavid du Colombier static void
kw_dtr(Uart * uart,int on)256154abd99SDavid du Colombier kw_dtr(Uart* uart, int on)
257154abd99SDavid du Colombier {
258154abd99SDavid du Colombier 	USED(uart, on);
259154abd99SDavid du Colombier }
260154abd99SDavid du Colombier 
261154abd99SDavid du Colombier static long
kw_status(Uart * uart,void * buf,long n,long offset)262154abd99SDavid du Colombier kw_status(Uart* uart, void* buf, long n, long offset)
263154abd99SDavid du Colombier {
264154abd99SDavid du Colombier 	USED(uart, buf, n, offset);
265154abd99SDavid du Colombier 	return 0;
266154abd99SDavid du Colombier }
267154abd99SDavid du Colombier 
268154abd99SDavid du Colombier static void
kw_fifo(Uart * uart,int level)269154abd99SDavid du Colombier kw_fifo(Uart* uart, int level)
270154abd99SDavid du Colombier {
271154abd99SDavid du Colombier 	USED(uart, level);
272154abd99SDavid du Colombier }
273154abd99SDavid du Colombier 
274154abd99SDavid du Colombier static int
kw_getc(Uart * uart)275154abd99SDavid du Colombier kw_getc(Uart *uart)
276154abd99SDavid du Colombier {
277154abd99SDavid du Colombier 	Ctlr *ctlr = uart->regs;
278154abd99SDavid du Colombier 	UartReg *regs = ctlr->regs;
279154abd99SDavid du Colombier 
280154abd99SDavid du Colombier 	while((regs->lsr&LSRrx) == 0)
281154abd99SDavid du Colombier 		;
282154abd99SDavid du Colombier 	return regs->rbr;
283154abd99SDavid du Colombier }
284154abd99SDavid du Colombier 
285154abd99SDavid du Colombier static void
kw_putc(Uart * uart,int c)286154abd99SDavid du Colombier kw_putc(Uart *uart, int c)
287154abd99SDavid du Colombier {
288154abd99SDavid du Colombier 	Ctlr *ctlr = uart->regs;
289154abd99SDavid du Colombier 	UartReg *regs = ctlr->regs;
290154abd99SDavid du Colombier 
291*7365b686SDavid du Colombier 	/* can be called from iprint, among many other places */
292*7365b686SDavid du Colombier 	if(regs == 0) {
293*7365b686SDavid du Colombier 		kirkwoodctlr[0].regs = (UartReg *)soc.uart[0];
294*7365b686SDavid du Colombier 		regs = (UartReg *)soc.uart[0];		/* caution */
295*7365b686SDavid du Colombier 		coherence();
296*7365b686SDavid du Colombier 	}
297154abd99SDavid du Colombier 	while((regs->lsr&LSRthre) == 0)
298154abd99SDavid du Colombier 		;
299154abd99SDavid du Colombier 	regs->thr = c;
300*7365b686SDavid du Colombier 	coherence();
301154abd99SDavid du Colombier }
302154abd99SDavid du Colombier 
303154abd99SDavid du Colombier PhysUart kwphysuart = {
304154abd99SDavid du Colombier 	.name		= "kirkwood",
305154abd99SDavid du Colombier 	.pnp		= kw_pnp,
306154abd99SDavid du Colombier 	.enable		= kw_enable,
307154abd99SDavid du Colombier 	.disable	= kw_disable,
308154abd99SDavid du Colombier 	.kick		= kw_kick,
309154abd99SDavid du Colombier 	.dobreak	= kw_break,
310154abd99SDavid du Colombier 	.baud		= kw_baud,
311154abd99SDavid du Colombier 	.bits		= kw_bits,
312154abd99SDavid du Colombier 	.stop		= kw_stop,
313154abd99SDavid du Colombier 	.parity		= kw_parity,
314154abd99SDavid du Colombier 	.modemctl	= kw_modemctl,
315154abd99SDavid du Colombier 	.rts		= kw_rts,
316154abd99SDavid du Colombier 	.dtr		= kw_dtr,
317154abd99SDavid du Colombier 	.status		= kw_status,
318154abd99SDavid du Colombier 	.fifo		= kw_fifo,
319154abd99SDavid du Colombier 	.getc		= kw_getc,
320154abd99SDavid du Colombier 	.putc		= kw_putc,
321154abd99SDavid du Colombier };
322154abd99SDavid du Colombier 
323154abd99SDavid du Colombier void
uartkirkwoodconsole(void)324154abd99SDavid du Colombier uartkirkwoodconsole(void)
325154abd99SDavid du Colombier {
326154abd99SDavid du Colombier 	Uart *uart;
327154abd99SDavid du Colombier 
328154abd99SDavid du Colombier 	uart = &kirkwooduart[0];
329154abd99SDavid du Colombier 	(*uart->phys->enable)(uart, 0);
330154abd99SDavid du Colombier 	uartctl(uart, "b115200 l8 pn s1 i1");
331154abd99SDavid du Colombier 	uart->console = 1;
332154abd99SDavid du Colombier 	consuart = uart;
333154abd99SDavid du Colombier //serialputs("uart0 kirkwood\n", strlen("uart0 kirkwood\n"));
334154abd99SDavid du Colombier }
335154abd99SDavid du Colombier 
336154abd99SDavid du Colombier void
serialputc(int c)337154abd99SDavid du Colombier serialputc(int c)
338154abd99SDavid du Colombier {
339154abd99SDavid du Colombier 	int cnt, s;
340*7365b686SDavid du Colombier 	UartReg *regs = (UartReg *)soc.uart[0];
341154abd99SDavid du Colombier 
342154abd99SDavid du Colombier 	s = splhi();
343154abd99SDavid du Colombier 	cnt = m->cpuhz;
344154abd99SDavid du Colombier 	if (cnt <= 0)			/* cpuhz not set yet? */
345154abd99SDavid du Colombier 		cnt = 1000000;
346*7365b686SDavid du Colombier 	while((regs->lsr & LSRthre) == 0 && --cnt > 0)
347154abd99SDavid du Colombier 		;
348*7365b686SDavid du Colombier 	regs->thr = c;
349*7365b686SDavid du Colombier 	coherence();
350154abd99SDavid du Colombier 	delay(1);
351154abd99SDavid du Colombier 	splx(s);
352154abd99SDavid du Colombier }
353154abd99SDavid du Colombier 
354154abd99SDavid du Colombier void
serialputs(char * p,int len)355154abd99SDavid du Colombier serialputs(char *p, int len)
356154abd99SDavid du Colombier {
357154abd99SDavid du Colombier 	while(--len >= 0) {
358154abd99SDavid du Colombier 		if(*p == '\n')
359154abd99SDavid du Colombier 			serialputc('\r');
360154abd99SDavid du Colombier 		serialputc(*p++);
361154abd99SDavid du Colombier 	}
362154abd99SDavid du Colombier }
363