]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/uartpci.c
merge
[plan9front.git] / sys / src / 9 / pc / uartpci.c
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 == Pcibccomm (7)) 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                 /* StarTech PCI8S9503V has ccru == 0x80 (other) */
103                 if(p->ccrb != Pcibccomm || p->ccru > 2 && p->ccru != 0x80)
104                         continue;
105
106                 switch(p->did<<16 | p->vid){
107                 default:
108                         continue;
109                 case (0x9835<<16)|0x9710:       /* StarTech PCI2S550 */
110                         uart = uartpci(ctlrno, p, 0, 1, 1843200, "PCI2S550-0", 8);
111                         if(uart == nil)
112                                 continue;
113                         uart->next = uartpci(ctlrno, p, 1, 1, 1843200,
114                                 "PCI2S550-1", 8);
115                         if(uart->next == nil)
116                                 continue;
117                         break;
118                 case (0x950A<<16)|0x1415:       /* Oxford Semi OX16PCI954 */
119                 case (0x9501<<16)|0x1415:
120                 case (0x9521<<16)|0x1415:
121                         /*
122                          * These are common devices used by 3rd-party
123                          * manufacturers.
124                          * Must check the subsystem VID and DID for correct
125                          * match.
126                          */
127                         subid = pcicfgr16(p, PciSVID);
128                         subid |= pcicfgr16(p, PciSID)<<16;
129                         switch(subid){
130                         default:
131                                 print("oxsemi uart %.8#ux of vid %#ux did %#ux unknown\n",
132                                         subid, p->vid, p->did);
133                                 continue;
134                         case (0<<16)|0x1415:
135                                 uart = uartpci(ctlrno, p, 0, 4, 1843200,
136                                         "starport-pex4s", 8);
137                                 break;
138                         case (1<<16)|0x1415:
139                                 uart = uartpci(ctlrno, p, 0, 2, 14745600,
140                                         "starport-pex2s", 8);
141                                 break;
142                         case (0x2000<<16)|0x131F:/* SIIG CyberSerial PCIe */
143                                 uart = uartpci(ctlrno, p, 0, 1, 18432000,
144                                         "CyberSerial-1S", 8);
145                                 break;
146                         }
147                         break;
148                 case (0x9505<<16)|0x1415:       /* Oxford Semi OXuPCI952 */
149                         name = "SATAGear-IOI-102";  /* PciSVID=1415, PciSID=0 */
150                         if (uartpci(ctlrno, p, 0, 1, 14745600, name, 8) != nil)
151                                 ctlrno++;
152                         if (uartpci(ctlrno, p, 1, 1, 14745600, name, 8) != nil)
153                                 ctlrno++;
154                         uart = nil;             /* don't ctlrno++ below */
155                         break;
156                 case (0x9050<<16)|0x10B5:       /* Perle PCI-Fast4 series */
157                 case (0x9030<<16)|0x10B5:       /* Perle Ultraport series */
158                         /*
159                          * These devices consists of a PLX bridge (the above
160                          * PCI VID+DID) behind which are some 16C654 UARTs.
161                          * Must check the subsystem VID and DID for correct
162                          * match.
163                          */
164                         subid = pcicfgr16(p, PciSVID);
165                         subid |= pcicfgr16(p, PciSID)<<16;
166                         freq = 7372800;
167                         switch(subid){
168                         default:
169                                 print("uartpci: unknown perle subid %#ux\n", subid);
170                                 continue;
171                         case (0x1588<<16)|0x10B5:       /* StarTech PCI8S9503V (P588UG) */
172                                 name = "P588UG";
173                                 /* max. baud rate is 921,600 */
174                                 freq = 1843200;
175                                 uart = uartpci(ctlrno, p, 2, 8, freq, name, 8);
176                                 break;
177                         case (0x0011<<16)|0x12E0:       /* Perle PCI-Fast16 */
178                                 name = "PCI-Fast16";
179                                 uart = uartpci(ctlrno, p, 2, 16, freq, name, 8);
180                                 break;
181                         case (0x0021<<16)|0x12E0:       /* Perle PCI-Fast8 */
182                                 name = "PCI-Fast8";
183                                 uart = uartpci(ctlrno, p, 2, 8, freq, name, 8);
184                                 break;
185                         case (0x0031<<16)|0x12E0:       /* Perle PCI-Fast4 */
186                                 name = "PCI-Fast4";
187                                 uart = uartpci(ctlrno, p, 2, 4, freq, name, 8);
188                                 break;
189                         case (0x0021<<16)|0x155F:       /* Perle Ultraport8 */
190                                 name = "Ultraport8";    /* 16C754 UARTs */
191                                 uart = uartpci(ctlrno, p, 2, 8, freq, name, 8);
192                                 break;
193                         case (0x0041<<16)|0x155F:       /* Perle Ultraport16 */
194                                 name = "Ultraport16";
195                                 uart = uartpci(ctlrno, p, 2, 16, 2 * freq,
196                                         name, 8);
197                                 break;
198                         case (0x0241<<16)|0x155F:       /* Perle Ultraport16 */
199                                 uart = ultraport16si(ctlrno, p, 4 * freq);
200                                 break;
201                         }
202                         break;
203                 }
204                 if(uart)
205                         ctlrno++;
206         }
207
208         return perlehead;
209 }
210
211 PhysUart pciphysuart = {
212         .name           = "UartPCI",
213         .pnp            = uartpcipnp,
214         .enable         = nil,
215         .disable        = nil,
216         .kick           = nil,
217         .dobreak        = nil,
218         .baud           = nil,
219         .bits           = nil,
220         .stop           = nil,
221         .parity         = nil,
222         .modemctl       = nil,
223         .rts            = nil,
224         .dtr            = nil,
225         .status         = nil,
226         .fifo           = nil,
227 };