Home | History | Annotate | Line # | Download | only in cardbus
com_cardbus.c revision 1.26
      1 /* $NetBSD: com_cardbus.c,v 1.26 2010/02/25 22:31:51 dyoung 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.26 2010/02/25 22:31:51 dyoung 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 	cardbus_intr_line_t	cc_intrline;
     61 	void			*cc_ih;
     62 	cardbus_devfunc_t	cc_ct;
     63 	bus_addr_t		cc_addr;
     64 	pcireg_t		cc_base;
     65 	bus_size_t		cc_size;
     66 	pcireg_t		cc_csr;
     67 	int			cc_cben;
     68 	pcitag_t		cc_tag;
     69 	pcireg_t		cc_reg;
     70 	int			cc_type;
     71 };
     72 
     73 #define DEVICET(CSC) ((CSC)->cc_com.sc_dev)
     74 
     75 static int com_cardbus_match (device_t, cfdata_t, void*);
     76 static void com_cardbus_attach (device_t, device_t, void*);
     77 static int com_cardbus_detach (device_t, int);
     78 
     79 static void com_cardbus_setup(struct com_cardbus_softc*);
     80 static int com_cardbus_enable (struct com_softc*);
     81 static void com_cardbus_disable(struct com_softc*);
     82 
     83 CFATTACH_DECL_NEW(com_cardbus, sizeof(struct com_cardbus_softc),
     84     com_cardbus_match, com_cardbus_attach, com_cardbus_detach, NULL);
     85 
     86 static struct csdev {
     87 	int		vendor;
     88 	int		product;
     89 	pcireg_t	reg;
     90 	int		type;
     91 } csdevs[] = {
     92 	{ PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
     93 	  CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
     94 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
     95 	  CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
     96 	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656_M,
     97 	  CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
     98 	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656B_M,
     99 	  CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
    100 	{ PCI_VENDOR_3COM, PCI_PRODUCT_3COM_3C656C_M,
    101 	  CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
    102 };
    103 
    104 static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
    105 
    106 static struct csdev*
    107 find_csdev(struct cardbus_attach_args *ca)
    108 {
    109 	struct csdev *cp;
    110 
    111 	for(cp = csdevs; cp < csdevs + ncsdevs; cp++)
    112 		if(cp->vendor == CARDBUS_VENDOR(ca->ca_id) &&
    113 		   cp->product == CARDBUS_PRODUCT(ca->ca_id))
    114 			return cp;
    115 	return NULL;
    116 }
    117 
    118 static int
    119 com_cardbus_match(device_t parent, cfdata_t match, void *aux)
    120 {
    121 	struct cardbus_attach_args *ca = aux;
    122 
    123 	/* known devices are ok */
    124 	if(find_csdev(ca) != NULL)
    125 	    return 10;
    126 
    127 	/* as are serial devices with a known UART */
    128 	if(ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
    129 	   ca->ca_cis.funce.serial.uart_present != 0 &&
    130 	   (ca->ca_cis.funce.serial.uart_type == 0 ||	/* 8250 */
    131 	    ca->ca_cis.funce.serial.uart_type == 1 ||	/* 16450 */
    132 	    ca->ca_cis.funce.serial.uart_type == 2))	/* 16550 */
    133 	    return 1;
    134 
    135 	return 0;
    136 }
    137 
    138 static int
    139 gofigure(struct cardbus_attach_args *ca, struct com_cardbus_softc *csc)
    140 {
    141 	int i, index = -1;
    142 	pcireg_t cis_ptr;
    143 	struct csdev *cp;
    144 
    145 	/* If this device is listed above, use the known values, */
    146 	cp = find_csdev(ca);
    147 	if(cp != NULL) {
    148 		csc->cc_reg = cp->reg;
    149 		csc->cc_type = cp->type;
    150 		return 0;
    151 	}
    152 
    153 	cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
    154 
    155 	/* otherwise try to deduce which BAR and type to use from CIS.  If
    156 	   there is only one BAR, it must be the one we should use, if
    157 	   there are more, we're out of luck.  */
    158 	for(i = 0; i < 7; i++) {
    159 		/* ignore zero sized BARs */
    160 		if(ca->ca_cis.bar[i].size == 0)
    161 			continue;
    162 		/* ignore the CIS BAR */
    163 		if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
    164 		   CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
    165 			continue;
    166 		if(index != -1)
    167 			goto multi_bar;
    168 		index = i;
    169 	}
    170 	if(index == -1) {
    171 		aprint_error(": couldn't find any base address tuple\n");
    172 		return 1;
    173 	}
    174 	csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
    175 	if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
    176 		csc->cc_type = CARDBUS_MAPREG_TYPE_MEM;
    177 	else
    178 		csc->cc_type = CARDBUS_MAPREG_TYPE_IO;
    179 	return 0;
    180 
    181   multi_bar:
    182 	aprint_error(": there are more than one possible base\n");
    183 
    184 	aprint_error_dev(DEVICET(csc), "address for this device, "
    185 	       "please report the following information\n");
    186 	aprint_error_dev(DEVICET(csc), "vendor 0x%x product 0x%x\n",
    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 		aprint_error_dev(DEVICET(csc),
    197 		       "base address %x type %s size %x\n",
    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 (device_t parent, device_t self, void *aux)
    207 {
    208 	struct com_softc *sc = device_private(self);
    209 	struct com_cardbus_softc *csc = device_private(self);
    210 	struct cardbus_attach_args *ca = aux;
    211 	bus_space_handle_t	ioh;
    212 	bus_space_tag_t		iot;
    213 
    214 	sc->sc_dev = self;
    215 	csc->cc_intrline = ca->ca_intrline;
    216 	csc->cc_ct = ca->ca_ct;
    217 	csc->cc_tag = ca->ca_tag;
    218 
    219 	if(gofigure(ca, csc) != 0)
    220 		return;
    221 
    222 	if(Cardbus_mapreg_map(ca->ca_ct,
    223 			      csc->cc_reg,
    224 			      csc->cc_type,
    225 			      0,
    226 			      &iot,
    227 			      &ioh,
    228 			      &csc->cc_addr,
    229 			      &csc->cc_size) != 0) {
    230 		aprint_error("failed to map memory");
    231 		return;
    232 	}
    233 
    234 	COM_INIT_REGS(sc->sc_regs, iot, ioh, csc->cc_addr);
    235 
    236 	csc->cc_base = csc->cc_addr;
    237 	csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
    238 	if(csc->cc_type == CARDBUS_MAPREG_TYPE_IO) {
    239 		csc->cc_base |= CARDBUS_MAPREG_TYPE_IO;
    240 		csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE;
    241 		csc->cc_cben = CARDBUS_IO_ENABLE;
    242 	} else {
    243 		csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
    244 		csc->cc_cben = CARDBUS_MEM_ENABLE;
    245 	}
    246 
    247 	sc->sc_frequency = COM_FREQ;
    248 
    249 	sc->enable = com_cardbus_enable;
    250 	sc->disable = com_cardbus_disable;
    251 	sc->enabled = 0;
    252 
    253 	if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
    254 		aprint_normal(": %s %s\n", ca->ca_cis.cis1_info[0],
    255 		    ca->ca_cis.cis1_info[1]);
    256 		aprint_normal("%s", device_xname(DEVICET(csc)));
    257 	}
    258 
    259 	com_cardbus_setup(csc);
    260 
    261 	com_attach_subr(sc);
    262 
    263 	Cardbus_function_disable(csc->cc_ct);
    264 }
    265 
    266 static void
    267 com_cardbus_setup(struct com_cardbus_softc *csc)
    268 {
    269         cardbus_devfunc_t ct = csc->cc_ct;
    270         cardbus_chipset_tag_t cc = ct->ct_cc;
    271         cardbus_function_tag_t cf = ct->ct_cf;
    272 	pcireg_t reg;
    273 
    274 	Cardbus_conf_write(ct, csc->cc_tag, csc->cc_reg, csc->cc_base);
    275 
    276 	/* enable accesses on cardbus bridge */
    277 	(*cf->cardbus_ctrl)(cc, csc->cc_cben);
    278 	(*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
    279 
    280 	/* and the card itself */
    281 	reg = Cardbus_conf_read(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG);
    282 	reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE);
    283 	reg |= csc->cc_csr;
    284 	Cardbus_conf_write(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
    285 
    286         /*
    287          * Make sure the latency timer is set to some reasonable
    288          * value.
    289          */
    290         reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG);
    291         if (CARDBUS_LATTIMER(reg) < 0x20) {
    292                 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
    293                 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
    294                 cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg);
    295         }
    296 }
    297 
    298 static int
    299 com_cardbus_enable(struct com_softc *sc)
    300 {
    301 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
    302 	cardbus_devfunc_t ct = csc->cc_ct;
    303 	cardbus_chipset_tag_t cc = ct->ct_cc;
    304 	cardbus_function_tag_t cf = ct->ct_cf;
    305 
    306 	Cardbus_function_enable(ct);
    307 
    308 	com_cardbus_setup(csc);
    309 
    310 	/* establish the interrupt. */
    311 	csc->cc_ih = cardbus_intr_establish(cc, cf, csc->cc_intrline,
    312 					    IPL_SERIAL, comintr, sc);
    313 	if (csc->cc_ih == NULL) {
    314 		aprint_error_dev(DEVICET(csc),
    315 		    "couldn't establish interrupt\n");
    316 		return 1;
    317 	}
    318 
    319 	return 0;
    320 }
    321 
    322 static void
    323 com_cardbus_disable(struct com_softc *sc)
    324 {
    325 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
    326 	cardbus_devfunc_t ct = csc->cc_ct;
    327 	cardbus_chipset_tag_t cc = ct->ct_cc;
    328 	cardbus_function_tag_t cf = ct->ct_cf;
    329 
    330 	cardbus_intr_disestablish(cc, cf, csc->cc_ih);
    331 	csc->cc_ih = NULL;
    332 
    333 	Cardbus_function_disable(ct);
    334 }
    335 
    336 static int
    337 com_cardbus_detach(device_t self, int flags)
    338 {
    339 	struct com_cardbus_softc *csc = device_private(self);
    340 	struct com_softc *sc = device_private(self);
    341 	cardbus_devfunc_t ct = csc->cc_ct;
    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(ct->ct_cc, ct->ct_cf, csc->cc_ih);
    349 
    350 	Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_regs.cr_iot,
    351 	    sc->sc_regs.cr_ioh, csc->cc_size);
    352 
    353 	return 0;
    354 }
    355