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