Home | History | Annotate | Line # | Download | only in dev
vme_pcc.c revision 1.6.24.5
      1 /*	$NetBSD: vme_pcc.c,v 1.6.24.5 2000/03/18 16:56:48 scw Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996-2000 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe and Steve C. Woodford.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * VME support specific to the Type 1 VMEchip found on the
     41  * MVME-147.
     42  *
     43  * For a manual on the MVME-147, call: 408.991.8634.  (Yes, this
     44  * is the Sunnyvale sales office.)
     45  */
     46 
     47 #include <sys/param.h>
     48 #include <sys/kernel.h>
     49 #include <sys/systm.h>
     50 #include <sys/device.h>
     51 #include <sys/malloc.h>
     52 #include <sys/kcore.h>
     53 
     54 #include <machine/cpu.h>
     55 #include <machine/bus.h>
     56 
     57 #include <dev/vme/vmereg.h>
     58 #include <dev/vme/vmevar.h>
     59 
     60 #include <mvme68k/mvme68k/isr.h>
     61 
     62 #include <mvme68k/dev/pccreg.h>
     63 #include <mvme68k/dev/pccvar.h>
     64 #include <mvme68k/dev/vme_pccreg.h>
     65 #include <mvme68k/dev/vme_pccvar.h>
     66 
     67 
     68 static int vme_pcc_match __P((struct device *, struct cfdata *, void *));
     69 static void vme_pcc_attach __P((struct device *, struct device *, void *));
     70 
     71 struct cfattach vmepcc_ca = {
     72 	sizeof(struct vme_pcc_softc), vme_pcc_match, vme_pcc_attach
     73 };
     74 
     75 extern	struct cfdriver vmepcc_cd;
     76 
     77 extern	phys_ram_seg_t mem_clusters[];
     78 static	int vme_pcc_attached;
     79 
     80 #ifdef DIAGNOSTIC
     81 const char *_vme1_mod_string __P((vme_addr_t, vme_size_t,
     82     vme_am_t, vme_datasize_t));
     83 #endif
     84 
     85 /*
     86  * Describe the VMEbus ranges available from the MVME147
     87  */
     88 struct vme_pcc_range {
     89 	vme_am_t	pr_am;		/* Address Modifier for this range */
     90 	vme_datasize_t	pr_datasize;	/* Usable Data Sizes (D8, D16, D32) */
     91 	vme_addr_t	pr_start;	/* Local-bus start address of range */
     92 	vme_addr_t	pr_end;		/* Local-bus end address of range */
     93 };
     94 
     95 static struct vme_pcc_range vme_pcc_ranges[] = {
     96     {VME_AM_MBO | VME_AM_A24 | VME_AM_DATA | VME_AM_SUPER,
     97      VME_D32 | VME_D16 | VME_D8, VME1_A24D32_START, VME1_A24D32_END},
     98     {VME_AM_MBO | VME_AM_A32 | VME_AM_DATA | VME_AM_SUPER,
     99      VME_D32 | VME_D16 | VME_D8, VME1_A32D32_START, VME1_A32D32_END},
    100     {VME_AM_MBO | VME_AM_A24 | VME_AM_DATA | VME_AM_SUPER,
    101      VME_D16 | VME_D8, VME1_A24D16_START, VME1_A24D16_END},
    102     {VME_AM_MBO | VME_AM_A32 | VME_AM_DATA | VME_AM_SUPER,
    103      VME_D16 | VME_D8, VME1_A32D16_START, VME1_A32D16_END},
    104     {VME_AM_MBO | VME_AM_A16 | VME_AM_DATA | VME_AM_SUPER,
    105      VME_D16 | VME_D8, VME1_A16D16_START, VME1_A16D16_END}
    106 };
    107 #define VME1_NRANGES	(sizeof(vme_pcc_ranges)/sizeof(struct vme_pcc_range))
    108 
    109 
    110 static int
    111 vme_pcc_match(parent, cf, aux)
    112 	struct device *parent;
    113 	struct cfdata *cf;
    114 	void *aux;
    115 {
    116 	struct pcc_attach_args *pa = aux;
    117 
    118 	/* Only one VME chip, please. */
    119 	if (vme_pcc_attached)
    120 		return (0);
    121 
    122 	if (strcmp(pa->pa_name, vmepcc_cd.cd_name))
    123 		return (0);
    124 
    125 	return (1);
    126 }
    127 
    128 static void
    129 vme_pcc_attach(parent, self, aux)
    130 	struct device *parent, *self;
    131 	void *aux;
    132 {
    133 	struct pcc_attach_args *pa;
    134 	struct vme_pcc_softc *sc;
    135 	struct vmebus_attach_args vaa;
    136 	u_int8_t reg;
    137 	int i;
    138 
    139 	sc = (struct vme_pcc_softc *) self;
    140 	pa = (struct pcc_attach_args *) aux;
    141 
    142 	sc->sc_dmat = pa->pa_dmat;
    143 	sc->sc_bust = pa->pa_bust;
    144 	sc->sc_vmet = MVME68K_VME_BUS_SPACE;
    145 
    146 	bus_space_map(sc->sc_bust, pa->pa_offset, VME1REG_SIZE,0, &sc->sc_bush);
    147 
    148 	/* Initialize the chip. */
    149 	reg = vme1_reg_read(sc, VME1REG_SCON) & ~VME1_SCON_SYSFAIL;
    150 	vme1_reg_write(sc, VME1REG_SCON, reg);
    151 
    152 	printf(": Type 1 VMEchip, scon jumper %s\n",
    153 	    (reg & VME1_SCON_SWITCH) ? "enabled" : "disabled");
    154 
    155 	sc->sc_vct.cookie = self;
    156 	sc->sc_vct.vct_probe = _vme_pcc_probe;
    157 	sc->sc_vct.vct_map = _vme_pcc_map;
    158 	sc->sc_vct.vct_unmap = _vme_pcc_unmap;
    159 	sc->sc_vct.vct_int_map = _vme_pcc_intmap;
    160 	sc->sc_vct.vct_int_establish = _vme_pcc_intr_establish;
    161 	sc->sc_vct.vct_int_disestablish = _vme_pcc_intr_disestablish;
    162 	sc->sc_vct.vct_dmamap_create = _vme_pcc_dmamap_create;
    163 	sc->sc_vct.vct_dmamap_destroy = _vme_pcc_dmamap_destroy;
    164 	sc->sc_vct.vct_dmamem_alloc = _vme_pcc_dmamem_alloc;
    165 	sc->sc_vct.vct_dmamem_free = _vme_pcc_dmamem_free;
    166 
    167 	/*
    168 	 * Adjust the start address of the first range in vme_pcc_ranges[]
    169 	 * according to how much onboard memory exists. Disable the first
    170 	 * range if onboard memory >= 16Mb, and adjust the start of the
    171 	 * second range (A32D32).
    172 	 */
    173 	vme_pcc_ranges[0].pr_start = (vme_addr_t) mem_clusters[0].size;
    174 	if ( mem_clusters[0].size >= 0x01000000 ) {
    175 		vme_pcc_ranges[0].pr_am = (vme_am_t) -1;
    176 		vme_pcc_ranges[1].pr_start +=
    177 		    (vme_addr_t) (mem_clusters[0].size - 0x01000000);
    178 	}
    179 
    180 #ifdef DIAGNOSTIC
    181 	for (i = 0; i < VME1_NRANGES; i++) {
    182 		vme_addr_t mask;
    183 
    184 		switch ( vme_pcc_ranges[i].pr_am & VME_AM_ADRSIZEMASK ) {
    185 		  case VME_AM_A32:
    186 			mask = 0xffffffffu;
    187 			break;
    188 
    189 		  case VME_AM_A24:
    190 			mask = 0x00ffffffu;
    191 			break;
    192 
    193 		  case VME_AM_A16:
    194 			mask = 0x0000ffffu;
    195 			break;
    196 
    197 		  default:
    198 			printf("%s: Map#%d: disabled\n",
    199 			    sc->sc_dev.dv_xname, i);
    200 			continue;
    201 		}
    202 
    203 		printf("%s: Map#%d: 0x%08x -> %s\n", sc->sc_dev.dv_xname, i,
    204 		    vme_pcc_ranges[i].pr_start,
    205 		    _vme1_mod_string(vme_pcc_ranges[i].pr_start & mask,
    206 			(vme_pcc_ranges[i].pr_end -
    207 			vme_pcc_ranges[i].pr_start) + 1,
    208 			vme_pcc_ranges[i].pr_am,
    209 			vme_pcc_ranges[i].pr_datasize));
    210 	}
    211 #endif
    212 
    213 	vaa.va_vct = &(sc->sc_vct);
    214 	vaa.va_bdt = sc->sc_dmat;
    215 	vaa.va_slaveconfig = NULL;
    216 
    217 	vme_pcc_attached = 1;
    218 
    219 	/* Attach the MI VMEbus glue. */
    220 	config_found(self, &vaa, 0);
    221 }
    222 
    223 int
    224 _vme_pcc_map(vsc, vmeaddr, len, am, datasize, swap, tag, handle, resc)
    225 	void *vsc;
    226 	vme_addr_t vmeaddr;
    227 	vme_size_t len;
    228 	vme_am_t am;
    229 	vme_datasize_t datasize;
    230 	vme_swap_t swap;
    231 	bus_space_tag_t *tag;
    232 	bus_space_handle_t *handle;
    233 	vme_mapresc_t *resc;
    234 {
    235 	struct vme_pcc_softc *sc;
    236 	struct vme_pcc_mapresc_t *pm;
    237 	struct vme_pcc_range *pr;
    238 	vme_addr_t end, mask;
    239 	paddr_t paddr;
    240 	int rv;
    241 	int i;
    242 
    243 	sc = (struct vme_pcc_softc *) vsc;
    244 
    245 	end = (vmeaddr + len) - 1;
    246 	mask = 0;
    247 	paddr = 0;
    248 
    249 	switch ( am & VME_AM_ADRSIZEMASK ) {
    250 	  case VME_AM_A32:
    251 		mask = 0xffffffffu;
    252 		break;
    253 
    254 	  case VME_AM_A24:
    255 		mask = 0x00ffffffu;
    256 		break;
    257 
    258 	  case VME_AM_A16:
    259 		mask = 0x0000ffffu;
    260 		break;
    261 
    262 	  case VME_AM_USERDEF:
    263 		printf("%s: User-defined address modifiers not supported\n",
    264 		    sc->sc_dev.dv_xname);
    265 		return EINVAL;
    266 	}
    267 
    268 	for (i = 0, pr = &vme_pcc_ranges[0]; i < VME1_NRANGES; i++, pr++) {
    269 		/* Ignore if range is disabled */
    270 		if ( pr->pr_am == (vme_am_t) -1 )
    271 			continue;
    272 
    273 		/*
    274 		 * Accept the range if it matches the constraints
    275 		 */
    276 		if ( am == pr->pr_am &&
    277 		     datasize <= pr->pr_datasize            &&
    278 		     vmeaddr >= (pr->pr_start & mask)       &&
    279 		     end <= (pr->pr_end & mask) ) {
    280 			/*
    281 			 * We have a match.
    282 			 */
    283 			paddr = pr->pr_start + vmeaddr;
    284 			break;
    285 		}
    286 	}
    287 
    288 	if ( paddr == 0 ) {
    289 #ifdef DIAGNOSTIC
    290 		printf("%s: Unable to map %s\n", sc->sc_dev.dv_xname,
    291 			_vme1_mod_string(vmeaddr, len, am, datasize));
    292 #endif
    293 		return ENOMEM;
    294 	}
    295 
    296 	if ( (rv = bus_space_map(sc->sc_vmet, paddr, len, 0, handle)) != 0 )
    297 		return rv;
    298 
    299 	if ( (pm = malloc(sizeof(*pm), M_DEVBUF, M_NOWAIT)) == NULL ) {
    300 		bus_space_unmap(sc->sc_vmet, *handle, len);
    301 		return ENOMEM;
    302 	}
    303 
    304 	*tag = sc->sc_vmet;
    305 	pm->pm_am = am;
    306 	pm->pm_datasize = datasize;
    307 	pm->pm_addr = vmeaddr;
    308 	pm->pm_size = len;
    309 	pm->pm_handle = *handle;
    310 	*resc = (vme_mapresc_t *) pm;
    311 
    312 	return 0;
    313 }
    314 
    315 void
    316 _vme_pcc_unmap(vsc, resc)
    317 	void *vsc;
    318 	vme_mapresc_t resc;
    319 {
    320 	struct vme_pcc_softc *sc;
    321 	struct vme_pcc_mapresc_t *pm;
    322 
    323 	sc = (struct vme_pcc_softc *) vsc;
    324 	pm = (struct vme_pcc_mapresc_t *) resc;
    325 
    326 	bus_space_unmap(sc->sc_vmet, pm->pm_handle, pm->pm_size);
    327 
    328 	free(pm, M_DEVBUF);
    329 }
    330 
    331 int
    332 _vme_pcc_probe(vsc, vmeaddr, len, am, datasize, callback, arg)
    333 	void *vsc;
    334 	vme_addr_t vmeaddr;
    335 	vme_size_t len;
    336 	vme_am_t am;
    337 	vme_datasize_t datasize;
    338 	int (*callback) __P((void *, bus_space_tag_t, bus_space_handle_t));
    339 	void *arg;
    340 {
    341 	bus_space_tag_t tag;
    342 	bus_space_handle_t handle;
    343 	vme_mapresc_t resc;
    344 	int rv;
    345 
    346 	rv = _vme_pcc_map(vsc, vmeaddr, len, am, datasize,
    347 	    0, &tag, &handle, &resc);
    348 	if ( rv )
    349 		return rv;
    350 
    351 	if ( callback )
    352 		rv = (*callback)(arg, tag, handle);
    353 	else {
    354 		/*
    355 		 * FIXME: datasize is fixed by hardware, so using badaddr() in
    356 		 * this way may cause several accesses to each VMEbus address.
    357 		 * Also, using 'handle' in this way is a bit presumptuous...
    358 		 */
    359 		rv = badaddr((caddr_t) handle, (int) len) ? EIO : 0;
    360 	}
    361 
    362 	_vme_pcc_unmap(vsc, resc);
    363 
    364 	return rv;
    365 }
    366 
    367 int
    368 _vme_pcc_intmap(vsc, level, vector, handlep)
    369 	void *vsc;
    370 	int level, vector;
    371 	vme_intr_handle_t *handlep;
    372 {
    373 	if ( level < 0x80 )
    374 		return EINVAL;
    375 
    376 	/* This is rather gross */
    377 	*handlep = (void *)(int)((level << 8) | vector);
    378 
    379 	return 0;
    380 }
    381 
    382 void *
    383 _vme_pcc_intr_establish(vsc, handle, prior, func, arg)
    384 	void *vsc;
    385 	vme_intr_handle_t handle;
    386 	int prior;
    387 	int (*func) __P((void *));
    388 	void *arg;
    389 {
    390 	struct vme_pcc_softc *sc;
    391 	int level, vector;
    392 
    393 	sc = (struct vme_pcc_softc *) vsc;
    394 	level = ((int)handle) >> 8;
    395 	vector = ((int)handle) & 0xff;
    396 
    397 	isrlink_vectored(func, arg, level, vector);
    398 	sc->sc_irqref[level]++;
    399 
    400 	/*
    401 	 * There had better not be another VMEbus master responding
    402 	 * to this interrupt level...
    403 	 */
    404 	vme1_reg_write(sc, VME1REG_IRQEN,
    405 	    vme1_reg_read(sc, VME1REG_IRQEN) | VME1_IRQ_VME(level));
    406 
    407 	return (void *) handle;
    408 }
    409 
    410 void
    411 _vme_pcc_intr_disestablish(vsc, handle)
    412 	void *vsc;
    413 	vme_intr_handle_t handle;
    414 {
    415 	struct vme_pcc_softc *sc;
    416 	int level, vector;
    417 
    418 	sc = (struct vme_pcc_softc *) vsc;
    419 	level = ((int)handle) >> 8;
    420 	vector = ((int)handle) & 0xff;
    421 
    422 	isrunlink_vectored(vector);
    423 
    424 	/* Disable VME IRQ if possible. */
    425 	switch (sc->sc_irqref[level]) {
    426 	case 0:
    427 		printf("vme_pcc_intr_disestablish: nothing using IRQ %d\n",
    428 		    level);
    429 		panic("vme_pcc_intr_disestablish");
    430 		/* NOTREACHED */
    431 
    432 	case 1:
    433 		vme1_reg_write(sc, VME1REG_IRQEN,
    434 		    vme1_reg_read(sc, VME1REG_IRQEN) & ~VME1_IRQ_VME(level));
    435 		/* FALLTHROUGH */
    436 
    437 	default:
    438 		sc->sc_irqref[level]--;
    439 	}
    440 }
    441 
    442 int
    443 _vme_pcc_dmamap_create(vsc, len, am, datasize, swap, nsegs,
    444 		       segsz, bound, flags, mapp)
    445 	void *vsc;
    446 	vme_size_t len;
    447 	vme_am_t am;
    448 	vme_datasize_t datasize;
    449 	vme_swap_t swap;
    450 	int nsegs;
    451 	vme_size_t segsz;
    452 	vme_addr_t bound;
    453 	int flags;
    454 	bus_dmamap_t *mapp;
    455 {
    456 	return (EINVAL);
    457 }
    458 
    459 void
    460 _vme_pcc_dmamap_destroy(vsc, map)
    461 	void *vsc;
    462 	bus_dmamap_t map;
    463 {
    464 }
    465 
    466 int
    467 _vme_pcc_dmamem_alloc(vsc, len, am, datasizes, swap,
    468 		      segs, nsegs, rsegs, flags)
    469 	void *vsc;
    470 	vme_size_t len;
    471 	vme_am_t am;
    472 	vme_datasize_t datasizes;
    473 	vme_swap_t swap;
    474 	bus_dma_segment_t *segs;
    475 	int nsegs;
    476 	int *rsegs;
    477 	int flags;
    478 {
    479 	return (EINVAL);
    480 }
    481 
    482 void
    483 _vme_pcc_dmamem_free(vsc, segs, nsegs)
    484 	void *vsc;
    485 	bus_dma_segment_t *segs;
    486 	int nsegs;
    487 {
    488 }
    489 
    490 #ifdef DIAGNOSTIC
    491 const char *
    492 _vme1_mod_string(addr, len, am, ds)
    493 	vme_addr_t addr;
    494 	vme_size_t len;
    495 	vme_am_t am;
    496 	vme_datasize_t ds;
    497 {
    498 	static const char *mode[] = {"BLT64)", "DATA)", "PROG)", "BLT32)"};
    499 	static char mstring[40];
    500 	static char mdata[10];
    501 	char *fmt;
    502 
    503 	mdata[0] = '\0';
    504 	if ( ds & VME_D32 )
    505 		strcat(mdata, "D32");
    506 	if ( ds & VME_D16 )
    507 		strcat(mdata, mdata[0] == '\0' ? "D16" : "|D16");
    508 	if ( ds & VME_D8 )
    509 		strcat(mdata, mdata[0] == '\0' ? "D8" : "|D8");
    510 
    511 	switch ( am & VME_AM_ADRSIZEMASK ) {
    512 	  case VME_AM_A32:
    513 		fmt = "A32%s:0x%08x-0x%08x";
    514 		break;
    515 
    516 	  case VME_AM_A24:
    517 		fmt = "A24%s:0x%06x-0x%06x";
    518 		break;
    519 
    520 	  case VME_AM_A16:
    521 		fmt = "A16%s:0x%04x-0x%04x";
    522 		break;
    523 
    524 	  case VME_AM_USERDEF:
    525 		fmt = "USR%s:0x%08x-0x%08x";
    526 		break;
    527 	}
    528 
    529 	sprintf(mstring, fmt, mdata, addr, addr + len - 1);
    530 	strcat(mstring, ((am & VME_AM_PRIVMASK) == VME_AM_USER) ?
    531 	    " (USER," : " (SUPER,");
    532 	strcat(mstring, mode[am & VME_AM_MODEMASK]);
    533 
    534 	return (mstring);
    535 }
    536 #endif
    537