1 /* $NetBSD: com_cardbus.c,v 1.15 2005/12/11 12:21:15 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Johan Danielsson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * 3. Neither the name of author nor the names of any contributors may 19 * be used to endorse or promote products derived from this 20 * software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* A driver for CardBus based serial devices. 36 37 If the CardBus device only has one BAR (that is not also the CIS 38 BAR) listed in the CIS, it is assumed to be the one to use. For 39 devices with more than one BAR, the list of known devices has to be 40 updated below. */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: com_cardbus.c,v 1.15 2005/12/11 12:21:15 christos Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/tty.h> 48 #include <sys/device.h> 49 50 #include <dev/cardbus/cardbusvar.h> 51 #include <dev/pci/pcidevs.h> 52 53 #include <dev/pcmcia/pcmciareg.h> 54 55 #include <dev/ic/comreg.h> 56 #include <dev/ic/comvar.h> 57 58 struct com_cardbus_softc { 59 struct com_softc cc_com; 60 void *cc_ih; 61 cardbus_devfunc_t cc_ct; 62 bus_addr_t cc_addr; 63 cardbusreg_t cc_base; 64 bus_size_t cc_size; 65 cardbusreg_t cc_csr; 66 int cc_cben; 67 cardbustag_t cc_tag; 68 cardbusreg_t cc_reg; 69 int cc_type; 70 }; 71 72 #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname) 73 74 static int com_cardbus_match (struct device*, struct cfdata*, void*); 75 static void com_cardbus_attach (struct device*, struct device*, void*); 76 static int com_cardbus_detach (struct device*, int); 77 78 static void com_cardbus_setup(struct com_cardbus_softc*); 79 static int com_cardbus_enable (struct com_softc*); 80 static void com_cardbus_disable(struct com_softc*); 81 82 CFATTACH_DECL(com_cardbus, sizeof(struct com_cardbus_softc), 83 com_cardbus_match, com_cardbus_attach, com_cardbus_detach, com_activate); 84 85 static struct csdev { 86 int vendor; 87 int product; 88 cardbusreg_t reg; 89 int type; 90 } csdevs[] = { 91 { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56, 92 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }, 93 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56, 94 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }, 95 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656_M, 96 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }, 97 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656B_M, 98 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }, 99 { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656C_M, 100 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }, 101 }; 102 103 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]); 104 105 static struct csdev* 106 find_csdev(struct cardbus_attach_args *ca) 107 { 108 struct csdev *cp; 109 110 for(cp = csdevs; cp < csdevs + ncsdevs; cp++) 111 if(cp->vendor == CARDBUS_VENDOR(ca->ca_id) && 112 cp->product == CARDBUS_PRODUCT(ca->ca_id)) 113 return cp; 114 return NULL; 115 } 116 117 static int 118 com_cardbus_match(struct device *parent, struct cfdata *match, void *aux) 119 { 120 struct cardbus_attach_args *ca = aux; 121 122 /* known devices are ok */ 123 if(find_csdev(ca) != NULL) 124 return 10; 125 126 /* as are serial devices with a known UART */ 127 if(ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL && 128 ca->ca_cis.funce.serial.uart_present != 0 && 129 (ca->ca_cis.funce.serial.uart_type == 0 || /* 8250 */ 130 ca->ca_cis.funce.serial.uart_type == 1 || /* 16450 */ 131 ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */ 132 return 1; 133 134 return 0; 135 } 136 137 static int 138 gofigure(struct cardbus_attach_args *ca, struct com_cardbus_softc *csc) 139 { 140 int i, index = -1; 141 cardbusreg_t cis_ptr; 142 struct csdev *cp; 143 144 /* If this device is listed above, use the known values, */ 145 cp = find_csdev(ca); 146 if(cp != NULL) { 147 csc->cc_reg = cp->reg; 148 csc->cc_type = cp->type; 149 return 0; 150 } 151 152 cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG); 153 154 /* otherwise try to deduce which BAR and type to use from CIS. If 155 there is only one BAR, it must be the one we should use, if 156 there are more, we're out of luck. */ 157 for(i = 0; i < 7; i++) { 158 /* ignore zero sized BARs */ 159 if(ca->ca_cis.bar[i].size == 0) 160 continue; 161 /* ignore the CIS BAR */ 162 if(CARDBUS_CIS_ASI_BAR(cis_ptr) == 163 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags)) 164 continue; 165 if(index != -1) 166 goto multi_bar; 167 index = i; 168 } 169 if(index == -1) { 170 printf(": couldn't find any base address tuple\n"); 171 return 1; 172 } 173 csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags); 174 if ((ca->ca_cis.bar[index].flags & 0x10) == 0) 175 csc->cc_type = CARDBUS_MAPREG_TYPE_MEM; 176 else 177 csc->cc_type = CARDBUS_MAPREG_TYPE_IO; 178 return 0; 179 180 multi_bar: 181 printf(": there are more than one possible base\n"); 182 183 printf("%s: address for this device, " 184 "please report the following information\n", 185 DEVNAME(csc)); 186 printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc), 187 CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id)); 188 for(i = 0; i < 7; i++) { 189 /* ignore zero sized BARs */ 190 if(ca->ca_cis.bar[i].size == 0) 191 continue; 192 /* ignore the CIS BAR */ 193 if(CARDBUS_CIS_ASI_BAR(cis_ptr) == 194 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags)) 195 continue; 196 printf("%s: base address %x type %s size %x\n", 197 DEVNAME(csc), 198 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags), 199 (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem", 200 ca->ca_cis.bar[i].size); 201 } 202 return 1; 203 } 204 205 static void 206 com_cardbus_attach (struct device *parent, struct device *self, void *aux) 207 { 208 struct com_softc *sc = (struct com_softc*)self; 209 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self; 210 struct cardbus_attach_args *ca = aux; 211 212 csc->cc_ct = ca->ca_ct; 213 csc->cc_tag = Cardbus_make_tag(csc->cc_ct); 214 215 if(gofigure(ca, csc) != 0) 216 return; 217 218 if(Cardbus_mapreg_map(ca->ca_ct, 219 csc->cc_reg, 220 csc->cc_type, 221 0, 222 &sc->sc_iot, 223 &sc->sc_ioh, 224 &csc->cc_addr, 225 &csc->cc_size) != 0) { 226 printf("failed to map memory"); 227 return; 228 } 229 230 csc->cc_base = csc->cc_addr; 231 csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE; 232 if(csc->cc_type == CARDBUS_MAPREG_TYPE_IO) { 233 csc->cc_base |= CARDBUS_MAPREG_TYPE_IO; 234 csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE; 235 csc->cc_cben = CARDBUS_IO_ENABLE; 236 } else { 237 csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE; 238 csc->cc_cben = CARDBUS_MEM_ENABLE; 239 } 240 sc->sc_iobase = csc->cc_addr; 241 242 sc->sc_frequency = COM_FREQ; 243 244 sc->enable = com_cardbus_enable; 245 sc->disable = com_cardbus_disable; 246 sc->enabled = 0; 247 248 if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) { 249 printf(": %s %s\n", ca->ca_cis.cis1_info[0], 250 ca->ca_cis.cis1_info[1]); 251 printf("%s", DEVNAME(csc)); 252 } 253 254 com_cardbus_setup(csc); 255 256 com_attach_subr(sc); 257 258 Cardbus_function_disable(csc->cc_ct); 259 } 260 261 static void 262 com_cardbus_setup(struct com_cardbus_softc *csc) 263 { 264 cardbus_devfunc_t ct = csc->cc_ct; 265 cardbus_chipset_tag_t cc = ct->ct_cc; 266 cardbus_function_tag_t cf = ct->ct_cf; 267 cardbusreg_t reg; 268 269 Cardbus_conf_write(ct, csc->cc_tag, csc->cc_reg, csc->cc_base); 270 271 /* enable accesses on cardbus bridge */ 272 (*cf->cardbus_ctrl)(cc, csc->cc_cben); 273 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 274 275 /* and the card itself */ 276 reg = Cardbus_conf_read(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG); 277 reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE); 278 reg |= csc->cc_csr; 279 Cardbus_conf_write(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg); 280 281 /* 282 * Make sure the latency timer is set to some reasonable 283 * value. 284 */ 285 reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG); 286 if (CARDBUS_LATTIMER(reg) < 0x20) { 287 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT); 288 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT); 289 cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg); 290 } 291 } 292 293 static int 294 com_cardbus_enable(struct com_softc *sc) 295 { 296 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc; 297 struct cardbus_softc *psc = 298 (struct cardbus_softc *)sc->sc_dev.dv_parent; 299 cardbus_chipset_tag_t cc = psc->sc_cc; 300 cardbus_function_tag_t cf = psc->sc_cf; 301 302 Cardbus_function_enable(csc->cc_ct); 303 304 com_cardbus_setup(csc); 305 306 /* establish the interrupt. */ 307 csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline, 308 IPL_SERIAL, comintr, sc); 309 if (csc->cc_ih == NULL) { 310 printf("%s: couldn't establish interrupt\n", 311 DEVNAME(csc)); 312 return 1; 313 } 314 315 printf("%s: interrupting at irq %d\n", 316 DEVNAME(csc), psc->sc_intrline); 317 318 return 0; 319 } 320 321 static void 322 com_cardbus_disable(struct com_softc *sc) 323 { 324 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc; 325 struct cardbus_softc *psc = 326 (struct cardbus_softc *)sc->sc_dev.dv_parent; 327 cardbus_chipset_tag_t cc = psc->sc_cc; 328 cardbus_function_tag_t cf = psc->sc_cf; 329 330 cardbus_intr_disestablish(cc, cf, csc->cc_ih); 331 csc->cc_ih = NULL; 332 333 Cardbus_function_disable(csc->cc_ct); 334 } 335 336 static int 337 com_cardbus_detach(struct device *self, int flags) 338 { 339 struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self; 340 struct com_softc *sc = (struct com_softc *) self; 341 struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent; 342 int error; 343 344 if ((error = com_detach(self, flags)) != 0) 345 return error; 346 347 if (csc->cc_ih != NULL) 348 cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih); 349 350 Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh, 351 csc->cc_size); 352 353 return 0; 354 } 355