Home | History | Annotate | Line # | Download | only in isa
i82365_isa.c revision 1.1.2.2
      1 #define PCICISADEBUG
      2 
      3 #include <sys/types.h>
      4 #include <sys/param.h>
      5 #include <sys/systm.h>
      6 #include <sys/device.h>
      7 #include <sys/extent.h>
      8 #include <sys/malloc.h>
      9 
     10 #include <vm/vm.h>
     11 
     12 #include <machine/bus.h>
     13 #include <machine/intr.h>
     14 
     15 #include <dev/isa/isareg.h>
     16 #include <dev/isa/isavar.h>
     17 
     18 #include <dev/pcmcia/pcmciareg.h>
     19 #include <dev/pcmcia/pcmciavar.h>
     20 #include <dev/pcmcia/pcmciachip.h>
     21 
     22 #include <dev/ic/i82365reg.h>
     23 #include <dev/ic/i82365var.h>
     24 
     25 #ifdef PCICISADEBUG
     26 int	pcicisa_debug = 0 /* XXX */;
     27 #define DPRINTF(arg) if (pcicisa_debug) printf arg;
     28 #else
     29 #define DPRINTF(arg)
     30 #endif
     31 
     32 int pcic_isa_probe __P((struct device *, void *, void *));
     33 void pcic_isa_attach __P((struct device *, struct device *, void *));
     34 
     35 void *pcic_isa_chip_intr_establish __P((pcmcia_chipset_handle_t,
     36 					struct pcmcia_function *, int,
     37 					int (*)(void *), void *));
     38 void pcic_isa_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *));
     39 
     40 struct cfattach pcic_isa_ca = {
     41 	sizeof(struct pcic_softc), pcic_isa_probe, pcic_isa_attach
     42 };
     43 
     44 static struct pcmcia_chip_functions pcic_isa_functions = {
     45     pcic_chip_mem_alloc,
     46     pcic_chip_mem_free,
     47     pcic_chip_mem_map,
     48     pcic_chip_mem_unmap,
     49 
     50     pcic_chip_io_alloc,
     51     pcic_chip_io_free,
     52     pcic_chip_io_map,
     53     pcic_chip_io_unmap,
     54 
     55     pcic_isa_chip_intr_establish,
     56     pcic_isa_chip_intr_disestablish,
     57 
     58     pcic_chip_socket_enable,
     59     pcic_chip_socket_disable,
     60 };
     61 
     62 int
     63 pcic_isa_probe(parent, match, aux)
     64 	struct device *parent;
     65 	void *match, *aux;
     66 {
     67     struct isa_attach_args *ia = aux;
     68     bus_space_tag_t iot = ia->ia_iot;
     69     bus_space_handle_t ioh, memh;
     70     int val, found;
     71 
     72     if (bus_space_map(iot, ia->ia_iobase, PCIC_IOSIZE, 0, &ioh))
     73 	return (0);
     74 
     75     if (ia->ia_msize == -1)
     76 	ia->ia_msize = PCIC_MEMSIZE;
     77 
     78     if (bus_space_map(ia->ia_memt, ia->ia_maddr, ia->ia_msize, 0, &memh))
     79 	return (0);
     80 
     81     found = 0;
     82 
     83     /* this could be done with a loop, but it would violate the
     84        abstraction */
     85 
     86     bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SA+PCIC_IDENT);
     87 
     88     val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
     89 
     90     if (pcic_ident_ok(val))
     91 	found++;
     92 
     93 
     94     bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C0SB+PCIC_IDENT);
     95 
     96     val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
     97 
     98     if (pcic_ident_ok(val))
     99 	found++;
    100 
    101 
    102     bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SA+PCIC_IDENT);
    103 
    104     val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
    105 
    106     if (pcic_ident_ok(val))
    107 	found++;
    108 
    109 
    110     bus_space_write_1(iot, ioh, PCIC_REG_INDEX, C1SB+PCIC_IDENT);
    111 
    112     val = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
    113 
    114     if (pcic_ident_ok(val))
    115 	found++;
    116 
    117 
    118     bus_space_unmap(iot, ioh, PCIC_IOSIZE);
    119     bus_space_unmap(ia->ia_memt, memh, ia->ia_msize);
    120 
    121     if (!found)
    122 	return(0);
    123 
    124     ia->ia_iosize = PCIC_IOSIZE;
    125 
    126     return(1);
    127 }
    128 
    129 #ifndef PCIC_ISA_ALLOC_IOBASE
    130 #define PCIC_ISA_ALLOC_IOBASE 0
    131 #endif
    132 
    133 #ifndef PCIC_ISA_ALLOC_IOSIZE
    134 #define PCIC_ISA_ALLOC_IOSIZE 0
    135 #endif
    136 
    137 int pcic_isa_alloc_iobase = PCIC_ISA_ALLOC_IOBASE;
    138 int pcic_isa_alloc_iosize = PCIC_ISA_ALLOC_IOSIZE;
    139 
    140 void
    141 pcic_isa_attach(parent, self, aux)
    142      struct device *parent, *self;
    143      void *aux;
    144 {
    145     struct pcic_softc *sc = (void *)self;
    146     struct isa_attach_args *ia = aux;
    147     isa_chipset_tag_t ic = ia->ia_ic;
    148     bus_space_tag_t iot = ia->ia_iot;
    149     bus_space_tag_t memt = ia->ia_memt;
    150     bus_space_handle_t ioh;
    151     bus_space_handle_t memh;
    152     bus_space_handle_t ioh_high;
    153     int i, iobuswidth, tmp1, tmp2;
    154 
    155     /* Map i/o space. */
    156     if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh))
    157 	panic("pcic_isa_attach: can't map i/o space");
    158 
    159     /* Map mem space. */
    160     if (bus_space_map(memt, ia->ia_maddr, ia->ia_msize, 0, &memh))
    161 	panic("pcic_isa_attach: can't map i/o space");
    162 
    163     sc->membase = ia->ia_maddr;
    164     sc->subregionmask = (1<<(ia->ia_msize/PCIC_MEM_PAGESIZE))-1;
    165 
    166     sc->intr_est = ic;
    167     sc->pct = (pcmcia_chipset_tag_t) &pcic_isa_functions;
    168 
    169     sc->iot = iot;
    170     sc->ioh = ioh;
    171     sc->memt = memt;
    172     sc->memh = memh;
    173 
    174     /* allocate an irq.  it will be used by both controllers.  I could
    175        use two different interrupts, but interrupts are relatively
    176        scarce, shareable, and for PCIC controllers, very infrequent. */
    177 
    178     if ((sc->irq = ia->ia_irq) == IRQUNK) {
    179 	/* XXX CHECK RETURN VALUE */
    180 	(void) isa_intr_alloc(ic,
    181 			      PCIC_CSC_INTR_IRQ_VALIDMASK,
    182 			      IST_EDGE, &sc->irq);
    183 	printf(": using irq %d", sc->irq);
    184     }
    185 
    186     printf("\n");
    187 
    188     pcic_attach(sc);
    189 
    190     /* figure out how wide the isa bus is.  Do this by checking if
    191        the pcic controller is mirrored 0x400 above where we expect it
    192        to be. */
    193 
    194     iobuswidth = 12;
    195 
    196     /* Map i/o space. */
    197     if (bus_space_map(iot, ia->ia_iobase+0x400, ia->ia_iosize, 0, &ioh_high))
    198 	panic("pcic_isa_attach: can't map high i/o space");
    199 
    200     for (i=0; i<PCIC_NSLOTS; i++) {
    201 	if (sc->handle[i].flags & PCIC_FLAG_SOCKETP) {
    202 	    /* read the ident flags from the normal space
    203 	       and from the mirror, and compare them */
    204 
    205 	    bus_space_write_1(iot, ioh, PCIC_REG_INDEX,
    206 			      sc->handle[i].sock+PCIC_IDENT);
    207 	    tmp1 = bus_space_read_1(iot, ioh, PCIC_REG_DATA);
    208 
    209 	    bus_space_write_1(iot, ioh_high, PCIC_REG_INDEX,
    210 			      sc->handle[i].sock+PCIC_IDENT);
    211 	    tmp2 = bus_space_read_1(iot, ioh_high, PCIC_REG_DATA);
    212 
    213 	    if (tmp1 == tmp2)
    214 		iobuswidth = 10;
    215 	}
    216     }
    217 
    218     bus_space_free(iot, ioh_high, ia->ia_iosize);
    219 
    220 /* XXX mycroft recommends I/O space range 0x400-0xfff .  I should put
    221    this in a header somewhere */
    222 
    223 /* XXX some hardware doesn't seem to grok addresses in 0x400 range--
    224    apparently missing a bit or more of address lines.
    225    (e.g. CIRRUS_PD672X with Linksys EthernetCard ne2000 clone in TI
    226    TravelMate 5000--not clear which is at fault)
    227 
    228    Add a kludge to detect 10 bit wide buses and deal with them, and
    229    also a config file option to override the probe. */
    230 
    231     if (iobuswidth == 10) {
    232 	sc->iobase = 0x300;
    233 	sc->iosize = 0x0ff;
    234     } else {
    235 	sc->iobase = 0x400;
    236 	sc->iosize = 0xbff;
    237     }
    238 
    239     DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx (probed)\n",
    240 	     sc->dev.dv_xname, (long) sc->iobase,
    241 	     (long) sc->iobase+sc->iosize));
    242 
    243     if (pcic_isa_alloc_iobase && pcic_isa_alloc_iosize) {
    244 	sc->iobase = pcic_isa_alloc_iobase;
    245 	sc->iosize = pcic_isa_alloc_iosize;
    246 
    247 	DPRINTF(("%s: bus_space_alloc range 0x%04lx-0x%04lx (config override)\n",
    248 		 sc->dev.dv_xname, (long) sc->iobase,
    249 		 (long) sc->iobase+sc->iosize));
    250     }
    251 
    252     sc->ih = isa_intr_establish(ic, sc->irq, IST_EDGE, IPL_TTY, pcic_intr, sc);
    253 
    254     pcic_attach_sockets(sc);
    255 }
    256 
    257 /* allow patching or kernel option file override of available IRQs.
    258    Useful if order of probing would screw up other devices, or if PCIC
    259    hardware/cards have trouble with certain interrupt lines. */
    260 
    261 #ifndef PCIC_INTR_ALLOC_MASK
    262 #define	PCIC_INTR_ALLOC_MASK	0xffff
    263 #endif
    264 
    265 int	pcic_intr_alloc_mask = PCIC_INTR_ALLOC_MASK;
    266 
    267 void *
    268 pcic_isa_chip_intr_establish(pch, pf, ipl, fct, arg)
    269      pcmcia_chipset_handle_t pch;
    270      struct pcmcia_function *pf;
    271      int ipl;
    272      int (*fct)(void *);
    273      void *arg;
    274 {
    275     struct pcic_handle *h = (struct pcic_handle *) pch;
    276     int irq, ist;
    277     void *ih;
    278     int reg;
    279 
    280     if (pf->cfe->flags & PCMCIA_CFE_IRQLEVEL)
    281 	ist = IST_LEVEL;
    282     else if (pf->cfe->flags & PCMCIA_CFE_IRQPULSE)
    283 	ist = IST_PULSE;
    284     else
    285 	ist = IST_LEVEL;
    286 
    287     if (isa_intr_alloc(h->sc->intr_est,
    288     		       PCIC_INTR_IRQ_VALIDMASK & pcic_intr_alloc_mask,
    289     		       ist, &irq))
    290 	return(NULL);
    291     if (!(ih = isa_intr_establish(h->sc->intr_est, irq, ist, ipl, fct, arg)))
    292 	return(NULL);
    293 
    294     reg = pcic_read(h, PCIC_INTR);
    295     reg &= ~PCIC_INTR_IRQ_MASK;
    296     reg |= irq;
    297     pcic_write(h, PCIC_INTR, reg);
    298 
    299     h->ih_irq = irq;
    300 
    301     printf("%s: card irq %d\n", h->pcmcia->dv_xname, irq);
    302 
    303     return(ih);
    304 }
    305 
    306 void pcic_isa_chip_intr_disestablish(pch, ih)
    307      pcmcia_chipset_handle_t pch;
    308      void *ih;
    309 {
    310     struct pcic_handle *h = (struct pcic_handle *) pch;
    311     int reg;
    312 
    313     h->ih_irq = 0;
    314 
    315     reg = pcic_read(h, PCIC_INTR);
    316     reg &= ~(PCIC_INTR_IRQ_MASK|PCIC_INTR_ENABLE);
    317     pcic_write(h, PCIC_INTR, reg);
    318 
    319     isa_intr_disestablish(h->sc->intr_est, ih);
    320 }
    321