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