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