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

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

1.1       nbrk        1: /* $NetBSD: s3c2800_intr.c,v 1.9 2005/12/24 20:06:52 perry Exp $ */
                      2:
                      3: /*
                      4:  * Copyright (c) 2002 Fujitsu Component Limited
                      5:  * Copyright (c) 2002 Genetec Corporation
                      6:  * All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of The Fujitsu Component Limited nor the name of
                     17:  *    Genetec corporation may not be used to endorse or promote products
                     18:  *    derived from this software without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
                     21:  * CORPORATION ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     22:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
                     23:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     24:  * DISCLAIMED.  IN NO EVENT SHALL FUJITSU COMPONENT LIMITED OR GENETEC
                     25:  * CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     26:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
                     27:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
                     28:  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
                     29:  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     30:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
                     31:  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  */
                     34:
                     35: /*
                     36:  * IRQ handler for Samsung S3C2800 processor.
                     37:  * It has integrated interrupt controller.
                     38:  */
                     39:
                     40: #include <sys/cdefs.h>
                     41: __KERNEL_RCSID(0, "$NetBSD: s3c2800_intr.c,v 1.9 2005/12/24 20:06:52 perry Exp $");
                     42:
                     43: #include <sys/param.h>
                     44: #include <sys/systm.h>
                     45: #include <sys/malloc.h>
                     46: #include <uvm/uvm_extern.h>
                     47: #include <machine/bus.h>
                     48: #include <machine/intr.h>
                     49: #include <arm/cpufunc.h>
                     50:
                     51: #include <arm/s3c2xx0/s3c2800reg.h>
                     52: #include <arm/s3c2xx0/s3c2800var.h>
                     53:
                     54: /*
                     55:  * interrupt dispatch table.
                     56:  */
                     57:
                     58: struct s3c2xx0_intr_dispatch handler[ICU_LEN];
                     59:
                     60: volatile int softint_pending;
                     61:
                     62: volatile int current_spl_level;
                     63: volatile int intr_mask;    /* XXX: does this need to be volatile? */
                     64: volatile int global_intr_mask = 0; /* mask some interrupts at all spl level */
                     65:
                     66: /* interrupt masks for each level */
                     67: int s3c2xx0_imask[NIPL];
                     68: int s3c2xx0_ilevel[ICU_LEN];
                     69:
                     70: vaddr_t intctl_base;           /* interrupt controller registers */
                     71: #define icreg(offset) \
                     72:        (*(volatile uint32_t *)(intctl_base+(offset)))
                     73:
                     74: /*
                     75:  * Map a software interrupt queue to an interrupt priority level.
                     76:  */
                     77: static const int si_to_ipl[SI_NQUEUES] = {
                     78:        IPL_SOFT,               /* SI_SOFT */
                     79:        IPL_SOFTCLOCK,          /* SI_SOFTCLOCK */
                     80:        IPL_SOFTNET,            /* SI_SOFTNET */
                     81:        IPL_SOFTSERIAL,         /* SI_SOFTSERIAL */
                     82: };
                     83:
                     84: /*
                     85:  *   Clearing interrupt pending bits affects some built-in
                     86:  * peripherals.  For example, IIC starts transmitting next data when
                     87:  * its interrupt pending bit is cleared.
                     88:  *   We need to leave those bits to peripheral handlers.
                     89:  */
                     90: #define PENDING_CLEAR_MASK     (~((1<<S3C2800_INT_IIC0)|(1<<S3C2800_INT_IIC1)))
                     91:
                     92: /*
                     93:  * called from irq_entry.
                     94:  */
                     95: void s3c2800_irq_handler(struct clockframe *);
                     96: void
                     97: s3c2800_irq_handler(struct clockframe *frame)
                     98: {
                     99:        uint32_t irqbits;
                    100:        int irqno;
                    101:        int saved_spl_level;
                    102:
                    103:        saved_spl_level = current_spl_level;
                    104:
                    105:        while ((irqbits = icreg(INTCTL_IRQPND) & ICU_INT_HWMASK) != 0) {
                    106:
                    107:                for (irqno = ICU_LEN-1; irqno >= 0; --irqno)
                    108:                        if (irqbits & (1<<irqno))
                    109:                                break;
                    110:
                    111:                if (irqno < 0)
                    112:                        break;
                    113:
                    114:                /* raise spl to stop interrupts of lower priorities */
                    115:                if (saved_spl_level < handler[irqno].level)
                    116:                        s3c2xx0_setipl(handler[irqno].level);
                    117:
                    118:                /* clear pending bit */
                    119:                icreg(INTCTL_SRCPND) = PENDING_CLEAR_MASK & (1 << irqno);
                    120:
                    121:                enable_interrupts(I32_bit); /* allow nested interrupts */
                    122:
                    123:                (*handler[irqno].func) (
                    124:                    handler[irqno].cookie == 0
                    125:                    ? frame : handler[irqno].cookie);
                    126:
                    127:                disable_interrupts(I32_bit);
                    128:
                    129:                /* restore spl to that was when this interrupt happen */
                    130:                s3c2xx0_setipl(saved_spl_level);
                    131:        }
                    132:
                    133:
                    134:        if (softint_pending & intr_mask)
                    135:                s3c2xx0_do_pending(1);
                    136:
                    137: }
                    138:
                    139: static const u_char s3c2800_ist[] = {
                    140:        EXTINTR_LOW,            /* NONE */
                    141:        EXTINTR_FALLING,        /* PULSE */
                    142:        EXTINTR_FALLING,        /* EDGE */
                    143:        EXTINTR_LOW,            /* LEVEL */
                    144:        EXTINTR_HIGH,
                    145:        EXTINTR_RISING,
                    146:        EXTINTR_BOTH,
                    147: };
                    148:
                    149: void *
                    150: s3c2800_intr_establish(int irqno, int level, int type,
                    151:     int (* func) (void *), void *cookie)
                    152: {
                    153:        int save;
                    154:
                    155:        if (irqno < 0 || irqno >= ICU_LEN ||
                    156:            type < IST_NONE || IST_EDGE_BOTH < type)
                    157:                panic("intr_establish: bogus irq or type");
                    158:
                    159:        save = disable_interrupts(I32_bit);
                    160:
                    161:        handler[irqno].cookie = cookie;
                    162:        handler[irqno].func = func;
                    163:        handler[irqno].level = level;
                    164:
                    165:        s3c2xx0_update_intr_masks(irqno, level);
                    166:
                    167:        if (irqno <= S3C2800_INT_EXT(7)) {
                    168:                /*
                    169:                 * Update external interrupt control
                    170:                 */
                    171:                uint32_t reg;
                    172:                u_int   trig;
                    173:
                    174:                trig = s3c2800_ist[type];
                    175:
                    176:                reg = bus_space_read_4(s3c2xx0_softc->sc_iot,
                    177:                                       s3c2xx0_softc->sc_gpio_ioh,
                    178:                                       GPIO_EXTINTR);
                    179:
                    180:                reg = reg & ~(0x0f << (4*irqno));
                    181:                reg |= trig << (4*irqno);
                    182:
                    183:                bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
                    184:                                  GPIO_EXTINTR, reg);
                    185:        }
                    186:
                    187:        s3c2xx0_setipl(current_spl_level);
                    188:
                    189:        restore_interrupts(save);
                    190:
                    191:        return (&handler[irqno]);
                    192: }
                    193:
                    194:
                    195: static void
                    196: init_interrupt_masks(void)
                    197: {
                    198:        int i;
                    199:
                    200:        s3c2xx0_imask[IPL_NONE] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
                    201:                SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK) |
                    202:                SI_TO_IRQBIT(SI_SOFT);
                    203:
                    204:        s3c2xx0_imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
                    205:                SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK);
                    206:
                    207:        /*
                    208:         * splsoftclock() is the only interface that users of the
                    209:         * generic software interrupt facility have to block their
                    210:         * soft intrs, so splsoftclock() must also block IPL_SOFT.
                    211:         */
                    212:        s3c2xx0_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
                    213:                SI_TO_IRQBIT(SI_SOFTNET);
                    214:
                    215:        /*
                    216:         * splsoftnet() must also block splsoftclock(), since we don't
                    217:         * want timer-driven network events to occur while we're
                    218:         * processing incoming packets.
                    219:         */
                    220:        s3c2xx0_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTSERIAL);
                    221:
                    222:        for (i = IPL_BIO; i < IPL_SOFTSERIAL; ++i)
                    223:                s3c2xx0_imask[i] = SI_TO_IRQBIT(SI_SOFTSERIAL);
                    224:        for (; i < NIPL; ++i)
                    225:                s3c2xx0_imask[i] = 0;
                    226: }
                    227:
                    228: void
                    229: s3c2800_intr_init(struct s3c2800_softc *sc)
                    230: {
                    231:        intctl_base = (vaddr_t) bus_space_vaddr(sc->sc_sx.sc_iot,
                    232:            sc->sc_sx.sc_intctl_ioh);
                    233:
                    234:        s3c2xx0_intr_mask_reg = (uint32_t *)(intctl_base + INTCTL_INTMSK);
                    235:
                    236:        /* clear all pending interrupt */
                    237:        icreg(INTCTL_SRCPND) = 0xffffffff;
                    238:
                    239:        init_interrupt_masks();
                    240:
                    241:        s3c2xx0_intr_init(handler, ICU_LEN);
                    242:
                    243: }

CVSweb