Annotation of sys/arch/arm/s3c2xx0/s3c2410_extint.c, Revision 1.1
1.1 ! nbrk 1: /* $NetBSD: s3c2410_extint.c,v 1.7 2006/02/23 05:37:46 thorpej Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2003 Genetec corporation. All rights reserved.
! 5: * Written by Hiroyuki Bessho for Genetec corporation.
! 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 corporation 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: * device driver to handle cascaded external interrupts of S3C2410.
! 34: *
! 35: * EXTINT [8..23] are cascaded to IRQ #5
! 36: * EXTINT [4..7] are cascaded to IRQ #4
! 37: * EXTINT [0..3] are not cascaded and connected directly as IRQ #[0..3].
! 38: * EXTINT [0..3] are handled by main interrupt handler in s3c2410_intr.c.
! 39: */
! 40:
! 41: #include <sys/cdefs.h>
! 42: __KERNEL_RCSID(0, "$NetBSD: s3c2410_extint.c,v 1.7 2006/02/23 05:37:46 thorpej Exp $");
! 43:
! 44: #include <sys/param.h>
! 45: #include <sys/systm.h>
! 46: #include <sys/malloc.h>
! 47: #include <uvm/uvm_extern.h>
! 48: #include <machine/bus.h>
! 49: #include <machine/intr.h>
! 50: #include <arm/cpufunc.h>
! 51:
! 52: #include <arm/s3c2xx0/s3c2410reg.h>
! 53: #include <arm/s3c2xx0/s3c2410var.h>
! 54:
! 55: #include "locators.h"
! 56: #include "opt_s3c2410.h" /* for S3C2410_EXTINT_MAX */
! 57:
! 58: #ifndef S3C2410_EXTINT_MAX
! 59: #define S3C2410_EXTINT_MAX 23
! 60: #endif
! 61:
! 62: #define EXTINT_CASCADE_MIN 4
! 63:
! 64: #if S3C2410_EXTINT_MAX < EXTINT_CASCADE_MIN
! 65: #error "Don't enable ssextio if you don't use extint[4..23]."
! 66: #endif
! 67:
! 68: #define N_EXTINT (S3C2410_EXTINT_MAX - EXTINT_CASCADE_MIN +1)
! 69:
! 70: struct ssextio_softc {
! 71: struct device sc_dev;
! 72:
! 73: bus_space_tag_t sc_iot;
! 74: bus_space_handle_t sc_ioh;
! 75:
! 76: uint32_t sc_pending;
! 77: uint32_t sc_mask;
! 78:
! 79: struct extint_handler {
! 80: int (* func)(void *);
! 81: void *arg;
! 82: void *sh; /* softintr handler */
! 83: int level; /* IPL */
! 84: } sc_handler[N_EXTINT];
! 85:
! 86: };
! 87:
! 88: static struct ssextio_softc *ssextio_softc = NULL;
! 89:
! 90: /* cookies */
! 91: #define EXTINT_4_7 1
! 92: #define EXTINT_8_23 2
! 93:
! 94: /* prototypes */
! 95: static int ssextio_match(struct device *, struct cfdata *, void *);
! 96: static void ssextio_attach(struct device *, struct device *, void *);
! 97: static int ssextio_search(struct device *, struct cfdata *,
! 98: const int *, void *);
! 99: static int ssextio_print(void *, const char *);
! 100:
! 101: static int ssextio_cascaded_intr(void *);
! 102: static void ssextio_softintr(void *);
! 103:
! 104: static inline void
! 105: update_hw_mask(void)
! 106: {
! 107: bus_space_write_4(ssextio_softc->sc_iot, ssextio_softc->sc_ioh,
! 108: GPIO_EINTMASK, ssextio_softc->sc_mask | ssextio_softc->sc_pending);
! 109: }
! 110:
! 111:
! 112: /* attach structures */
! 113: CFATTACH_DECL(ssextio, sizeof(struct ssextio_softc), ssextio_match, ssextio_attach,
! 114: NULL, NULL);
! 115:
! 116: static int
! 117: ssextio_print(void *aux, const char *name)
! 118: {
! 119: struct s3c2xx0_attach_args *sa = (struct s3c2xx0_attach_args*)aux;
! 120:
! 121: if (sa->sa_addr != SSEXTIOCF_ADDR_DEFAULT)
! 122: aprint_normal(" addr 0x%lx", sa->sa_addr);
! 123: if (sa->sa_intr > 0)
! 124: aprint_normal(" intr %d", sa->sa_intr);
! 125: return (UNCONF);
! 126: }
! 127:
! 128: int
! 129: ssextio_match(struct device *parent, struct cfdata *match, void *aux)
! 130: {
! 131: #if S3C2410_EXTINT_MAX < 4
! 132: /* better not configure this driver */
! 133: return 0;
! 134: #else
! 135: if (ssextio_softc != NULL)
! 136: return 0;
! 137:
! 138: return 1;
! 139: #endif
! 140: }
! 141:
! 142: void
! 143: ssextio_attach(struct device *parent, struct device *self, void *aux)
! 144: {
! 145: struct ssextio_softc *sc = (struct ssextio_softc*)self;
! 146: struct s3c24x0_softc *cpuc = (struct s3c24x0_softc *)parent;
! 147:
! 148: aprint_normal("\n");
! 149:
! 150: ssextio_softc = sc;
! 151:
! 152: sc->sc_iot = cpuc->sc_sx.sc_iot;
! 153: sc->sc_ioh = cpuc->sc_sx.sc_gpio_ioh;
! 154:
! 155: sc->sc_pending = 0;
! 156: sc->sc_mask = ~0;
! 157:
! 158: s3c24x0_intr_establish(S3C2410_INT_4_7, IPL_HIGH, IST_NONE,
! 159: ssextio_cascaded_intr, (void *)EXTINT_4_7);
! 160: #if S3C2410_EXTINT_MAX >= 8
! 161: s3c24x0_intr_establish(S3C2410_INT_8_23, IPL_HIGH, IST_NONE,
! 162: ssextio_cascaded_intr, (void *)EXTINT_8_23);
! 163: #endif
! 164: /*
! 165: * Attach each devices
! 166: */
! 167: config_search_ia(ssextio_search, self, "ssextio", NULL);
! 168: }
! 169:
! 170: static int
! 171: ssextio_search(struct device *parent, struct cfdata *cf,
! 172: const int *ldesc, void *aux)
! 173: {
! 174: struct ssextio_softc *sc = (struct ssextio_softc *)parent;
! 175: struct s3c24x0_softc *cpuc =(struct s3c24x0_softc *) device_parent(&sc->sc_dev);
! 176: struct s3c2xx0_attach_args sa;
! 177:
! 178: sa.sa_sc = sc;
! 179: sa.sa_iot = sc->sc_iot;
! 180: sa.sa_addr = cf->cf_loc[SSEXTIOCF_ADDR];
! 181: sa.sa_size = cf->cf_loc[SSEXTIOCF_SIZE];
! 182: sa.sa_intr = cf->cf_loc[SSEXTIOCF_INTR];
! 183: sa.sa_dmat = cpuc->sc_sx.sc_dmat;
! 184:
! 185: if (config_match(parent, cf, &sa))
! 186: config_attach(parent, cf, &sa, ssextio_print);
! 187:
! 188: return 0;
! 189: }
! 190:
! 191: void *
! 192: s3c2410_extint_establish(int extint, int ipl, int type,
! 193: int (*func)(void *), void *arg)
! 194: {
! 195: int save;
! 196: int idx;
! 197: int soft_level;
! 198:
! 199: if (extint < 0 || N_EXTINT <= extint)
! 200: panic("Bad interrupt no for extio");
! 201:
! 202: if (extint < EXTINT_CASCADE_MIN) {
! 203: /*
! 204: * EXINT[0..3] are not cascaded. they are handled by
! 205: * the main interrupt controller.
! 206: */
! 207: return s3c24x0_intr_establish(extint, ipl, type, func, arg);
! 208: }
! 209:
! 210: #ifdef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
! 211: soft_level = ipl;
! 212: #else
! 213: if (ipl >= IPL_SOFTSERIAL)
! 214: soft_level = IPL_SOFTSERIAL;
! 215: else if (ipl >= IPL_SOFTNET)
! 216: soft_level = IPL_SOFTNET;
! 217: else
! 218: soft_level = IPL_SOFT;
! 219: #endif
! 220:
! 221: idx = extint - EXTINT_CASCADE_MIN;
! 222:
! 223: save = disable_interrupts(I32_bit);
! 224:
! 225: ssextio_softc->sc_handler[idx].func = func;
! 226: ssextio_softc->sc_handler[idx].arg = arg;
! 227: ssextio_softc->sc_handler[idx].level = ipl;
! 228:
! 229: ssextio_softc->sc_handler[idx].sh = softintr_establish(soft_level,
! 230: ssextio_softintr, &ssextio_softc->sc_handler[idx]);
! 231:
! 232: s3c2410_setup_extint(extint, type);
! 233:
! 234: bus_space_write_4(ssextio_softc->sc_iot, ssextio_softc->sc_ioh,
! 235: GPIO_EINTPEND, 1U << extint);
! 236: ssextio_softc->sc_mask &= ~(1U << extint);
! 237: update_hw_mask();
! 238:
! 239: restore_interrupts(save);
! 240: return &ssextio_softc->sc_handler[idx];
! 241: }
! 242:
! 243:
! 244: static int
! 245: ssextio_cascaded_intr(void *cookie)
! 246: {
! 247: uint32_t pending_mask, pending;
! 248: int int_min;
! 249: bus_space_tag_t iot = ssextio_softc->sc_iot;
! 250: bus_space_handle_t ioh = ssextio_softc->sc_ioh;
! 251: int save, i;
! 252:
! 253: switch((int)cookie) {
! 254: case EXTINT_4_7:
! 255: pending_mask = 0x000000f0;
! 256: int_min = 4;
! 257: break;
! 258:
! 259: case EXTINT_8_23:
! 260: pending_mask = 0x00ffff00;
! 261: int_min = 8;
! 262: break;
! 263:
! 264: default:
! 265: panic("Bad cookie for %s", __FUNCTION__);
! 266: }
! 267:
! 268:
! 269: save = disable_interrupts(I32_bit);;
! 270: pending = pending_mask & bus_space_read_4(iot, ioh, GPIO_EINTPEND);
! 271: pending &= ~ssextio_softc->sc_mask;
! 272: ssextio_softc->sc_pending |= pending;
! 273: /* disable the extint until the handler is called. */
! 274: update_hw_mask();
! 275: restore_interrupts(save);
! 276:
! 277: for (i=int_min; pending; ++i) {
! 278: if (pending & (1<<i)) {
! 279: assert(ssextio_softc->sc_handler[i-EXTINT_CASCADE_MIN].sh != NULL);
! 280:
! 281: softintr_schedule(
! 282: ssextio_softc->sc_handler[i-EXTINT_CASCADE_MIN].sh);
! 283: pending &= ~ (1<<i);
! 284: }
! 285: }
! 286:
! 287: return 1;
! 288: }
! 289:
! 290: static void
! 291: ssextio_softintr(void *cookie)
! 292: {
! 293: struct extint_handler *h = cookie;
! 294: int extint = EXTINT_CASCADE_MIN + h - ssextio_softc->sc_handler;
! 295: int s, save;
! 296:
! 297: save = disable_interrupts(I32_bit);
! 298: /* clear hardware pending bits */
! 299: bus_space_write_4(ssextio_softc->sc_iot, ssextio_softc->sc_ioh,
! 300: GPIO_EINTPEND, 1<<extint);
! 301: ssextio_softc->sc_pending &= ~(1<<extint);
! 302: update_hw_mask();
! 303: restore_interrupts(save);
! 304:
! 305: s = _splraise(h->level);
! 306: h->func(h->arg);
! 307: splx(s);
! 308: }
CVSweb