1*6bbfed0dSDavid du Colombier /*
2*6bbfed0dSDavid du Colombier * Oxford Semiconductor OXPCIe95x UART driver
3*6bbfed0dSDavid du Colombier */
4*6bbfed0dSDavid du Colombier #include "u.h"
5*6bbfed0dSDavid du Colombier #include "../port/lib.h"
6*6bbfed0dSDavid du Colombier #include "mem.h"
7*6bbfed0dSDavid du Colombier #include "dat.h"
8*6bbfed0dSDavid du Colombier #include "fns.h"
9*6bbfed0dSDavid du Colombier #include "io.h"
10*6bbfed0dSDavid du Colombier #include "../port/error.h"
11*6bbfed0dSDavid du Colombier
12*6bbfed0dSDavid du Colombier extern PhysUart oxphysuart;
13*6bbfed0dSDavid du Colombier
14*6bbfed0dSDavid du Colombier enum {
15*6bbfed0dSDavid du Colombier Ccr = 0x0000/4, /* Class Code and Revision ID */
16*6bbfed0dSDavid du Colombier Nuart = 0x0004/4, /* Decimal Number of UARTs */
17*6bbfed0dSDavid du Colombier Gis = 0x0008/4, /* Global UART IRQ Status */
18*6bbfed0dSDavid du Colombier Gie = 0x000C/4, /* Global UART IRQ Enable */
19*6bbfed0dSDavid du Colombier Gid = 0x0010/4, /* Global UART IRQ Disable */
20*6bbfed0dSDavid du Colombier Gwe = 0x0014/4, /* Global UART Wake Enable */
21*6bbfed0dSDavid du Colombier Gwd = 0x0018/4, /* Global UART Wake Disable */
22*6bbfed0dSDavid du Colombier };
23*6bbfed0dSDavid du Colombier
24*6bbfed0dSDavid du Colombier enum {
25*6bbfed0dSDavid du Colombier Thr = 0x00, /* Transmitter Holding */
26*6bbfed0dSDavid du Colombier Rhr = 0x00, /* Receiver Holding */
27*6bbfed0dSDavid du Colombier Ier = 0x01, /* Interrupt Enable */
28*6bbfed0dSDavid du Colombier Fcr = 0x02, /* FIFO Control */
29*6bbfed0dSDavid du Colombier Isr = 0x02, /* Interrupt Status */
30*6bbfed0dSDavid du Colombier Lcr = 0x03, /* Line Control */
31*6bbfed0dSDavid du Colombier Mcr = 0x04, /* Modem Control */
32*6bbfed0dSDavid du Colombier Lsr = 0x05, /* Line Status */
33*6bbfed0dSDavid du Colombier Msr = 0x06, /* Modem Status */
34*6bbfed0dSDavid du Colombier Spr = 0x07, /* Scratch Pad */
35*6bbfed0dSDavid du Colombier Dll = 0x00, /* Divisor Latch LSB */
36*6bbfed0dSDavid du Colombier Dlm = 0x01, /* Divisor Latch MSB */
37*6bbfed0dSDavid du Colombier Efr = 0x02, /* Enhanced Feature */
38*6bbfed0dSDavid du Colombier };
39*6bbfed0dSDavid du Colombier
40*6bbfed0dSDavid du Colombier typedef struct Port Port;
41*6bbfed0dSDavid du Colombier typedef struct Ctlr Ctlr;
42*6bbfed0dSDavid du Colombier
43*6bbfed0dSDavid du Colombier struct Port {
44*6bbfed0dSDavid du Colombier Uart;
45*6bbfed0dSDavid du Colombier Ctlr *ctlr;
46*6bbfed0dSDavid du Colombier u8int *mem;
47*6bbfed0dSDavid du Colombier
48*6bbfed0dSDavid du Colombier int level;
49*6bbfed0dSDavid du Colombier int dtr, rts;
50*6bbfed0dSDavid du Colombier int ri;
51*6bbfed0dSDavid du Colombier };
52*6bbfed0dSDavid du Colombier
53*6bbfed0dSDavid du Colombier struct Ctlr {
54*6bbfed0dSDavid du Colombier Lock;
55*6bbfed0dSDavid du Colombier char *name;
56*6bbfed0dSDavid du Colombier Pcidev *pcidev;
57*6bbfed0dSDavid du Colombier u32int *mem;
58*6bbfed0dSDavid du Colombier
59*6bbfed0dSDavid du Colombier u32int im;
60*6bbfed0dSDavid du Colombier
61*6bbfed0dSDavid du Colombier Port port[0x10];
62*6bbfed0dSDavid du Colombier int nport;
63*6bbfed0dSDavid du Colombier };
64*6bbfed0dSDavid du Colombier
65*6bbfed0dSDavid du Colombier static Uart *
oxpnp(void)66*6bbfed0dSDavid du Colombier oxpnp(void)
67*6bbfed0dSDavid du Colombier {
68*6bbfed0dSDavid du Colombier Pcidev *p;
69*6bbfed0dSDavid du Colombier Ctlr *ctlr;
70*6bbfed0dSDavid du Colombier Port *port;
71*6bbfed0dSDavid du Colombier int i;
72*6bbfed0dSDavid du Colombier char *model;
73*6bbfed0dSDavid du Colombier char name[12+1];
74*6bbfed0dSDavid du Colombier Uart *head, *tail;
75*6bbfed0dSDavid du Colombier static int ctlrno;
76*6bbfed0dSDavid du Colombier
77*6bbfed0dSDavid du Colombier p = nil;
78*6bbfed0dSDavid du Colombier head = tail = nil;
79*6bbfed0dSDavid du Colombier while(p = pcimatch(p, 0x1415, 0)){
80*6bbfed0dSDavid du Colombier switch(p->did){
81*6bbfed0dSDavid du Colombier case 0xc101:
82*6bbfed0dSDavid du Colombier case 0xc105:
83*6bbfed0dSDavid du Colombier case 0xc11b:
84*6bbfed0dSDavid du Colombier case 0xc11f:
85*6bbfed0dSDavid du Colombier case 0xc120:
86*6bbfed0dSDavid du Colombier case 0xc124:
87*6bbfed0dSDavid du Colombier case 0xc138:
88*6bbfed0dSDavid du Colombier case 0xc13d:
89*6bbfed0dSDavid du Colombier case 0xc140:
90*6bbfed0dSDavid du Colombier case 0xc141:
91*6bbfed0dSDavid du Colombier case 0xc144:
92*6bbfed0dSDavid du Colombier case 0xc145:
93*6bbfed0dSDavid du Colombier case 0xc158:
94*6bbfed0dSDavid du Colombier case 0xc15d:
95*6bbfed0dSDavid du Colombier model = "OXPCIe952";
96*6bbfed0dSDavid du Colombier break;
97*6bbfed0dSDavid du Colombier case 0xc208:
98*6bbfed0dSDavid du Colombier case 0xc20d:
99*6bbfed0dSDavid du Colombier model = "OXPCIe954";
100*6bbfed0dSDavid du Colombier break;
101*6bbfed0dSDavid du Colombier case 0xc308:
102*6bbfed0dSDavid du Colombier case 0xc30d:
103*6bbfed0dSDavid du Colombier model = "OXPCIe958";
104*6bbfed0dSDavid du Colombier break;
105*6bbfed0dSDavid du Colombier default:
106*6bbfed0dSDavid du Colombier continue;
107*6bbfed0dSDavid du Colombier }
108*6bbfed0dSDavid du Colombier ctlr = malloc(sizeof *ctlr);
109*6bbfed0dSDavid du Colombier if(ctlr == nil){
110*6bbfed0dSDavid du Colombier print("oxpnp: out of memory\n");
111*6bbfed0dSDavid du Colombier continue;
112*6bbfed0dSDavid du Colombier }
113*6bbfed0dSDavid du Colombier ctlr->pcidev = p;
114*6bbfed0dSDavid du Colombier ctlr->mem = vmap(p->mem[0].bar & ~0xf, p->mem[0].size);
115*6bbfed0dSDavid du Colombier if(ctlr->mem == nil){
116*6bbfed0dSDavid du Colombier print("oxpnp: vmap failed\n");
117*6bbfed0dSDavid du Colombier free(ctlr);
118*6bbfed0dSDavid du Colombier continue;
119*6bbfed0dSDavid du Colombier }
120*6bbfed0dSDavid du Colombier snprint(name, sizeof name, "uartox%d", ctlrno);
121*6bbfed0dSDavid du Colombier kstrdup(&ctlr->name, name);
122*6bbfed0dSDavid du Colombier ctlr->nport = ctlr->mem[Nuart] & 0x1f;
123*6bbfed0dSDavid du Colombier for(i = 0; i < ctlr->nport; ++i){
124*6bbfed0dSDavid du Colombier port = &ctlr->port[i];
125*6bbfed0dSDavid du Colombier port->ctlr = ctlr;
126*6bbfed0dSDavid du Colombier port->mem = (u8int *)ctlr->mem + 0x1000 + 0x200*i;
127*6bbfed0dSDavid du Colombier port->regs = port;
128*6bbfed0dSDavid du Colombier snprint(name, sizeof name, "%s.%d", ctlr->name, i);
129*6bbfed0dSDavid du Colombier kstrdup(&port->name, name);
130*6bbfed0dSDavid du Colombier port->phys = &oxphysuart;
131*6bbfed0dSDavid du Colombier if(head == nil)
132*6bbfed0dSDavid du Colombier head = port;
133*6bbfed0dSDavid du Colombier else
134*6bbfed0dSDavid du Colombier tail->next = port;
135*6bbfed0dSDavid du Colombier tail = port;
136*6bbfed0dSDavid du Colombier }
137*6bbfed0dSDavid du Colombier print("%s: %s: %d ports irq %d\n",
138*6bbfed0dSDavid du Colombier ctlr->name, model, ctlr->nport, p->intl);
139*6bbfed0dSDavid du Colombier ctlrno++;
140*6bbfed0dSDavid du Colombier }
141*6bbfed0dSDavid du Colombier return head;
142*6bbfed0dSDavid du Colombier }
143*6bbfed0dSDavid du Colombier
144*6bbfed0dSDavid du Colombier static void
oxinterrupt(Ureg *,void * arg)145*6bbfed0dSDavid du Colombier oxinterrupt(Ureg *, void *arg)
146*6bbfed0dSDavid du Colombier {
147*6bbfed0dSDavid du Colombier Ctlr *ctlr;
148*6bbfed0dSDavid du Colombier Port *port;
149*6bbfed0dSDavid du Colombier Uart *uart;
150*6bbfed0dSDavid du Colombier int i, old;
151*6bbfed0dSDavid du Colombier u8int val;
152*6bbfed0dSDavid du Colombier char ch;
153*6bbfed0dSDavid du Colombier
154*6bbfed0dSDavid du Colombier ctlr = arg;
155*6bbfed0dSDavid du Colombier
156*6bbfed0dSDavid du Colombier ilock(ctlr);
157*6bbfed0dSDavid du Colombier if(!(ctlr->im & ctlr->mem[Gis])){
158*6bbfed0dSDavid du Colombier iunlock(ctlr);
159*6bbfed0dSDavid du Colombier return;
160*6bbfed0dSDavid du Colombier }
161*6bbfed0dSDavid du Colombier for(i = 0; i < ctlr->nport; ++i){
162*6bbfed0dSDavid du Colombier if(!(ctlr->im & 1<<i))
163*6bbfed0dSDavid du Colombier continue;
164*6bbfed0dSDavid du Colombier port = &ctlr->port[i];
165*6bbfed0dSDavid du Colombier uart = port; /* "Come Clarity" */
166*6bbfed0dSDavid du Colombier switch(port->mem[Isr] & 0x3f){
167*6bbfed0dSDavid du Colombier case 0x06: /* Receiver status error */
168*6bbfed0dSDavid du Colombier case 0x04: /* Receiver data available */
169*6bbfed0dSDavid du Colombier case 0x0c: /* Receiver time-out */
170*6bbfed0dSDavid du Colombier for(;;){
171*6bbfed0dSDavid du Colombier val = port->mem[Lsr];
172*6bbfed0dSDavid du Colombier if(!(val & 1<<0)) /* RxRDY */
173*6bbfed0dSDavid du Colombier break;
174*6bbfed0dSDavid du Colombier if(val & 1<<1) /* Overrun Error */
175*6bbfed0dSDavid du Colombier uart->oerr++;
176*6bbfed0dSDavid du Colombier if(val & 1<<2) /* Parity Error */
177*6bbfed0dSDavid du Colombier uart->perr++;
178*6bbfed0dSDavid du Colombier if(val & 1<<3) /* Framing Error */
179*6bbfed0dSDavid du Colombier uart->ferr++;
180*6bbfed0dSDavid du Colombier ch = port->mem[Rhr];
181*6bbfed0dSDavid du Colombier if(!(val & 1<<7)) /* Data Error */
182*6bbfed0dSDavid du Colombier uartrecv(uart, ch);
183*6bbfed0dSDavid du Colombier }
184*6bbfed0dSDavid du Colombier break;
185*6bbfed0dSDavid du Colombier case 0x02: /* Transmitter THR empty */
186*6bbfed0dSDavid du Colombier uartkick(uart);
187*6bbfed0dSDavid du Colombier break;
188*6bbfed0dSDavid du Colombier case 0x00: /* Modem status change */
189*6bbfed0dSDavid du Colombier val = port->mem[Msr];
190*6bbfed0dSDavid du Colombier if(val & 1<<0){ /* Delta nCTS */
191*6bbfed0dSDavid du Colombier ilock(&uart->tlock);
192*6bbfed0dSDavid du Colombier old = uart->cts;
193*6bbfed0dSDavid du Colombier uart->cts = val & 1<<4; /* CTS */
194*6bbfed0dSDavid du Colombier if(!old && uart->cts)
195*6bbfed0dSDavid du Colombier uart->ctsbackoff = 2;
196*6bbfed0dSDavid du Colombier iunlock(&uart->tlock);
197*6bbfed0dSDavid du Colombier }
198*6bbfed0dSDavid du Colombier if(val & 1<<1){ /* Delta nDSR */
199*6bbfed0dSDavid du Colombier old = val & 1<<5; /* DSR */
200*6bbfed0dSDavid du Colombier if(!old && uart->dsr && uart->hup_dsr)
201*6bbfed0dSDavid du Colombier uart->dohup = 1;
202*6bbfed0dSDavid du Colombier uart->dsr = old;
203*6bbfed0dSDavid du Colombier }
204*6bbfed0dSDavid du Colombier port->ri = val & 1<<6; /* RI */
205*6bbfed0dSDavid du Colombier if(val & 1<<3){ /* Delta nDCD */
206*6bbfed0dSDavid du Colombier old = val & 1<<7; /* DCD */
207*6bbfed0dSDavid du Colombier if(!old && uart->dcd && uart->hup_dcd)
208*6bbfed0dSDavid du Colombier uart->dohup = 1;
209*6bbfed0dSDavid du Colombier uart->dcd = old;
210*6bbfed0dSDavid du Colombier }
211*6bbfed0dSDavid du Colombier break;
212*6bbfed0dSDavid du Colombier }
213*6bbfed0dSDavid du Colombier }
214*6bbfed0dSDavid du Colombier iunlock(ctlr);
215*6bbfed0dSDavid du Colombier }
216*6bbfed0dSDavid du Colombier
217*6bbfed0dSDavid du Colombier #define MASK(p) (1UL<<((p)-(p)->ctlr->port))
218*6bbfed0dSDavid du Colombier
219*6bbfed0dSDavid du Colombier static void
oxenable(Uart * uart,int)220*6bbfed0dSDavid du Colombier oxenable(Uart *uart, int)
221*6bbfed0dSDavid du Colombier {
222*6bbfed0dSDavid du Colombier Ctlr *ctlr;
223*6bbfed0dSDavid du Colombier Port *port;
224*6bbfed0dSDavid du Colombier
225*6bbfed0dSDavid du Colombier port = uart->regs;
226*6bbfed0dSDavid du Colombier ctlr = port->ctlr;
227*6bbfed0dSDavid du Colombier
228*6bbfed0dSDavid du Colombier ilock(ctlr);
229*6bbfed0dSDavid du Colombier if(ctlr->im == 0)
230*6bbfed0dSDavid du Colombier intrenable(ctlr->pcidev->intl, oxinterrupt, ctlr,
231*6bbfed0dSDavid du Colombier ctlr->pcidev->tbdf, ctlr->name);
232*6bbfed0dSDavid du Colombier ctlr->im |= MASK(port);
233*6bbfed0dSDavid du Colombier iunlock(ctlr);
234*6bbfed0dSDavid du Colombier
235*6bbfed0dSDavid du Colombier /* Enable 950 Mode */
236*6bbfed0dSDavid du Colombier port->mem[Lcr] |= 1<<7; /* Divisor latch access */
237*6bbfed0dSDavid du Colombier port->mem[Efr] = 1<<4; /* Enhanced mode */
238*6bbfed0dSDavid du Colombier port->mem[Lcr] &= ~(1<<7);
239*6bbfed0dSDavid du Colombier
240*6bbfed0dSDavid du Colombier port->mem[Ier] = 1<<2|1<<1|1<<0; /* Rx Stat, THRE, RxRDY */
241*6bbfed0dSDavid du Colombier
242*6bbfed0dSDavid du Colombier (*uart->phys->dtr)(uart, 1);
243*6bbfed0dSDavid du Colombier (*uart->phys->rts)(uart, 1);
244*6bbfed0dSDavid du Colombier
245*6bbfed0dSDavid du Colombier /* Enable FIFO */
246*6bbfed0dSDavid du Colombier (*uart->phys->fifo)(uart, ~0);
247*6bbfed0dSDavid du Colombier }
248*6bbfed0dSDavid du Colombier
249*6bbfed0dSDavid du Colombier static void
oxdisable(Uart * uart)250*6bbfed0dSDavid du Colombier oxdisable(Uart *uart)
251*6bbfed0dSDavid du Colombier {
252*6bbfed0dSDavid du Colombier Ctlr *ctlr;
253*6bbfed0dSDavid du Colombier Port *port;
254*6bbfed0dSDavid du Colombier
255*6bbfed0dSDavid du Colombier port = uart->regs;
256*6bbfed0dSDavid du Colombier ctlr = port->ctlr;
257*6bbfed0dSDavid du Colombier
258*6bbfed0dSDavid du Colombier (*uart->phys->dtr)(uart, 0);
259*6bbfed0dSDavid du Colombier (*uart->phys->rts)(uart, 0);
260*6bbfed0dSDavid du Colombier (*uart->phys->fifo)(uart, 0);
261*6bbfed0dSDavid du Colombier
262*6bbfed0dSDavid du Colombier port->mem[Ier] = 0;
263*6bbfed0dSDavid du Colombier
264*6bbfed0dSDavid du Colombier ilock(ctlr);
265*6bbfed0dSDavid du Colombier ctlr->im &= ~MASK(port);
266*6bbfed0dSDavid du Colombier if(ctlr->im == 0)
267*6bbfed0dSDavid du Colombier intrdisable(ctlr->pcidev->intl, oxinterrupt, ctlr,
268*6bbfed0dSDavid du Colombier ctlr->pcidev->tbdf, ctlr->name);
269*6bbfed0dSDavid du Colombier iunlock(ctlr);
270*6bbfed0dSDavid du Colombier }
271*6bbfed0dSDavid du Colombier
272*6bbfed0dSDavid du Colombier static void
oxkick(Uart * uart)273*6bbfed0dSDavid du Colombier oxkick(Uart *uart)
274*6bbfed0dSDavid du Colombier {
275*6bbfed0dSDavid du Colombier Port *port;
276*6bbfed0dSDavid du Colombier
277*6bbfed0dSDavid du Colombier if(uart->cts == 0 || uart->blocked)
278*6bbfed0dSDavid du Colombier return;
279*6bbfed0dSDavid du Colombier
280*6bbfed0dSDavid du Colombier port = uart->regs;
281*6bbfed0dSDavid du Colombier
282*6bbfed0dSDavid du Colombier for(;;){
283*6bbfed0dSDavid du Colombier if(!(port->mem[Lsr] & 1<<5)) /* THR Empty */
284*6bbfed0dSDavid du Colombier break;
285*6bbfed0dSDavid du Colombier if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
286*6bbfed0dSDavid du Colombier break;
287*6bbfed0dSDavid du Colombier port->mem[Thr] = *(uart->op++);
288*6bbfed0dSDavid du Colombier }
289*6bbfed0dSDavid du Colombier }
290*6bbfed0dSDavid du Colombier
291*6bbfed0dSDavid du Colombier static void
oxdobreak(Uart * uart,int ms)292*6bbfed0dSDavid du Colombier oxdobreak(Uart *uart, int ms)
293*6bbfed0dSDavid du Colombier {
294*6bbfed0dSDavid du Colombier Port *port;
295*6bbfed0dSDavid du Colombier
296*6bbfed0dSDavid du Colombier if(ms <= 0)
297*6bbfed0dSDavid du Colombier ms = 200;
298*6bbfed0dSDavid du Colombier
299*6bbfed0dSDavid du Colombier port = uart->regs;
300*6bbfed0dSDavid du Colombier
301*6bbfed0dSDavid du Colombier port->mem[Lcr] |= 1<<6; /* Transmission break */
302*6bbfed0dSDavid du Colombier if(!waserror()){
303*6bbfed0dSDavid du Colombier tsleep(&up->sleep, return0, nil, ms);
304*6bbfed0dSDavid du Colombier poperror();
305*6bbfed0dSDavid du Colombier }
306*6bbfed0dSDavid du Colombier port->mem[Lcr] &= ~(1<<6);
307*6bbfed0dSDavid du Colombier }
308*6bbfed0dSDavid du Colombier
309*6bbfed0dSDavid du Colombier static int
oxbaud(Uart * uart,int baud)310*6bbfed0dSDavid du Colombier oxbaud(Uart *uart, int baud)
311*6bbfed0dSDavid du Colombier {
312*6bbfed0dSDavid du Colombier Port *port;
313*6bbfed0dSDavid du Colombier u16int val;
314*6bbfed0dSDavid du Colombier
315*6bbfed0dSDavid du Colombier if(baud <= 0)
316*6bbfed0dSDavid du Colombier return -1;
317*6bbfed0dSDavid du Colombier
318*6bbfed0dSDavid du Colombier port = uart->regs;
319*6bbfed0dSDavid du Colombier
320*6bbfed0dSDavid du Colombier /*
321*6bbfed0dSDavid du Colombier * We aren't terribly interested in non-standard baud rates.
322*6bbfed0dSDavid du Colombier * Rather than mess about with generator constants, we instead
323*6bbfed0dSDavid du Colombier * program DLM and DLL according to Table 37 in the datasheet.
324*6bbfed0dSDavid du Colombier */
325*6bbfed0dSDavid du Colombier switch(baud){
326*6bbfed0dSDavid du Colombier case 1200:
327*6bbfed0dSDavid du Colombier val = 0x0cb6;
328*6bbfed0dSDavid du Colombier break;
329*6bbfed0dSDavid du Colombier case 2400:
330*6bbfed0dSDavid du Colombier val = 0x065b;
331*6bbfed0dSDavid du Colombier break;
332*6bbfed0dSDavid du Colombier case 4800:
333*6bbfed0dSDavid du Colombier val = 0x032d;
334*6bbfed0dSDavid du Colombier break;
335*6bbfed0dSDavid du Colombier case 9600:
336*6bbfed0dSDavid du Colombier val = 0x0196;
337*6bbfed0dSDavid du Colombier break;
338*6bbfed0dSDavid du Colombier case 19200:
339*6bbfed0dSDavid du Colombier val = 0x00cb;
340*6bbfed0dSDavid du Colombier break;
341*6bbfed0dSDavid du Colombier case 38400:
342*6bbfed0dSDavid du Colombier val = 0x0066;
343*6bbfed0dSDavid du Colombier break;
344*6bbfed0dSDavid du Colombier case 57600:
345*6bbfed0dSDavid du Colombier val = 0x0044;
346*6bbfed0dSDavid du Colombier break;
347*6bbfed0dSDavid du Colombier case 115200:
348*6bbfed0dSDavid du Colombier val = 0x0022;
349*6bbfed0dSDavid du Colombier break;
350*6bbfed0dSDavid du Colombier default:
351*6bbfed0dSDavid du Colombier return -1;
352*6bbfed0dSDavid du Colombier }
353*6bbfed0dSDavid du Colombier port->mem[Lcr] |= 1<<7; /* Divisor latch access */
354*6bbfed0dSDavid du Colombier port->mem[Dlm] = val>>8;
355*6bbfed0dSDavid du Colombier port->mem[Dll] = val;
356*6bbfed0dSDavid du Colombier port->mem[Lcr] &= ~(1<<7);
357*6bbfed0dSDavid du Colombier uart->baud = baud;
358*6bbfed0dSDavid du Colombier return 0;
359*6bbfed0dSDavid du Colombier }
360*6bbfed0dSDavid du Colombier
361*6bbfed0dSDavid du Colombier static int
oxbits(Uart * uart,int bits)362*6bbfed0dSDavid du Colombier oxbits(Uart *uart, int bits)
363*6bbfed0dSDavid du Colombier {
364*6bbfed0dSDavid du Colombier Port *port;
365*6bbfed0dSDavid du Colombier u8int val;
366*6bbfed0dSDavid du Colombier
367*6bbfed0dSDavid du Colombier port = uart->regs;
368*6bbfed0dSDavid du Colombier
369*6bbfed0dSDavid du Colombier val = port->mem[Lcr] & 0x7c;
370*6bbfed0dSDavid du Colombier switch(bits){
371*6bbfed0dSDavid du Colombier case 8:
372*6bbfed0dSDavid du Colombier val |= 0x3; /* Data length */
373*6bbfed0dSDavid du Colombier break;
374*6bbfed0dSDavid du Colombier case 7:
375*6bbfed0dSDavid du Colombier val |= 0x2;
376*6bbfed0dSDavid du Colombier break;
377*6bbfed0dSDavid du Colombier case 6:
378*6bbfed0dSDavid du Colombier val |= 0x1;
379*6bbfed0dSDavid du Colombier break;
380*6bbfed0dSDavid du Colombier case 5:
381*6bbfed0dSDavid du Colombier break;
382*6bbfed0dSDavid du Colombier default:
383*6bbfed0dSDavid du Colombier return -1;
384*6bbfed0dSDavid du Colombier }
385*6bbfed0dSDavid du Colombier port->mem[Lcr] = val;
386*6bbfed0dSDavid du Colombier uart->bits = bits;
387*6bbfed0dSDavid du Colombier return 0;
388*6bbfed0dSDavid du Colombier }
389*6bbfed0dSDavid du Colombier
390*6bbfed0dSDavid du Colombier static int
oxstop(Uart * uart,int stop)391*6bbfed0dSDavid du Colombier oxstop(Uart *uart, int stop)
392*6bbfed0dSDavid du Colombier {
393*6bbfed0dSDavid du Colombier Port *port;
394*6bbfed0dSDavid du Colombier u8int val;
395*6bbfed0dSDavid du Colombier
396*6bbfed0dSDavid du Colombier port = uart->regs;
397*6bbfed0dSDavid du Colombier
398*6bbfed0dSDavid du Colombier val = port->mem[Lcr] & 0x7b;
399*6bbfed0dSDavid du Colombier switch(stop){
400*6bbfed0dSDavid du Colombier case 2:
401*6bbfed0dSDavid du Colombier val |= 1<<2; /* Number of Stop Bits */
402*6bbfed0dSDavid du Colombier break;
403*6bbfed0dSDavid du Colombier case 1:
404*6bbfed0dSDavid du Colombier break;
405*6bbfed0dSDavid du Colombier default:
406*6bbfed0dSDavid du Colombier return -1;
407*6bbfed0dSDavid du Colombier }
408*6bbfed0dSDavid du Colombier port->mem[Lcr] = val;
409*6bbfed0dSDavid du Colombier uart->stop = stop;
410*6bbfed0dSDavid du Colombier return 0;
411*6bbfed0dSDavid du Colombier }
412*6bbfed0dSDavid du Colombier
413*6bbfed0dSDavid du Colombier static int
oxparity(Uart * uart,int parity)414*6bbfed0dSDavid du Colombier oxparity(Uart *uart, int parity)
415*6bbfed0dSDavid du Colombier {
416*6bbfed0dSDavid du Colombier Port *port;
417*6bbfed0dSDavid du Colombier u8int val;
418*6bbfed0dSDavid du Colombier
419*6bbfed0dSDavid du Colombier port = uart->regs;
420*6bbfed0dSDavid du Colombier
421*6bbfed0dSDavid du Colombier val = port->mem[Lcr] & 0x67;
422*6bbfed0dSDavid du Colombier switch(parity){
423*6bbfed0dSDavid du Colombier case 'e':
424*6bbfed0dSDavid du Colombier val |= 1<<4; /* Even/Odd Parity */
425*6bbfed0dSDavid du Colombier case 'o':
426*6bbfed0dSDavid du Colombier val |= 1<<3; /* Parity Enable */
427*6bbfed0dSDavid du Colombier break;
428*6bbfed0dSDavid du Colombier case 'n':
429*6bbfed0dSDavid du Colombier break;
430*6bbfed0dSDavid du Colombier default:
431*6bbfed0dSDavid du Colombier return -1;
432*6bbfed0dSDavid du Colombier }
433*6bbfed0dSDavid du Colombier port->mem[Lcr] = val;
434*6bbfed0dSDavid du Colombier uart->parity = parity;
435*6bbfed0dSDavid du Colombier return 0;
436*6bbfed0dSDavid du Colombier }
437*6bbfed0dSDavid du Colombier
438*6bbfed0dSDavid du Colombier static void
oxmodemctl(Uart * uart,int on)439*6bbfed0dSDavid du Colombier oxmodemctl(Uart *uart, int on)
440*6bbfed0dSDavid du Colombier {
441*6bbfed0dSDavid du Colombier Ctlr *ctlr;
442*6bbfed0dSDavid du Colombier Port *port;
443*6bbfed0dSDavid du Colombier
444*6bbfed0dSDavid du Colombier port = uart->regs;
445*6bbfed0dSDavid du Colombier ctlr = port->ctlr;
446*6bbfed0dSDavid du Colombier
447*6bbfed0dSDavid du Colombier ilock(ctlr);
448*6bbfed0dSDavid du Colombier ilock(&uart->tlock);
449*6bbfed0dSDavid du Colombier if(on){
450*6bbfed0dSDavid du Colombier port->mem[Ier] |= 1<<3; /* Modem */
451*6bbfed0dSDavid du Colombier uart->cts = port->mem[Msr] & 1<<4; /* CTS */
452*6bbfed0dSDavid du Colombier }else{
453*6bbfed0dSDavid du Colombier port->mem[Ier] &= ~(1<<3);
454*6bbfed0dSDavid du Colombier uart->cts = 1;
455*6bbfed0dSDavid du Colombier }
456*6bbfed0dSDavid du Colombier uart->modem = on;
457*6bbfed0dSDavid du Colombier iunlock(&uart->tlock);
458*6bbfed0dSDavid du Colombier iunlock(ctlr);
459*6bbfed0dSDavid du Colombier }
460*6bbfed0dSDavid du Colombier
461*6bbfed0dSDavid du Colombier static void
oxrts(Uart * uart,int on)462*6bbfed0dSDavid du Colombier oxrts(Uart *uart, int on)
463*6bbfed0dSDavid du Colombier {
464*6bbfed0dSDavid du Colombier Port *port;
465*6bbfed0dSDavid du Colombier
466*6bbfed0dSDavid du Colombier port = uart->regs;
467*6bbfed0dSDavid du Colombier
468*6bbfed0dSDavid du Colombier if(on)
469*6bbfed0dSDavid du Colombier port->mem[Mcr] |= 1<<1; /* RTS */
470*6bbfed0dSDavid du Colombier else
471*6bbfed0dSDavid du Colombier port->mem[Mcr] &= ~(1<<1);
472*6bbfed0dSDavid du Colombier port->rts = on;
473*6bbfed0dSDavid du Colombier }
474*6bbfed0dSDavid du Colombier
475*6bbfed0dSDavid du Colombier static void
oxdtr(Uart * uart,int on)476*6bbfed0dSDavid du Colombier oxdtr(Uart *uart, int on)
477*6bbfed0dSDavid du Colombier {
478*6bbfed0dSDavid du Colombier Port *port;
479*6bbfed0dSDavid du Colombier
480*6bbfed0dSDavid du Colombier port = uart->regs;
481*6bbfed0dSDavid du Colombier
482*6bbfed0dSDavid du Colombier if(on)
483*6bbfed0dSDavid du Colombier port->mem[Mcr] |= 1<<0; /* DTR */
484*6bbfed0dSDavid du Colombier else
485*6bbfed0dSDavid du Colombier port->mem[Mcr] &= ~(1<<0);
486*6bbfed0dSDavid du Colombier port->dtr = on;
487*6bbfed0dSDavid du Colombier }
488*6bbfed0dSDavid du Colombier
489*6bbfed0dSDavid du Colombier static long
oxstatus(Uart * uart,void * buf,long n,long offset)490*6bbfed0dSDavid du Colombier oxstatus(Uart *uart, void *buf, long n, long offset)
491*6bbfed0dSDavid du Colombier {
492*6bbfed0dSDavid du Colombier Port *port;
493*6bbfed0dSDavid du Colombier
494*6bbfed0dSDavid du Colombier if(offset > 0)
495*6bbfed0dSDavid du Colombier return 0;
496*6bbfed0dSDavid du Colombier
497*6bbfed0dSDavid du Colombier port = uart->regs;
498*6bbfed0dSDavid du Colombier
499*6bbfed0dSDavid du Colombier return snprint(buf, n,
500*6bbfed0dSDavid du Colombier "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
501*6bbfed0dSDavid du Colombier "dev(%d) type(%d) framing(%d) overruns(%d) "
502*6bbfed0dSDavid du Colombier "berr(%d) serr(%d)%s%s%s%s\n",
503*6bbfed0dSDavid du Colombier
504*6bbfed0dSDavid du Colombier uart->baud,
505*6bbfed0dSDavid du Colombier uart->hup_dcd,
506*6bbfed0dSDavid du Colombier port->dtr,
507*6bbfed0dSDavid du Colombier uart->hup_dsr,
508*6bbfed0dSDavid du Colombier uart->bits,
509*6bbfed0dSDavid du Colombier uart->modem,
510*6bbfed0dSDavid du Colombier uart->parity,
511*6bbfed0dSDavid du Colombier port->rts,
512*6bbfed0dSDavid du Colombier uart->stop,
513*6bbfed0dSDavid du Colombier port->level,
514*6bbfed0dSDavid du Colombier
515*6bbfed0dSDavid du Colombier uart->dev,
516*6bbfed0dSDavid du Colombier uart->type,
517*6bbfed0dSDavid du Colombier uart->ferr,
518*6bbfed0dSDavid du Colombier uart->oerr,
519*6bbfed0dSDavid du Colombier uart->berr,
520*6bbfed0dSDavid du Colombier uart->serr,
521*6bbfed0dSDavid du Colombier uart->cts ? " cts": "",
522*6bbfed0dSDavid du Colombier uart->dsr ? " dsr": "",
523*6bbfed0dSDavid du Colombier port->ri ? " ring": "",
524*6bbfed0dSDavid du Colombier uart->dcd ? " dcd": ""
525*6bbfed0dSDavid du Colombier );
526*6bbfed0dSDavid du Colombier }
527*6bbfed0dSDavid du Colombier
528*6bbfed0dSDavid du Colombier static void
oxfifo(Uart * uart,int level)529*6bbfed0dSDavid du Colombier oxfifo(Uart *uart, int level)
530*6bbfed0dSDavid du Colombier {
531*6bbfed0dSDavid du Colombier Ctlr *ctlr;
532*6bbfed0dSDavid du Colombier Port *port;
533*6bbfed0dSDavid du Colombier
534*6bbfed0dSDavid du Colombier port = uart->regs;
535*6bbfed0dSDavid du Colombier ctlr = port->ctlr;
536*6bbfed0dSDavid du Colombier
537*6bbfed0dSDavid du Colombier /*
538*6bbfed0dSDavid du Colombier * 950 Mode FIFOs have a depth of 128 bytes; devuart only
539*6bbfed0dSDavid du Colombier * cares about setting RHR trigger levels. THR trigger
540*6bbfed0dSDavid du Colombier * levels are not supported.
541*6bbfed0dSDavid du Colombier */
542*6bbfed0dSDavid du Colombier ilock(ctlr);
543*6bbfed0dSDavid du Colombier if(level == 0)
544*6bbfed0dSDavid du Colombier port->mem[Fcr] = 0; /* Disable FIFO */
545*6bbfed0dSDavid du Colombier else{
546*6bbfed0dSDavid du Colombier port->mem[Fcr] = 1<<0; /* Enable FIFO */
547*6bbfed0dSDavid du Colombier switch(level){
548*6bbfed0dSDavid du Colombier default:
549*6bbfed0dSDavid du Colombier level = 112;
550*6bbfed0dSDavid du Colombier case 112:
551*6bbfed0dSDavid du Colombier port->mem[Fcr] = 0x03<<6|1<<0; /* RHR Trigger Level */
552*6bbfed0dSDavid du Colombier break;
553*6bbfed0dSDavid du Colombier case 64:
554*6bbfed0dSDavid du Colombier port->mem[Fcr] = 0x02<<6|1<<0;
555*6bbfed0dSDavid du Colombier break;
556*6bbfed0dSDavid du Colombier case 32:
557*6bbfed0dSDavid du Colombier port->mem[Fcr] = 0x01<<6|1<<0;
558*6bbfed0dSDavid du Colombier break;
559*6bbfed0dSDavid du Colombier case 16:
560*6bbfed0dSDavid du Colombier break;
561*6bbfed0dSDavid du Colombier }
562*6bbfed0dSDavid du Colombier }
563*6bbfed0dSDavid du Colombier port->level = level;
564*6bbfed0dSDavid du Colombier iunlock(ctlr);
565*6bbfed0dSDavid du Colombier }
566*6bbfed0dSDavid du Colombier
567*6bbfed0dSDavid du Colombier PhysUart oxphysuart = {
568*6bbfed0dSDavid du Colombier .name = "OXPCIe95x",
569*6bbfed0dSDavid du Colombier .pnp = oxpnp,
570*6bbfed0dSDavid du Colombier .enable = oxenable,
571*6bbfed0dSDavid du Colombier .disable = oxdisable,
572*6bbfed0dSDavid du Colombier .kick = oxkick,
573*6bbfed0dSDavid du Colombier .dobreak = oxdobreak,
574*6bbfed0dSDavid du Colombier .baud = oxbaud,
575*6bbfed0dSDavid du Colombier .bits = oxbits,
576*6bbfed0dSDavid du Colombier .stop = oxstop,
577*6bbfed0dSDavid du Colombier .parity = oxparity,
578*6bbfed0dSDavid du Colombier .modemctl = oxmodemctl,
579*6bbfed0dSDavid du Colombier .rts = oxrts,
580*6bbfed0dSDavid du Colombier .dtr = oxdtr,
581*6bbfed0dSDavid du Colombier .status = oxstatus,
582*6bbfed0dSDavid du Colombier .fifo = oxfifo,
583*6bbfed0dSDavid du Colombier };
584