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