Home | History | Annotate | Line # | Download | only in dev
frodo.c revision 1.29.22.1
      1 /*	$NetBSD: frodo.c,v 1.29.22.1 2011/03/05 20:50:21 rmind Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1997, 1998, 1999 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.
      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  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1997 Michael Smith.  All rights reserved.
     34  *
     35  * Redistribution and use in source and binary forms, with or without
     36  * modification, are permitted provided that the following conditions
     37  * are met:
     38  * 1. Redistributions of source code must retain the above copyright
     39  *    notice, this list of conditions and the following disclaimer.
     40  * 2. Redistributions in binary form must reproduce the above copyright
     41  *    notice, this list of conditions and the following disclaimer in the
     42  *    documentation and/or other materials provided with the distribution.
     43  *
     44  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     45  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     46  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     47  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     48  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     49  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     50  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     51  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     52  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     53  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     54  * SUCH DAMAGE.
     55  */
     56 
     57 /*
     58  * Support for the "Frodo" (a.k.a. "Apollo Utility") chip found
     59  * in HP Apollo 9000/4xx workstations, as well as 9000/382 controllers.
     60  */
     61 
     62 #include <sys/cdefs.h>
     63 __KERNEL_RCSID(0, "$NetBSD: frodo.c,v 1.29.22.1 2011/03/05 20:50:21 rmind Exp $");
     64 
     65 #define	_HP300_INTR_H_PRIVATE
     66 
     67 #include <sys/param.h>
     68 #include <sys/systm.h>
     69 #include <sys/kernel.h>
     70 #include <sys/syslog.h>
     71 #include <sys/device.h>
     72 
     73 #include <machine/bus.h>
     74 #include <machine/cpu.h>
     75 #include <machine/intr.h>
     76 #include <machine/hp300spu.h>
     77 
     78 #include <hp300/dev/intiovar.h>
     79 
     80 #include <hp300/dev/frodoreg.h>
     81 #include <hp300/dev/frodovar.h>
     82 
     83 /*
     84  * Description of a Frodo interrupt handler.
     85  */
     86 struct frodo_interhand {
     87 	int	(*ih_fn)(void *);
     88 	void	*ih_arg;
     89 	int	ih_priority;
     90 };
     91 
     92 struct frodo_softc {
     93 	device_t	sc_dev;		/* generic device glue */
     94 	volatile uint8_t *sc_regs;	/* register base */
     95 	struct frodo_interhand sc_intr[FRODO_NINTR]; /* interrupt handlers */
     96 	int		sc_ipl;
     97 	void		*sc_ih;		/* out interrupt cookie */
     98 	int		sc_refcnt;	/* number of interrupt refs */
     99 	struct bus_space_tag sc_tag;	/* bus space tag */
    100 };
    101 
    102 static int	frodomatch(device_t, cfdata_t, void *);
    103 static void	frodoattach(device_t, device_t, void *);
    104 
    105 static int	frodoprint(void *, const char *);
    106 static int	frodosubmatch(device_t, cfdata_t, const int *, void *);
    107 
    108 static int	frodointr(void *);
    109 
    110 static void	frodo_imask(struct frodo_softc *, uint16_t, uint16_t);
    111 
    112 CFATTACH_DECL_NEW(frodo, sizeof(struct frodo_softc),
    113     frodomatch, frodoattach, NULL, NULL);
    114 
    115 static const struct frodo_device frodo_subdevs[] = {
    116 	{ "dnkbd",	FRODO_APCI_OFFSET(0),	FRODO_INTR_APCI0 },
    117 	{ "com",	FRODO_APCI_OFFSET(1),	FRODO_INTR_APCI1 },
    118 	{ "com",	FRODO_APCI_OFFSET(2),	FRODO_INTR_APCI2 },
    119 	{ "com",	FRODO_APCI_OFFSET(3),	FRODO_INTR_APCI3 },
    120 	{ NULL,		0,			0 }
    121 };
    122 
    123 static int
    124 frodomatch(device_t parent, cfdata_t cf, void *aux)
    125 {
    126 	struct intio_attach_args *ia = aux;
    127 	static int frodo_matched = 0;
    128 
    129 	/* only allow one instance */
    130 	if (frodo_matched)
    131 		return 0;
    132 
    133 	if (strcmp(ia->ia_modname, "frodo") != 0)
    134 		return 0;
    135 
    136 	if (badaddr((void *)ia->ia_addr))
    137 		return 0;
    138 
    139 	frodo_matched = 1;
    140 	return 1;
    141 }
    142 
    143 static void
    144 frodoattach(device_t parent, device_t self, void *aux)
    145 {
    146 	struct frodo_softc *sc = device_private(self);
    147 	struct intio_attach_args *ia = aux;
    148 	bus_space_tag_t bst = &sc->sc_tag;
    149 	const struct frodo_device *fd;
    150 	struct frodo_attach_args fa;
    151 
    152 	sc->sc_dev = self;
    153 	sc->sc_regs = (volatile uint8_t *)ia->ia_addr;
    154 	sc->sc_ipl = ia->ia_ipl;
    155 
    156 	if ((FRODO_READ(sc, FRODO_IISR) & FRODO_IISR_SERVICE) == 0)
    157 		aprint_error(": service mode enabled");
    158 	aprint_normal("\n");
    159 
    160 	/* Initialize bus_space_tag_t for frodo */
    161 	frodo_init_bus_space(bst);
    162 
    163 	/* Clear all of the interrupt handlers. */
    164 	memset(sc->sc_intr, 0, sizeof(sc->sc_intr));
    165 	sc->sc_refcnt = 0;
    166 
    167 	/*
    168 	 * Disable all of the interrupt lines; we reenable them
    169 	 * as subdevices attach.
    170 	 */
    171 	frodo_imask(sc, 0, 0xffff);
    172 
    173 	/* Clear any pending interrupts. */
    174 	FRODO_WRITE(sc, FRODO_PIC_PU, 0xff);
    175 	FRODO_WRITE(sc, FRODO_PIC_PL, 0xff);
    176 
    177 	/* Set interrupt polarities. */
    178 	FRODO_WRITE(sc, FRODO_PIO_IPR, 0x10);
    179 
    180 	/* ...and configure for edge triggering. */
    181 	FRODO_WRITE(sc, FRODO_PIO_IELR, 0xcf);
    182 
    183 	/*
    184 	 * We defer hooking up our interrupt handler until
    185 	 * a subdevice hooks up theirs.
    186 	 */
    187 	sc->sc_ih = NULL;
    188 
    189 	/* ... and attach subdevices. */
    190 	for (fd = frodo_subdevs; fd->fd_name != NULL; fd++) {
    191 		/*
    192 		 * Skip the first serial port if we're not a 425e;
    193 		 * it's mapped to the DCA at select code 9 on all
    194 		 * other models.
    195 		 */
    196 		if (fd->fd_offset == FRODO_APCI_OFFSET(1) &&
    197 		    mmuid != MMUID_425_E)
    198 			continue;
    199 		fa.fa_name = fd->fd_name;
    200 		fa.fa_bst = bst;
    201 		fa.fa_base = ia->ia_iobase;
    202 		fa.fa_offset = fd->fd_offset;
    203 		fa.fa_line = fd->fd_line;
    204 		config_found_sm_loc(self, "frodo", NULL, &fa, frodoprint,
    205 		    frodosubmatch);
    206 	}
    207 }
    208 
    209 static int
    210 frodosubmatch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
    211 {
    212 	struct frodo_attach_args *fa = aux;
    213 
    214 	if (cf->frodocf_offset != FRODO_UNKNOWN_OFFSET &&
    215 	    cf->frodocf_offset != fa->fa_offset)
    216 		return 0;
    217 
    218 	return config_match(parent, cf, aux);
    219 }
    220 
    221 static int
    222 frodoprint(void *aux, const char *pnp)
    223 {
    224 	struct frodo_attach_args *fa = aux;
    225 
    226 	if (pnp)
    227 		aprint_normal("%s at %s", fa->fa_name, pnp);
    228 	aprint_normal(" offset 0x%x", fa->fa_offset);
    229 	return UNCONF;
    230 }
    231 
    232 void
    233 frodo_intr_establish(device_t frdev, int (*func)(void *), void *arg,
    234     int line, int priority)
    235 {
    236 	struct frodo_softc *sc = device_private(frdev);
    237 	struct hp300_intrhand *ih = sc->sc_ih;
    238 
    239 	if (line < 0 || line >= FRODO_NINTR) {
    240 		aprint_error_dev(frdev, "bad interrupt line %d\n", line);
    241 		goto lose;
    242 	}
    243 	if (sc->sc_intr[line].ih_fn != NULL) {
    244 		aprint_error_dev(frdev, "interrupt line %d already used\n",
    245 		    line);
    246 		goto lose;
    247 	}
    248 
    249 	/* Install the handler. */
    250 	sc->sc_intr[line].ih_fn = func;
    251 	sc->sc_intr[line].ih_arg = arg;
    252 	sc->sc_intr[line].ih_priority = priority;
    253 
    254 	/*
    255 	 * If this is the first one, establish the frodo
    256 	 * interrupt handler.  If not, reestablish at a
    257 	 * higher priority if necessary.
    258 	 */
    259 	if (ih == NULL || ih->ih_priority < priority) {
    260 		if (ih != NULL)
    261 			intr_disestablish(ih);
    262 		sc->sc_ih = intr_establish(frodointr, sc, sc->sc_ipl, priority);
    263 	}
    264 
    265 	sc->sc_refcnt++;
    266 
    267 	/* Enable the interrupt line. */
    268 	frodo_imask(sc, (1 << line), 0);
    269 	return;
    270  lose:
    271 	panic("frodo_intr_establish");
    272 }
    273 
    274 void
    275 frodo_intr_disestablish(device_t frdev, int line)
    276 {
    277 	struct frodo_softc *sc = device_private(frdev);
    278 	struct hp300_intrhand *ih = sc->sc_ih;
    279 	int newpri;
    280 
    281 	if (sc->sc_intr[line].ih_fn == NULL) {
    282 		printf("%s: no handler for line %d\n",
    283 		    device_xname(sc->sc_dev), line);
    284 		panic("frodo_intr_disestablish");
    285 	}
    286 
    287 	sc->sc_intr[line].ih_fn = NULL;
    288 	frodo_imask(sc, 0, (1 << line));
    289 
    290 	/* If this was the last, unhook ourselves. */
    291 	if (sc->sc_refcnt-- == 1) {
    292 		intr_disestablish(ih);
    293 		return;
    294 	}
    295 
    296 	/* Lower our priority, if appropriate. */
    297 	for (newpri = 0, line = 0; line < FRODO_NINTR; line++)
    298 		if (sc->sc_intr[line].ih_fn != NULL &&
    299 		    sc->sc_intr[line].ih_priority > newpri)
    300 			newpri = sc->sc_intr[line].ih_priority;
    301 
    302 	if (newpri != ih->ih_priority) {
    303 		intr_disestablish(ih);
    304 		sc->sc_ih = intr_establish(frodointr, sc, sc->sc_ipl, newpri);
    305 	}
    306 }
    307 
    308 static int
    309 frodointr(void *arg)
    310 {
    311 	struct frodo_softc *sc = arg;
    312 	struct frodo_interhand *fih;
    313 	int line, taken = 0;
    314 
    315 	/* Any interrupts pending? */
    316 	if (FRODO_GETPEND(sc) == 0)
    317 		return 0;
    318 
    319 	do {
    320 		/*
    321 		 * Get pending interrupt; this also clears it for us.
    322 		 */
    323 		line = FRODO_IPEND(sc);
    324 		fih = &sc->sc_intr[line];
    325 		if (fih->ih_fn == NULL ||
    326 		    (*fih->ih_fn)(fih->ih_arg) == 0)
    327 			printf("%s: spurious interrupt on line %d\n",
    328 			    device_xname(sc->sc_dev), line);
    329 		if (taken++ > 100)
    330 			panic("frodointr: looping!");
    331 	} while (FRODO_GETPEND(sc) != 0);
    332 
    333 	return 1;
    334 }
    335 
    336 static void
    337 frodo_imask(struct frodo_softc *sc, uint16_t set, uint16_t clear)
    338 {
    339 	uint16_t imask;
    340 
    341 	imask = FRODO_GETMASK(sc);
    342 
    343 	imask |= set;
    344 	imask &= ~clear;
    345 
    346 	FRODO_SETMASK(sc, imask);
    347 }
    348 
    349 /*
    350  * frodo chip specific bus_space(9) support functions.
    351  */
    352 static uint8_t frodo_bus_space_read_sparse_1(bus_space_tag_t,
    353     bus_space_handle_t, bus_size_t);
    354 static void frodo_bus_space_write_sparse_1(bus_space_tag_t,
    355     bus_space_handle_t, bus_size_t, uint8_t);
    356 
    357 static void frodo_bus_space_read_multi_sparse_1(bus_space_tag_t,
    358     bus_space_handle_t, bus_size_t, uint8_t *, bus_size_t);
    359 static void frodo_bus_space_write_multi_sparse_1(bus_space_tag_t,
    360     bus_space_handle_t, bus_size_t, const uint8_t *, bus_size_t);
    361 
    362 static void frodo_bus_space_read_region_sparse_1(bus_space_tag_t,
    363     bus_space_handle_t, bus_size_t, uint8_t *, bus_size_t);
    364 static void frodo_bus_space_write_region_sparse_1(bus_space_tag_t,
    365     bus_space_handle_t, bus_size_t, const uint8_t *, bus_size_t);
    366 
    367 static void frodo_bus_space_set_multi_sparse_1(bus_space_tag_t,
    368     bus_space_handle_t, bus_size_t, uint8_t, bus_size_t);
    369 
    370 static void frodo_bus_space_set_region_sparse_1(bus_space_tag_t,
    371     bus_space_handle_t, bus_size_t, uint8_t, bus_size_t);
    372 
    373 /*
    374  * frodo_init_bus_space():
    375  *	Initialize bus_space functions in bus_space_tag_t
    376  *	for frodo devices which have sparse address space.
    377  */
    378 void
    379 frodo_init_bus_space(bus_space_tag_t bst)
    380 {
    381 
    382 	memset(bst, 0, sizeof(struct bus_space_tag));
    383 	bst->bustype = HP300_BUS_SPACE_INTIO;
    384 
    385 	bst->bsr1 = frodo_bus_space_read_sparse_1;
    386 	bst->bsw1 = frodo_bus_space_write_sparse_1;
    387 
    388 	bst->bsrm1 = frodo_bus_space_read_multi_sparse_1;
    389 	bst->bswm1 = frodo_bus_space_write_multi_sparse_1;
    390 
    391 	bst->bsrr1 = frodo_bus_space_read_region_sparse_1;
    392 	bst->bswr1 = frodo_bus_space_write_region_sparse_1;
    393 
    394 	bst->bssm1 = frodo_bus_space_set_multi_sparse_1;
    395 
    396 	bst->bssr1 = frodo_bus_space_set_region_sparse_1;
    397 }
    398 
    399 static uint8_t
    400 frodo_bus_space_read_sparse_1(bus_space_tag_t bst, bus_space_handle_t bsh,
    401     bus_size_t offset)
    402 {
    403 
    404 	return *(volatile uint8_t *)(bsh + (offset << 2));
    405 }
    406 
    407 static void
    408 frodo_bus_space_write_sparse_1(bus_space_tag_t bst, bus_space_handle_t bsh,
    409     bus_size_t offset, uint8_t val)
    410 {
    411 
    412 	*(volatile uint8_t *)(bsh + (offset << 2)) = val;
    413 }
    414 
    415 static void
    416 frodo_bus_space_read_multi_sparse_1(bus_space_tag_t bst, bus_space_handle_t bsh,
    417     bus_size_t offset, uint8_t *addr, bus_size_t len)
    418 {
    419 
    420 	__asm volatile (
    421 	"	movl	%0,%%a0		;\n"
    422 	"	movl	%1,%%a1		;\n"
    423 	"	movl	%2,%%d0		;\n"
    424 	"1:	movb	%%a0@,%%a1@+	;\n"
    425 	"	subql	#1,%%d0		;\n"
    426 	"	jne	1b"
    427 	    :
    428 	    : "r" (bsh + (offset << 2)), "g" (addr), "g" (len)
    429 	    : "%a0","%a1","%d0");
    430 }
    431 
    432 static void
    433 frodo_bus_space_write_multi_sparse_1(bus_space_tag_t bst,
    434     bus_space_handle_t bsh, bus_size_t offset, const uint8_t *addr,
    435     bus_size_t len)
    436 {
    437 
    438 	__asm volatile (
    439 	"	movl	%0,%%a0		;\n"
    440 	"	movl	%1,%%a1		;\n"
    441 	"	movl	%2,%%d0		;\n"
    442 	"1:	movb	%%a1@+,%%a0@	;\n"
    443 	"	subql	#1,%%d0		;\n"
    444 	"	jne	1b"
    445 	    :
    446 	    : "r" (bsh + (offset << 2)), "g" (addr), "g" (len)
    447 	    : "%a0","%a1","%d0");
    448 }
    449 
    450 static void
    451 frodo_bus_space_read_region_sparse_1(bus_space_tag_t bst,
    452     bus_space_handle_t bsh, bus_size_t offset, uint8_t *addr, bus_size_t len)
    453 {
    454 	__asm volatile (
    455 	"	movl	%0,%%a0		;\n"
    456 	"	movl	%1,%%a1		;\n"
    457 	"	movl	%2,%%d0		;\n"
    458 	"1:	movb	%%a0@,%%a1@+	;\n"
    459 	"	addql	#4,%%a0		;\n"
    460 	"	subql	#1,%%d0		;\n"
    461 	"	jne	1b"
    462 	    :
    463 	    : "r" (bsh + (offset << 2)), "g" (addr), "g" (len)
    464 	    : "%a0","%a1","%d0");
    465 }
    466 
    467 static void
    468 frodo_bus_space_write_region_sparse_1(bus_space_tag_t bst,
    469     bus_space_handle_t bsh, bus_size_t offset, const uint8_t *addr,
    470     bus_size_t len)
    471 {
    472 
    473 	__asm volatile (
    474 	"	movl	%0,%%a0		;\n"
    475 	"	movl	%1,%%a1		;\n"
    476 	"	movl	%2,%%d0		;\n"
    477 	"1:	movb	%%a1@+,%%a0@	;\n"
    478 	"	addql	#4,%%a0		;\n"
    479 	"	subql	#1,%%d0		;\n"
    480 	"	jne	1b"
    481 	    :
    482 	    : "r" (bsh + (offset << 2)), "g" (addr), "g" (len)
    483 	    : "%a0","%a1","%d0");
    484 }
    485 
    486 static void
    487 frodo_bus_space_set_multi_sparse_1(bus_space_tag_t bst, bus_space_handle_t bsh,
    488     bus_size_t offset, uint8_t val, bus_size_t count)
    489 {
    490 	__asm volatile (
    491 	"	movl	%0,%%a0		;\n"
    492 	"	movl	%1,%%d1		;\n"
    493 	"	movl	%2,%%d0		;\n"
    494 	"1:	movb	%%d1,%%a0@	;\n"
    495 	"	subql	#1,%%d0		;\n"
    496 	"	jne	1b"
    497 	    :
    498 	    : "r" (bsh + (offset << 2)), "g" (val), "g" (count)
    499 	    : "%a0","%d0","%d1");
    500 }
    501 
    502 static void
    503 frodo_bus_space_set_region_sparse_1(bus_space_tag_t bst, bus_space_handle_t bsh,
    504     bus_size_t offset, uint8_t val, bus_size_t count)
    505 {
    506 
    507 	__asm volatile (
    508 	"	movl	%0,%%a0		;\n"
    509 	"	movl	%1,%%d1		;\n"
    510 	"	movl	%2,%%d0		;\n"
    511 	"1:	movb	%%d1,%%a0@	;\n"
    512 	"	addql	#4,%%a0		;\n"
    513 	"	subql	#1,%%d0		;\n"
    514 	"	jne	1b"
    515 	    :
    516 	    : "r" (bsh + (offset << 2)), "g" (val), "g" (count)
    517 	    : "%a0","%d0","%d1");
    518 }
    519