xref: /plan9/sys/src/9/pc/uartpci.c (revision a8482e058adfb9039bb8aaa40ea4270fc64ff0a4)
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 *perlehead, *perletail;
14 
15 static Uart*
16 uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name,
17 	int iosize)
18 {
19 	int i, io;
20 	void *ctlr;
21 	char buf[64];
22 	Uart *head, *uart;
23 
24 	io = p->mem[barno].bar & ~0x01;
25 	snprint(buf, sizeof(buf), "%s%d", pciphysuart.name, ctlrno);
26 	if(ioalloc(io, p->mem[barno].size, 0, buf) < 0){
27 		print("uartpci: I/O 0x%uX in use\n", io);
28 		return nil;
29 	}
30 
31 	head = uart = malloc(sizeof(Uart)*n);
32 	for(i = 0; i < n; i++){
33 		ctlr = i8250alloc(io, p->intl, p->tbdf);
34 		io += iosize;
35 		if(ctlr == nil)
36 			continue;
37 
38 		uart->regs = ctlr;
39 		snprint(buf, sizeof(buf), "%s.%8.8uX", name, p->tbdf);
40 		kstrdup(&uart->name, buf);
41 		uart->freq = freq;
42 		uart->phys = &i8250physuart;
43 		if(uart != head)
44 			(uart-1)->next = uart;
45 		uart++;
46 	}
47 
48 	if (head) {
49 		if(perlehead != nil)
50 			perletail->next = head;
51 		else
52 			perlehead = head;
53 		for(perletail = head; perletail->next != nil;
54 		    perletail = perletail->next)
55 			;
56 	}
57 	return head;
58 }
59 
60 static Uart *
61 ultraport16si(int ctlrno, Pcidev *p, ulong freq)
62 {
63 	int io, i;
64 	char *name;
65 	Uart *uart;
66 
67 	name = "Ultraport16si";		/* 16L788 UARTs */
68 	io = p->mem[4].bar & ~1;
69 	if (ioalloc(io, p->mem[4].size, 0, name) < 0) {
70 		print("uartpci: can't get IO space to set %s to rs-232\n", name);
71 		return nil;
72 	}
73 	for (i = 0; i < 16; i++) {
74 		outb(io, i << 4);
75 		outb(io, (i << 4) + 1);	/* set to RS232 mode  (Don't ask!) */
76 	}
77 
78 	uart = uartpci(ctlrno, p, 2, 8, freq, name, 16);
79 	if(uart)
80 		uart = uartpci(ctlrno, p, 3, 8, freq, name, 16);
81 	return uart;
82 }
83 
84 static Uart*
85 uartpcipnp(void)
86 {
87 	Pcidev *p;
88 	char *name;
89 	int ctlrno, subid;
90 	ulong freq;
91 	Uart *uart;
92 
93 	/*
94 	 * Loop through all PCI devices looking for simple serial
95 	 * controllers (ccrb == 0x07) and configure the ones which
96 	 * are familiar. All suitable devices are configured to
97 	 * simply point to the generic i8250 driver.
98 	 */
99 	perlehead = perletail = nil;
100 	ctlrno = 0;
101 	for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
102 		if(p->ccrb != 0x07 || p->ccru > 2)
103 			continue;
104 
105 		switch(p->did<<16 | p->vid){
106 		default:
107 			continue;
108 		case (0x9835<<16)|0x9710:	/* StarTech PCI2S550 */
109 			uart = uartpci(ctlrno, p, 0, 1, 1843200, "PCI2S550-0", 8);
110 			if(uart == nil)
111 				continue;
112 			uart->next = uartpci(ctlrno, p, 1, 1, 1843200,
113 				"PCI2S550-1", 8);
114 			if(uart->next == nil)
115 				continue;
116 			break;
117 		case (0x950A<<16)|0x1415:	/* Oxford Semi OX16PCI954 */
118 		case (0x9501<<16)|0x1415:
119 			/*
120 			 * These are common devices used by 3rd-party
121 			 * manufacturers.
122 			 * Must check the subsystem VID and DID for correct
123 			 * match.
124 			 */
125 			subid = pcicfgr16(p, PciSVID);
126 			subid |= pcicfgr16(p, PciSID)<<16;
127 			switch(subid){
128 			default:
129 				print("oxsemi uart %.8#ux of vid %#ux did %#ux unknown\n",
130 					subid, p->vid, p->did);
131 				continue;
132 			case (0<<16)|0x1415:
133 				uart = uartpci(ctlrno, p, 0, 4, 1843200,
134 					"starport-pex4s", 8);
135 				break;
136 			case (0x2000<<16)|0x131F:/* SIIG CyberSerial PCIe */
137 				uart = uartpci(ctlrno, p, 0, 1, 18432000,
138 					"CyberSerial-1S", 8);
139 				break;
140 			}
141 			break;
142 		case (0x9050<<16)|0x10B5:	/* Perle PCI-Fast4 series */
143 		case (0x9030<<16)|0x10B5:	/* Perle Ultraport series */
144 			/*
145 			 * These devices consists of a PLX bridge (the above
146 			 * PCI VID+DID) behind which are some 16C654 UARTs.
147 			 * Must check the subsystem VID and DID for correct
148 			 * match.
149 			 */
150 			subid = pcicfgr16(p, PciSVID);
151 			subid |= pcicfgr16(p, PciSID)<<16;
152 			freq = 7372800;
153 			switch(subid){
154 			default:
155 				continue;
156 			case (0x0011<<16)|0x12E0:	/* Perle PCI-Fast16 */
157 				name = "PCI-Fast16";
158 				uart = uartpci(ctlrno, p, 2, 16, freq, name, 8);
159 				break;
160 			case (0x0021<<16)|0x12E0:	/* Perle PCI-Fast8 */
161 				name = "PCI-Fast8";
162 				uart = uartpci(ctlrno, p, 2, 8, freq, name, 8);
163 				break;
164 			case (0x0031<<16)|0x12E0:	/* Perle PCI-Fast4 */
165 				name = "PCI-Fast4";
166 				uart = uartpci(ctlrno, p, 2, 4, freq, name, 8);
167 				break;
168 			case (0x0021<<16)|0x155F:	/* Perle Ultraport8 */
169 				name = "Ultraport8";	/* 16C754 UARTs */
170 				uart = uartpci(ctlrno, p, 2, 8, freq, name, 8);
171 				break;
172 			case (0x0041<<16)|0x155F:	/* Perle Ultraport16 */
173 				name = "Ultraport16";
174 				uart = uartpci(ctlrno, p, 2, 16, 2 * freq,
175 					name, 8);
176 				break;
177 			case (0x0241<<16)|0x155F:	/* Perle Ultraport16 */
178 				uart = ultraport16si(ctlrno, p, 4 * freq);
179 				break;
180 			}
181 			break;
182 		}
183 		if(uart)
184 			ctlrno++;
185 	}
186 
187 	return perlehead;
188 }
189 
190 PhysUart pciphysuart = {
191 	.name		= "UartPCI",
192 	.pnp		= uartpcipnp,
193 	.enable		= nil,
194 	.disable	= nil,
195 	.kick		= nil,
196 	.dobreak	= nil,
197 	.baud		= nil,
198 	.bits		= nil,
199 	.stop		= nil,
200 	.parity		= nil,
201 	.modemctl	= nil,
202 	.rts		= nil,
203 	.dtr		= nil,
204 	.status		= nil,
205 	.fifo		= nil,
206 };
207