com_cardbus.c revision 1.2       1  1.2  joda /* $NetBSD: com_cardbus.c,v 1.2 2000/04/13 16:17:55 joda Exp $ */
      2  1.1  joda 
      3  1.1  joda /*
      4  1.1  joda  * Copyright (c) 2000 Johan Danielsson
      5  1.1  joda  * All rights reserved.
      6  1.1  joda  *
      7  1.1  joda  * Redistribution and use in source and binary forms, with or without
      8  1.1  joda  * modification, are permitted provided that the following conditions
      9  1.1  joda  * are met:
     10  1.1  joda  *
     11  1.1  joda  * 1. Redistributions of source code must retain the above copyright
     12  1.1  joda  *    notice, this list of conditions and the following disclaimer.
     13  1.1  joda  *
     14  1.1  joda  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.1  joda  *    notice, this list of conditions and the following disclaimer in the
     16  1.1  joda  *    documentation and/or other materials provided with the distribution.
     17  1.1  joda  *
     18  1.1  joda  * 3. Neither the name of author nor the names of any contributors may
     19  1.1  joda  *    be used to endorse or promote products derived from this
     20  1.1  joda  *    software without specific prior written permission.
     21  1.1  joda  *
     22  1.1  joda  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     23  1.1  joda  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  1.1  joda  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     25  1.1  joda  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
     26  1.1  joda  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     27  1.1  joda  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     28  1.1  joda  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     29  1.1  joda  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     30  1.1  joda  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     31  1.1  joda  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     32  1.1  joda  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33  1.1  joda  */
     34  1.1  joda 
     35  1.1  joda /* This is a driver for CardBus based serial devices. It is less
     36  1.1  joda    generic than it could be, but it keeps the complexity down. So far
     37  1.1  joda    it assumes that anything that reports itself as a `serial' device
     38  1.1  joda    is infact a 16x50 or 8250, which is not necessarily true (in
     39  1.1  joda    practice this shouldn't be a problem). It also does not handle
     40  1.1  joda    devices in the `multiport serial' or `modem' sub-classes, I've
     41  1.1  joda    never seen any of thise, so I don't know what they might look like.
     42  1.1  joda 
     43  1.1  joda    If the CardBus device only has one BAR (that is not also the CIS
     44  1.1  joda    BAR) listed in the CIS, it is assumed to be the one to use. For
     45  1.1  joda    devices with more than one BAR, the list of known devies has to be
     46  1.1  joda    updated below.  */
     47  1.1  joda 
     48  1.1  joda #include <sys/param.h>
     49  1.1  joda #include <sys/systm.h>
     50  1.1  joda #include <sys/tty.h>
     51  1.1  joda #include <sys/device.h>
     52  1.1  joda 
     53  1.1  joda #include <dev/cardbus/cardbusvar.h>
     54  1.1  joda #include <dev/cardbus/cardbusdevs.h>
     55  1.1  joda 
     56  1.1  joda #include <dev/ic/comreg.h>
     57  1.1  joda #include <dev/ic/comvar.h>
     58  1.1  joda 
     59  1.1  joda struct com_cardbus_softc {
     60  1.1  joda 	struct com_softc	cc_com;
     61  1.1  joda 	void			*cc_ih;
     62  1.1  joda 	cardbus_devfunc_t	cc_ct;
     63  1.1  joda 	bus_addr_t		cc_addr;
     64  1.1  joda 	cardbusreg_t		cc_base;
     65  1.1  joda 	bus_size_t		cc_size;
     66  1.1  joda 	cardbusreg_t		cc_csr;
     67  1.1  joda 	int			cc_cben;
     68  1.1  joda 	cardbustag_t		cc_tag;
     69  1.1  joda 	cardbusreg_t		cc_reg;
     70  1.1  joda 	int			cc_type;
     71  1.1  joda };
     72  1.1  joda 
     73  1.1  joda #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)
     74  1.1  joda 
     75  1.1  joda static int com_cardbus_match (struct device*, struct cfdata*, void*);
     76  1.1  joda static void com_cardbus_attach (struct device*, struct device*, void*);
     77  1.1  joda static int com_cardbus_detach (struct device*, int);
     78  1.1  joda 
     79  1.1  joda static void com_cardbus_setup(struct com_cardbus_softc*);
     80  1.1  joda static int com_cardbus_enable (struct com_softc*);
     81  1.1  joda static void com_cardbus_disable (struct com_softc*);
     82  1.1  joda 
     83  1.1  joda struct cfattach com_cardbus_ca = {
     84  1.1  joda 	sizeof(struct com_cardbus_softc), com_cardbus_match,
     85  1.1  joda 	com_cardbus_attach, com_cardbus_detach, com_activate
     86  1.1  joda };
     87  1.1  joda 
     88  1.1  joda static struct csdev {
     89  1.1  joda 	int		vendor;
     90  1.1  joda 	int		product;
     91  1.1  joda 	cardbusreg_t	reg;
     92  1.1  joda 	int		type;
     93  1.1  joda } csdevs[] = {
     94  1.1  joda 	/* example entry */
     95  1.1  joda 	{ CARDBUS_VENDOR_XIRCOM, CARDBUS_PRODUCT_XIRCOM_MODEM56,
     96  1.1  joda 	  CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }
     97  1.1  joda };
     98  1.1  joda 
     99  1.1  joda static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
    100  1.1  joda 
    101  1.1  joda static struct csdev*
    102  1.1  joda find_csdev(struct cardbus_attach_args *ca)
    103  1.1  joda {
    104  1.1  joda 	struct csdev *cp;
    105  1.1  joda 
    106  1.1  joda 	for(cp = csdevs; cp < csdevs + ncsdevs; cp++)
    107  1.1  joda 		if(cp->vendor == CARDBUS_VENDOR(ca->ca_id) &&
    108  1.1  joda 		   cp->product == CARDBUS_PRODUCT(ca->ca_id))
    109  1.1  joda 			return cp;
    110  1.1  joda 	return NULL;
    111  1.1  joda }
    112  1.1  joda 
    113  1.1  joda static int
    114  1.1  joda com_cardbus_match(struct device *parent, struct cfdata *match, void *aux)
    115  1.1  joda {
    116  1.1  joda 	struct cardbus_attach_args *ca = aux;
    117  1.1  joda 
    118  1.1  joda 	if(CARDBUS_CLASS(ca->ca_class) == CARDBUS_CLASS_COMMUNICATIONS &&
    119  1.1  joda 	   CARDBUS_SUBCLASS(ca->ca_class) == CARDBUS_SUBCLASS_COMMUNICATIONS_SERIAL) {
    120  1.1  joda 		if(find_csdev(ca) != NULL)
    121  1.1  joda 			return 10;
    122  1.1  joda 		return 1;
    123  1.1  joda 	}
    124  1.1  joda 	return 0;
    125  1.1  joda }
    126  1.1  joda 
    127  1.1  joda static int
    128  1.1  joda gofigure(struct cardbus_attach_args *ca, struct com_cardbus_softc *csc)
    129  1.1  joda {
    130  1.1  joda 	int i, index = -1;
    131  1.1  joda 	cardbusreg_t cis_ptr;
    132  1.1  joda 	struct csdev *cp;
    133  1.1  joda 
    134  1.1  joda 	/* If this device is listed above, use the known values, */
    135  1.1  joda 	cp = find_csdev(ca);
    136  1.1  joda 	if(cp != NULL) {
    137  1.1  joda 		csc->cc_reg = cp->reg;
    138  1.1  joda 		csc->cc_type = cp->type;
    139  1.1  joda 		return 0;
    140  1.1  joda 	}
    141  1.1  joda 
    142  1.1  joda 	cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
    143  1.1  joda 
    144  1.1  joda 	/* otherwise try to deduce which BAR and type to use from CIS.  If
    145  1.1  joda 	   there is only one BAR, it must be the one we should use, if
    146  1.1  joda 	   there are more, we're out of luck.  */
    147  1.1  joda 	for(i = 0; i < 7; i++) {
    148  1.1  joda 		/* ignore zero sized BARs */
    149  1.1  joda 		if(ca->ca_cis.bar[i].size == 0)
    150  1.1  joda 			continue;
    151  1.1  joda 		/* ignore the CIS BAR */
    152  1.1  joda 		if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
    153  1.1  joda 		   CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
    154  1.1  joda 			continue;
    155  1.1  joda 		if(index != -1)
    156  1.1  joda 			goto multi_bar;
    157  1.1  joda 		index = i;
    158  1.1  joda 	}
    159  1.1  joda 	if(index == -1) {
    160  1.1  joda 		printf(": couldn't find any base address tuple\n");
    161  1.1  joda 		return 1;
    162  1.1  joda 	}
    163  1.1  joda 	csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
    164  1.1  joda 	if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
    165  1.1  joda 		csc->cc_type = CARDBUS_MAPREG_TYPE_MEM;
    166  1.1  joda 	else
    167  1.1  joda 		csc->cc_type = CARDBUS_MAPREG_TYPE_IO;
    168  1.1  joda 	return 0;
    169  1.1  joda 
    170  1.1  joda   multi_bar:
    171  1.1  joda 	printf(": there are more than one possible base\n");
    172  1.1  joda 
    173  1.1  joda 	printf("%s: address for this device, "
    174  1.1  joda 	       "please report the following information\n",
    175  1.1  joda 	       DEVNAME(csc));
    176  1.1  joda 	printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
    177  1.1  joda 	       CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id));
    178  1.1  joda 	for(i = 0; i < 7; i++) {
    179  1.1  joda 		/* ignore zero sized BARs */
    180  1.1  joda 		if(ca->ca_cis.bar[i].size == 0)
    181  1.1  joda 			continue;
    182  1.1  joda 		/* ignore the CIS BAR */
    183  1.1  joda 		if(CARDBUS_CIS_ASI_BAR(cis_ptr) ==
    184  1.1  joda 		   CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
    185  1.1  joda 			continue;
    186  1.1  joda 		printf("%s: base address %x type %s size %x\n",
    187  1.1  joda 		       DEVNAME(csc),
    188  1.1  joda 		       CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
    189  1.1  joda 		       (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
    190  1.1  joda 		       ca->ca_cis.bar[i].size);
    191  1.1  joda 	}
    192  1.1  joda 	return 1;
    193  1.1  joda }
    194  1.1  joda 
    195  1.1  joda static void
    196  1.1  joda com_cardbus_attach (struct device *parent, struct device *self, void *aux)
    197  1.1  joda {
    198  1.1  joda 	struct com_softc *sc = (struct com_softc*)self;
    199  1.1  joda 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
    200  1.1  joda 	struct cardbus_attach_args *ca = aux;
    201  1.1  joda 
    202  1.1  joda 	csc->cc_ct = ca->ca_ct;
    203  1.1  joda 	csc->cc_tag = Cardbus_make_tag(csc->cc_ct);
    204  1.1  joda 
    205  1.1  joda 	if(gofigure(ca, csc) != 0)
    206  1.1  joda 		return;
    207  1.1  joda 
    208  1.1  joda 	if(Cardbus_mapreg_map(ca->ca_ct,
    209  1.1  joda 			      csc->cc_reg,
    210  1.1  joda 			      csc->cc_type,
    211  1.1  joda 			      0,
    212  1.1  joda 			      &sc->sc_iot,
    213  1.1  joda 			      &sc->sc_ioh,
    214  1.1  joda 			      &csc->cc_addr,
    215  1.1  joda 			      &csc->cc_size) != 0) {
    216  1.1  joda 		printf("failed to map memory");
    217  1.1  joda 		return;
    218  1.1  joda 	}
    219  1.1  joda 
    220  1.1  joda 	csc->cc_base = csc->cc_addr;
    221  1.1  joda 	csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
    222  1.1  joda 	if(csc->cc_type == CARDBUS_MAPREG_TYPE_IO) {
    223  1.1  joda 		csc->cc_base |= CARDBUS_MAPREG_TYPE_IO;
    224  1.1  joda 		csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE;
    225  1.1  joda 		csc->cc_cben = CARDBUS_IO_ENABLE;
    226  1.1  joda 	} else {
    227  1.1  joda 		csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
    228  1.1  joda 		csc->cc_cben = CARDBUS_MEM_ENABLE;
    229  1.1  joda 	}
    230  1.1  joda 	sc->sc_iobase = csc->cc_addr;
    231  1.1  joda 
    232  1.1  joda 	sc->sc_frequency = COM_FREQ;
    233  1.1  joda 
    234  1.1  joda 	sc->enable = com_cardbus_enable;
    235  1.1  joda 	sc->disable = com_cardbus_disable;
    236  1.1  joda 	sc->enabled = 0;
    237  1.1  joda 
    238  1.1  joda 	if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
    239  1.1  joda 		printf(": %s %s\n", ca->ca_cis.cis1_info[0],
    240  1.1  joda 		    ca->ca_cis.cis1_info[1]);
    241  1.1  joda 		printf("%s", DEVNAME(csc));
    242  1.1  joda 	}
    243  1.1  joda 
    244  1.1  joda 	com_cardbus_setup(csc);
    245  1.1  joda 
    246  1.1  joda 	com_attach_subr(sc);
    247  1.2  joda 
    248  1.2  joda 	Cardbus_function_disable(csc->cc_ct);
    249  1.1  joda }
    250  1.1  joda 
    251  1.1  joda static void
    252  1.1  joda com_cardbus_setup(struct com_cardbus_softc *csc)
    253  1.1  joda {
    254  1.1  joda         cardbus_devfunc_t ct = csc->cc_ct;
    255  1.1  joda         cardbus_chipset_tag_t cc = ct->ct_cc;
    256  1.1  joda         cardbus_function_tag_t cf = ct->ct_cf;
    257  1.1  joda 	cardbusreg_t reg;
    258  1.1  joda 
    259  1.1  joda 	Cardbus_conf_write(ct, csc->cc_tag, csc->cc_reg, csc->cc_base);
    260  1.1  joda 
    261  1.1  joda 	/* enable accesses on cardbus bridge */
    262  1.1  joda 	(*cf->cardbus_ctrl)(cc, csc->cc_cben);
    263  1.1  joda 	(*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
    264  1.1  joda 
    265  1.1  joda 	/* and the card itself */
    266  1.1  joda 	reg = Cardbus_conf_read(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG);
    267  1.1  joda 	reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE);
    268  1.1  joda 	reg |= csc->cc_csr;
    269  1.1  joda 	Cardbus_conf_write(ct, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
    270  1.1  joda 
    271  1.1  joda         /*
    272  1.1  joda          * Make sure the latency timer is set to some reasonable
    273  1.1  joda          * value.
    274  1.1  joda          */
    275  1.1  joda         reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG);
    276  1.1  joda         if (CARDBUS_LATTIMER(reg) < 0x20) {
    277  1.1  joda                 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
    278  1.1  joda                 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
    279  1.1  joda                 cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg);
    280  1.1  joda         }
    281  1.1  joda }
    282  1.1  joda 
    283  1.1  joda static int
    284  1.1  joda com_cardbus_enable(struct com_softc *sc)
    285  1.1  joda {
    286  1.1  joda 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
    287  1.1  joda 	struct cardbus_softc *psc =
    288  1.1  joda 		(struct cardbus_softc *)sc->sc_dev.dv_parent;
    289  1.1  joda 	cardbus_chipset_tag_t cc = psc->sc_cc;
    290  1.1  joda 	cardbus_function_tag_t cf = psc->sc_cf;
    291  1.1  joda 
    292  1.1  joda 	Cardbus_function_enable(csc->cc_ct);
    293  1.1  joda 
    294  1.1  joda 	com_cardbus_setup(csc);
    295  1.1  joda 
    296  1.1  joda 	/* establish the interrupt. */
    297  1.1  joda 	csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
    298  1.1  joda 					    IPL_SERIAL, comintr, sc);
    299  1.1  joda 	if (csc->cc_ih == NULL) {
    300  1.1  joda 		printf("%s: couldn't establish interrupt\n",
    301  1.1  joda 		       DEVNAME(csc));
    302  1.1  joda 		return 1;
    303  1.1  joda 	}
    304  1.1  joda 
    305  1.1  joda 	printf("%s: interrupting at irq %d\n",
    306  1.1  joda 	       DEVNAME(csc), psc->sc_intrline);
    307  1.1  joda 
    308  1.1  joda 	return 0;
    309  1.1  joda }
    310  1.1  joda 
    311  1.1  joda static void
    312  1.1  joda com_cardbus_disable(struct com_softc *sc)
    313  1.1  joda {
    314  1.1  joda 	struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
    315  1.1  joda 	struct cardbus_softc *psc =
    316  1.1  joda 		(struct cardbus_softc *)sc->sc_dev.dv_parent;
    317  1.1  joda 	cardbus_chipset_tag_t cc = psc->sc_cc;
    318  1.1  joda 	cardbus_function_tag_t cf = psc->sc_cf;
    319  1.1  joda 
    320  1.1  joda 	cardbus_intr_disestablish(cc, cf, csc->cc_ih);
    321  1.1  joda 	Cardbus_function_disable(csc->cc_ct);
    322  1.1  joda }
    323  1.1  joda 
    324  1.1  joda static int
    325  1.1  joda com_cardbus_detach(struct device *self, int flags)
    326  1.1  joda {
    327  1.1  joda 	struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
    328  1.1  joda 	struct com_softc *sc = (struct com_softc *) self;
    329  1.1  joda 	struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
    330  1.1  joda 	int error;
    331  1.1  joda 
    332  1.1  joda 	if ((error = com_detach(self, flags)) != 0)
    333  1.1  joda 		return error;
    334  1.1  joda 
    335  1.1  joda 	cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
    336  1.1  joda 
    337  1.1  joda 	Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
    338  1.1  joda 			     csc->cc_size);
    339  1.1  joda 
    340  1.1  joda 	return 0;
    341  1.1  joda }
    342