1 | /* $NetBSD: puccn.c,v 1.14 2014/03/05 05:56:04 msaitoh Exp $ */ |
2 | |
3 | /* |
4 | * Derived from pci.c |
5 | * Copyright (c) 2000 Geocast Networks Systems. All rights reserved. |
6 | * |
7 | * Copyright (c) 1995, 1996, 1997, 1998 |
8 | * Christopher G. Demetriou. All rights reserved. |
9 | * Copyright (c) 1994 Charles M. Hannum. All rights reserved. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. |
19 | * 3. All advertising materials mentioning features or use of this software |
20 | * must display the following acknowledgement: |
21 | * This product includes software developed by Charles M. Hannum. |
22 | * 4. The name of the author may not be used to endorse or promote products |
23 | * derived from this software without specific prior written permission. |
24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
26 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
27 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
28 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
29 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
30 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | */ |
36 | |
37 | |
38 | /* |
39 | * Machine independent support for PCI serial console support. |
40 | * |
41 | * Scan the PCI bus for something which resembles a 16550 |
42 | */ |
43 | |
44 | #include <sys/cdefs.h> |
45 | __KERNEL_RCSID(0, "$NetBSD: puccn.c,v 1.14 2014/03/05 05:56:04 msaitoh Exp $" ); |
46 | |
47 | #include "opt_kgdb.h" |
48 | |
49 | #include <sys/param.h> |
50 | #include <sys/systm.h> |
51 | #include <sys/conf.h> |
52 | #include <sys/device.h> |
53 | |
54 | #include <dev/pci/pcireg.h> |
55 | #include <dev/pci/pcivar.h> |
56 | #include <dev/pci/pcidevs.h> |
57 | |
58 | #include <sys/termios.h> |
59 | #include <dev/ic/comreg.h> |
60 | #include <dev/ic/comvar.h> |
61 | |
62 | #include <dev/cons.h> |
63 | |
64 | #include <dev/pci/pucvar.h> |
65 | #include <dev/pci/puccn.h> |
66 | |
67 | #ifndef CONSPEED |
68 | #define CONSPEED TTYDEF_SPEED |
69 | #endif |
70 | #ifndef CONMODE |
71 | #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE|CSTOPB|PARENB))|CS8) /* 8N1 */ |
72 | #endif |
73 | |
74 | cons_decl(com); |
75 | |
76 | static bus_addr_t puccnbase; |
77 | static bus_space_tag_t puctag; |
78 | static int puccnflags; |
79 | |
80 | #ifdef KGDB |
81 | static bus_addr_t pucgdbbase; |
82 | #endif |
83 | |
84 | /* |
85 | * Static dev/func variables allow pucprobe to be called multiple times, |
86 | * resuming the search where it left off, never retrying the same adaptor. |
87 | */ |
88 | |
89 | static bus_addr_t |
90 | pucprobe_doit(struct consdev *cn) |
91 | { |
92 | struct pci_attach_args pa; |
93 | int bus; |
94 | static int dev = 0, func = 0; |
95 | int maxdev, nfunctions = 0, i; /* XXX */ |
96 | pcireg_t reg, bhlcr, subsys = 0; /* XXX */ |
97 | int foundport = 0; |
98 | const struct puc_device_description *desc; |
99 | pcireg_t base; |
100 | |
101 | /* Fetch our tags */ |
102 | #if defined(amd64) || defined(i386) |
103 | if (cpu_puc_cnprobe(cn, &pa) != 0) |
104 | #endif |
105 | return 0; |
106 | |
107 | pci_decompose_tag(pa.pa_pc, pa.pa_tag, &bus, &maxdev, NULL); |
108 | |
109 | /* Scan through devices and find a communication class device. */ |
110 | for (; dev <= maxdev ; dev++) { |
111 | pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, 0); |
112 | reg = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG); |
113 | if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID |
114 | || PCI_VENDOR(reg) == 0) |
115 | continue; |
116 | bhlcr = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_BHLC_REG); |
117 | if (PCI_HDRTYPE_MULTIFN(bhlcr)) { |
118 | nfunctions = 8; |
119 | } else { |
120 | nfunctions = 1; |
121 | } |
122 | resume_scan: |
123 | for (; func < nfunctions; func++) { |
124 | pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, func); |
125 | reg = pci_conf_read(pa.pa_pc, pa.pa_tag, |
126 | PCI_CLASS_REG); |
127 | if (PCI_CLASS(reg) == PCI_CLASS_COMMUNICATIONS |
128 | && PCI_SUBCLASS(reg) |
129 | == PCI_SUBCLASS_COMMUNICATIONS_SERIAL) { |
130 | pa.pa_id = pci_conf_read(pa.pa_pc, pa.pa_tag, |
131 | PCI_ID_REG); |
132 | subsys = pci_conf_read(pa.pa_pc, pa.pa_tag, |
133 | PCI_SUBSYS_ID_REG); |
134 | foundport = 1; |
135 | break; |
136 | } |
137 | } |
138 | if (foundport) |
139 | break; |
140 | |
141 | func = 0; |
142 | } |
143 | |
144 | /* |
145 | * If all devices was scanned and couldn't find any communication |
146 | * device, return with 0. |
147 | */ |
148 | if (!foundport) |
149 | return 0; |
150 | |
151 | /* Clear foundport flag */ |
152 | foundport = 0; |
153 | |
154 | /* Check whether the device is in the puc device table or not */ |
155 | desc = puc_find_description(PCI_VENDOR(pa.pa_id), |
156 | PCI_PRODUCT(pa.pa_id), PCI_VENDOR(subsys), PCI_PRODUCT(subsys)); |
157 | |
158 | /* If not, check the next communication device */ |
159 | if (desc == NULL) { |
160 | /* Resume from the next function */ |
161 | func++; |
162 | goto resume_scan; |
163 | } |
164 | |
165 | /* |
166 | * We found a device and it's on the puc table. Set the tag and |
167 | * the base address. |
168 | */ |
169 | for (i = 0; PUC_PORT_VALID(desc, i); i++) { |
170 | if (desc->ports[i].type != PUC_PORT_TYPE_COM) |
171 | continue; |
172 | puccnflags = desc->ports[i].flags; |
173 | base = pci_conf_read(pa.pa_pc, pa.pa_tag, desc->ports[i].bar); |
174 | base += desc->ports[i].offset; |
175 | |
176 | if (PCI_MAPREG_TYPE(base) == PCI_MAPREG_TYPE_IO) { |
177 | puctag = pa.pa_iot; |
178 | base = PCI_MAPREG_IO_ADDR(base); |
179 | } |
180 | #if 0 /* For MMIO device */ |
181 | else { |
182 | puctag = pa.pa_memt; |
183 | base = PCI_MAPREG_MEM_ADDR(base); |
184 | } |
185 | #endif |
186 | |
187 | if (com_is_console(puctag, base, NULL)) |
188 | continue; |
189 | foundport = 1; |
190 | break; |
191 | } |
192 | |
193 | if (foundport == 0) { |
194 | func++; |
195 | goto resume_scan; |
196 | } |
197 | |
198 | #if 0 |
199 | cn->cn_pri = CN_REMOTE; |
200 | #else |
201 | if (cn) |
202 | cn->cn_pri = CN_REMOTE; |
203 | #endif |
204 | return base; |
205 | } |
206 | |
207 | #ifdef KGDB |
208 | void |
209 | puc_gdbprobe(struct consdev *cn) |
210 | { |
211 | |
212 | pucgdbbase = pucprobe_doit(cn); |
213 | } |
214 | |
215 | void |
216 | puc_gdbinit(struct consdev *cn) |
217 | { |
218 | |
219 | if (pucgdbbase == 0) |
220 | return; |
221 | |
222 | com_kgdb_attach(puctag, pucgdbbase, CONSPEED, COM_FREQ, |
223 | COM_TYPE_NORMAL, CONMODE); |
224 | } |
225 | #endif |
226 | |
227 | void |
228 | puc_cnprobe(struct consdev *cn) |
229 | { |
230 | |
231 | puccnbase = pucprobe_doit(cn); |
232 | } |
233 | |
234 | int |
235 | puc_cninit(struct consdev *cn) |
236 | { |
237 | |
238 | if (puccnbase == 0) |
239 | return -1; |
240 | |
241 | return comcnattach(puctag, puccnbase, CONSPEED, |
242 | puccnflags & PUC_COM_CLOCKMASK, COM_TYPE_NORMAL, |
243 | CONMODE); |
244 | } |
245 | |
246 | /* comcngetc, comcnputc, comcnpollc provided by dev/ic/com.c */ |
247 | |