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