Home | History | Annotate | Line # | Download | only in tc
ioasic.c revision 1.10
      1 /*	$NetBSD: ioasic.c,v 1.10 1996/12/05 01:39:41 cgd Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
      5  * All rights reserved.
      6  *
      7  * Author: Keith Bostic, Chris G. Demetriou
      8  *
      9  * Permission to use, copy, modify and distribute this software and
     10  * its documentation is hereby granted, provided that both the copyright
     11  * notice and this permission notice appear in all copies of the
     12  * software, derivative works or modified versions, and any portions
     13  * thereof, and that both notices appear in supporting documentation.
     14  *
     15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     17  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     18  *
     19  * Carnegie Mellon requests users of this software to return to
     20  *
     21  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     22  *  School of Computer Science
     23  *  Carnegie Mellon University
     24  *  Pittsburgh PA 15213-3890
     25  *
     26  * any improvements or extensions that they make and grant Carnegie the
     27  * rights to redistribute these changes.
     28  */
     29 
     30 #include <sys/param.h>
     31 #include <sys/kernel.h>
     32 #include <sys/systm.h>
     33 #include <sys/device.h>
     34 
     35 #include <machine/autoconf.h>
     36 #include <machine/pte.h>
     37 #include <machine/rpb.h>
     38 #ifndef EVCNT_COUNTERS
     39 #include <machine/intrcnt.h>
     40 #endif
     41 
     42 #include <dev/tc/tcvar.h>
     43 #include <alpha/tc/ioasicreg.h>
     44 #include <dev/tc/ioasicvar.h>
     45 
     46 struct ioasic_softc {
     47 	struct	device sc_dv;
     48 
     49 	tc_addr_t sc_base;
     50 	void	*sc_cookie;
     51 };
     52 
     53 /* Definition of the driver for autoconfig. */
     54 #ifdef __BROKEN_INDIRECT_CONFIG
     55 int	ioasicmatch __P((struct device *, void *, void *));
     56 #else
     57 int	ioasicmatch __P((struct device *, struct cfdata *, void *));
     58 #endif
     59 void	ioasicattach __P((struct device *, struct device *, void *));
     60 int     ioasicprint(void *, const char *);
     61 
     62 struct cfattach ioasic_ca = {
     63 	sizeof(struct ioasic_softc), ioasicmatch, ioasicattach,
     64 };
     65 
     66 struct cfdriver ioasic_cd = {
     67 	NULL, "ioasic", DV_DULL,
     68 };
     69 
     70 int	ioasic_intr __P((void *));
     71 int	ioasic_intrnull __P((void *));
     72 
     73 #define	C(x)	((void *)(x))
     74 
     75 #define	IOASIC_DEV_LANCE	0
     76 #define	IOASIC_DEV_SCC0		1
     77 #define	IOASIC_DEV_SCC1		2
     78 #define	IOASIC_DEV_ISDN		3
     79 
     80 #define	IOASIC_DEV_BOGUS	-1
     81 
     82 #define	IOASIC_NCOOKIES		4
     83 
     84 struct ioasic_dev {
     85 	char		*iad_modname;
     86 	tc_offset_t	iad_offset;
     87 	void		*iad_cookie;
     88 	u_int32_t	iad_intrbits;
     89 } ioasic_devs[] = {
     90 	/* XXX lance name */
     91 	{ "lance",    0x000c0000, C(IOASIC_DEV_LANCE), IOASIC_INTR_LANCE, },
     92 	{ "z8530   ", 0x00100000, C(IOASIC_DEV_SCC0),  IOASIC_INTR_SCC_0, },
     93 	{ "z8530   ", 0x00180000, C(IOASIC_DEV_SCC1),  IOASIC_INTR_SCC_1, },
     94 	{ "TOY_RTC ", 0x00200000, C(IOASIC_DEV_BOGUS), 0,                 },
     95 	{ "AMD79c30", 0x00240000, C(IOASIC_DEV_ISDN),  IOASIC_INTR_ISDN,  },
     96 };
     97 int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]);
     98 
     99 struct ioasicintr {
    100 	int	(*iai_func) __P((void *));
    101 	void	*iai_arg;
    102 } ioasicintrs[IOASIC_NCOOKIES];
    103 
    104 tc_addr_t ioasic_base;		/* XXX XXX XXX */
    105 
    106 /* There can be only one. */
    107 int ioasicfound;
    108 
    109 extern int cputype;
    110 
    111 int
    112 ioasicmatch(parent, cfdata, aux)
    113 	struct device *parent;
    114 #ifdef __BROKEN_INDIRECT_CONFIG
    115 	void *cfdata;
    116 #else
    117 	struct cfdata *cfdata;
    118 #endif
    119 	void *aux;
    120 {
    121 	struct tc_attach_args *ta = aux;
    122 
    123 	/* Make sure that we're looking for this type of device. */
    124 	if (strncmp("FLAMG-IO", ta->ta_modname, TC_ROM_LLEN))
    125 		return (0);
    126 
    127 	/* Check that it can actually exist. */
    128 	if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
    129 		panic("ioasicmatch: how did we get here?");
    130 
    131 	if (ioasicfound)
    132 		return (0);
    133 
    134 	return (1);
    135 }
    136 
    137 void
    138 ioasicattach(parent, self, aux)
    139 	struct device *parent, *self;
    140 	void *aux;
    141 {
    142 	struct ioasic_softc *sc = (struct ioasic_softc *)self;
    143 	struct tc_attach_args *ta = aux;
    144 	struct ioasicdev_attach_args ioasicdev;
    145 	u_long i;
    146 
    147 	ioasicfound = 1;
    148 
    149 	sc->sc_base = ta->ta_addr;
    150 	ioasic_base = sc->sc_base;			/* XXX XXX XXX */
    151 	sc->sc_cookie = ta->ta_cookie;
    152 
    153 #ifdef DEC_3000_300
    154 	if (cputype == ST_DEC_3000_300) {
    155 		*(volatile u_int *)IOASIC_REG_CSR(sc->sc_base) |=
    156 		    IOASIC_CSR_FASTMODE;
    157 		tc_mb();
    158 		printf(": slow mode\n");
    159 	} else
    160 #endif
    161 		printf(": fast mode\n");
    162 
    163 	/*
    164 	 * Turn off all device interrupt bits.
    165 	 * (This does _not_ include 3000/300 TC option slot bits.
    166 	 */
    167 	for (i = 0; i < ioasic_ndevs; i++)
    168 		*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
    169 			~ioasic_devs[i].iad_intrbits;
    170 	tc_mb();
    171 
    172 	/*
    173 	 * Set up interrupt handlers.
    174 	 */
    175 	for (i = 0; i < IOASIC_NCOOKIES; i++) {
    176 		ioasicintrs[i].iai_func = ioasic_intrnull;
    177 		ioasicintrs[i].iai_arg = (void *)i;
    178 	}
    179 	tc_intr_establish(parent, sc->sc_cookie, TC_IPL_NONE, ioasic_intr, sc);
    180 
    181         /*
    182 	 * Try to configure each device.
    183 	 */
    184         for (i = 0; i < ioasic_ndevs; i++) {
    185 		strncpy(ioasicdev.iada_modname, ioasic_devs[i].iad_modname,
    186 			TC_ROM_LLEN);
    187 		ioasicdev.iada_modname[TC_ROM_LLEN] = '\0';
    188 		ioasicdev.iada_offset = ioasic_devs[i].iad_offset;
    189 		ioasicdev.iada_addr = sc->sc_base + ioasic_devs[i].iad_offset;
    190 		ioasicdev.iada_cookie = ioasic_devs[i].iad_cookie;
    191 
    192                 /* Tell the autoconfig machinery we've found the hardware. */
    193                 config_found(self, &ioasicdev, ioasicprint);
    194         }
    195 }
    196 
    197 int
    198 ioasicprint(aux, pnp)
    199 	void *aux;
    200 	const char *pnp;
    201 {
    202 	struct ioasicdev_attach_args *d = aux;
    203 
    204         if (pnp)
    205                 printf("%s at %s", d->iada_modname, pnp);
    206         printf(" offset 0x%lx", (long)d->iada_offset);
    207         return (UNCONF);
    208 }
    209 
    210 int
    211 ioasic_submatch(match, d)
    212 	struct cfdata *match;
    213 	struct ioasicdev_attach_args *d;
    214 {
    215 
    216 	return ((match->ioasiccf_offset == d->iada_offset) ||
    217 		(match->ioasiccf_offset == IOASIC_OFFSET_UNKNOWN));
    218 }
    219 
    220 void
    221 ioasic_intr_establish(ioa, cookie, level, func, arg)
    222 	struct device *ioa;
    223 	void *cookie, *arg;
    224 	tc_intrlevel_t level;
    225 	int (*func) __P((void *));
    226 {
    227 	u_long dev, i;
    228 
    229 	dev = (u_long)cookie;
    230 #ifdef DIAGNOSTIC
    231 	/* XXX check cookie. */
    232 #endif
    233 
    234 	if (ioasicintrs[dev].iai_func != ioasic_intrnull)
    235 		panic("ioasic_intr_establish: cookie %d twice", dev);
    236 
    237 	ioasicintrs[dev].iai_func = func;
    238 	ioasicintrs[dev].iai_arg = arg;
    239 
    240 	/* Enable interrupts for the device. */
    241 	for (i = 0; i < ioasic_ndevs; i++)
    242 		if (ioasic_devs[i].iad_cookie == cookie)
    243 			break;
    244 	if (i == ioasic_ndevs)
    245 		panic("ioasic_intr_establish: invalid cookie.");
    246 	*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |=
    247 		ioasic_devs[i].iad_intrbits;
    248 	tc_mb();
    249 }
    250 
    251 void
    252 ioasic_intr_disestablish(ioa, cookie)
    253 	struct device *ioa;
    254 	void *cookie;
    255 {
    256 	u_long dev, i;
    257 
    258 	dev = (u_long)cookie;
    259 #ifdef DIAGNOSTIC
    260 	/* XXX check cookie. */
    261 #endif
    262 
    263 	if (ioasicintrs[dev].iai_func == ioasic_intrnull)
    264 		panic("ioasic_intr_disestablish: cookie %d missing intr", dev);
    265 
    266 	/* Enable interrupts for the device. */
    267 	for (i = 0; i < ioasic_ndevs; i++)
    268 		if (ioasic_devs[i].iad_cookie == cookie)
    269 			break;
    270 	if (i == ioasic_ndevs)
    271 		panic("ioasic_intr_disestablish: invalid cookie.");
    272 	*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
    273 		~ioasic_devs[i].iad_intrbits;
    274 	tc_mb();
    275 
    276 	ioasicintrs[dev].iai_func = ioasic_intrnull;
    277 	ioasicintrs[dev].iai_arg = (void *)dev;
    278 }
    279 
    280 int
    281 ioasic_intrnull(val)
    282 	void *val;
    283 {
    284 
    285 	panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld\n",
    286 	    (u_long)val);
    287 }
    288 
    289 /*
    290  * asic_intr --
    291  *	ASIC interrupt handler.
    292  */
    293 int
    294 ioasic_intr(val)
    295 	void *val;
    296 {
    297 	register struct ioasic_softc *sc = val;
    298 	register int ifound;
    299 	int gifound;
    300 	u_int32_t sir;
    301 	volatile u_int32_t *sirp;
    302 
    303 	sirp = (volatile u_int32_t *)IOASIC_REG_INTR(sc->sc_base);
    304 
    305 	gifound = 0;
    306 	do {
    307 		ifound = 0;
    308 		tc_syncbus();
    309 
    310 		sir = *sirp;
    311 
    312 #ifdef EVCNT_COUNTERS
    313 	/* No interrupt counting via evcnt counters */
    314 	XXX BREAK HERE XXX
    315 #else /* !EVCNT_COUNTERS */
    316 #define	INCRINTRCNT(slot)	intrcnt[INTRCNT_IOASIC + slot]++
    317 #endif /* EVCNT_COUNTERS */
    318 
    319 		/* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
    320 #define	CHECKINTR(slot, bits)						\
    321 		if (sir & bits) {					\
    322 			ifound = 1;					\
    323 			INCRINTRCNT(slot);				\
    324 			(*ioasicintrs[slot].iai_func)			\
    325 			    (ioasicintrs[slot].iai_arg);		\
    326 		}
    327 		CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0);
    328 		CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1);
    329 		CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE);
    330 		CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN);
    331 
    332 		gifound |= ifound;
    333 	} while (ifound);
    334 
    335 	return (gifound);
    336 }
    337 
    338 /* XXX */
    339 char *
    340 ioasic_lance_ether_address()
    341 {
    342 
    343 	return (u_char *)IOASIC_SYS_ETHER_ADDRESS(ioasic_base);
    344 }
    345 
    346 void
    347 ioasic_lance_dma_setup(v)
    348 	void *v;
    349 {
    350 	volatile u_int32_t *ldp;
    351 	tc_addr_t tca;
    352 
    353 	tca = (tc_addr_t)v;
    354 
    355 	ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base);
    356 	*ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f);
    357 	tc_wmb();
    358 
    359 	*(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |=
    360 	    IOASIC_CSR_DMAEN_LANCE;
    361 	tc_mb();
    362 }
    363