[BACK]Return to via.c CVS log [TXT][DIR] Up to [local] / sys / arch / mac68k / mac68k

Annotation of sys/arch/mac68k/mac68k/via.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: via.c,v 1.30 2007/07/29 21:25:23 miod Exp $   */
                      2: /*     $NetBSD: via.c,v 1.62 1997/09/10 04:38:48 scottr Exp $  */
                      3:
                      4: /*-
                      5:  * Copyright (C) 1993  Allen K. Briggs, Chris P. Caputo,
                      6:  *                     Michael L. Finch, Bradley A. Grantham, and
                      7:  *                     Lawrence A. Kesteloot
                      8:  * All rights reserved.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *     This product includes software developed by the Alice Group.
                     21:  * 4. The names of the Alice Group or any of its members may not be used
                     22:  *    to endorse or promote products derived from this software without
                     23:  *    specific prior written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR
                     26:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     27:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     28:  * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT,
                     29:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     30:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     31:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     32:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     33:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
                     34:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     35:  *
                     36:  */
                     37:
                     38: /*
                     39:  *     This code handles both the VIA, RBV and OSS functionality.
                     40:  */
                     41:
                     42: #include <sys/param.h>
                     43: #include <sys/kernel.h>
                     44: #include <sys/syslog.h>
                     45: #include <sys/systm.h>
                     46: #include <sys/evcount.h>
                     47:
                     48: #include <machine/cpu.h>
                     49: #include <machine/frame.h>
                     50: #include <machine/intr.h>
                     51: #include <machine/viareg.h>
                     52:
                     53: int    rtclock_intr(void *);
                     54:
                     55: int    via1_intr(void *);
                     56: int    via2_intr(void *);
                     57: int    rbv_intr(void *);
                     58: int    oss_intr(void *);
                     59: int    via2_nubus_intr(void *);
                     60: int    rbv_nubus_intr(void *);
                     61:
                     62: static int slot_ignore(void *);
                     63:
                     64: int    VIA2 = VIA2OFF;         /* default for II, IIx, IIcx, SE/30. */
                     65:
                     66: struct intrhand via1intrs[7];
                     67: via2hand_t via2intrs[7];
                     68:
                     69: /*
                     70:  * Nubus slot interrupt routines and parameters for slots 9-15.  Note
                     71:  * that for simplicity of code, "v2IRQ0" for internal video is treated
                     72:  * as a slot 15 interrupt; this slot is quite fictitious in real-world
                     73:  * Macs.  See also GMFH, pp. 165-167, and "Monster, Loch Ness."
                     74:  */
                     75: struct intrhand slotintrs[7];
                     76:
                     77: static struct via2hand nubus_intr;
                     78:
                     79: void
                     80: via_init()
                     81: {
                     82:        unsigned int i;
                     83:
                     84:        /* Initialize VIA1 */
                     85:        /* set all timers to 0 */
                     86:        via_reg(VIA1, vT1L) = 0;
                     87:        via_reg(VIA1, vT1LH) = 0;
                     88:        via_reg(VIA1, vT1C) = 0;
                     89:        via_reg(VIA1, vT1CH) = 0;
                     90:        via_reg(VIA1, vT2C) = 0;
                     91:        via_reg(VIA1, vT2CH) = 0;
                     92:
                     93:        /* turn off timer latch */
                     94:        via_reg(VIA1, vACR) &= 0x3f;
                     95:
                     96:        intr_establish(via1_intr, NULL, mac68k_machine.via1_ipl, "via1");
                     97:
                     98:        /* register default VIA1 interrupts */
                     99:        via1_register_irq(VIA1_T1, rtclock_intr, NULL, "clock");
                    100:
                    101:        for (i = 0; i < 7; i++)
                    102:                SLIST_INIT(&via2intrs[i]);
                    103:
                    104:        if (VIA2 == VIA2OFF) {
                    105:                /* Initialize VIA2 */
                    106:                via2_reg(vT1L) = 0;
                    107:                via2_reg(vT1LH) = 0;
                    108:                via2_reg(vT1C) = 0;
                    109:                via2_reg(vT1CH) = 0;
                    110:                via2_reg(vT2C) = 0;
                    111:                via2_reg(vT2CH) = 0;
                    112:
                    113:                /* turn off timer latch */
                    114:                via2_reg(vACR) &= 0x3f;
                    115:
                    116:                /* register default VIA2 interrupts */
                    117:                nubus_intr.vh_ipl = 1;
                    118:                nubus_intr.vh_fn = via2_nubus_intr;
                    119:                via2_register_irq(&nubus_intr, NULL);
                    120:                /* 4 snd_intr, 5 via2t2_intr */
                    121:
                    122:                /*
                    123:                 * Turn off SE/30 video interrupts.
                    124:                 */
                    125:                if (mac68k_machine.machineid == MACH_MACSE30) {
                    126:                        via_reg(VIA1, vBufB) |= (0x40);
                    127:                        via_reg(VIA1, vDirB) |= (0x40);
                    128:                }
                    129:
                    130:                /*
                    131:                 * Set vPCR for SCSI interrupts.
                    132:                 */
                    133:                via2_reg(vPCR)   = 0x66;
                    134:                switch(mac68k_machine.machineid) {
                    135:                case MACH_MACPB140:
                    136:                case MACH_MACPB145:
                    137:                case MACH_MACPB150:
                    138:                case MACH_MACPB160:
                    139:                case MACH_MACPB165:
                    140:                case MACH_MACPB165C:
                    141:                case MACH_MACPB170:
                    142:                case MACH_MACPB180:
                    143:                case MACH_MACPB180C:
                    144:                        break;
                    145:                default:
                    146:                        via2_reg(vBufB) |= 0x02;        /* Unlock NuBus */
                    147:                        via2_reg(vDirB) |= 0x02;
                    148:                        break;
                    149:                }
                    150:
                    151:                intr_establish(via2_intr, NULL, 2, "via2");
                    152:        } else if (current_mac_model->class == MACH_CLASSIIfx) { /* OSS */
                    153:                volatile u_char *ossintr;
                    154:                ossintr = (volatile u_char *)Via2Base + 6;
                    155:                *ossintr = 0;
                    156:                intr_establish(oss_intr, NULL, 2, "via2");
                    157:        } else {        /* RBV */
                    158:                if (current_mac_model->class == MACH_CLASSIIci) {
                    159:                        /*
                    160:                         * Disable cache card. (p. 174--GtMFH)
                    161:                         */
                    162:                        via2_reg(rBufB) |= DB2O_CEnable;
                    163:                }
                    164:                intr_establish(rbv_intr, NULL, 2, "via2");
                    165:
                    166:                nubus_intr.vh_ipl = 1;
                    167:                nubus_intr.vh_fn = rbv_nubus_intr;
                    168:                via2_register_irq(&nubus_intr, NULL);
                    169:                /* XXX necessary? */
                    170:                add_nubus_intr(0, slot_ignore, (void *)0, "dummy");
                    171:        }
                    172: }
                    173:
                    174: /*
                    175:  * Set the state of the modem serial port's clock source.
                    176:  */
                    177: void
                    178: via_set_modem(int onoff)
                    179: {
                    180:        via_reg(VIA1, vDirA) |= DA1O_vSync;
                    181:        if (onoff)
                    182:                via_reg(VIA1, vBufA) |= DA1O_vSync;
                    183:        else
                    184:                via_reg(VIA1, vBufA) &= ~DA1O_vSync;
                    185: }
                    186:
                    187: int
                    188: via1_intr(void *arg)
                    189: {
                    190:        struct intrhand *ih;
                    191:        u_int8_t intbits, bitnum;
                    192:        u_int mask;
                    193:
                    194:        intbits = via_reg(VIA1, vIFR);          /* get interrupts pending */
                    195:        intbits &= via_reg(VIA1, vIER);         /* only care about enabled */
                    196:
                    197:        if (intbits == 0)
                    198:                return (0);
                    199:
                    200:        /*
                    201:         * Unflag interrupts here.  If we do it after each interrupt,
                    202:         * the MRG ADB hangs up.
                    203:         */
                    204:        via_reg(VIA1, vIFR) = intbits;
                    205:
                    206:        intbits &= 0x7f;
                    207:        mask = 1;
                    208:        for (bitnum = 0, ih = via1intrs; ; bitnum++, ih++) {
                    209:                if ((intbits & mask) != 0 && ih->ih_fn != NULL)
                    210:                        if ((*ih->ih_fn)(ih->ih_arg) != 0)
                    211:                                ih->ih_count.ec_count++;
                    212:                mask <<= 1;
                    213:                if (intbits < mask)
                    214:                        break;
                    215:        }
                    216:
                    217:        return (1);
                    218: }
                    219:
                    220: int
                    221: via2_intr(void *arg)
                    222: {
                    223:        struct via2hand *v2h;
                    224:        via2hand_t *anchor;
                    225:        u_int8_t intbits, bitnum;
                    226:        u_int mask;
                    227:        int handled, rc;
                    228:
                    229:        intbits = via2_reg(vIFR);               /* get interrupts pending */
                    230:        intbits &= via2_reg(vIER);              /* only care about enabled */
                    231:
                    232:        if (intbits == 0)
                    233:                return (0);
                    234:
                    235:        via2_reg(vIFR) = intbits;
                    236:
                    237:        intbits &= 0x7f;
                    238:        mask = 1;
                    239:        for (bitnum = 0, anchor = via2intrs; ; bitnum++, anchor++) {
                    240:                if ((intbits & mask) != 0) {
                    241:                        handled = 0;
                    242:                        SLIST_FOREACH(v2h, anchor, v2h_link) {
                    243:                                struct intrhand *ih = &v2h->v2h_ih;
                    244:                                rc = (*ih->ih_fn)(ih->ih_arg);
                    245:                                if (rc != 0) {
                    246:                                        ih->ih_count.ec_count++;
                    247:                                        handled |= rc;
                    248:                                }
                    249:                        }
                    250:                }
                    251:                mask <<= 1;
                    252:                if (intbits < mask)
                    253:                        break;
                    254:        }
                    255:
                    256:        return (1);
                    257: }
                    258:
                    259: int
                    260: rbv_intr(void *arg)
                    261: {
                    262:        struct via2hand *v2h;
                    263:        via2hand_t *anchor;
                    264:        u_int8_t intbits, bitnum;
                    265:        u_int mask;
                    266:        int handled, rc;
                    267:
                    268:        intbits = via2_reg(vIFR + rIFR);
                    269:        intbits &= via2_reg(vIER + rIER);
                    270:
                    271:        if (intbits == 0)
                    272:                return (0);
                    273:
                    274:        via2_reg(rIFR) = intbits;
                    275:
                    276:        intbits &= 0x7f;
                    277:        mask = 1;
                    278:        for (bitnum = 0, anchor = via2intrs; ; bitnum++, anchor++) {
                    279:                if ((intbits & mask) != 0) {
                    280:                        handled = 0;
                    281:                        SLIST_FOREACH(v2h, anchor, v2h_link) {
                    282:                                struct intrhand *ih = &v2h->v2h_ih;
                    283:                                rc = (*ih->ih_fn)(ih->ih_arg);
                    284:                                if (rc != 0) {
                    285:                                        ih->ih_count.ec_count++;
                    286:                                        handled |= rc;
                    287:                                }
                    288:                        }
                    289:                }
                    290:                mask <<= 1;
                    291:                if (intbits < mask)
                    292:                        break;
                    293:        }
                    294:
                    295:        return (1);
                    296: }
                    297:
                    298: int nubus_intr_mask = 0;
                    299:
                    300: void
                    301: add_nubus_intr(int slot, int (*func)(void *), void *client_data,
                    302:     const char *name)
                    303: {
                    304:        struct intrhand *ih;
                    305:        int s;
                    306:
                    307:        /*
                    308:         * Map Nubus slot 0 to "slot" 15; see note on Nubus slot
                    309:         * interrupt tables.
                    310:         */
                    311: #ifdef DIAGNOSTIC
                    312:        if (slot != 0 && (slot < 9 || slot > 14))
                    313:                panic("add_nubus_intr: wrong slot %d", slot + 9);
                    314: #endif
                    315:        if (slot == 0)
                    316:                slot = 15 - 9;
                    317:        else
                    318:                slot -= 9;
                    319:
                    320:        s = splhigh();
                    321:
                    322:        ih = &slotintrs[slot];
                    323:
                    324: #ifdef DIAGNOSTIC
                    325:        if (ih->ih_fn != NULL)
                    326:                panic("add_nubus_intr: attempt to share slot %d", slot + 9);
                    327: #endif
                    328:
                    329:        ih->ih_fn = func;
                    330:        ih->ih_arg = client_data;
                    331:        ih->ih_ipl = slot + 9;
                    332:        evcount_attach(&ih->ih_count, name, (void *)&ih->ih_ipl, &evcount_intr);
                    333:
                    334:        nubus_intr_mask |= (1 << slot);
                    335:
                    336:        splx(s);
                    337: }
                    338:
                    339: void
                    340: enable_nubus_intr()
                    341: {
                    342:        if ((nubus_intr_mask & 0x3f) == 0)
                    343:                return;
                    344:
                    345:        if (VIA2 == VIA2OFF)
                    346:                via2_reg(vIER) = 0x80 | V2IF_SLOTINT;
                    347:        else
                    348:                via2_reg(rIER) = 0x80 | V2IF_SLOTINT;
                    349: }
                    350:
                    351: int
                    352: oss_intr(void *arg)
                    353: {
                    354:        struct intrhand *ih;
                    355:        u_int8_t intbits, bitnum;
                    356:        u_int mask;
                    357:
                    358:        intbits = via2_reg(vIFR + rIFR);
                    359:
                    360:        if (intbits == 0)
                    361:                return (0);
                    362:
                    363:        intbits &= 0x7f;
                    364:        mask = 1;
                    365:        for (bitnum = 0, ih = slotintrs; ; bitnum++, ih++) {
                    366:                if (intbits & mask) {
                    367:                        if (ih->ih_fn != NULL) {
                    368:                                if ((*ih->ih_fn)(ih->ih_arg) != 0)
                    369:                                        ih->ih_count.ec_count++;
                    370:                        }
                    371:                        via2_reg(rIFR) = mask;
                    372:                }
                    373:                mask <<= 1;
                    374:                if (intbits < mask)
                    375:                        break;
                    376:        }
                    377:
                    378:        return (1);
                    379: }
                    380:
                    381: /*ARGSUSED*/
                    382: int
                    383: via2_nubus_intr(void *bitarg)
                    384: {
                    385:        struct intrhand *ih;
                    386:        u_int8_t i, intbits, mask;
                    387:        int rv = 0;
                    388:
                    389:        via2_reg(vIFR) = V2IF_SLOTINT;
                    390:        while ((intbits = (~via2_reg(vBufA)) & nubus_intr_mask)) {
                    391:                for (i = 6, ih = &slotintrs[i], mask = 1 << i; mask != 0;
                    392:                    i--, ih--, mask >>= 1) {
                    393:                        if (intbits & mask) {
                    394:                                if (ih->ih_fn != NULL) {
                    395:                                        if ((*ih->ih_fn)(ih->ih_arg) != 0) {
                    396:                                                ih->ih_count.ec_count++;
                    397:                                                rv = 1;
                    398:                                        }
                    399:                                }
                    400:                        }
                    401:                }
                    402:                via2_reg(vIFR) = V2IF_SLOTINT;
                    403:        }
                    404:        return (rv);
                    405: }
                    406:
                    407: /*ARGSUSED*/
                    408: int
                    409: rbv_nubus_intr(void *bitarg)
                    410: {
                    411:        struct intrhand *ih;
                    412:        u_int8_t i, intbits, mask;
                    413:        int rv = 0;
                    414:
                    415:        via2_reg(rIFR) = 0x80 | V2IF_SLOTINT;
                    416:        while ((intbits = (~via2_reg(rBufA)) & via2_reg(rSlotInt))) {
                    417:                for (i = 6, ih = &slotintrs[i], mask = 1 << i; mask != 0;
                    418:                    i--, ih--, mask >>= 1) {
                    419:                        if (intbits & mask) {
                    420:                                if (ih->ih_fn != NULL) {
                    421:                                        if ((*ih->ih_fn)(ih->ih_arg) != 0) {
                    422:                                                ih->ih_count.ec_count++;
                    423:                                                rv = 1;
                    424:                                        }
                    425:                                }
                    426:                        }
                    427:                }
                    428:                via2_reg(rIFR) = 0x80 | V2IF_SLOTINT;
                    429:        }
                    430:        return (rv);
                    431: }
                    432:
                    433: static int
                    434: slot_ignore(void *client_data)
                    435: {
                    436:        int mask = (1 << (int)client_data);
                    437:
                    438:        if (VIA2 == VIA2OFF) {
                    439:                via2_reg(vDirA) |= mask;
                    440:                via2_reg(vBufA) = mask;
                    441:                via2_reg(vDirA) &= ~mask;
                    442:        } else
                    443:                via2_reg(rBufA) = mask;
                    444:
                    445:        return (1);
                    446: }
                    447:
                    448: void
                    449: via_powerdown()
                    450: {
                    451:        if (VIA2 == VIA2OFF) {
                    452:                via2_reg(vDirB) |= 0x04;  /* Set write for bit 2 */
                    453:                via2_reg(vBufB) &= ~0x04; /* Shut down */
                    454:        } else if (VIA2 == RBVOFF) {
                    455:                via2_reg(rBufB) &= ~0x04;
                    456:        } else if (VIA2 == OSSOFF) {
                    457:                /*
                    458:                 * Thanks to Brad Boyer <flar@cegt201.bradley.edu> for the
                    459:                 * Linux/mac68k code that I derived this from.
                    460:                 */
                    461:                via2_reg(OSS_oRCR) |= OSS_POWEROFF;
                    462:        }
                    463: }
                    464:
                    465: void
                    466: via1_register_irq(int irq, int (*irq_func)(void *), void *client_data,
                    467:     const char *name)
                    468: {
                    469:        struct intrhand *ih;
                    470:
                    471: #ifdef DIAGNOSTIC
                    472:        if (irq < 0 || irq > 7)
                    473:                panic("via1_register_irq: bad irq %d", irq);
                    474: #endif
                    475:
                    476:        ih = &via1intrs[irq];
                    477:
                    478:        /*
                    479:         * VIA1 interrupts are special, since we start with temporary handlers,
                    480:         * and later switch to better routines whenever possible.
                    481:         * To avoid a loop in evcount lists, only invoke evcount_attach() if
                    482:         * name is non-NULL, and have the replacements calls in adb_direct.c,
                    483:         * clock.c and pm_direct.c pass a NULL pointer.
                    484:         */
                    485: #ifdef DIAGNOSTIC
                    486:        if (ih->ih_fn != NULL && name != NULL)
                    487:                panic("via1_register_irq: improper invocation");
                    488: #endif
                    489:
                    490:        ih->ih_fn = irq_func;
                    491:        ih->ih_arg = client_data;
                    492:        ih->ih_ipl = irq;
                    493:        if (name != NULL)
                    494:                evcount_attach(&ih->ih_count, name, (void *)&ih->ih_ipl,
                    495:                    &evcount_intr);
                    496: }
                    497:
                    498: int
                    499: via2_register_irq(struct via2hand *vh, const char *name)
                    500: {
                    501:        int irq = vh->vh_ipl;
                    502:
                    503: #ifdef DIAGNOSTIC
                    504:        if (irq < 0 || irq > 7)
                    505:                panic("via2_register_irq: bad irq %d", irq);
                    506: #endif
                    507:
                    508:        if (name != NULL)
                    509:                evcount_attach(&vh->vh_count, name, (void *)&vh->vh_ipl,
                    510:                    &evcount_intr);
                    511:        SLIST_INSERT_HEAD(&via2intrs[irq], vh, v2h_link);
                    512:        return (0);
                    513: }

CVSweb