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