xref: /plan9/sys/src/9/pc/uartpci.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 
9 extern PhysUart i8250physuart;
10 extern PhysUart pciphysuart;
11 extern void* i8250alloc(int, int, int);
12 
13 static Uart*
14 uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name)
15 {
16 	int i, io;
17 	void *ctlr;
18 	char buf[64];
19 	Uart *head, *uart;
20 
21 	io = p->mem[barno].bar & ~0x01;
22 	snprint(buf, sizeof(buf), "%s%d", pciphysuart.name, ctlrno);
23 	if(ioalloc(io, p->mem[barno].size, 0, buf) < 0){
24 		print("uartpci: I/O 0x%uX in use\n", io);
25 		return nil;
26 	}
27 
28 	head = uart = malloc(sizeof(Uart)*n);
29 
30 	for(i = 0; i < n; i++){
31 		ctlr = i8250alloc(io, p->intl, p->tbdf);
32 		io += 8;
33 		if(ctlr == nil)
34 			continue;
35 
36 		uart->regs = ctlr;
37 		snprint(buf, sizeof(buf), "%s.%8.8uX", name, p->tbdf);
38 		kstrdup(&uart->name, buf);
39 		uart->freq = freq;
40 		uart->phys = &i8250physuart;
41 		if(uart != head)
42 			(uart-1)->next = uart;
43 		uart++;
44 	}
45 
46 	return head;
47 }
48 
49 static Uart*
50 uartpcipnp(void)
51 {
52 	Pcidev *p;
53 	char *name;
54 	int ctlrno, n, subid;
55 	Uart *head, *tail, *uart;
56 
57 	/*
58 	 * Loop through all PCI devices looking for simple serial
59 	 * controllers (ccrb == 0x07) and configure the ones which
60 	 * are familiar. All suitable devices are configured to
61 	 * simply point to the generic i8250 driver.
62 	 */
63 	head = tail = nil;
64 	ctlrno = 0;
65 	for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
66 		if(p->ccrb != 0x07 || p->ccru != 0)
67 			continue;
68 
69 		switch((p->did<<16)|p->vid){
70 		default:
71 			continue;
72 		case (0x9050<<16)|0x10B5:	/* Perle PCI-Fast4 series */
73 		case (0x9030<<16)|0x10B5:	/* Perle Ultraport series */
74 			/*
75 			 * These devices consists of a PLX bridge (the above
76 			 * PCI VID+DID) behind which are some 16C654 UARTs.
77 			 * Must check the subsystem VID and DID for correct
78 			 * match.
79 			 */
80 			subid = pcicfgr16(p, PciSVID);
81 			subid |= pcicfgr16(p, PciSID)<<16;
82 			switch(subid){
83 			default:
84 				continue;
85 			case (0x0011<<16)|0x12E0:	/* Perle PCI-Fast16 */
86 				n = 16;
87 				name = "PCI-Fast16";
88 				break;
89 			case (0x0021<<16)|0x12E0:	/* Perle PCI-Fast8 */
90 				n = 8;
91 				name = "PCI-Fast8";
92 				break;
93 			case (0x0031<<16)|0x12E0:	/* Perle PCI-Fast4 */
94 				n = 4;
95 				name = "PCI-Fast4";
96 				break;
97 			case (0x0021<<16)|0x155F:	/* Perle Ultraport8 */
98 				n = 8;
99 				name = "Ultraport8";	/* 16C754 UARTs */
100 				break;
101 			}
102 			uart = uartpci(ctlrno, p, 2, n, 7372800, name);
103 			if(uart == nil)
104 				continue;
105 			break;
106 		}
107 
108 		if(head != nil)
109 			tail->next = uart;
110 		else
111 			head = uart;
112 		for(tail = uart; tail->next != nil; tail = tail->next)
113 			;
114 		ctlrno++;
115 	}
116 
117 	return head;
118 }
119 
120 PhysUart pciphysuart = {
121 	.name		= "UartPCI",
122 	.pnp		= uartpcipnp,
123 	.enable		= nil,
124 	.disable	= nil,
125 	.kick		= nil,
126 	.dobreak	= nil,
127 	.baud		= nil,
128 	.bits		= nil,
129 	.stop		= nil,
130 	.parity		= nil,
131 	.modemctl	= nil,
132 	.rts		= nil,
133 	.dtr		= nil,
134 	.status		= nil,
135 	.fifo		= nil,
136 };
137