Home | History | Annotate | Line # | Download | only in g42xxeb
obio.c revision 1.1
      1 /*	$NetBSD: obio.c,v 1.1 2005/02/26 10:49:53 bsh Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2002, 2003, 2005  Genetec corp.  All rights reserved.
      5  * Written by Hiroyuki Bessho for Genetec corp.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of Genetec corp. may not be used to endorse
     16  *    or promote products derived from this software without specific prior
     17  *    written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
     20  * 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 GENETEC CORP.
     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 #include <sys/param.h>
     34 #include <sys/systm.h>
     35 #include <sys/device.h>
     36 #include <sys/kernel.h>
     37 #include <sys/reboot.h>
     38 
     39 #include <machine/cpu.h>
     40 #include <machine/bus.h>
     41 #include <machine/intr.h>
     42 #include <arm/cpufunc.h>
     43 
     44 #include <arm/mainbus/mainbus.h>
     45 #include <arm/xscale/pxa2x0reg.h>
     46 #include <arm/xscale/pxa2x0var.h>
     47 #include <arm/xscale/pxa2x0_gpio.h>
     48 #include <arm/sa11x0/sa11x0_var.h>
     49 #include <evbarm/g42xxeb/g42xxeb_reg.h>
     50 #include <evbarm/g42xxeb/g42xxeb_var.h>
     51 
     52 #include "locators.h"
     53 
     54 /* prototypes */
     55 static int	obio_match(struct device *, struct cfdata *, void *);
     56 static void	obio_attach(struct device *, struct device *, void *);
     57 static int 	obio_search(struct device *, struct cfdata *, void *);
     58 static int	obio_print(void *, const char *);
     59 
     60 /* attach structures */
     61 CFATTACH_DECL(obio, sizeof(struct obio_softc), obio_match, obio_attach,
     62     NULL, NULL);
     63 
     64 static int
     65 obio_spurious(void *arg)
     66 {
     67 	int irqno = (int)arg;
     68 
     69 	printf("Spurious interrupt %d on On-board peripheral", irqno);
     70 	return 1;
     71 }
     72 
     73 
     74 /*
     75  * interrupt handler for GPIO0 (on-board peripherals)
     76  *
     77  * On G4250ebx, 10 interrupts are ORed through on-board logic,
     78  * and routed to GPIO0 of PXA250 processor.
     79  */
     80 static int
     81 obio_intr(void *arg)
     82 {
     83 	int irqno, pending;
     84 	struct obio_softc *sc = (struct obio_softc *)arg;
     85 	int n=0;
     86 
     87 #define get_pending(sc) \
     88 	(bus_space_read_2( sc->sc_iot, sc->sc_obioreg_ioh, G42XXEB_INTSTS1) \
     89 	& ~(sc->sc_intr_pending|sc->sc_intr_mask))
     90 
     91 #ifdef DEBUG
     92 	printf("obio_intr: pend=%x, mask=%x, pend=%x, mask=%x\n",
     93 	    bus_space_read_2(sc->sc_iot, sc->sc_obioreg_ioh, G42XXEB_INTSTS1),
     94 	    bus_space_read_2(sc->sc_iot, sc->sc_obioreg_ioh, G42XXEB_INTMASK),
     95 	    sc->sc_intr_pending,
     96 	    sc->sc_intr_mask);
     97 #endif
     98 
     99 	for (pending = get_pending(sc);
    100 	     (irqno = find_first_bit(pending)) >= 0;
    101 	     pending = get_pending(sc)) {
    102 
    103 		/* reset pending bit */
    104 		bus_space_write_2(sc->sc_iot, sc->sc_obioreg_ioh,
    105 		    G42XXEB_INTSTS1, ~(1<<irqno));
    106 
    107 #if 0
    108 		if (sc->sc_handler[irqno].level > saved_spl_level) {
    109 			int spl_save = _splraise(sc->sc_handler[irqno].level);
    110 			(* sc->sc_handler[irqno].func)(
    111 				sc->sc_handler[irqno].arg);
    112 			splx(spl_save);
    113 		}
    114 		else
    115 #endif
    116 		{
    117 			int psw = disable_interrupts(I32_bit); /* XXX */
    118 
    119 			/* mask this interrupt until software
    120 			   interrupt is handled. */
    121 			sc->sc_intr_pending |= (1U<<irqno);
    122 			obio_update_intrmask(sc);
    123 
    124 			restore_interrupts(psw);
    125 			++n;
    126 		}
    127 #ifdef DIAGNOSTIC
    128 		if (n > 1000)
    129 			panic("obio_intr: stayed too long");
    130 #endif
    131 	}
    132 
    133 	if (n > 0) {
    134 		/* handle it later */
    135 		softintr_schedule(sc->sc_si);
    136 	}
    137 
    138 	/* GPIO interrupt is edge triggered.  make a pulse
    139 	   to let Cotulla notice when other interrupts are
    140 	   still pending */
    141 	bus_space_write_2(sc->sc_iot, sc->sc_obioreg_ioh,
    142 	    G42XXEB_INTMASK, 0xffff);
    143 	obio_update_intrmask(sc);
    144 
    145 	return 1;
    146 }
    147 
    148 static void
    149 obio_softintr(void *arg)
    150 {
    151 	struct obio_softc *sc = (struct obio_softc *)arg;
    152 	int irqno;
    153 	int spl_save = current_spl_level;
    154 	int psw;
    155 
    156 	psw = disable_interrupts(I32_bit);
    157 	while ((irqno = find_first_bit(sc->sc_intr_pending)) >= 0) {
    158 		sc->sc_intr_pending &= ~(1U<<irqno);
    159 
    160 		restore_interrupts(psw);
    161 
    162 		_splraise(sc->sc_handler[irqno].level);
    163 		(* sc->sc_handler[irqno].func)(
    164 			sc->sc_handler[irqno].arg);
    165 		splx(spl_save);
    166 
    167 		psw = disable_interrupts(I32_bit);
    168 	}
    169 
    170 	/* assert(sc->sc_intr_pending==0) */
    171 
    172 	bus_space_write_2(sc->sc_iot, sc->sc_obioreg_ioh,
    173 	    G42XXEB_INTMASK, 0xffff);
    174 	obio_update_intrmask(sc);
    175 
    176 	restore_interrupts(psw);
    177 }
    178 
    179 /*
    180  * int obio_print(void *aux, const char *name)
    181  * print configuration info for children
    182  */
    183 
    184 static int
    185 obio_print(void *aux, const char *name)
    186 {
    187 	struct obio_attach_args *oba = (struct obio_attach_args*)aux;
    188 
    189 	if (oba->oba_addr != OBIOCF_ADDR_DEFAULT)
    190                 printf(" addr 0x%lx", oba->oba_addr);
    191         if (oba->oba_intr > 0)
    192                 printf(" intr %d", oba->oba_intr);
    193         return (UNCONF);
    194 }
    195 
    196 int
    197 obio_match(struct device *parent, struct cfdata *match, void *aux)
    198 {
    199 	return 1;
    200 }
    201 
    202 void
    203 obio_attach(struct device *parent, struct device *self, void *aux)
    204 {
    205 	struct obio_softc *sc = (struct obio_softc*)self;
    206 	struct sa11x0_attach_args *sa = (struct sa11x0_attach_args *)aux;
    207 	bus_space_tag_t iot = sa->sa_iot;
    208 	int i;
    209 	uint16_t reg;
    210 
    211 	/* tweak memory access timing for CS3.
    212 	   the value set by redboot is too slow */
    213 	if (bus_space_map(iot, PXA2X0_MEMCTL_BASE, PXA2X0_MEMCTL_SIZE, 0,
    214 		&sc->sc_memctl_ioh))
    215 		goto fail;
    216 	bus_space_write_4(iot, sc->sc_memctl_ioh, MEMCTL_MSC1,
    217 	    (0xffff & bus_space_read_4(iot, sc->sc_memctl_ioh, MEMCTL_MSC1))
    218 	    | (0x6888 << 16));
    219 
    220 	/* Map on-board FPGA registers */
    221 	sc->sc_iot = iot;
    222 	if (bus_space_map(iot, G42XXEB_PLDREG_BASE, G42XXEB_PLDREG_SIZE,
    223 	    0, &(sc->sc_obioreg_ioh)))
    224 		goto fail;
    225 
    226 	/*
    227 	 *  Mask all interrupts.
    228 	 *  They are later unmasked at each device's attach routine.
    229 	 */
    230 	sc->sc_intr_mask = 0xffff;
    231 	bus_space_write_2(iot, sc->sc_obioreg_ioh, G42XXEB_INTMASK,
    232 	    sc->sc_intr_mask );
    233 
    234 #if 0
    235 	sc->sc_intr = 8;		/* GPIO0 */
    236 #endif
    237 	sc->sc_intr_pending = 0;
    238 
    239 	for (i=0; i < G42XXEB_N_INTS; ++i) {
    240 		sc->sc_handler[i].func = obio_spurious;
    241 		sc->sc_handler[i].arg = (void *)i;
    242 	}
    243 
    244 	obio_peripheral_reset(sc, 1, 0);
    245 
    246 	/*
    247 	 * establish interrupt handler.
    248 	 * level is very high to allow high priority sub-interrupts.
    249 	 */
    250 	sc->sc_ipl = IPL_AUDIO;
    251 	sc->sc_ih = pxa2x0_gpio_intr_establish(0, IST_EDGE_FALLING, sc->sc_ipl,
    252 	    obio_intr, sc);
    253 	sc->sc_si = softintr_establish(IPL_SOFTNET, obio_softintr, sc);
    254 
    255 	reg = bus_space_read_2(iot, sc->sc_obioreg_ioh, G42XXEB_PLDVER);
    256 	aprint_normal(": board %d version %x\n", reg>>8, reg & 0xff);
    257 
    258 	/*
    259 	 *  Attach each devices
    260 	 */
    261 	config_search(obio_search, self, NULL);
    262 	return;
    263 
    264  fail:
    265 	printf( "%s: can't map FPGA registers\n", self->dv_xname );
    266 }
    267 
    268 int
    269 obio_search(struct device *parent, struct cfdata *cf, void *aux)
    270 {
    271 	struct obio_softc *sc = (struct obio_softc *)parent;
    272 	struct obio_attach_args oba;
    273 
    274 	oba.oba_sc = sc;
    275         oba.oba_iot = sc->sc_iot;
    276         oba.oba_addr = cf->cf_loc[OBIOCF_ADDR];
    277         oba.oba_intr = cf->cf_loc[OBIOCF_INTR];
    278 
    279         if (config_match(parent, cf, &oba) > 0)
    280                 config_attach(parent, cf, &oba, obio_print);
    281 
    282         return 0;
    283 }
    284 
    285 void *
    286 obio_intr_establish(struct obio_softc *sc, int irq, int ipl,
    287     int type, int (*func)(void *), void *arg)
    288 {
    289 	int save;
    290 	int regidx, sft;
    291 	uint16_t reg;
    292 	static const uint8_t ist_code[] = {
    293 		0,
    294 		G42XXEB_INT_EDGE_FALLING, /* pulse */
    295 		G42XXEB_INT_EDGE_FALLING, /* IST_EDGE */
    296 		G42XXEB_INT_LEVEL_LOW,	   /* IST_LEVEL */
    297 		G42XXEB_INT_LEVEL_HIGH,   /* IST_LEVEL_HIGH */
    298 		G42XXEB_INT_EDGE_RISING,  /* IST_EDGE_RISING */
    299 		G42XXEB_INT_EDGE_BOTH,	   /* IST_EDGE_BOTH */
    300 	};
    301 
    302 	if (irq < 0 || G42XXEB_N_INTS <= irq)
    303 		panic("Bad irq no. for obio (%d)", irq);
    304 
    305 	if (type < 0 || IST_EDGE_BOTH < type)
    306 		panic("Bad interrupt type for obio (%d)", type);
    307 
    308 	regidx = G42XXEB_INTCNTL;
    309 	sft = 3 * irq;
    310 	if (irq >= 5) {
    311 		regidx = G42XXEB_INTCNTH;
    312 		sft -= 3*5;
    313 	}
    314 
    315 	save = disable_interrupts(I32_bit);
    316 
    317 	sc->sc_handler[irq].func = func;
    318 	sc->sc_handler[irq].arg = arg;
    319 	sc->sc_handler[irq].level = ipl;
    320 
    321 	/* set interrupt type */
    322 	reg = bus_space_read_2(sc->sc_iot, sc->sc_obioreg_ioh, regidx);
    323 	bus_space_write_2(sc->sc_iot, sc->sc_obioreg_ioh, regidx,
    324 	    (reg & ~(7<<sft)) | (ist_code[type] << sft));
    325 
    326 #ifdef DEBUG
    327 	printf("INTCTL=%x,%x\n",
    328 	    bus_space_read_2(sc->sc_iot, sc->sc_obioreg_ioh, G42XXEB_INTCNTL),
    329 	    bus_space_read_2(sc->sc_iot, sc->sc_obioreg_ioh, G42XXEB_INTCNTH));
    330 #endif
    331 
    332 	sc->sc_intr_mask &= ~(1U << irq);
    333 	obio_update_intrmask(sc);
    334 
    335 	restore_interrupts(save);
    336 
    337 #if 0
    338 	if (ipl > sc->sc_ipl) {
    339 		pxa2x0_update_intr_masks(sc->sc_intr, ipl);
    340 		sc->sc_ipl = ipl;
    341 	}
    342 #endif
    343 
    344 	return &sc->sc_handler[irq];
    345 }
    346 
    347 void
    348 obio_intr_disestablish(struct obio_softc *sc, int irq, int (* func)(void *))
    349 {
    350 	int error = 0;
    351 	int save;
    352 
    353 	save = disable_interrupts(I32_bit);
    354 
    355 	if (sc->sc_handler[irq].func != func)
    356 		error = 1;
    357 	else {
    358 		sc->sc_handler[irq].func = obio_spurious;
    359 		sc->sc_handler[irq].level = IPL_NONE;
    360 
    361 		sc->sc_intr_pending &= ~(1U << irq);
    362 		sc->sc_intr_mask |= (1U << irq);
    363 		obio_update_intrmask(sc);
    364 	}
    365 
    366 	restore_interrupts(save);
    367 
    368 	if (error)
    369 		aprint_error("%s: bad intr_disestablish\n",
    370 		    sc->sc_dev.dv_xname);
    371 }
    372 
    373 void
    374 obio_intr_mask(struct obio_softc *sc, struct obio_handler *ih)
    375 {
    376 	int irqno;
    377 	int save;
    378 
    379 	irqno = ih - sc->sc_handler;
    380 #ifdef DIAGNOSTIC
    381 	if (ih == NULL || ih->func==NULL || irqno < 0 ||
    382 	    irqno >= G42XXEB_N_INTS)
    383 		panic("Bad arg for obio_intr_mask");
    384 #endif
    385 
    386 	save = disable_interrupts(I32_bit);
    387 	sc->sc_intr_mask |= 1U<<irqno;
    388 	obio_update_intrmask(sc);
    389 	restore_interrupts(save);
    390 }
    391 
    392 void
    393 obio_intr_unmask(struct obio_softc *sc, struct obio_handler *ih)
    394 {
    395 	int irqno;
    396 	int save;
    397 
    398 	irqno = ih - sc->sc_handler;
    399 #ifdef DIAGNOSTIC
    400 	if (ih == NULL || ih->func==NULL || irqno < 0 ||
    401 	    irqno >= G42XXEB_N_INTS)
    402 		panic("Bad arg for obio_intr_unmask");
    403 #endif
    404 
    405 	save = disable_interrupts(I32_bit);
    406 	sc->sc_intr_mask &= ~(1U<<irqno);
    407 	obio_update_intrmask(sc);
    408 	restore_interrupts(save);
    409 }
    410 
    411 void
    412 obio_peripheral_reset(struct obio_softc *bsc, int no, int onoff)
    413 {
    414 	uint16_t reg;
    415 
    416 	reg = bus_space_read_2(bsc->sc_iot, bsc->sc_obioreg_ioh,
    417 	    G42XXEB_RST);
    418 	bus_space_write_2(bsc->sc_iot, bsc->sc_obioreg_ioh, G42XXEB_RST,
    419 	    onoff ?  (reg & ~RST_EXT(no)) : (reg | RST_EXT(no)));
    420 }
    421 
    422