1 /* $NetBSD: puccn.c,v 1.4 2001/11/13 07:48:48 lukem 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.4 2001/11/13 07:48:48 lukem 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 #ifdef i386 /* Handle i386 directly */ 75 int 76 cpu_comcnprobe(struct consdev *cn, struct pci_attach_args *pa) 77 { 78 pci_mode_detect(); 79 pa->pa_iot = I386_BUS_SPACE_IO; 80 pa->pa_pc = 0; 81 pa->pa_tag = pci_make_tag(0, 0, 31, 0); 82 return 0; 83 } 84 #endif 85 86 cons_decl(com); 87 88 static bus_addr_t puccnbase; 89 static bus_space_tag_t puctag; 90 91 #ifdef KGDB 92 static bus_addr_t pucgdbbase; 93 #endif 94 95 /* 96 * Static dev/func variables allow pucprobe to be called multiple times, 97 * resuming the search where it left off, never retrying the same adaptor. 98 */ 99 100 static bus_addr_t 101 pucprobe_doit(struct consdev *cn) 102 { 103 struct pci_attach_args pa; 104 int bus; 105 static int dev = 0, func = 0; 106 int maxdev, nfunctions, i; 107 pcireg_t reg, bhlcr, subsys; 108 int foundport = 0; 109 const struct puc_device_description *desc; 110 pcireg_t base; 111 112 /* Fetch our tags */ 113 if (cpu_comcnprobe(cn, &pa) != 0) { 114 return 0; 115 } 116 puctag = pa.pa_iot; 117 pci_decompose_tag(pa.pa_pc, pa.pa_tag, &bus, &maxdev, NULL); 118 119 /* scan through devices */ 120 121 for (; dev <= maxdev ; dev++) { 122 pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, 0); 123 reg = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG); 124 if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID 125 || PCI_VENDOR(reg) == 0) 126 continue; 127 bhlcr = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_BHLC_REG); 128 if (PCI_HDRTYPE_MULTIFN(bhlcr)) { 129 nfunctions = 8; 130 } else { 131 nfunctions = 1; 132 } 133 resume_scan: 134 for (; func < nfunctions; func++) { 135 pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, func); 136 reg = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_CLASS_REG); 137 if (PCI_CLASS(reg) == PCI_CLASS_COMMUNICATIONS 138 && PCI_SUBCLASS(reg) 139 == PCI_SUBCLASS_COMMUNICATIONS_SERIAL) { 140 pa.pa_id = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG); 141 subsys = pci_conf_read(pa.pa_pc, pa.pa_tag, 142 PCI_SUBSYS_ID_REG); 143 foundport = 1; 144 break; 145 } 146 } 147 if (foundport) 148 break; 149 150 func = 0; 151 } 152 if (!foundport) 153 return 0; 154 foundport = 0; 155 156 desc = puc_find_description(PCI_VENDOR(pa.pa_id), 157 PCI_PRODUCT(pa.pa_id), PCI_VENDOR(subsys), PCI_PRODUCT(subsys)); 158 if (desc == NULL) { 159 func++; 160 goto resume_scan; 161 } 162 163 for (i = 0; PUC_PORT_VALID(desc, i); i++) 164 { 165 if (desc->ports[i].type != PUC_PORT_TYPE_COM) 166 continue; 167 base = pci_conf_read(pa.pa_pc, pa.pa_tag, desc->ports[i].bar); 168 base += desc->ports[i].offset; 169 170 if (PCI_MAPREG_TYPE(base) != PCI_MAPREG_TYPE_IO) 171 continue; 172 base = PCI_MAPREG_IO_ADDR(base); 173 if (com_is_console(puctag, base, NULL)) 174 continue; 175 foundport = 1; 176 break; 177 } 178 179 if (foundport == 0) { 180 func++; 181 goto resume_scan; 182 } 183 184 cn->cn_pri = CN_REMOTE; 185 return PCI_MAPREG_IO_ADDR(base); 186 } 187 188 #ifdef KGDB 189 void comgdbprobe(struct consdev *); 190 void comgdbinit(struct consdev *); 191 192 void 193 comgdbprobe(struct consdev *cn) 194 { 195 pucgdbbase = pucprobe_doit(cn); 196 } 197 198 void 199 comgdbinit(struct consdev *cn) 200 { 201 if (pucgdbbase == 0) { 202 return; 203 } 204 com_kgdb_attach(puctag, pucgdbbase, CONSPEED, COM_FREQ, CONMODE); 205 } 206 #endif 207 208 void 209 comcnprobe(struct consdev *cn) 210 { 211 puccnbase = pucprobe_doit(cn); 212 } 213 214 void 215 comcninit(struct consdev *cn) 216 { 217 if (puccnbase == 0) { 218 return; 219 } 220 comcnattach(puctag, puccnbase, CONSPEED, COM_FREQ, CONMODE); 221 } 222 223 /* comcngetc, comcnputc, comcnpollc provided by dev/ic/com.c */ 224