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 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 * 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* 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