Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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