[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     ! 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