Home | History | Annotate | Line # | Download | only in dev
vme_pcc.c revision 1.6.24.2
      1 /*	$NetBSD: vme_pcc.c,v 1.6.24.2 2000/03/13 19:09:03 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/dev/pccvar.h>
     61 #include <mvme68k/dev/vme_pccreg.h>
     62 #include <mvme68k/dev/vme_pccvar.h>
     63 
     64 
     65 static int vme_pcc_match __P((struct device *, struct cfdata *, void *));
     66 static void vme_pcc_attach __P((struct device *, struct device *, void *));
     67 
     68 struct cfattach vmepcc_ca = {
     69 	sizeof(struct vme_pcc_softc), vme_pcc_match, vme_pcc_attach
     70 };
     71 
     72 extern	struct cfdriver vmepcc_cd;
     73 
     74 extern	phys_ram_seg_t mem_clusters[];
     75 static	int vme_pcc_attached;
     76 
     77 const char *_vme_mod_string __P((vme_addr_t, vme_size_t,
     78     vme_am_t, vme_datasize_t));
     79 
     80 /*
     81  * Describe the VMEbus ranges available from the MVME147
     82  */
     83 struct vme_pcc_range {
     84 	vme_am_t	pr_am;		/* Address Modifier for this range */
     85 	vme_datasize_t	pr_datasize;	/* Usable Data Sizes (D8, D16, D32) */
     86 	vme_addr_t	pr_start;	/* Local-bus start address of range */
     87 	vme_addr_t	pr_end;		/* Local-bus end address of range */
     88 };
     89 
     90 static struct vme_pcc_range vme_pcc_ranges[] = {
     91     {VME_AM_A24, VME_D32|VME_D16|VME_D8, VME1_A24D32_START, VME1_A24D32_END},
     92     {VME_AM_A32, VME_D32|VME_D16|VME_D8, VME1_A32D32_START, VME1_A32D32_END},
     93     {VME_AM_A24, VME_D16|VME_D8,         VME1_A24D16_START, VME1_A24D16_END},
     94     {VME_AM_A32, VME_D16|VME_D8,         VME1_A32D16_START, VME1_A32D16_END},
     95     {VME_AM_A16, VME_D16|VME_D8,         VME1_A16D16_START, VME1_A16D16_END}
     96 };
     97 #define VME1_NRANGES	(sizeof(vme_pcc_ranges)/sizeof(struct vme_pcc_range))
     98 
     99 
    100 static int
    101 vme_pcc_match(parent, cf, aux)
    102 	struct device *parent;
    103 	struct cfdata *cf;
    104 	void *aux;
    105 {
    106 	struct pcc_attach_args *pa = aux;
    107 
    108 	/* Only one VME chip, please. */
    109 	if (vme_pcc_attached)
    110 		return (0);
    111 
    112 	if (strcmp(pa->pa_name, vmepcc_cd.cd_name))
    113 		return (0);
    114 
    115 	return (1);
    116 }
    117 
    118 static void
    119 vme_pcc_attach(parent, self, aux)
    120 	struct device *parent, *self;
    121 	void *aux;
    122 {
    123 	struct pcc_attach_args *pa;
    124 	struct vme_pcc_softc *sc;
    125 	struct vmebus_attach_args vaa;
    126 	u_int8_t reg;
    127 	char pbuf[9];
    128 
    129 	sc = (struct vme_pcc_softc *) self;
    130 	pa = (struct pcc_attach_args *) aux;
    131 
    132 	sc->sc_dmat = pa->pa_dmat;
    133 	sc->sc_bust = pa->pa_bust;
    134 	sc->sc_vmet = MVME68K_VME_BUS_SPACE;
    135 
    136 	bus_space_map(sc->sc_bust, pa->pa_offset, VME1REG_SIZE,0, &sc->sc_bush);
    137 
    138 	/* Initialize the chip. */
    139 	reg = vme1_reg_read(sc, VME1REG_SCON) & ~VME1_SCON_SYSFAIL;
    140 	vme1_reg_write(sc, VME1REG_SCON, reg);
    141 
    142 	printf(": Type 1 VMEchip, scon jumper %s\n",
    143 	    (reg & VME1_SCON_SWITCH) ? "enabled" : "disabled");
    144 	format_bytes(pbuf, sizeof(pbuf), VMEIOMAPSIZE);
    145 	printf("%s: VMEbus map size: %s\n", sc->sc_dev.dv_xname, pbuf);
    146 
    147 	sc->sc_vct.cookie = self;
    148 	sc->sc_vct.vct_probe = _vme_pcc_probe;
    149 	sc->sc_vct.vct_map = _vme_pcc_map;
    150 	sc->sc_vct.vct_unmap = _vme_pcc_unmap;
    151 	sc->sc_vct.vct_int_map = _vme_pcc_intmap;
    152 	sc->sc_vct.vct_int_establish = _vme_pcc_intr_establish;
    153 	sc->sc_vct.vct_int_disestablish = _vme_pcc_intr_disestablish;
    154 	sc->sc_vct.vct_dmamap_create = _vme_pcc_dmamap_create;
    155 	sc->sc_vct.vct_dmamap_destroy = _vme_pcc_dmamap_destroy;
    156 	sc->sc_vct.vct_dmamem_alloc = _vme_pcc_dmamem_alloc;
    157 	sc->sc_vct.vct_dmamem_free = _vme_pcc_dmamem_free;
    158 
    159 	/*
    160 	 * Adjust the start address of the first range in vme_pcc_ranges[]
    161 	 * according to how much onboard memory exists. Disable the first
    162 	 * range if onboard memory >= 16Mb, and adjust the start of the
    163 	 * second range (A32D32).
    164 	 */
    165 	vme_pcc_ranges[0].pr_start = (vme_addr_t) mem_clusters[0].size;
    166 	if ( mem_clusters[0].size >= 0x01000000 ) {
    167 		vme_pcc_ranges[0].pr_am = (vme_am_t) -1;
    168 		vme_pcc_ranges[1].pr_start +=
    169 		    (vme_addr_t) (mem_clusters[0].size - 0x01000000);
    170 	}
    171 
    172 	/*
    173 	 * We keep A16 space permanently mapped into KVA to avoid
    174 	 * problems when drivers try to bus_space_map() register ranges
    175 	 * which are closer than NBPG to each other (highly likely in
    176 	 * A16 address space).
    177 	 * The _vme_bus_map() function re-uses this mapping to satisfy
    178 	 * requests to map A16 ranges.
    179 	 */
    180 	if ( bus_space_map(sc->sc_vmet, VME1_A16D16_START, 0x10000,
    181 	    0, &sc->sc_a16bush) < 0 ) {
    182 		panic("vme_pcc_attach: failed to map A16 VMEbus space");
    183 		/* NOTREACHED */
    184 	}
    185 
    186 	vaa.va_vct = &(sc->sc_vct);
    187 	vaa.va_bdt = sc->sc_dmat;
    188 	vaa.va_slaveconfig = NULL;
    189 
    190 	vme_pcc_attached = 1;
    191 
    192 	/* Attach the MI VMEbus glue. */
    193 	config_found(self, &vaa, 0);
    194 }
    195 
    196 int
    197 _vme_pcc_map(vsc, vmeaddr, len, am, datasize, swap, tag, handle, resc)
    198 	void *vsc;
    199 	vme_addr_t vmeaddr;
    200 	vme_size_t len;
    201 	vme_am_t am;
    202 	vme_datasize_t datasize;
    203 	vme_swap_t swap;
    204 	bus_space_tag_t *tag;
    205 	bus_space_handle_t *handle;
    206 	vme_mapresc_t *resc;
    207 {
    208 	struct vme_pcc_softc *sc;
    209 	struct vme_pcc_mapresc_t *pm;
    210 	struct vme_pcc_range *pr;
    211 	vme_addr_t end, mask;
    212 	paddr_t paddr;
    213 	int rv;
    214 	int i;
    215 
    216 	sc = (struct vme_pcc_softc *) vsc;
    217 
    218 	end = (vmeaddr + len) - 1;
    219 	mask = 0;
    220 	paddr = 0;
    221 
    222 	switch ( am & VME_AM_ADRSIZEMASK ) {
    223 	  case VME_AM_A32:
    224 		mask = 0xffffffffu;
    225 		break;
    226 
    227 	  case VME_AM_A24:
    228 		mask = 0x00ffffffu;
    229 		break;
    230 
    231 	  case VME_AM_A16:
    232 		mask = 0x0000ffffu;
    233 		break;
    234 
    235 	  case VME_AM_USERDEF:
    236 		printf("%s: User-defined address modifiers not supported\n",
    237 		    sc->sc_dev.dv_xname);
    238 		return EINVAL;
    239 	}
    240 
    241 	for (i = 0, pr = &vme_pcc_ranges[0]; i < VME1_NRANGES; i++, pr++) {
    242 		/* Ignore if range is disabled */
    243 		if ( pr->pr_am == (vme_addr_t) -1 )
    244 			continue;
    245 
    246 		/*
    247 		 * Accept the range if it matches the constraints
    248 		 */
    249 		if ( (am & VME_AM_ADRSIZEMASK) == pr->pr_am &&
    250 		     datasize <= pr->pr_datasize            &&
    251 		     vmeaddr >= (pr->pr_start & mask)       &&
    252 		     end <= (pr->pr_end & mask) ) {
    253 			/*
    254 			 * We have a match.
    255 			 */
    256 			paddr = pr->pr_start + vmeaddr;
    257 			break;
    258 		}
    259 	}
    260 
    261 	if ( paddr == 0 ) {
    262 #ifdef DIAGNOSTIC
    263 		printf("%s: Unable to map %s\n", sc->sc_dev.dv_xname,
    264 			_vme_mod_string(vmeaddr, len, am, datasize));
    265 #endif
    266 		return ENOMEM;
    267 	}
    268 
    269 	if ( (am & VME_AM_ADRSIZEMASK) == VME_AM_A16 )
    270 		bus_space_subregion(sc->sc_vmet, sc->sc_a16bush,
    271 		    vmeaddr, len, handle);
    272 	else
    273 	if ( (rv = bus_space_map(sc->sc_vmet, paddr, len, 0, handle)) != 0 )
    274 		return rv;
    275 
    276 	if ( (pm = malloc(sizeof(*pm), M_DEVBUF, M_NOWAIT)) == NULL ) {
    277 		if ( (am & VME_AM_ADRSIZEMASK) != VME_AM_A16 )
    278 			bus_space_unmap(sc->sc_vmet, *handle, len);
    279 		return ENOMEM;
    280 	}
    281 
    282 	*tag = sc->sc_vmet;
    283 	pm->pm_am = am;
    284 	pm->pm_datasize = datasize;
    285 	pm->pm_addr = vmeaddr;
    286 	pm->pm_size = len;
    287 	pm->pm_handle = *handle;
    288 	*resc = (vme_mapresc_t *) pm;
    289 
    290 	return 0;
    291 }
    292 
    293 void
    294 _vme_pcc_unmap(vsc, resc)
    295 	void *vsc;
    296 	vme_mapresc_t resc;
    297 {
    298 	struct vme_pcc_softc *sc;
    299 	struct vme_pcc_mapresc_t *pm;
    300 
    301 	sc = (struct vme_pcc_softc *) vsc;
    302 	pm = (struct vme_pcc_mapresc_t *) resc;
    303 
    304 	if ( (pm->pm_am & VME_AM_ADRSIZEMASK) != VME_AM_A16 )
    305 		bus_space_unmap(sc->sc_vmet, pm->pm_handle, pm->pm_size);
    306 
    307 	free(pm, M_DEVBUF);
    308 }
    309 
    310 int
    311 _vme_pcc_probe(vsc, vmeaddr, len, am, datasize, callback, arg)
    312 	void *vsc;
    313 	vme_addr_t vmeaddr;
    314 	vme_size_t len;
    315 	vme_am_t am;
    316 	vme_datasize_t datasize;
    317 	int (*callback) __P((void *, bus_space_tag_t, bus_space_handle_t));
    318 	void *arg;
    319 {
    320 	bus_space_tag_t tag;
    321 	bus_space_handle_t handle;
    322 	vme_mapresc_t resc;
    323 	int rv;
    324 
    325 	rv = _vme_pcc_map(vsc, vmeaddr, len, am, datasize,
    326 	    0, &tag, &handle, &resc);
    327 	if ( rv )
    328 		return rv;
    329 
    330 	if ( callback )
    331 		rv = (*callback)(arg, tag, handle);
    332 	else {
    333 		/*
    334 		 * FIXME: datasize is fixed by hardware, so using badaddr() in
    335 		 * this way may cause several accesses to each VMEbus address.
    336 		 * Also, using 'handle' in this way is a bit presumptuous...
    337 		 */
    338 		rv = badaddr((caddr_t) handle, (int) len) ? EIO : 0;
    339 	}
    340 
    341 	_vme_pcc_unmap(vsc, resc);
    342 
    343 	return rv;
    344 }
    345 
    346 int
    347 _vme_pcc_intmap(vsc, level, vector, handlep)
    348 	void *vsc;
    349 	int level, vector;
    350 	vme_intr_handle_t *handlep;
    351 {
    352 	if ( level < 0x80 )
    353 		return EINVAL;
    354 
    355 	/* This is rather gross */
    356 	*handlep = (void *)(int)((level << 8) | vector);
    357 
    358 	return 0;
    359 }
    360 
    361 void *
    362 _vme_pcc_intr_establish(vsc, handle, prior, func, arg)
    363 	void *vsc;
    364 	vme_intr_handle_t handle;
    365 	int prior;
    366 	int (*func) __P((void *));
    367 	void *arg;
    368 {
    369 	struct vme_pcc_softc *sc;
    370 	int level, vector;
    371 
    372 	sc = (struct vme_pcc_softc *) vsc;
    373 	level = ((int)handle) >> 8;
    374 	vector = ((int)handle) & 0xff;
    375 
    376 	isrlink_vectored(func, arg, level, vector);
    377 	sc->sc_irqref[level]++;
    378 
    379 	/*
    380 	 * There had better not be another VMEbus master responding
    381 	 * to this interrupt level...
    382 	 */
    383 	vme1_reg_write(sc, VME1REG_IRQEN,
    384 	    vme1_reg_read(sc, VME1REG_IRQEN) | VME1_IRQ_VME(level));
    385 }
    386 
    387 void
    388 _vme_pcc_intr_disestablish(vsc, handle)
    389 	void *vsc;
    390 	vme_intr_handle_t handle;
    391 {
    392 	struct vme_pcc_softc *sc;
    393 	int level, vector;
    394 
    395 	sc = (struct vme_pcc_softc *) vsc;
    396 	level = ((int)handle) >> 8;
    397 	vector = ((int)handle) & 0xff;
    398 
    399 	isrunlink_vectored(vector);
    400 
    401 	/* Disable VME IRQ if possible. */
    402 	switch (sc->sc_irqref[level]) {
    403 	case 0:
    404 		printf("vme_pcc_intr_disestablish: nothing using IRQ %d\n",
    405 		    level);
    406 		panic("vme_pcc_intr_disestablish");
    407 		/* NOTREACHED */
    408 
    409 	case 1:
    410 		vme1_reg_write(sc, VME1REG_IRQEN,
    411 		    vme1_reg_read(sc, VME1REG_IRQEN) & ~VME1_IRQ_VME(level));
    412 		/* FALLTHROUGH */
    413 
    414 	default:
    415 		sc->sc_irqref[level]--;
    416 	}
    417 }
    418 
    419 int
    420 _vme_pcc_dmamap_create(vsc, len, am, datasize, swap, nsegs,
    421 		       segsz, bound, flags, mapp)
    422 	void *vsc;
    423 	vme_size_t len;
    424 	vme_am_t am;
    425 	vme_datasize_t datasize;
    426 	vme_swap_t swap;
    427 	int nsegs;
    428 	vme_size_t segsz;
    429 	vme_addr_t bound;
    430 	int flags;
    431 	bus_dmamap_t *mapp;
    432 {
    433 	return (EINVAL);
    434 }
    435 
    436 void
    437 _vme_pcc_dmamap_destroy(vsc, map)
    438 	void *vsc;
    439 	bus_dmamap_t map;
    440 {
    441 }
    442 
    443 int
    444 _vme_pcc_dmamem_alloc(vsc, len, am, datasizes, swap,
    445 		      segs, nsegs, rsegs, flags)
    446 	void *vsc;
    447 	vme_size_t len;
    448 	vme_am_t am;
    449 	vme_datasize_t datasizes;
    450 	vme_swap_t swap;
    451 	bus_dma_segment_t *segs;
    452 	int nsegs;
    453 	int *rsegs;
    454 	int flags;
    455 {
    456 	return (EINVAL);
    457 }
    458 
    459 void
    460 _vme_pcc_dmamem_free(vsc, segs, nsegs)
    461 	void *vsc;
    462 	bus_dma_segment_t *segs;
    463 	int nsegs;
    464 {
    465 }
    466 
    467 const char *
    468 _vme_mod_string(addr, len, am, ds)
    469 	vme_addr_t addr;
    470 	vme_size_t len;
    471 	vme_am_t am;
    472 	vme_datasize_t ds;
    473 {
    474 	static const char *mode[] = {"BLT64)", "DATA)", "PROG)", "BLT32)"};
    475 	static char mstring[40];
    476 	static char mdata[10];
    477 	char *fmt;
    478 
    479 	mdata[0] = '\0';
    480 	if ( ds & VME_D32 )
    481 		strcat(mdata, "D32");
    482 	if ( ds & VME_D16 )
    483 		strcat(mdata, mdata[0] == '\0' ? "D16" : "|D16");
    484 	if ( ds & VME_D8 )
    485 		strcat(mdata, mdata[0] == '\0' ? "D8" : "|D8");
    486 
    487 	switch ( am & VME_AM_ADRSIZEMASK ) {
    488 	  case VME_AM_A32:
    489 		fmt = "A24%s:%08x-%08x";
    490 		break;
    491 
    492 	  case VME_AM_A24:
    493 		fmt = "A24%s:%06x-%06x";
    494 		break;
    495 
    496 	  case VME_AM_A16:
    497 		fmt = "A16%s:%04x-%04x";
    498 		break;
    499 
    500 	  case VME_AM_USERDEF:
    501 		fmt = "USR%s:%08x-%08x";
    502 		break;
    503 	}
    504 
    505 	sprintf(mstring, fmt, mdata, addr, addr + len - 1);
    506 	strcat(mstring, ((am & VME_AM_PRIVMASK) == VME_AM_USER) ?
    507 	    " (USER," : " (SUPER,");
    508 	strcat(mstring, mode[am & VME_AM_MODEMASK]);
    509 
    510 	return (mstring);
    511 }
    512