1 /* $NetBSD: com_cardbus.c,v 1.9 2002/10/02 16:33:41 thorpej 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.9 2002/10/02 16:33:41 thorpej 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/cardbus/cardbusdevs.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 { CARDBUS_VENDOR_XIRCOM, CARDBUS_PRODUCT_XIRCOM_MODEM56, 92 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }, 93 { CARDBUS_VENDOR_INTEL, CARDBUS_PRODUCT_INTEL_MODEM56, 94 CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO } 95 }; 96 97 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]); 98 99 static struct csdev* 100 find_csdev(struct cardbus_attach_args *ca) 101 { 102 struct csdev *cp; 103 104 for(cp = csdevs; cp < csdevs + ncsdevs; cp++) 105 if(cp->vendor == CARDBUS_VENDOR(ca->ca_id) && 106 cp->product == CARDBUS_PRODUCT(ca->ca_id)) 107 return cp; 108 return NULL; 109 } 110 111 static int 112 com_cardbus_match(struct device *parent, struct cfdata *match, void *aux) 113 { 114 struct cardbus_attach_args *ca = aux; 115 116 /* known devices are ok */ 117 if(find_csdev(ca) != NULL) 118 return 10; 119 120 /* as are serial devices with a known UART */ 121 if(ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL && 122 ca->ca_cis.funce.serial.uart_present != 0 && 123 (ca->ca_cis.funce.serial.uart_type == 0 || /* 8250 */ 124 ca->ca_cis.funce.serial.uart_type == 1 || /* 16450 */ 125 ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */ 126 return 1; 127 128 return 0; 129 } 130 131 static int 132 gofigure(struct cardbus_attach_args *ca, struct com_cardbus_softc *csc) 133 { 134 int i, index = -1; 135 cardbusreg_t cis_ptr; 136 struct csdev *cp; 137 138 /* If this device is listed above, use the known values, */ 139 cp = find_csdev(ca); 140 if(cp != NULL) { 141 csc->cc_reg = cp->reg; 142 csc->cc_type = cp->type; 143 return 0; 144 } 145 146 cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG); 147 148 /* otherwise try to deduce which BAR and type to use from CIS. If 149 there is only one BAR, it must be the one we should use, if 150 there are more, we're out of luck. */ 151 for(i = 0; i < 7; i++) { 152 /* ignore zero sized BARs */ 153 if(ca->ca_cis.bar[i].size == 0) 154 continue; 155 /* ignore the CIS BAR */ 156 if(CARDBUS_CIS_ASI_BAR(cis_ptr) == 157 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags)) 158 continue; 159 if(index != -1) 160 goto multi_bar; 161 index = i; 162 } 163 if(index == -1) { 164 printf(": couldn't find any base address tuple\n"); 165 return 1; 166 } 167 csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags); 168 if ((ca->ca_cis.bar[index].flags & 0x10) == 0) 169 csc->cc_type = CARDBUS_MAPREG_TYPE_MEM; 170 else 171 csc->cc_type = CARDBUS_MAPREG_TYPE_IO; 172 return 0; 173 174 multi_bar: 175 printf(": there are more than one possible base\n"); 176 177 printf("%s: address for this device, " 178 "please report the following information\n", 179 DEVNAME(csc)); 180 printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc), 181 CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id)); 182 for(i = 0; i < 7; i++) { 183 /* ignore zero sized BARs */ 184 if(ca->ca_cis.bar[i].size == 0) 185 continue; 186 /* ignore the CIS BAR */ 187 if(CARDBUS_CIS_ASI_BAR(cis_ptr) == 188 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags)) 189 continue; 190 printf("%s: base address %x type %s size %x\n", 191 DEVNAME(csc), 192 CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags), 193 (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem", 194 ca->ca_cis.bar[i].size); 195 } 196 return 1; 197 } 198 199 static void 200 com_cardbus_attach (struct device *parent, struct device *self, void *aux) 201 { 202 struct com_softc *sc = (struct com_softc*)self; 203 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self; 204 struct cardbus_attach_args *ca = aux; 205 206 csc->cc_ct = ca->ca_ct; 207 csc->cc_tag = Cardbus_make_tag(csc->cc_ct); 208 209 if(gofigure(ca, csc) != 0) 210 return; 211 212 if(Cardbus_mapreg_map(ca->ca_ct, 213 csc->cc_reg, 214 csc->cc_type, 215 0, 216 &sc->sc_iot, 217 &sc->sc_ioh, 218 &csc->cc_addr, 219 &csc->cc_size) != 0) { 220 printf("failed to map memory"); 221 return; 222 } 223 224 csc->cc_base = csc->cc_addr; 225 csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE; 226 if(csc->cc_type == CARDBUS_MAPREG_TYPE_IO) { 227 csc->cc_base |= CARDBUS_MAPREG_TYPE_IO; 228 csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE; 229 csc->cc_cben = CARDBUS_IO_ENABLE; 230 } else { 231 csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE; 232 csc->cc_cben = CARDBUS_MEM_ENABLE; 233 } 234 sc->sc_iobase = csc->cc_addr; 235 236 sc->sc_frequency = COM_FREQ; 237 238 sc->enable = com_cardbus_enable; 239 sc->disable = com_cardbus_disable; 240 sc->enabled = 0; 241 242 if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) { 243 printf(": %s %s\n", ca->ca_cis.cis1_info[0], 244 ca->ca_cis.cis1_info[1]); 245 printf("%s", DEVNAME(csc)); 246 } 247 248 com_cardbus_setup(csc); 249 250 com_attach_subr(sc); 251 252 Cardbus_function_disable(csc->cc_ct); 253 } 254 255 static void 256 com_cardbus_setup(struct com_cardbus_softc *csc) 257 { 258 cardbus_devfunc_t ct = csc->cc_ct; 259 cardbus_chipset_tag_t cc = ct->ct_cc; 260 cardbus_function_tag_t cf = ct->ct_cf; 261 cardbusreg_t reg; 262 263 Cardbus_conf_write(ct, csc->cc_tag, csc->cc_reg, csc->cc_base); 264 265 /* enable accesses on cardbus bridge */ 266 (*cf->cardbus_ctrl)(cc, csc->cc_cben); 267 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 268 269 /* and the card itself */ 270 reg = Cardbus_conf_read(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG); 271 reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE); 272 reg |= csc->cc_csr; 273 Cardbus_conf_write(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg); 274 275 /* 276 * Make sure the latency timer is set to some reasonable 277 * value. 278 */ 279 reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG); 280 if (CARDBUS_LATTIMER(reg) < 0x20) { 281 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT); 282 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT); 283 cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg); 284 } 285 } 286 287 static int 288 com_cardbus_enable(struct com_softc *sc) 289 { 290 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc; 291 struct cardbus_softc *psc = 292 (struct cardbus_softc *)sc->sc_dev.dv_parent; 293 cardbus_chipset_tag_t cc = psc->sc_cc; 294 cardbus_function_tag_t cf = psc->sc_cf; 295 296 Cardbus_function_enable(csc->cc_ct); 297 298 com_cardbus_setup(csc); 299 300 /* establish the interrupt. */ 301 csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline, 302 IPL_SERIAL, comintr, sc); 303 if (csc->cc_ih == NULL) { 304 printf("%s: couldn't establish interrupt\n", 305 DEVNAME(csc)); 306 return 1; 307 } 308 309 printf("%s: interrupting at irq %d\n", 310 DEVNAME(csc), psc->sc_intrline); 311 312 return 0; 313 } 314 315 static void 316 com_cardbus_disable(struct com_softc *sc) 317 { 318 struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc; 319 struct cardbus_softc *psc = 320 (struct cardbus_softc *)sc->sc_dev.dv_parent; 321 cardbus_chipset_tag_t cc = psc->sc_cc; 322 cardbus_function_tag_t cf = psc->sc_cf; 323 324 cardbus_intr_disestablish(cc, cf, csc->cc_ih); 325 Cardbus_function_disable(csc->cc_ct); 326 } 327 328 static int 329 com_cardbus_detach(struct device *self, int flags) 330 { 331 struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self; 332 struct com_softc *sc = (struct com_softc *) self; 333 struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent; 334 int error; 335 336 if ((error = com_detach(self, flags)) != 0) 337 return error; 338 339 cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih); 340 341 Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh, 342 csc->cc_size); 343 344 return 0; 345 } 346