Home | History | Annotate | Line # | Download | only in tc
ioasic.c revision 1.1
      1 /*	$NetBSD: ioasic.c,v 1.1 1995/12/20 00:43:20 cgd Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1994, 1995 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 
     39 #include <dev/tc/tcvar.h>
     40 #include <alpha/tc/ioasicreg.h>
     41 #include <dev/tc/ioasicvar.h>
     42 
     43 struct ioasic_softc {
     44 	struct	device sc_dv;
     45 
     46 	tc_addr_t sc_base;
     47 	void	*sc_cookie;
     48 };
     49 
     50 /* Definition of the driver for autoconfig. */
     51 int	ioasicmatch __P((struct device *, void *, void *));
     52 void	ioasicattach __P((struct device *, struct device *, void *));
     53 int     ioasicprint(void *, char *);
     54 struct cfdriver ioasiccd =
     55     { NULL, "ioasic", ioasicmatch, ioasicattach, DV_DULL,
     56     sizeof(struct ioasic_softc) };
     57 
     58 int	ioasic_intr __P((void *));
     59 int	ioasic_intrnull __P((void *));
     60 
     61 #define	C(x)	((void *)(x))
     62 
     63 #define	IOASIC_DEV_LANCE	0
     64 #define	IOASIC_DEV_SCC0		1
     65 #define	IOASIC_DEV_SCC1		2
     66 #define	IOASIC_DEV_ISDN		3
     67 
     68 #define	IOASIC_DEV_BOGUS	-1
     69 
     70 #define	IOASIC_NCOOKIES		4
     71 
     72 struct ioasic_dev {
     73 	char		*iad_modname;
     74 	tc_offset_t	iad_offset;
     75 	void		*iad_cookie;
     76 	u_int32_t	iad_intrbits;
     77 } ioasic_devs[] = {
     78 	{ "lance   ", 0x000c0000, C(IOASIC_DEV_LANCE), IOASIC_INTR_LANCE, },
     79 	{ "z8530   ", 0x00100000, C(IOASIC_DEV_SCC0),  IOASIC_INTR_SCC_0, },
     80 	{ "z8530   ", 0x00180000, C(IOASIC_DEV_SCC1),  IOASIC_INTR_SCC_1, },
     81 	{ "TOY_RTC ", 0x00200000, C(IOASIC_DEV_BOGUS), 0,                 },
     82 	{ "AMD79c30", 0x00240000, C(IOASIC_DEV_ISDN),  IOASIC_INTR_ISDN,  },
     83 };
     84 int ioasic_ndevs = sizeof(ioasic_devs) / sizeof(ioasic_devs[0]);
     85 
     86 struct ioasicintr {
     87 	int	(*iai_func) __P((void *));
     88 	void	*iai_arg;
     89 } ioasicintrs[IOASIC_NCOOKIES];
     90 
     91 tc_addr_t ioasic_base;		/* XXX XXX XXX */
     92 
     93 /* There can be only one. */
     94 int ioasicfound;
     95 
     96 extern int cputype;
     97 
     98 int
     99 ioasicmatch(parent, cfdata, aux)
    100 	struct device *parent;
    101 	void *cfdata;
    102 	void *aux;
    103 {
    104 	struct tcdev_attach_args *tcdev = aux;
    105 
    106 	/* Make sure that we're looking for this type of device. */
    107 	if (strncmp("FLAMG-IO", tcdev->tcda_modname, TC_ROM_LLEN))
    108 		return (0);
    109 
    110 	/* Check that it can actually exist. */
    111 	if ((cputype != ST_DEC_3000_500) && (cputype != ST_DEC_3000_300))
    112 		panic("ioasicmatch: how did we get here?");
    113 
    114 	if (ioasicfound)
    115 		return (0);
    116 
    117 	return (1);
    118 }
    119 
    120 void
    121 ioasicattach(parent, self, aux)
    122 	struct device *parent, *self;
    123 	void *aux;
    124 {
    125 	struct ioasic_softc *sc = (struct ioasic_softc *)self;
    126 	struct tcdev_attach_args *tcdev = aux;
    127 	struct ioasicdev_attach_args ioasicdev;
    128 	u_long i;
    129 
    130 	ioasicfound = 1;
    131 
    132 	sc->sc_base = tcdev->tcda_addr;
    133 	ioasic_base = sc->sc_base;			/* XXX XXX XXX */
    134 	sc->sc_cookie = tcdev->tcda_cookie;
    135 
    136 #ifdef DEC_3000_300
    137 	if (cputype == ST_DEC_3000_300) {
    138 		*(volatile u_int *)IOASIC_REG_CSR(sc->sc_base) |=
    139 		    IOASIC_CSR_FASTMODE;
    140 		tc_mb();
    141 		printf(": slow mode\n");
    142 	} else
    143 #endif
    144 		printf(": fast mode\n");
    145 
    146 	/*
    147 	 * Turn off all device interrupt bits.
    148 	 * (This does _not_ include 3000/300 TC option slot bits.
    149 	 */
    150 	for (i = 0; i < ioasic_ndevs; i++)
    151 		*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
    152 			~ioasic_devs[i].iad_intrbits;
    153 	tc_mb();
    154 
    155 	/*
    156 	 * Set up interrupt handlers.
    157 	 */
    158 	for (i = 0; i < IOASIC_NCOOKIES; i++) {
    159 		ioasicintrs[i].iai_func = ioasic_intrnull;
    160 		ioasicintrs[i].iai_arg = (void *)i;
    161 	}
    162 	tc_intr_establish(parent, sc->sc_cookie, TC_IPL_NONE, ioasic_intr, sc);
    163 
    164         /*
    165 	 * Try to configure each device.
    166 	 */
    167         for (i = 0; i < ioasic_ndevs; i++) {
    168 		strncpy(ioasicdev.iada_modname, ioasic_devs[i].iad_modname,
    169 			TC_ROM_LLEN);
    170 		ioasicdev.iada_modname[TC_ROM_LLEN] = '\0';
    171 		ioasicdev.iada_offset = ioasic_devs[i].iad_offset;
    172 		ioasicdev.iada_addr = sc->sc_base + ioasic_devs[i].iad_offset;
    173 		ioasicdev.iada_cookie = ioasic_devs[i].iad_cookie;
    174 
    175                 /* Tell the autoconfig machinery we've found the hardware. */
    176                 config_found(self, &ioasicdev, ioasicprint);
    177         }
    178 }
    179 
    180 int
    181 ioasicprint(aux, pnp)
    182 	void *aux;
    183 	char *pnp;
    184 {
    185 	struct ioasicdev_attach_args *d = aux;
    186 
    187         if (pnp)
    188                 printf("%s at %s", d->iada_modname, pnp);
    189         printf(" offset 0x%lx", (long)d->iada_offset);
    190         return (UNCONF);
    191 }
    192 
    193 int
    194 ioasic_submatch(match, d)
    195 	struct cfdata *match;
    196 	struct ioasicdev_attach_args *d;
    197 {
    198 
    199 	return ((match->ioasiccf_offset == d->iada_offset) ||
    200 		(match->ioasiccf_offset == IOASIC_OFFSET_UNKNOWN));
    201 }
    202 
    203 void
    204 ioasic_intr_establish(ioa, cookie, level, func, arg)
    205 	struct device *ioa;
    206 	void *cookie, *arg;
    207 	tc_intrlevel_t level;
    208 	int (*func) __P((void *));
    209 {
    210 	u_long dev, i;
    211 
    212 	dev = (u_long)cookie;
    213 #ifdef DIAGNOSTIC
    214 	/* XXX check cookie. */
    215 #endif
    216 
    217 	if (ioasicintrs[dev].iai_func != ioasic_intrnull)
    218 		panic("ioasic_intr_establish: cookie %d twice", dev);
    219 
    220 	ioasicintrs[dev].iai_func = func;
    221 	ioasicintrs[dev].iai_arg = arg;
    222 
    223 	/* Enable interrupts for the device. */
    224 	for (i = 0; i < ioasic_ndevs; i++)
    225 		if (ioasic_devs[i].iad_cookie == cookie)
    226 			break;
    227 	if (i == ioasic_ndevs)
    228 		panic("ioasic_intr_establish: invalid cookie.");
    229 	*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |=
    230 		ioasic_devs[i].iad_intrbits;
    231 	tc_mb();
    232 }
    233 
    234 void
    235 ioasic_intr_disestablish(ioa, cookie)
    236 	struct device *ioa;
    237 	void *cookie;
    238 {
    239 	u_long dev, i;
    240 
    241 	dev = (u_long)cookie;
    242 #ifdef DIAGNOSTIC
    243 	/* XXX check cookie. */
    244 #endif
    245 
    246 	if (ioasicintrs[dev].iai_func == ioasic_intrnull)
    247 		panic("ioasic_intr_disestablish: cookie %d missing intr", dev);
    248 
    249 	/* Enable interrupts for the device. */
    250 	for (i = 0; i < ioasic_ndevs; i++)
    251 		if (ioasic_devs[i].iad_cookie == cookie)
    252 			break;
    253 	if (i == ioasic_ndevs)
    254 		panic("ioasic_intr_disestablish: invalid cookie.");
    255 	*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
    256 		~ioasic_devs[i].iad_intrbits;
    257 	tc_mb();
    258 
    259 	ioasicintrs[dev].iai_func = ioasic_intrnull;
    260 	ioasicintrs[dev].iai_arg = (void *)dev;
    261 }
    262 
    263 int
    264 ioasic_intrnull(val)
    265 	void *val;
    266 {
    267 
    268 	panic("ioasic_intrnull: uncaught IOASIC intr for cookie %ld\n",
    269 	    (u_long)val);
    270 }
    271 
    272 /*
    273  * asic_intr --
    274  *	ASIC interrupt handler.
    275  */
    276 int
    277 ioasic_intr(val)
    278 	void *val;
    279 {
    280 	register struct ioasic_softc *sc = val;
    281 	register int i, ifound;
    282 	int gifound;
    283 	u_int32_t sir, junk;
    284 	volatile u_int32_t *sirp, *junkp;
    285 
    286 	sirp = (volatile u_int32_t *)IOASIC_REG_INTR(sc->sc_base);
    287 
    288 	gifound = 0;
    289 	do {
    290 		ifound = 0;
    291 		tc_syncbus();
    292 
    293 		sir = *sirp;
    294 
    295 		/* XXX DUPLICATION OF INTERRUPT BIT INFORMATION... */
    296 #define	CHECKINTR(slot, bits)						\
    297 		if (sir & bits) {					\
    298 			ifound = 1;					\
    299 			(*ioasicintrs[slot].iai_func)			\
    300 			    (ioasicintrs[slot].iai_arg);		\
    301 		}
    302 		CHECKINTR(IOASIC_DEV_SCC0, IOASIC_INTR_SCC_0);
    303 		CHECKINTR(IOASIC_DEV_SCC1, IOASIC_INTR_SCC_1);
    304 		CHECKINTR(IOASIC_DEV_LANCE, IOASIC_INTR_LANCE);
    305 		CHECKINTR(IOASIC_DEV_ISDN, IOASIC_INTR_ISDN);
    306 
    307 		gifound |= ifound;
    308 	} while (ifound);
    309 
    310 	return (gifound);
    311 }
    312 
    313 /* XXX */
    314 char *
    315 ioasic_lance_ether_address()
    316 {
    317 
    318 	return (u_char *)IOASIC_SYS_ETHER_ADDRESS(ioasic_base);
    319 }
    320 
    321 void
    322 ioasic_lance_dma_setup(v)
    323 	void *v;
    324 {
    325 	volatile u_int32_t *ldp;
    326 	tc_addr_t tca;
    327 
    328 	tca = (tc_addr_t)v;
    329 
    330 	ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base);
    331 	*ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f);
    332 	tc_wmb();
    333 
    334 	*(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |=
    335 	    IOASIC_CSR_DMAEN_LANCE;
    336 	tc_mb();
    337 }
    338 
    339 #ifdef DEC_3000_300
    340 void
    341 ioasic_intr_300_opt0_enable(enable)
    342 	int enable;
    343 {
    344 
    345 	if (enable)
    346 		*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |=
    347 			IOASIC_INTR_300_OPT0;
    348 	else
    349 		*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
    350 			~IOASIC_INTR_300_OPT0;
    351 }
    352 
    353 void
    354 ioasic_intr_300_opt1_enable(enable)
    355 	int enable;
    356 {
    357 
    358 	if (enable)
    359 		*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) |=
    360 			IOASIC_INTR_300_OPT1;
    361 	else
    362 		*(volatile u_int32_t *)IOASIC_REG_IMSK(ioasic_base) &=
    363 			~IOASIC_INTR_300_OPT1;
    364 }
    365 
    366 void
    367 ioasic_300_opts_isintr(opt0, opt1)
    368 	int *opt0, *opt1;
    369 {
    370 	u_int32_t sir;
    371 
    372 	sir = *(volatile u_int32_t *)IOASIC_REG_INTR(ioasic_base);
    373 	*opt0 = sir & IOASIC_INTR_300_OPT0;
    374 	*opt1 = sir & IOASIC_INTR_300_OPT1;
    375 }
    376 #endif
    377