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

Annotation of sys/arch/arm/s3c2xx0/s3c2410_intr.c, Revision 1.1.1.1

1.1       nbrk        1: /* $NetBSD: s3c2410_intr.c,v 1.6 2005/12/24 20:06:52 perry 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:  * IRQ handler for Samsung S3C2410 processor.
                     34:  * It has integrated interrupt controller.
                     35:  */
                     36:
                     37: #include <sys/cdefs.h>
                     38: __KERNEL_RCSID(0, "$NetBSD: s3c2410_intr.c,v 1.6 2005/12/24 20:06:52 perry Exp $");
                     39:
                     40: #include <sys/param.h>
                     41: #include <sys/systm.h>
                     42: #include <sys/malloc.h>
                     43: #include <uvm/uvm_extern.h>
                     44: #include <machine/bus.h>
                     45: #include <machine/intr.h>
                     46: #include <arm/cpufunc.h>
                     47:
                     48: #include <arm/s3c2xx0/s3c2410reg.h>
                     49: #include <arm/s3c2xx0/s3c2410var.h>
                     50:
                     51: /*
                     52:  * interrupt dispatch table.
                     53:  */
                     54:
                     55: struct s3c2xx0_intr_dispatch handler[ICU_LEN];
                     56:
                     57: volatile int softint_pending;
                     58:
                     59: volatile int current_spl_level;
                     60: volatile int intr_mask;
                     61: volatile int soft_intr_mask;
                     62: volatile int global_intr_mask = 0; /* mask some interrupts at all spl level */
                     63:
                     64: /* interrupt masks for each level */
                     65: int s3c2xx0_imask[NIPL];
                     66: int s3c2xx0_ilevel[ICU_LEN];
                     67: int s3c24x0_soft_imask[NIPL];
                     68:
                     69: vaddr_t intctl_base;           /* interrupt controller registers */
                     70: #define icreg(offset) \
                     71:        (*(volatile uint32_t *)(intctl_base+(offset)))
                     72:
                     73: /*
                     74:  * Map a software interrupt queue to an interrupt priority level.
                     75:  */
                     76: static const int si_to_ipl[SI_NQUEUES] = {
                     77:        IPL_SOFT,               /* SI_SOFT */
                     78:        IPL_SOFTCLOCK,          /* SI_SOFTCLOCK */
                     79:        IPL_SOFTNET,            /* SI_SOFTNET */
                     80:        IPL_SOFTSERIAL,         /* SI_SOFTSERIAL */
                     81: };
                     82:
                     83: #define PENDING_CLEAR_MASK     (~0)
                     84:
                     85: /*
                     86:  * called from irq_entry.
                     87:  */
                     88: void s3c2410_irq_handler(struct clockframe *);
                     89: void
                     90: s3c2410_irq_handler(struct clockframe *frame)
                     91: {
                     92:        uint32_t irqbits;
                     93:        int irqno;
                     94:        int saved_spl_level;
                     95:
                     96:        saved_spl_level = current_spl_level;
                     97:
                     98: #ifdef DIAGNOSTIC
                     99:        if (current_intr_depth > 10)
                    100:                panic("nested intr too deep");
                    101: #endif
                    102:
                    103:        while ((irqbits = icreg(INTCTL_INTPND)) != 0) {
                    104:
                    105:                /* Note: Only one bit in INTPND register is set */
                    106:
                    107:                irqno = icreg(INTCTL_INTOFFSET);
                    108:
                    109: #ifdef DIAGNOSTIC
                    110:                if (__predict_false((irqbits & (1<<irqno)) == 0)) {
                    111:                        /* This shouldn't happen */
                    112:                        printf("INTOFFSET=%d, INTPND=%x\n", irqno, irqbits);
                    113:                        break;
                    114:                }
                    115: #endif
                    116:                /* raise spl to stop interrupts of lower priorities */
                    117:                if (saved_spl_level < handler[irqno].level)
                    118:                        s3c2xx0_setipl(handler[irqno].level);
                    119:
                    120:                /* clear pending bit */
                    121:                icreg(INTCTL_SRCPND) = PENDING_CLEAR_MASK & (1 << irqno);
                    122:                icreg(INTCTL_INTPND) = PENDING_CLEAR_MASK & (1 << irqno);
                    123:
                    124:                enable_interrupts(I32_bit); /* allow nested interrupts */
                    125:
                    126:                (*handler[irqno].func) (
                    127:                    handler[irqno].cookie == 0
                    128:                    ? frame : handler[irqno].cookie);
                    129:
                    130:                disable_interrupts(I32_bit);
                    131:
                    132:                /* restore spl to that was when this interrupt happen */
                    133:                s3c2xx0_setipl(saved_spl_level);
                    134:
                    135:        }
                    136:
                    137:
                    138:        if (get_pending_softint())
                    139:                s3c2xx0_do_pending(1);
                    140:
                    141: }
                    142:
                    143: /*
                    144:  * Handler for main IRQ of cascaded interrupts.
                    145:  */
                    146: static int
                    147: cascade_irq_handler(void *cookie)
                    148: {
                    149:        int index = (int)cookie - 1;
                    150:        uint32_t irqbits;
                    151:        int irqno, i;
                    152:        int save = disable_interrupts(I32_bit);
                    153:
                    154:        KASSERT(0 <= index && index <= 3);
                    155:
                    156:        irqbits = icreg(INTCTL_SUBSRCPND) &
                    157:            ~icreg(INTCTL_INTSUBMSK) & (0x07 << (3*index));
                    158:
                    159:        for (irqno = 3*index; irqbits; ++irqno) {
                    160:                if ((irqbits & (1<<irqno)) == 0)
                    161:                        continue;
                    162:
                    163:                /* clear pending bit */
                    164:                irqbits &= ~(1<<irqno);
                    165:                icreg(INTCTL_SUBSRCPND) = (1 << irqno);
                    166:
                    167:                /* allow nested interrupts. SPL is already set
                    168:                 * correctly by main handler. */
                    169:                restore_interrupts(save);
                    170:
                    171:                i = S3C2410_SUBIRQ_MIN + irqno;
                    172:                (* handler[i].func)(handler[i].cookie);
                    173:
                    174:                disable_interrupts(I32_bit);
                    175:        }
                    176:
                    177:        return 1;
                    178: }
                    179:
                    180:
                    181: static const uint8_t subirq_to_main[] = {
                    182:        S3C2410_INT_UART0,
                    183:        S3C2410_INT_UART0,
                    184:        S3C2410_INT_UART0,
                    185:        S3C2410_INT_UART1,
                    186:        S3C2410_INT_UART1,
                    187:        S3C2410_INT_UART1,
                    188:        S3C2410_INT_UART2,
                    189:        S3C2410_INT_UART2,
                    190:        S3C2410_INT_UART2,
                    191:        S3C24X0_INT_ADCTC,
                    192:        S3C24X0_INT_ADCTC,
                    193: };
                    194:
                    195: void *
                    196: s3c24x0_intr_establish(int irqno, int level, int type,
                    197:     int (* func) (void *), void *cookie)
                    198: {
                    199:        int save;
                    200:
                    201:        if (irqno < 0 || irqno >= ICU_LEN ||
                    202:            type < IST_NONE || IST_EDGE_BOTH < type)
                    203:                panic("intr_establish: bogus irq or type");
                    204:
                    205:        save = disable_interrupts(I32_bit);
                    206:
                    207:        handler[irqno].cookie = cookie;
                    208:        handler[irqno].func = func;
                    209:        handler[irqno].level = level;
                    210:
                    211:        if (irqno >= S3C2410_SUBIRQ_MIN) {
                    212:                /* cascaded interrupts. */
                    213:                int main_irqno;
                    214:                int i = (irqno - S3C2410_SUBIRQ_MIN);
                    215:
                    216:                main_irqno = subirq_to_main[i];
                    217:
                    218:                /* establish main irq if first time
                    219:                 * be careful that cookie shouldn't be 0 */
                    220:                if (handler[main_irqno].func != cascade_irq_handler)
                    221:                        s3c24x0_intr_establish(main_irqno, level, type,
                    222:                            cascade_irq_handler, (void *)((i/3) + 1));
                    223:
                    224:                /* unmask it in submask register */
                    225:                icreg(INTCTL_INTSUBMSK) &= ~(1<<i);
                    226:
                    227:                restore_interrupts(save);
                    228:                return &handler[irqno];
                    229:        }
                    230:
                    231:        s3c2xx0_update_intr_masks(irqno, level);
                    232:
                    233:        /*
                    234:         * set trigger type for external interrupts 0..3
                    235:         */
                    236:        if (irqno <= S3C24X0_INT_EXT(3)) {
                    237:                /*
                    238:                 * Update external interrupt control
                    239:                 */
                    240:                s3c2410_setup_extint(irqno, type);
                    241:        }
                    242:
                    243:        s3c2xx0_setipl(current_spl_level);
                    244:
                    245:        restore_interrupts(save);
                    246:
                    247:        return &handler[irqno];
                    248: }
                    249:
                    250:
                    251: static void
                    252: init_interrupt_masks(void)
                    253: {
                    254:        int i;
                    255:
                    256:        for (i=0; i < NIPL; ++i)
                    257:                s3c2xx0_imask[i] = 0;
                    258:
                    259:        s3c24x0_soft_imask[IPL_NONE] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
                    260:                SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK) |
                    261:                SI_TO_IRQBIT(SI_SOFT);
                    262:
                    263:        s3c24x0_soft_imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
                    264:                SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK);
                    265:
                    266:        /*
                    267:         * splsoftclock() is the only interface that users of the
                    268:         * generic software interrupt facility have to block their
                    269:         * soft intrs, so splsoftclock() must also block IPL_SOFT.
                    270:         */
                    271:        s3c24x0_soft_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
                    272:                SI_TO_IRQBIT(SI_SOFTNET);
                    273:
                    274:        /*
                    275:         * splsoftnet() must also block splsoftclock(), since we don't
                    276:         * want timer-driven network events to occur while we're
                    277:         * processing incoming packets.
                    278:         */
                    279:        s3c24x0_soft_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTSERIAL);
                    280:
                    281:        for (i = IPL_BIO; i < IPL_SOFTSERIAL; ++i)
                    282:                s3c24x0_soft_imask[i] = SI_TO_IRQBIT(SI_SOFTSERIAL);
                    283: }
                    284:
                    285: void
                    286: s3c2410_intr_init(struct s3c24x0_softc *sc)
                    287: {
                    288:        intctl_base = (vaddr_t) bus_space_vaddr(sc->sc_sx.sc_iot,
                    289:            sc->sc_sx.sc_intctl_ioh);
                    290:
                    291:        s3c2xx0_intr_mask_reg = (uint32_t *)(intctl_base + INTCTL_INTMSK);
                    292:
                    293:        /* clear all pending interrupt */
                    294:        icreg(INTCTL_SRCPND) = ~0;
                    295:        icreg(INTCTL_INTPND) = ~0;
                    296:
                    297:        /* mask all sub interrupts */
                    298:        icreg(INTCTL_INTSUBMSK) = 0x7ff;
                    299:
                    300:        init_interrupt_masks();
                    301:
                    302:        s3c2xx0_intr_init(handler, ICU_LEN);
                    303:
                    304: }
                    305:
                    306:
                    307: /*
                    308:  * mask/unmask sub interrupts
                    309:  */
                    310: void
                    311: s3c2410_mask_subinterrupts(int bits)
                    312: {
                    313:        atomic_set_bit((uint32_t *)__UNVOLATILE(&icreg(INTCTL_INTSUBMSK)),
                    314:                bits);
                    315: }
                    316:
                    317: void
                    318: s3c2410_unmask_subinterrupts(int bits)
                    319: {
                    320:        atomic_clear_bit((uint32_t *)__UNVOLATILE(&icreg(INTCTL_INTSUBMSK)),
                    321:                bits);
                    322: }
                    323:
                    324: /*
                    325:  * Update external interrupt control
                    326:  */
                    327: static const u_char s3c24x0_ist[] = {
                    328:        EXTINTR_LOW,            /* NONE */
                    329:        EXTINTR_FALLING,        /* PULSE */
                    330:        EXTINTR_FALLING,        /* EDGE */
                    331:        EXTINTR_LOW,            /* LEVEL */
                    332:        EXTINTR_HIGH,
                    333:        EXTINTR_RISING,
                    334:        EXTINTR_BOTH,
                    335: };
                    336:
                    337: void
                    338: s3c2410_setup_extint(int extint, int type)
                    339: {
                    340:         uint32_t reg;
                    341:         u_int   trig;
                    342:         int     i = extint % 8;
                    343:         int     regidx = extint/8;      /* GPIO_EXTINT[0:2] */
                    344:        int     save;
                    345:
                    346:         trig = s3c24x0_ist[type];
                    347:
                    348:        save = disable_interrupts(I32_bit);
                    349:
                    350:         reg = bus_space_read_4(s3c2xx0_softc->sc_iot,
                    351:             s3c2xx0_softc->sc_gpio_ioh,
                    352:             GPIO_EXTINT(regidx));
                    353:
                    354:         reg = reg & ~(0x07 << (4*i));
                    355:         reg |= trig << (4*i);
                    356:
                    357:         bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
                    358:             GPIO_EXTINT(regidx), reg);
                    359:
                    360:        restore_interrupts(save);
                    361: }

CVSweb