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