Home | History | Annotate | Line # | Download | only in tc
ioasic.c revision 1.1.2.4
      1 /* $NetBSD: ioasic.c,v 1.1.2.4 1999/03/29 16:50:35 drochner Exp $ */
      2 
      3 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
      4 
      5 __KERNEL_RCSID(0, "$NetBSD: ioasic.c,v 1.1.2.4 1999/03/29 16:50:35 drochner Exp $");
      6 
      7 #include <sys/param.h>
      8 #include <sys/systm.h>
      9 #include <sys/device.h>
     10 
     11 #include <machine/autoconf.h>
     12 #include <machine/bus.h>
     13 #include <machine/intr.h>
     14 
     15 #include <dev/tc/tcvar.h>
     16 #include <dev/tc/ioasicvar.h>
     17 #include <pmax/tc/ioasicreg.h>
     18 #include <pmax/pmax/pmaxtype.h>
     19 
     20 int	ioasicmatch __P((struct device *, struct cfdata *, void *));
     21 void	ioasicattach __P((struct device *, struct device *, void *));
     22 int     ioasicprint __P((void *, const char *));
     23 int	ioasic_submatch __P((struct cfdata *, struct ioasicdev_attach_args *));
     24 
     25 tc_addr_t ioasic_base;
     26 
     27 struct cfattach ioasic_ca = {
     28 	sizeof(struct ioasic_softc), ioasicmatch, ioasicattach,
     29 };
     30 
     31 /* XXX XXX XXX */
     32 #define	IOASIC_INTR_SCSI	0x000e0200
     33 #define	IOASIC_INTR_DTOP	0x00000001
     34 #define	IOASIC_INTR_FDC		0x00000090
     35 #define	XINE_INTR_TC_0		0x00001000
     36 #define	XINE_INTR_TC_1		0x00000020
     37 #define	KN03_INTR_TC_0		0x00000800
     38 #define	KN03_INTR_TC_1		0x00001000
     39 #define	KN03_INTR_TC_2		0x00002000
     40 #define	KMIN_INTR_CLOCK		0x00000020
     41 
     42 extern u_int32_t iplmask[], oldiplmask[];
     43 /* XXX XXX XXX */
     44 
     45 #define	C(x)	(void *)(x)
     46 
     47 struct ioasic_dev xine_ioasic_devs[] = {
     48 	{ "lance",	0x0c0000, C(SYS_DEV_LANCE), IOASIC_INTR_LANCE,	},
     49 	{ "z8530   ",	0x100000, C(SYS_DEV_SCC0),  IOASIC_INTR_SCC_0,	},
     50 	{ "mc146818",	0x200000, C(SYS_DEV_BOGUS), 0, 			},
     51 	{ "isdn",	0x240000, C(SYS_DEV_ISDN),  IOASIC_INTR_ISDN,	},
     52 	{ "dtop",	0x280000, C(SYS_DEV_DTOP),  IOASIC_INTR_DTOP,	},
     53 	{ "fdc",	0x2C0000, C(SYS_DEV_FDC),   IOASIC_INTR_FDC,	},
     54 	{ "asc",	0x300000, C(SYS_DEV_SCSI),  IOASIC_INTR_SCSI	},
     55 	{ "(TC0)",	0x0,	  C(SYS_DEV_OPT0),  XINE_INTR_TC_0	},
     56 	{ "(TC1)",	0x0,	  C(SYS_DEV_OPT1),  XINE_INTR_TC_1	},
     57 };
     58 int xine_builtin_ndevs = 7;
     59 int xine_ioasic_ndevs = sizeof(xine_ioasic_devs)/sizeof(xine_ioasic_devs[0]);
     60 
     61 struct ioasic_dev kn03_ioasic_devs[] = {
     62 	{ "lance",	0x0c0000, C(SYS_DEV_LANCE), IOASIC_INTR_LANCE,	},
     63 	{ "z8530   ",	0x100000, C(SYS_DEV_SCC0),  IOASIC_INTR_SCC_0,	},
     64 	{ "z8530   ",	0x180000, C(SYS_DEV_SCC1),  IOASIC_INTR_SCC_1,	},
     65 	{ "mc146818",	0x200000, C(SYS_DEV_BOGUS), KMIN_INTR_CLOCK,	},
     66 	{ "asc",	0x300000, C(SYS_DEV_SCSI),  IOASIC_INTR_SCSI	},
     67 	{ "(TC0)",	0x0,	  C(SYS_DEV_OPT0),  KN03_INTR_TC_0	},
     68 	{ "(TC1)",	0x0,	  C(SYS_DEV_OPT1),  KN03_INTR_TC_1	},
     69 	{ "(TC2)",	0x0,	  C(SYS_DEV_OPT2),  KN03_INTR_TC_2	},
     70 };
     71 int kn03_builtin_ndevs = 5;
     72 int kn03_ioasic_ndevs = sizeof(kn03_ioasic_devs)/sizeof(kn03_ioasic_devs[0]);
     73 
     74 struct ioasic_dev *ioasic_devs;
     75 int ioasic_ndevs, builtin_ndevs;
     76 
     77 /* There can be only one. */
     78 int ioasicfound;
     79 
     80 extern int systype;
     81 
     82 int
     83 ioasicmatch(parent, cfdata, aux)
     84 	struct device *parent;
     85 	struct cfdata *cfdata;
     86 	void *aux;
     87 {
     88 	struct tc_attach_args *ta = aux;
     89 
     90 	/* Make sure that we're looking for this type of device. */
     91 	if (strncmp("IOCTL   ", ta->ta_modname, TC_ROM_LLEN))
     92 		return (0);
     93 
     94 	if (systype == DS_MAXINE) {
     95 		ioasic_devs = xine_ioasic_devs;
     96 		ioasic_ndevs = xine_ioasic_ndevs;
     97 		builtin_ndevs = xine_builtin_ndevs;
     98 	}
     99 	else if (systype == DS_3MIN || systype == DS_3MAXPLUS) {
    100 		ioasic_devs = kn03_ioasic_devs;
    101 		ioasic_ndevs = kn03_ioasic_ndevs;
    102 		builtin_ndevs = kn03_builtin_ndevs;
    103 	}
    104 	else
    105 		panic("ioasicmatch: how did we get here?");
    106 
    107 	if (ioasicfound)
    108 		return (0);
    109 
    110 	return (1);
    111 }
    112 
    113 void
    114 ioasicattach(parent, self, aux)
    115 	struct device *parent, *self;
    116 	void *aux;
    117 {
    118 	struct ioasic_softc *sc = (struct ioasic_softc *)self;
    119 	struct tc_attach_args *ta = aux;
    120 	int i;
    121 
    122 	ioasicfound = 1;
    123 
    124 	sc->sc_bst = ta->ta_memt;
    125 	sc->sc_dmat = ta->ta_dmat;
    126 	if (bus_space_map(ta->ta_memt, ta->ta_addr,
    127 			  0x400000, 0, &sc->sc_bsh)) {
    128 		printf("%s: unable to map device\n", sc->sc_dv.dv_xname);
    129 		return;
    130 	}
    131 	sc->sc_cookie = ta->ta_cookie;
    132 
    133 	/* XXX XXX XXX */
    134 	sc->sc_base = ta->ta_addr;
    135 
    136 	printf("\n");
    137 
    138 #if 1	/* !!! necessary? already all-0 upon booting as documented !!! */
    139 	/*
    140 	 * Turn off all device interrupt bits.
    141 	 * (This _does_ include TC option slot bits.
    142 	 */
    143 	for (i = 0; i < ioasic_ndevs; i++)
    144 		*(volatile u_int32_t *)(sc->sc_base + IOASIC_IMSK)
    145 			&= ~ioasic_devs[i].iad_intrbits;
    146 	tc_mb();
    147 #endif
    148 
    149 #if 0
    150 	/*
    151 	 * Set up the LANCE DMA area.
    152 	 */
    153 	ioasic_lance_dma_setup(sc);
    154 #endif
    155 
    156 	ioasic_attach_devs(sc, ioasic_devs, builtin_ndevs);
    157 }
    158 
    159 void
    160 ioasic_intr_establish(ioa, cookie, level, func, arg)
    161 	struct device *ioa;
    162 	void *cookie, *arg;
    163 	tc_intrlevel_t level;
    164 	int (*func) __P((void *));
    165 {
    166 	struct ioasic_softc *sc = (void *)ioasic_cd.cd_devs[0];
    167 	u_int dev, i, intrbits;
    168 
    169 	dev = (u_long)cookie;
    170 
    171 	intrtab[dev].ih_func = func;
    172 	intrtab[dev].ih_arg = arg;
    173 
    174 	for (i = 0; i < ioasic_ndevs; i++) {
    175 		if (ioasic_devs[i].iad_cookie == cookie)
    176 			break;
    177 	}
    178 	if (i == ioasic_ndevs) {
    179 		printf("\ndevice %s with cookie %d ", ioa->dv_xname, dev);
    180 		panic("ioasic_intr_establish: invalid cookie.");
    181 	}
    182 
    183 	intrbits = ioasic_devs[i].iad_intrbits;
    184 	iplmask[level] |= intrbits;
    185 	*(volatile u_int32_t *)(sc->sc_base + IOASIC_IMSK) |= intrbits;
    186 	tc_mb();
    187 }
    188 
    189 void
    190 ioasic_intr_disestablish(ioa, cookie)
    191 	struct device *ioa;
    192 	void *cookie;
    193 {
    194 	printf("device %s with cookie %d: ", ioa->dv_xname, (int)cookie);
    195 	panic("ioasic_intr_disestablish called");
    196 }
    197 
    198 char *
    199 ioasic_lance_ether_address()
    200 {
    201 
    202 	return (char *)(ioasic_base + IOASIC_SLOT_2_START);
    203 }
    204 
    205 #if 0 /* Jason's new LANCE DMA region */
    206 /*
    207  * DMA area for IOASIC LANCE.
    208  * XXX Should be done differently, but this is better than it used to be.
    209  */
    210 #define	LE_IOASIC_MEMSIZE	(128*1024)
    211 #define	LE_IOASIC_MEMALIGN	(128*1024)
    212 caddr_t	le_iomem;
    213 
    214 void	ioasic_lance_dma_setup __P((struct ioasic_softc *));
    215 
    216 void
    217 ioasic_lance_dma_setup(sc)
    218 	struct ioasic_softc *sc;
    219 {
    220 	bus_dma_tag_t dmat = sc->sc_dmat;
    221 	bus_dma_segment_t seg;
    222 	u_int32_t csr;
    223 	tc_addr_t tca;
    224 	int rseg;
    225 
    226 	/*
    227 	 * Allocate a DMA area for the chip.
    228 	 */
    229 	if (bus_dmamem_alloc(dmat, LE_IOASIC_MEMSIZE, LE_IOASIC_MEMALIGN,
    230 	    0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
    231 		printf("%s: can't allocate DMA area for LANCE\n",
    232 		    sc->sc_dv.dv_xname);
    233 		return;
    234 	}
    235 	if (bus_dmamem_map(dmat, &seg, rseg, LE_IOASIC_MEMSIZE,
    236 	    &le_iomem, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
    237 		printf("%s: can't map DMA area for LANCE\n",
    238 		    sc->sc_dv.dv_xname);
    239 		bus_dmamem_free(dmat, &seg, rseg);
    240 		return;
    241 	}
    242 
    243 	/*
    244 	 * Create and load the DMA map for the DMA area.
    245 	 */
    246 	if (bus_dmamap_create(dmat, LE_IOASIC_MEMSIZE, 1,
    247 	    LE_IOASIC_MEMSIZE, 0, BUS_DMA_NOWAIT, &sc->sc_lance_dmam)) {
    248 		printf("%s: can't create DMA map\n", sc->sc_dv.dv_xname);
    249 		goto bad;
    250 	}
    251 	if (bus_dmamap_load(dmat, sc->sc_lance_dmam,
    252 	    le_iomem, LE_IOASIC_MEMSIZE, NULL, BUS_DMA_NOWAIT)) {
    253 		printf("%s: can't load DMA map\n", sc->sc_dv.dv_xname);
    254 		goto bad;
    255 	}
    256 
    257 	tca = (tc_addr_t)sc->sc_lance_dmam->dm_segs[0].ds_addr;
    258 	if (tca != sc->sc_lance_dmam->dm_segs[0].ds_addr) {
    259 		printf("%s: bad LANCE DMA address\n", sc->sc_dv.dv_xname);
    260 		bus_dmamap_unload(dmat, sc->sc_lance_dmam);
    261 		goto bad;
    262 	}
    263 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    264 		IOASIC_LANCE_DMAPTR,
    265 		((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f));
    266 	csr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR);
    267 	csr |= IOASIC_CSR_DMAEN_LANCE;
    268 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, csr);
    269 	return;
    270 
    271  bad:
    272 	bus_dmamem_unmap(dmat, le_iomem, LE_IOASIC_MEMSIZE);
    273 	bus_dmamem_free(dmat, &seg, rseg);
    274 	le_iomem = 0;
    275 }
    276 #else	/* old NetBSD/pmax code */
    277 void	ioasic_lance_dma_setup __P((void *));
    278 
    279 void
    280 ioasic_lance_dma_setup(v)
    281 	void *v;
    282 {
    283 	volatile u_int32_t *ldp;
    284 	tc_addr_t tca;
    285 
    286 	tca = (tc_addr_t)v;
    287 
    288 	ldp = (volatile u_int *)IOASIC_REG_LANCE_DMAPTR(ioasic_base);
    289 	*ldp = ((tca << 3) & ~(tc_addr_t)0x1f) | ((tca >> 29) & 0x1f);
    290 	tc_wmb();
    291 
    292 	*(volatile u_int32_t *)IOASIC_REG_CSR(ioasic_base) |=
    293 	    IOASIC_CSR_DMAEN_LANCE;
    294 	tc_mb();
    295 }
    296 #endif
    297 
    298 /*
    299  * spl(9) for IOASIC DECstations
    300  */
    301 
    302 int _splraise_ioasic __P((int));
    303 int _spllower_ioasic __P((int));
    304 int _splx_ioasic __P((int));
    305 
    306 int
    307 _splraise_ioasic(lvl)
    308 	int lvl;
    309 {
    310 	u_int32_t new;
    311 
    312 	new = oldiplmask[lvl] = *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
    313 	new &= ~iplmask[lvl];
    314 	*(u_int32_t *)(ioasic_base + IOASIC_IMSK) = new;
    315 	tc_wmb();
    316 	return lvl | _splraise(MIPS_SOFT_INT_MASK_0|MIPS_SOFT_INT_MASK_1);
    317 }
    318 
    319 int
    320 _spllower_ioasic(mask)
    321 {
    322 	int s;
    323 
    324 	s = IPL_NONE | _spllower(mask);
    325 	oldiplmask[IPL_NONE] =  *(u_int32_t *)(ioasic_base + IOASIC_IMSK);
    326 	*(u_int32_t *)(ioasic_base + IOASIC_IMSK) = iplmask[IPL_HIGH];
    327 	tc_wmb();
    328 	return s;
    329 }
    330 
    331 int
    332 _splx_ioasic(lvl)
    333 	int lvl;
    334 {
    335 	(void)_splset(lvl & MIPS_INT_MASK);
    336 	if (lvl & 0xff) {
    337 		*(u_int32_t *)(ioasic_base + IOASIC_IMSK) =
    338 			oldiplmask[lvl & 0xff];
    339 		tc_wmb();
    340 	}
    341 	return 0;
    342 }
    343