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