[BACK]Return to s3c2410_extint.c CVS log [TXT][DIR] Up to [local] / sys / arch / arm / s3c2xx0

Annotation of sys/arch/arm/s3c2xx0/s3c2410_extint.c, Revision 1.1.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