[BACK]Return to zs.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / macppc / dev

Annotation of src/sys/arch/macppc/dev/zs.c, Revision 1.42.10.1

1.42.10.1! macallan    1: /*     $NetBSD: zs.c,v 1.42 2007/03/04 06:00:10 christos Exp $ */
1.1       tsubai      2:
                      3: /*
1.7       wrstuden    4:  * Copyright (c) 1996, 1998 Bill Studenmund
1.1       tsubai      5:  * Copyright (c) 1995 Gordon W. Ross
                      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. The name of the author may not be used to endorse or promote products
                     17:  *    derived from this software without specific prior written permission.
                     18:  * 4. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *      This product includes software developed by Gordon Ross
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     32:  */
                     33:
                     34: /*
                     35:  * Zilog Z8530 Dual UART driver (machine-dependent part)
                     36:  *
                     37:  * Runs two serial lines per chip using slave drivers.
                     38:  * Plain tty/async lines use the zs_async slave.
                     39:  * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
                     40:  * Other ports use their own mice & keyboard slaves.
                     41:  *
                     42:  * Credits & history:
                     43:  *
                     44:  * With NetBSD 1.1, port-mac68k started using a port of the port-sparc
                     45:  * (port-sun3?) zs.c driver (which was in turn based on code in the
                     46:  * Berkeley 4.4 Lite release). Bill Studenmund did the port, with
1.28      keihan     47:  * help from Allen Briggs and Gordon Ross <gwr@NetBSD.org>. Noud de
1.1       tsubai     48:  * Brouwer field-tested the driver at a local ISP.
                     49:  *
1.41      wiz        50:  * Bill Studenmund and Gordon Ross then ported the machine-independent
1.1       tsubai     51:  * z8530 driver to work with port-mac68k. NetBSD 1.2 contained an
                     52:  * intermediate version (mac68k using a local, patched version of
                     53:  * the m.i. drivers), with NetBSD 1.3 containing a full version.
                     54:  */
1.27      lukem      55:
                     56: #include <sys/cdefs.h>
1.42.10.1! macallan   57: __KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.42 2007/03/04 06:00:10 christos Exp $");
1.3       jonathan   58:
                     59: #include "opt_ddb.h"
1.19      dbj        60: #include "opt_kgdb.h"
1.1       tsubai     61:
                     62: #include <sys/param.h>
                     63: #include <sys/systm.h>
                     64: #include <sys/proc.h>
                     65: #include <sys/device.h>
                     66: #include <sys/conf.h>
                     67: #include <sys/file.h>
                     68: #include <sys/ioctl.h>
                     69: #include <sys/tty.h>
                     70: #include <sys/time.h>
                     71: #include <sys/kernel.h>
                     72: #include <sys/syslog.h>
1.19      dbj        73: #ifdef KGDB
                     74: #include <sys/kgdb.h>
                     75: #endif
1.1       tsubai     76:
                     77: #include <dev/cons.h>
                     78: #include <dev/ofw/openfirm.h>
                     79: #include <dev/ic/z8530reg.h>
                     80:
                     81: #include <machine/z8530var.h>
                     82: #include <machine/autoconf.h>
                     83: #include <machine/cpu.h>
                     84: #include <machine/pio.h>
                     85:
                     86: /* Are these in a header file anywhere? */
                     87: /* Booter flags interface */
                     88: #define ZSMAC_RAW      0x01
                     89: #define ZSMAC_LOCALTALK        0x02
1.11      mycroft    90:
1.1       tsubai     91: /*
                     92:  * Some warts needed by z8530tty.c -
                     93:  */
                     94: int zs_def_cflag = (CREAD | CS8 | HUPCL);
                     95:
                     96: /*
                     97:  * abort detection on console will now timeout after iterating on a loop
                     98:  * the following # of times. Cheep hack. Also, abort detection is turned
                     99:  * off after a timeout (i.e. maybe there's not a terminal hooked up).
                    100:  */
                    101: #define ZSABORT_DELAY 3000000
                    102:
                    103: struct zsdevice {
                    104:        /* Yes, they are backwards. */
                    105:        struct  zschan zs_chan_b;
                    106:        struct  zschan zs_chan_a;
                    107: };
                    108:
1.31      chs       109: static int zs_defspeed[2] = {
                    110:        38400,          /* ttyZ0 */
                    111:        38400,          /* ttyZ1 */
1.1       tsubai    112: };
1.15      tsubai    113:
1.1       tsubai    114: /* console stuff */
                    115: void   *zs_conschan = 0;
1.32      matt      116: int    zs_conschannel = -1;
1.1       tsubai    117: #ifdef ZS_CONSOLE_ABORT
                    118: int    zs_cons_canabort = 1;
                    119: #else
                    120: int    zs_cons_canabort = 0;
                    121: #endif /* ZS_CONSOLE_ABORT*/
                    122:
                    123: /* device to which the console is attached--if serial. */
                    124: /* Mac stuff */
                    125:
1.30      chs       126: static int zs_get_speed(struct zs_chanstate *);
1.1       tsubai    127:
                    128: /*
                    129:  * Even though zsparam will set up the clock multiples, etc., we
                    130:  * still set them here as: 1) mice & keyboards don't use zsparam,
                    131:  * and 2) the console stuff uses these defaults before device
                    132:  * attach.
                    133:  */
                    134:
                    135: static u_char zs_init_reg[16] = {
                    136:        0,      /* 0: CMD (reset, etc.) */
                    137:        0,      /* 1: No interrupts yet. */
                    138:        0,      /* IVECT */
                    139:        ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
                    140:        ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
                    141:        ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
                    142:        0,      /* 6: TXSYNC/SYNCLO */
                    143:        0,      /* 7: RXSYNC/SYNCHI */
                    144:        0,      /* 8: alias for data port */
                    145:        ZSWR9_MASTER_IE,
                    146:        0,      /*10: Misc. TX/RX control bits */
                    147:        ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
1.11      mycroft   148:        ((PCLK/32)/38400)-2,    /*12: BAUDLO (default=38400) */
                    149:        0,                      /*13: BAUDHI (default=38400) */
1.12      wrstuden  150:        ZSWR14_BAUD_ENA,
1.10      mycroft   151:        ZSWR15_BREAK_IE,
1.1       tsubai    152: };
                    153:
                    154: /****************************************************************
                    155:  * Autoconfig
                    156:  ****************************************************************/
                    157:
                    158: /* Definition of the driver for autoconfig. */
1.30      chs       159: static int     zsc_match(struct device *, struct cfdata *, void *);
                    160: static void    zsc_attach(struct device *, struct device *, void *);
                    161: static int     zsc_print(void *, const char *);
1.1       tsubai    162:
1.23      thorpej   163: CFATTACH_DECL(zsc, sizeof(struct zsc_softc),
                    164:     zsc_match, zsc_attach, NULL, NULL);
1.1       tsubai    165:
                    166: extern struct cfdriver zsc_cd;
                    167:
1.31      chs       168: int zsc_attached;
                    169:
1.30      chs       170: int zshard(void *);
1.1       tsubai    171: #ifdef ZS_TXDMA
1.30      chs       172: static int zs_txdma_int(void *);
1.1       tsubai    173: #endif
                    174:
1.30      chs       175: void zscnprobe(struct consdev *);
                    176: void zscninit(struct consdev *);
                    177: int  zscngetc(dev_t);
                    178: void zscnputc(dev_t, int);
                    179: void zscnpollc(dev_t, int);
1.1       tsubai    180:
                    181: /*
                    182:  * Is the zs chip present?
                    183:  */
                    184: static int
1.30      chs       185: zsc_match(struct device *parent, struct cfdata *cf, void *aux)
1.1       tsubai    186: {
                    187:        struct confargs *ca = aux;
                    188:
                    189:        if (strcmp(ca->ca_name, "escc") != 0)
                    190:                return 0;
                    191:
1.31      chs       192:        if (zsc_attached)
1.1       tsubai    193:                return 0;
                    194:
                    195:        return 1;
                    196: }
                    197:
                    198: /*
                    199:  * Attach a found zs.
                    200:  *
                    201:  * Match slave number to zs unit number, so that misconfiguration will
                    202:  * not set up the keyboard as ttya, etc.
                    203:  */
                    204: static void
1.30      chs       205: zsc_attach(struct device *parent, struct device *self, void *aux)
1.1       tsubai    206: {
                    207:        struct zsc_softc *zsc = (void *)self;
                    208:        struct confargs *ca = aux;
                    209:        struct zsc_attach_args zsc_args;
                    210:        volatile struct zschan *zc;
                    211:        struct xzs_chanstate *xcs;
                    212:        struct zs_chanstate *cs;
1.15      tsubai    213:        struct zsdevice *zsd;
1.31      chs       214:        int channel;
1.1       tsubai    215:        int s, chip, theflags;
                    216:        int node, intr[2][3];
                    217:        u_int regs[6];
                    218:
1.31      chs       219:        zsc_attached = 1;
                    220:
1.15      tsubai    221:        chip = 0;
1.8       tsubai    222:        ca->ca_reg[0] += ca->ca_baseaddr;
1.15      tsubai    223:        zsd = mapiodev(ca->ca_reg[0], ca->ca_reg[1]);
1.8       tsubai    224:
                    225:        node = OF_child(ca->ca_node);   /* ch-a */
1.1       tsubai    226:
                    227:        for (channel = 0; channel < 2; channel++) {
1.8       tsubai    228:                if (OF_getprop(node, "AAPL,interrupts",
1.9       tsubai    229:                               intr[channel], sizeof(intr[0])) == -1 &&
1.8       tsubai    230:                    OF_getprop(node, "interrupts",
1.9       tsubai    231:                               intr[channel], sizeof(intr[0])) == -1) {
1.8       tsubai    232:                        printf(": cannot find interrupt property\n");
                    233:                        return;
                    234:                }
                    235:
                    236:                if (OF_getprop(node, "reg", regs, sizeof(regs)) < 24) {
                    237:                        printf(": cannot find reg property\n");
                    238:                        return;
                    239:                }
1.1       tsubai    240:                regs[2] += ca->ca_baseaddr;
                    241:                regs[4] += ca->ca_baseaddr;
                    242: #ifdef ZS_TXDMA
                    243:                zsc->zsc_txdmareg[channel] = mapiodev(regs[2], regs[3]);
                    244:                zsc->zsc_txdmacmd[channel] =
                    245:                        dbdma_alloc(sizeof(dbdma_command_t) * 3);
1.18      wiz       246:                memset(zsc->zsc_txdmacmd[channel], 0,
                    247:                        sizeof(dbdma_command_t) * 3);
1.1       tsubai    248:                dbdma_reset(zsc->zsc_txdmareg[channel]);
                    249: #endif
                    250:                node = OF_peer(node);   /* ch-b */
                    251:        }
                    252:
                    253:        printf(": irq %d,%d\n", intr[0][0], intr[1][0]);
                    254:
                    255:        /*
                    256:         * Initialize software state for each channel.
                    257:         */
                    258:        for (channel = 0; channel < 2; channel++) {
                    259:                zsc_args.channel = channel;
1.31      chs       260:                zsc_args.hwflags = (channel == zs_conschannel ?
                    261:                                    ZS_HWFLAG_CONSOLE : 0);
1.1       tsubai    262:                xcs = &zsc->xzsc_xcs_store[channel];
                    263:                cs  = &xcs->xzs_cs;
                    264:                zsc->zsc_cs[channel] = cs;
                    265:
1.25      pk        266:                simple_lock_init(&cs->cs_lock);
1.1       tsubai    267:                cs->cs_channel = channel;
                    268:                cs->cs_private = NULL;
                    269:                cs->cs_ops = &zsops_null;
                    270:
1.15      tsubai    271:                zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b;
                    272:
1.1       tsubai    273:                cs->cs_reg_csr  = &zc->zc_csr;
                    274:                cs->cs_reg_data = &zc->zc_data;
                    275:
1.18      wiz       276:                memcpy(cs->cs_creg, zs_init_reg, 16);
                    277:                memcpy(cs->cs_preg, zs_init_reg, 16);
1.1       tsubai    278:
                    279:                /* Current BAUD rate generator clock. */
1.11      mycroft   280:                cs->cs_brg_clk = PCLK / 16;     /* RTxC is 230400*16, so use 230400 */
1.13      tsubai    281:                if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
                    282:                        cs->cs_defspeed = zs_get_speed(cs);
                    283:                else
1.31      chs       284:                        cs->cs_defspeed = zs_defspeed[channel];
1.1       tsubai    285:                cs->cs_defcflag = zs_def_cflag;
                    286:
                    287:                /* Make these correspond to cs_defcflag (-crtscts) */
                    288:                cs->cs_rr0_dcd = ZSRR0_DCD;
                    289:                cs->cs_rr0_cts = 0;
                    290:                cs->cs_wr5_dtr = ZSWR5_DTR;
                    291:                cs->cs_wr5_rts = 0;
                    292:
                    293: #ifdef __notyet__
                    294:                cs->cs_slave_type = ZS_SLAVE_NONE;
                    295: #endif
                    296:
                    297:                /* Define BAUD rate stuff. */
1.11      mycroft   298:                xcs->cs_clocks[0].clk = PCLK;
1.7       wrstuden  299:                xcs->cs_clocks[0].flags = ZSC_RTXBRG | ZSC_RTXDIV;
1.1       tsubai    300:                xcs->cs_clocks[1].flags =
                    301:                        ZSC_RTXBRG | ZSC_RTXDIV | ZSC_VARIABLE | ZSC_EXTERN;
                    302:                xcs->cs_clocks[2].flags = ZSC_TRXDIV | ZSC_VARIABLE;
                    303:                xcs->cs_clock_count = 3;
                    304:                if (channel == 0) {
                    305:                        theflags = 0; /*mac68k_machine.modem_flags;*/
1.6       tsubai    306:                        /*xcs->cs_clocks[1].clk = mac68k_machine.modem_dcd_clk;*/
                    307:                        /*xcs->cs_clocks[2].clk = mac68k_machine.modem_cts_clk;*/
                    308:                        xcs->cs_clocks[1].clk = 0;
1.1       tsubai    309:                        xcs->cs_clocks[2].clk = 0;
                    310:                } else {
                    311:                        theflags = 0; /*mac68k_machine.print_flags;*/
                    312:                        xcs->cs_clocks[1].flags = ZSC_VARIABLE;
                    313:                        /*
                    314:                         * Yes, we aren't defining ANY clock source enables for the
                    315:                         * printer's DCD clock in. The hardware won't let us
                    316:                         * use it. But a clock will freak out the chip, so we
                    317:                         * let you set it, telling us to bar interrupts on the line.
                    318:                         */
1.6       tsubai    319:                        /*xcs->cs_clocks[1].clk = mac68k_machine.print_dcd_clk;*/
                    320:                        /*xcs->cs_clocks[2].clk = mac68k_machine.print_cts_clk;*/
                    321:                        xcs->cs_clocks[1].clk = 0;
1.1       tsubai    322:                        xcs->cs_clocks[2].clk = 0;
                    323:                }
                    324:                if (xcs->cs_clocks[1].clk)
                    325:                        zsc_args.hwflags |= ZS_HWFLAG_NO_DCD;
                    326:                if (xcs->cs_clocks[2].clk)
                    327:                        zsc_args.hwflags |= ZS_HWFLAG_NO_CTS;
                    328:
                    329:                /* Set defaults in our "extended" chanstate. */
                    330:                xcs->cs_csource = 0;
                    331:                xcs->cs_psource = 0;
                    332:                xcs->cs_cclk_flag = 0;  /* Nothing fancy by default */
                    333:                xcs->cs_pclk_flag = 0;
                    334:
                    335:                if (theflags & ZSMAC_RAW) {
                    336:                        zsc_args.hwflags |= ZS_HWFLAG_RAW;
                    337:                        printf(" (raw defaults)");
                    338:                }
                    339:
                    340:                /*
                    341:                 * XXX - This might be better done with a "stub" driver
                    342:                 * (to replace zstty) that ignores LocalTalk for now.
                    343:                 */
                    344:                if (theflags & ZSMAC_LOCALTALK) {
                    345:                        printf(" shielding from LocalTalk");
                    346:                        cs->cs_defspeed = 1;
                    347:                        cs->cs_creg[ZSRR_BAUDLO] = cs->cs_preg[ZSRR_BAUDLO] = 0xff;
                    348:                        cs->cs_creg[ZSRR_BAUDHI] = cs->cs_preg[ZSRR_BAUDHI] = 0xff;
                    349:                        zs_write_reg(cs, ZSRR_BAUDLO, 0xff);
                    350:                        zs_write_reg(cs, ZSRR_BAUDHI, 0xff);
                    351:                        /*
                    352:                         * If we might have LocalTalk, then make sure we have the
                    353:                         * Baud rate low-enough to not do any damage.
                    354:                         */
                    355:                }
                    356:
                    357:                /*
                    358:                 * We used to disable chip interrupts here, but we now
                    359:                 * do that in zscnprobe, just in case MacOS left the chip on.
                    360:                 */
                    361:
                    362:                xcs->cs_chip = chip;
                    363:
                    364:                /* Stash away a copy of the final H/W flags. */
                    365:                xcs->cs_hwflags = zsc_args.hwflags;
                    366:
                    367:                /*
                    368:                 * Look for a child driver for this channel.
                    369:                 * The child attach will setup the hardware.
                    370:                 */
                    371:                if (!config_found(self, (void *)&zsc_args, zsc_print)) {
                    372:                        /* No sub-driver.  Just reset it. */
                    373:                        u_char reset = (channel == 0) ?
                    374:                                ZSWR9_A_RESET : ZSWR9_B_RESET;
                    375:                        s = splzs();
                    376:                        zs_write_reg(cs, 9, reset);
                    377:                        splx(s);
                    378:                }
                    379:        }
                    380:
                    381:        /* XXX - Now safe to install interrupt handlers. */
1.42.10.1! macallan  382:        intr_establish(intr[0][0], IST_EDGE, IPL_TTY, zshard, zsc);
        !           383:        intr_establish(intr[1][0], IST_EDGE, IPL_TTY, zshard, zsc);
1.1       tsubai    384: #ifdef ZS_TXDMA
1.42.10.1! macallan  385:        intr_establish(intr[0][1], IST_EDGE, IPL_TTY, zs_txdma_int, (void *)0);
        !           386:        intr_establish(intr[1][1], IST_EDGE, IPL_TTY, zs_txdma_int, (void *)1);
1.1       tsubai    387: #endif
                    388:
1.29      matt      389:        zsc->zsc_si = softintr_establish(IPL_SOFTSERIAL,
                    390:                (void (*)(void *)) zsc_intr_soft, zsc);
                    391:
1.1       tsubai    392:        /*
                    393:         * Set the master interrupt enable and interrupt vector.
                    394:         * (common to both channels, do it on A)
                    395:         */
                    396:        cs = zsc->zsc_cs[0];
                    397:        s = splzs();
                    398:        /* interrupt vector */
                    399:        zs_write_reg(cs, 2, zs_init_reg[2]);
                    400:        /* master interrupt control (enable) */
                    401:        zs_write_reg(cs, 9, zs_init_reg[9]);
                    402:        splx(s);
                    403: }
                    404:
                    405: static int
1.30      chs       406: zsc_print(void *aux, const char *name)
1.1       tsubai    407: {
                    408:        struct zsc_attach_args *args = aux;
                    409:
                    410:        if (name != NULL)
1.24      thorpej   411:                aprint_normal("%s: ", name);
1.1       tsubai    412:
                    413:        if (args->channel != -1)
1.24      thorpej   414:                aprint_normal(" channel %d", args->channel);
1.1       tsubai    415:
                    416:        return UNCONF;
1.6       tsubai    417: }
                    418:
                    419: int
1.42      christos  420: zsmdioctl(struct zs_chanstate *cs, u_long cmd, void *data)
1.6       tsubai    421: {
                    422:        switch (cmd) {
                    423:        default:
1.20      atatat    424:                return (EPASSTHROUGH);
1.6       tsubai    425:        }
                    426:        return (0);
                    427: }
                    428:
                    429: void
1.30      chs       430: zsmd_setclock(struct zs_chanstate *cs)
1.6       tsubai    431: {
1.16      matt      432: #ifdef NOTYET
1.6       tsubai    433:        struct xzs_chanstate *xcs = (void *)cs;
                    434:
                    435:        if (cs->cs_channel != 0)
                    436:                return;
                    437:
                    438:        /*
                    439:         * If the new clock has the external bit set, then select the
                    440:         * external source.
                    441:         */
1.16      matt      442:        via_set_modem((xcs->cs_pclk_flag & ZSC_EXTERN) ? 1 : 0);
                    443: #endif
1.1       tsubai    444: }
                    445:
                    446: int
1.30      chs       447: zshard(void *arg)
1.1       tsubai    448: {
1.30      chs       449:        struct zsc_softc *zsc;
1.39      tsutsui   450:        int rval;
1.1       tsubai    451:
1.39      tsutsui   452:        zsc = arg;
                    453:        rval = zsc_intr_hard(zsc);
                    454:        if ((zsc->zsc_cs[0]->cs_softreq) || (zsc->zsc_cs[1]->cs_softreq))
                    455:                softintr_schedule(zsc->zsc_si);
                    456:
                    457:        return rval;
1.1       tsubai    458: }
                    459:
                    460: #ifdef ZS_TXDMA
                    461: int
1.30      chs       462: zs_txdma_int(void *arg)
1.1       tsubai    463: {
                    464:        int ch = (int)arg;
                    465:        struct zsc_softc *zsc;
                    466:        struct zs_chanstate *cs;
                    467:        int unit = 0;                   /* XXX */
                    468:
                    469:        zsc = zsc_cd.cd_devs[unit];
                    470:        if (zsc == NULL)
                    471:                panic("zs_txdma_int");
                    472:
                    473:        cs = zsc->zsc_cs[ch];
                    474:        zstty_txdma_int(cs);
                    475:
1.38      tsutsui   476:        if (cs->cs_softreq)
1.29      matt      477:                softintr_schedule(zsc->zsc_si);
1.38      tsutsui   478:
1.1       tsubai    479:        return 1;
                    480: }
                    481:
                    482: void
1.42      christos  483: zs_dma_setup(struct zs_chanstate *cs, void *pa, int len)
1.1       tsubai    484: {
                    485:        struct zsc_softc *zsc;
                    486:        dbdma_command_t *cmdp;
                    487:        int ch = cs->cs_channel;
                    488:
                    489:        zsc = zsc_cd.cd_devs[ch];
                    490:        cmdp = zsc->zsc_txdmacmd[ch];
                    491:
                    492:        DBDMA_BUILD(cmdp, DBDMA_CMD_OUT_LAST, 0, len, kvtop(pa),
                    493:                DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
                    494:        cmdp++;
                    495:        DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
                    496:                DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
                    497:
1.35      perry     498:        __asm volatile("eieio");
1.1       tsubai    499:
                    500:        dbdma_start(zsc->zsc_txdmareg[ch], zsc->zsc_txdmacmd[ch]);
                    501: }
                    502: #endif
                    503:
                    504: /*
1.13      tsubai    505:  * Compute the current baud rate given a ZS channel.
                    506:  * XXX Assume internal BRG.
1.1       tsubai    507:  */
                    508: int
1.30      chs       509: zs_get_speed(struct zs_chanstate *cs)
1.1       tsubai    510: {
1.13      tsubai    511:        int tconst;
1.1       tsubai    512:
1.13      tsubai    513:        tconst = zs_read_reg(cs, 12);
                    514:        tconst |= zs_read_reg(cs, 13) << 8;
                    515:        return TCONST_TO_BPS(cs->cs_brg_clk, tconst);
1.1       tsubai    516: }
1.13      tsubai    517:
                    518: #ifndef ZS_TOLERANCE
                    519: #define ZS_TOLERANCE 51
                    520: /* 5% in tenths of a %, plus 1 so that exactly 5% will be ok. */
                    521: #endif
1.1       tsubai    522:
                    523: /*
                    524:  * Search through the signal sources in the channel, and
                    525:  * pick the best one for the baud rate requested. Return
                    526:  * a -1 if not achievable in tolerance. Otherwise return 0
                    527:  * and fill in the values.
                    528:  *
                    529:  * This routine draws inspiration from the Atari port's zs.c
                    530:  * driver in NetBSD 1.1 which did the same type of source switching.
                    531:  * Tolerance code inspired by comspeed routine in isa/com.c.
                    532:  *
                    533:  * By Bill Studenmund, 1996-05-12
                    534:  */
                    535: int
1.30      chs       536: zs_set_speed(struct zs_chanstate *cs, int bps)
1.1       tsubai    537: {
                    538:        struct xzs_chanstate *xcs = (void *) cs;
                    539:        int i, tc, tc0 = 0, tc1, s, sf = 0;
                    540:        int src, rate0, rate1, err, tol;
                    541:
                    542:        if (bps == 0)
                    543:                return (0);
                    544:
                    545:        src = -1;               /* no valid source yet */
                    546:        tol = ZS_TOLERANCE;
                    547:
                    548:        /*
                    549:         * Step through all the sources and see which one matches
                    550:         * the best. A source has to match BETTER than tol to be chosen.
                    551:         * Thus if two sources give the same error, the first one will be
                    552:         * chosen. Also, allow for the possability that one source might run
                    553:         * both the BRG and the direct divider (i.e. RTxC).
                    554:         */
                    555:        for (i = 0; i < xcs->cs_clock_count; i++) {
                    556:                if (xcs->cs_clocks[i].clk <= 0)
1.17      wiz       557:                        continue;       /* skip non-existent or bad clocks */
1.1       tsubai    558:                if (xcs->cs_clocks[i].flags & ZSC_BRG) {
                    559:                        /* check out BRG at /16 */
                    560:                        tc1 = BPS_TO_TCONST(xcs->cs_clocks[i].clk >> 4, bps);
                    561:                        if (tc1 >= 0) {
                    562:                                rate1 = TCONST_TO_BPS(xcs->cs_clocks[i].clk >> 4, tc1);
                    563:                                err = abs(((rate1 - bps)*1000)/bps);
                    564:                                if (err < tol) {
                    565:                                        tol = err;
                    566:                                        src = i;
                    567:                                        sf = xcs->cs_clocks[i].flags & ~ZSC_DIV;
                    568:                                        tc0 = tc1;
                    569:                                        rate0 = rate1;
                    570:                                }
                    571:                        }
                    572:                }
                    573:                if (xcs->cs_clocks[i].flags & ZSC_DIV) {
                    574:                        /*
                    575:                         * Check out either /1, /16, /32, or /64
                    576:                         * Note: for /1, you'd better be using a synchronized
                    577:                         * clock!
                    578:                         */
                    579:                        int b0 = xcs->cs_clocks[i].clk, e0 = abs(b0-bps);
                    580:                        int b1 = b0 >> 4, e1 = abs(b1-bps);
                    581:                        int b2 = b1 >> 1, e2 = abs(b2-bps);
                    582:                        int b3 = b2 >> 1, e3 = abs(b3-bps);
                    583:
                    584:                        if (e0 < e1 && e0 < e2 && e0 < e3) {
                    585:                                err = e0;
                    586:                                rate1 = b0;
                    587:                                tc1 = ZSWR4_CLK_X1;
                    588:                        } else if (e0 > e1 && e1 < e2  && e1 < e3) {
                    589:                                err = e1;
                    590:                                rate1 = b1;
                    591:                                tc1 = ZSWR4_CLK_X16;
                    592:                        } else if (e0 > e2 && e1 > e2 && e2 < e3) {
                    593:                                err = e2;
                    594:                                rate1 = b2;
                    595:                                tc1 = ZSWR4_CLK_X32;
                    596:                        } else {
                    597:                                err = e3;
                    598:                                rate1 = b3;
                    599:                                tc1 = ZSWR4_CLK_X64;
                    600:                        }
                    601:
                    602:                        err = (err * 1000)/bps;
                    603:                        if (err < tol) {
                    604:                                tol = err;
                    605:                                src = i;
                    606:                                sf = xcs->cs_clocks[i].flags & ~ZSC_BRG;
                    607:                                tc0 = tc1;
                    608:                                rate0 = rate1;
                    609:                        }
                    610:                }
                    611:        }
                    612: #ifdef ZSMACDEBUG
                    613:        zsprintf("Checking for rate %d. Found source #%d.\n",bps, src);
                    614: #endif
                    615:        if (src == -1)
                    616:                return (EINVAL); /* no can do */
                    617:
                    618:        /*
                    619:         * The M.I. layer likes to keep cs_brg_clk current, even though
                    620:         * we are the only ones who should be touching the BRG's rate.
                    621:         *
                    622:         * Note: we are assuming that any ZSC_EXTERN signal source comes in
                    623:         * on the RTxC pin. Correct for the mac68k obio zsc.
                    624:         */
                    625:        if (sf & ZSC_EXTERN)
                    626:                cs->cs_brg_clk = xcs->cs_clocks[i].clk >> 4;
                    627:        else
1.11      mycroft   628:                cs->cs_brg_clk = PCLK / 16;
1.1       tsubai    629:
                    630:        /*
                    631:         * Now we have a source, so set it up.
                    632:         */
                    633:        s = splzs();
                    634:        xcs->cs_psource = src;
                    635:        xcs->cs_pclk_flag = sf;
                    636:        bps = rate0;
                    637:        if (sf & ZSC_BRG) {
                    638:                cs->cs_preg[4] = ZSWR4_CLK_X16;
                    639:                cs->cs_preg[11]= ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD;
                    640:                if (sf & ZSC_PCLK) {
                    641:                        cs->cs_preg[14] = ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK;
                    642:                } else {
                    643:                        cs->cs_preg[14] = ZSWR14_BAUD_ENA;
                    644:                }
                    645:                tc = tc0;
                    646:        } else {
                    647:                cs->cs_preg[4] = tc0;
                    648:                if (sf & ZSC_RTXDIV) {
                    649:                        cs->cs_preg[11] = ZSWR11_RXCLK_RTXC | ZSWR11_TXCLK_RTXC;
                    650:                } else {
                    651:                        cs->cs_preg[11] = ZSWR11_RXCLK_TRXC | ZSWR11_TXCLK_TRXC;
                    652:                }
                    653:                cs->cs_preg[14]= 0;
                    654:                tc = 0xffff;
                    655:        }
                    656:        /* Set the BAUD rate divisor. */
                    657:        cs->cs_preg[12] = tc;
                    658:        cs->cs_preg[13] = tc >> 8;
                    659:        splx(s);
                    660:
                    661: #ifdef ZSMACDEBUG
                    662:        zsprintf("Rate is %7d, tc is %7d, source no. %2d, flags %4x\n", \
                    663:            bps, tc, src, sf);
                    664:        zsprintf("Registers are: 4 %x, 11 %x, 14 %x\n\n",
                    665:                cs->cs_preg[4], cs->cs_preg[11], cs->cs_preg[14]);
                    666: #endif
                    667:
                    668:        cs->cs_preg[5] |= ZSWR5_RTS;    /* Make sure the drivers are on! */
                    669:
                    670:        /* Caller will stuff the pending registers. */
                    671:        return (0);
                    672: }
                    673:
                    674: int
1.30      chs       675: zs_set_modes(struct zs_chanstate *cs, int cflag)
1.1       tsubai    676: {
                    677:        struct xzs_chanstate *xcs = (void*)cs;
                    678:        int s;
                    679:
                    680:        /*
                    681:         * Make sure we don't enable hfc on a signal line we're ignoring.
                    682:         * As we enable CTS interrupts only if we have CRTSCTS or CDTRCTS,
                    683:         * this code also effectivly turns off ZSWR15_CTS_IE.
                    684:         *
                    685:         * Also, disable DCD interrupts if we've been told to ignore
                    686:         * the DCD pin. Happens on mac68k because the input line for
                    687:         * DCD can also be used as a clock input.  (Just set CLOCAL.)
                    688:         *
                    689:         * If someone tries to turn an invalid flow mode on, Just Say No
                    690:         * (Suggested by gwr)
                    691:         */
                    692:        if ((cflag & CDTRCTS) && (cflag & (CRTSCTS | MDMBUF)))
                    693:                return (EINVAL);
                    694:        if (xcs->cs_hwflags & ZS_HWFLAG_NO_DCD) {
                    695:                if (cflag & MDMBUF)
                    696:                        return (EINVAL);
                    697:                cflag |= CLOCAL;
                    698:        }
                    699:        if ((xcs->cs_hwflags & ZS_HWFLAG_NO_CTS) && (cflag & (CRTSCTS | CDTRCTS)))
                    700:                return (EINVAL);
                    701:
                    702:        /*
                    703:         * Output hardware flow control on the chip is horrendous:
                    704:         * if carrier detect drops, the receiver is disabled, and if
                    705:         * CTS drops, the transmitter is stoped IN MID CHARACTER!
                    706:         * Therefore, NEVER set the HFC bit, and instead use the
                    707:         * status interrupt to detect CTS changes.
                    708:         */
                    709:        s = splzs();
                    710:        if ((cflag & (CLOCAL | MDMBUF)) != 0)
                    711:                cs->cs_rr0_dcd = 0;
                    712:        else
                    713:                cs->cs_rr0_dcd = ZSRR0_DCD;
                    714:        /*
                    715:         * The mac hardware only has one output, DTR (HSKo in Mac
                    716:         * parlance). In HFC mode, we use it for the functions
                    717:         * typically served by RTS and DTR on other ports, so we
                    718:         * have to fake the upper layer out some.
                    719:         *
                    720:         * CRTSCTS we use CTS as an input which tells us when to shut up.
                    721:         * We make no effort to shut up the other side of the connection.
                    722:         * DTR is used to hang up the modem.
                    723:         *
                    724:         * In CDTRCTS, we use CTS to tell us to stop, but we use DTR to
                    725:         * shut up the other side.
                    726:         */
                    727:        if ((cflag & CRTSCTS) != 0) {
                    728:                cs->cs_wr5_dtr = ZSWR5_DTR;
                    729:                cs->cs_wr5_rts = 0;
                    730:                cs->cs_rr0_cts = ZSRR0_CTS;
                    731:        } else if ((cflag & CDTRCTS) != 0) {
                    732:                cs->cs_wr5_dtr = 0;
                    733:                cs->cs_wr5_rts = ZSWR5_DTR;
                    734:                cs->cs_rr0_cts = ZSRR0_CTS;
                    735:        } else if ((cflag & MDMBUF) != 0) {
                    736:                cs->cs_wr5_dtr = 0;
                    737:                cs->cs_wr5_rts = ZSWR5_DTR;
                    738:                cs->cs_rr0_cts = ZSRR0_DCD;
                    739:        } else {
                    740:                cs->cs_wr5_dtr = ZSWR5_DTR;
                    741:                cs->cs_wr5_rts = 0;
                    742:                cs->cs_rr0_cts = 0;
                    743:        }
                    744:        splx(s);
                    745:
                    746:        /* Caller will stuff the pending registers. */
                    747:        return (0);
                    748: }
                    749:
                    750:
                    751: /*
                    752:  * Read or write the chip with suitable delays.
                    753:  * MacII hardware has the delay built in.
                    754:  * No need for extra delay. :-) However, some clock-chirped
                    755:  * macs, or zsc's on serial add-on boards might need it.
                    756:  */
                    757: #define        ZS_DELAY()
                    758:
                    759: u_char
1.30      chs       760: zs_read_reg(struct zs_chanstate *cs, u_char reg)
1.1       tsubai    761: {
                    762:        u_char val;
                    763:
                    764:        out8(cs->cs_reg_csr, reg);
                    765:        ZS_DELAY();
                    766:        val = in8(cs->cs_reg_csr);
                    767:        ZS_DELAY();
                    768:        return val;
                    769: }
                    770:
                    771: void
1.30      chs       772: zs_write_reg(struct zs_chanstate *cs, u_char reg, u_char val)
1.1       tsubai    773: {
                    774:        out8(cs->cs_reg_csr, reg);
                    775:        ZS_DELAY();
                    776:        out8(cs->cs_reg_csr, val);
                    777:        ZS_DELAY();
                    778: }
                    779:
1.30      chs       780: u_char
                    781: zs_read_csr(struct zs_chanstate *cs)
1.1       tsubai    782: {
1.30      chs       783:        u_char val;
1.1       tsubai    784:
                    785:        val = in8(cs->cs_reg_csr);
                    786:        ZS_DELAY();
                    787:        /* make up for the fact CTS is wired backwards */
                    788:        val ^= ZSRR0_CTS;
                    789:        return val;
                    790: }
                    791:
1.30      chs       792: void
                    793: zs_write_csr(struct zs_chanstate *cs, u_char val)
1.1       tsubai    794: {
                    795:        /* Note, the csr does not write CTS... */
                    796:        out8(cs->cs_reg_csr, val);
                    797:        ZS_DELAY();
                    798: }
                    799:
1.30      chs       800: u_char
                    801: zs_read_data(struct zs_chanstate *cs)
1.1       tsubai    802: {
1.30      chs       803:        u_char val;
1.1       tsubai    804:
                    805:        val = in8(cs->cs_reg_data);
                    806:        ZS_DELAY();
                    807:        return val;
                    808: }
                    809:
1.30      chs       810: void
                    811: zs_write_data(struct zs_chanstate *cs, u_char val)
1.1       tsubai    812: {
                    813:        out8(cs->cs_reg_data, val);
                    814:        ZS_DELAY();
                    815: }
                    816:
                    817: /****************************************************************
                    818:  * Console support functions (powermac specific!)
                    819:  * Note: this code is allowed to know about the layout of
                    820:  * the chip registers, and uses that to keep things simple.
                    821:  * XXX - I think I like the mvme167 code better. -gwr
                    822:  * XXX - Well :-P  :-)  -wrs
                    823:  ****************************************************************/
                    824:
                    825: #define zscnpollc      nullcnpollc
                    826: cons_decl(zs);
                    827:
1.4       tsubai    828: static int stdin, stdout;
                    829:
1.1       tsubai    830: /*
                    831:  * Console functions.
                    832:  */
                    833:
                    834: /*
                    835:  * zscnprobe is the routine which gets called as the kernel is trying to
                    836:  * figure out where the console should be. Each io driver which might
                    837:  * be the console (as defined in mac68k/conf.c) gets probed. The probe
                    838:  * fills in the consdev structure. Important parts are the device #,
                    839:  * and the console priority. Values are CN_DEAD (don't touch me),
                    840:  * CN_NORMAL (I'm here, but elsewhere might be better), CN_INTERNAL
                    841:  * (the video, better than CN_NORMAL), and CN_REMOTE (pick me!)
                    842:  *
                    843:  * As the mac's a bit different, we do extra work here. We mainly check
                    844:  * to see if we have serial echo going on. Also chould check for default
                    845:  * speeds.
                    846:  */
                    847:
                    848: /*
                    849:  * Polled input char.
                    850:  */
                    851: int
1.30      chs       852: zs_getc(void *v)
1.1       tsubai    853: {
1.30      chs       854:        volatile struct zschan *zc = v;
                    855:        int s, c, rr0;
1.1       tsubai    856:
                    857:        s = splhigh();
                    858:        /* Wait for a character to arrive. */
                    859:        do {
                    860:                rr0 = in8(&zc->zc_csr);
                    861:                ZS_DELAY();
                    862:        } while ((rr0 & ZSRR0_RX_READY) == 0);
                    863:
                    864:        c = in8(&zc->zc_data);
                    865:        ZS_DELAY();
                    866:        splx(s);
                    867:
                    868:        /*
                    869:         * This is used by the kd driver to read scan codes,
                    870:         * so don't translate '\r' ==> '\n' here...
                    871:         */
                    872:        return (c);
                    873: }
                    874:
                    875: /*
                    876:  * Polled output char.
                    877:  */
                    878: void
1.30      chs       879: zs_putc(void *v, int c)
1.1       tsubai    880: {
1.30      chs       881:        volatile struct zschan *zc = v;
                    882:        int s, rr0;
                    883:        long wait = 0;
1.1       tsubai    884:
                    885:        s = splhigh();
                    886:        /* Wait for transmitter to become ready. */
                    887:        do {
                    888:                rr0 = in8(&zc->zc_csr);
                    889:                ZS_DELAY();
                    890:        } while (((rr0 & ZSRR0_TX_READY) == 0) && (wait++ < 1000000));
                    891:
                    892:        if ((rr0 & ZSRR0_TX_READY) != 0) {
                    893:                out8(&zc->zc_data, c);
                    894:                ZS_DELAY();
                    895:        }
                    896:        splx(s);
                    897: }
                    898:
                    899:
                    900: /*
                    901:  * Polled console input putchar.
                    902:  */
                    903: int
1.30      chs       904: zscngetc(dev_t dev)
1.1       tsubai    905: {
1.30      chs       906:        volatile struct zschan *zc = zs_conschan;
                    907:        int c;
1.1       tsubai    908:
1.4       tsubai    909:        if (zc) {
1.33      matt      910:                c = zs_getc(__UNVOLATILE(zc));
1.4       tsubai    911:        } else {
                    912:                char ch = 0;
                    913:                OF_read(stdin, &ch, 1);
                    914:                c = ch;
                    915:        }
                    916:        return c;
1.1       tsubai    917: }
                    918:
                    919: /*
                    920:  * Polled console output putchar.
                    921:  */
                    922: void
1.30      chs       923: zscnputc(dev_t dev, int c)
1.1       tsubai    924: {
1.30      chs       925:        volatile struct zschan *zc = zs_conschan;
1.1       tsubai    926:
1.4       tsubai    927:        if (zc) {
1.33      matt      928:                zs_putc(__UNVOLATILE(zc), c);
1.4       tsubai    929:        } else {
                    930:                char ch = c;
                    931:                OF_write(stdout, &ch, 1);
                    932:        }
1.1       tsubai    933: }
                    934:
                    935: /*
                    936:  * Handle user request to enter kernel debugger.
                    937:  */
                    938: void
1.30      chs       939: zs_abort(struct zs_chanstate *cs)
1.1       tsubai    940: {
                    941:        volatile struct zschan *zc = zs_conschan;
                    942:        int rr0;
1.30      chs       943:        long wait = 0;
1.1       tsubai    944:
                    945:        if (zs_cons_canabort == 0)
                    946:                return;
                    947:
                    948:        /* Wait for end of break to avoid PROM abort. */
                    949:        do {
                    950:                rr0 = in8(&zc->zc_csr);
                    951:                ZS_DELAY();
                    952:        } while ((rr0 & ZSRR0_BREAK) && (wait++ < ZSABORT_DELAY));
                    953:
                    954:        if (wait > ZSABORT_DELAY) {
                    955:                zs_cons_canabort = 0;
                    956:        /* If we time out, turn off the abort ability! */
                    957:        }
                    958:
1.19      dbj       959: #if defined(KGDB)
                    960:        kgdb_connect(1);
                    961: #elif defined(DDB)
1.1       tsubai    962:        Debugger();
                    963: #endif
                    964: }
                    965:
1.30      chs       966: extern int ofccngetc(dev_t);
                    967: extern void ofccnputc(dev_t, int);
1.1       tsubai    968:
                    969: struct consdev consdev_zs = {
                    970:        zscnprobe,
                    971:        zscninit,
1.4       tsubai    972:        zscngetc,
                    973:        zscnputc,
1.1       tsubai    974:        zscnpollc,
                    975: };
                    976:
                    977: void
1.30      chs       978: zscnprobe(struct consdev *cp)
1.1       tsubai    979: {
1.4       tsubai    980:        int chosen, pkg;
                    981:        char name[16];
                    982:
                    983:        if ((chosen = OF_finddevice("/chosen")) == -1)
                    984:                return;
                    985:
                    986:        if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1)
                    987:                return;
                    988:        if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1)
                    989:                return;
                    990:
                    991:        if ((pkg = OF_instance_to_package(stdin)) == -1)
                    992:                return;
1.1       tsubai    993:
1.18      wiz       994:        memset(name, 0, sizeof(name));
1.4       tsubai    995:        if (OF_getprop(pkg, "device_type", name, sizeof(name)) == -1)
1.1       tsubai    996:                return;
                    997:
1.4       tsubai    998:        if (strcmp(name, "serial") != 0)
                    999:                return;
                   1000:
1.18      wiz      1001:        memset(name, 0, sizeof(name));
1.4       tsubai   1002:        if (OF_getprop(pkg, "name", name, sizeof(name)) == -1)
1.1       tsubai   1003:                return;
                   1004:
1.4       tsubai   1005:        cp->cn_pri = CN_REMOTE;
1.1       tsubai   1006: }
                   1007:
                   1008: void
1.30      chs      1009: zscninit(struct consdev *cp)
1.1       tsubai   1010: {
1.15      tsubai   1011:        int escc, escc_ch, obio, zs_offset;
                   1012:        u_int32_t reg[5];
1.4       tsubai   1013:        char name[16];
1.1       tsubai   1014:
1.15      tsubai   1015:        if ((escc_ch = OF_instance_to_package(stdin)) == -1)
1.1       tsubai   1016:                return;
                   1017:
1.18      wiz      1018:        memset(name, 0, sizeof(name));
1.15      tsubai   1019:        if (OF_getprop(escc_ch, "name", name, sizeof(name)) == -1)
1.1       tsubai   1020:                return;
                   1021:
1.37      macallan 1022:        zs_conschannel = strcmp(name, "ch-b") == 0;
1.15      tsubai   1023:
                   1024:        if (OF_getprop(escc_ch, "reg", reg, sizeof(reg)) < 4)
                   1025:                return;
                   1026:        zs_offset = reg[0];
                   1027:
                   1028:        escc = OF_parent(escc_ch);
                   1029:        obio = OF_parent(escc);
                   1030:
                   1031:        if (OF_getprop(obio, "assigned-addresses", reg, sizeof(reg)) < 12)
                   1032:                return;
                   1033:        zs_conschan = (void *)(reg[2] + zs_offset);
1.1       tsubai   1034: }

CVSweb <webmaster@jp.NetBSD.org>