Home | History | Annotate | Line # | Download | only in sbd
zs_sbdio.c revision 1.7
      1  1.7       ad /*	$NetBSD: zs_sbdio.c,v 1.7 2007/11/26 23:29:37 ad Exp $	*/
      2  1.1  tsutsui 
      3  1.1  tsutsui /*-
      4  1.1  tsutsui  * Copyright (c) 1996, 2005 The NetBSD Foundation, Inc.
      5  1.1  tsutsui  * All rights reserved.
      6  1.1  tsutsui  *
      7  1.1  tsutsui  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1  tsutsui  * by Gordon W. Ross.
      9  1.1  tsutsui  *
     10  1.1  tsutsui  * Redistribution and use in source and binary forms, with or without
     11  1.1  tsutsui  * modification, are permitted provided that the following conditions
     12  1.1  tsutsui  * are met:
     13  1.1  tsutsui  * 1. Redistributions of source code must retain the above copyright
     14  1.1  tsutsui  *    notice, this list of conditions and the following disclaimer.
     15  1.1  tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1  tsutsui  *    notice, this list of conditions and the following disclaimer in the
     17  1.1  tsutsui  *    documentation and/or other materials provided with the distribution.
     18  1.1  tsutsui  * 3. All advertising materials mentioning features or use of this software
     19  1.1  tsutsui  *    must display the following acknowledgement:
     20  1.1  tsutsui  *        This product includes software developed by the NetBSD
     21  1.1  tsutsui  *        Foundation, Inc. and its contributors.
     22  1.1  tsutsui  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  1.1  tsutsui  *    contributors may be used to endorse or promote products derived
     24  1.1  tsutsui  *    from this software without specific prior written permission.
     25  1.1  tsutsui  *
     26  1.1  tsutsui  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  1.1  tsutsui  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  1.1  tsutsui  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  1.1  tsutsui  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  1.1  tsutsui  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  1.1  tsutsui  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  1.1  tsutsui  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  1.1  tsutsui  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  1.1  tsutsui  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  1.1  tsutsui  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  1.1  tsutsui  * POSSIBILITY OF SUCH DAMAGE.
     37  1.1  tsutsui  */
     38  1.1  tsutsui 
     39  1.1  tsutsui /*
     40  1.1  tsutsui  * Zilog Z8530 Dual UART driver (machine-dependent part)
     41  1.1  tsutsui  *
     42  1.1  tsutsui  * Runs two serial lines per chip using slave drivers.
     43  1.1  tsutsui  * Plain tty/async lines use the zs_async slave.
     44  1.1  tsutsui  */
     45  1.1  tsutsui 
     46  1.1  tsutsui #include <sys/cdefs.h>
     47  1.7       ad __KERNEL_RCSID(0, "$NetBSD: zs_sbdio.c,v 1.7 2007/11/26 23:29:37 ad Exp $");
     48  1.1  tsutsui 
     49  1.1  tsutsui #include <sys/param.h>
     50  1.1  tsutsui #include <sys/systm.h>
     51  1.1  tsutsui #include <sys/device.h>
     52  1.1  tsutsui #include <sys/tty.h>
     53  1.1  tsutsui #include <sys/conf.h>
     54  1.7       ad #include <sys/intr.h>
     55  1.1  tsutsui 
     56  1.1  tsutsui #include <dev/cons.h>
     57  1.1  tsutsui #include <dev/ic/z8530reg.h>
     58  1.1  tsutsui 
     59  1.1  tsutsui #include <machine/sbdiovar.h>
     60  1.1  tsutsui #include <machine/z8530var.h>
     61  1.1  tsutsui 
     62  1.1  tsutsui #define ZS_DEFSPEED	9600
     63  1.1  tsutsui #define PCLK		(9600 * 512)		/* 4.915200MHz */
     64  1.1  tsutsui 
     65  1.1  tsutsui /* The layout of this is hardware-dependent (padding, order). */
     66  1.1  tsutsui struct zschan {
     67  1.1  tsutsui 	volatile uint8_t zc_csr;	/* ctrl, status, and indirect access */
     68  1.1  tsutsui 	uint8_t padding1[3];
     69  1.1  tsutsui 	volatile uint8_t zc_data;	/* data */
     70  1.1  tsutsui 	uint8_t padding2[3];
     71  1.1  tsutsui } __attribute__((__packed__));
     72  1.1  tsutsui 
     73  1.1  tsutsui struct zsdevice {
     74  1.1  tsutsui 	/* Yes, they are backwards. */
     75  1.1  tsutsui 	struct	zschan zs_chan_b;
     76  1.1  tsutsui 	struct	zschan zs_chan_a;
     77  1.1  tsutsui } __attribute__((__packed__));
     78  1.1  tsutsui 
     79  1.1  tsutsui static uint8_t zs_init_reg[16] = {
     80  1.1  tsutsui 	0,				/*  0: CMD (reset, etc.) */
     81  1.1  tsutsui 	0,				/*  1: No interrupts yet. */
     82  1.1  tsutsui 	0,				/*  2: IVECT EWS-UX don't set this. */
     83  1.1  tsutsui 	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
     84  1.1  tsutsui 	ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
     85  1.1  tsutsui 	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
     86  1.1  tsutsui 	0,				/*  6: TXSYNC/SYNCLO */
     87  1.1  tsutsui 	0,				/*  7: RXSYNC/SYNCHI */
     88  1.1  tsutsui 	0,				/*  8: alias for data port */
     89  1.1  tsutsui 	ZSWR9_MASTER_IE,
     90  1.1  tsutsui 	0,				/* 10: Misc. TX/RX control bits */
     91  1.1  tsutsui 	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
     92  1.1  tsutsui 	BPS_TO_TCONST((PCLK/16), ZS_DEFSPEED), /* 12: BAUDLO (default=9600) */
     93  1.1  tsutsui 	0,				/*13: BAUDHI (default=9600) */
     94  1.1  tsutsui 	ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
     95  1.1  tsutsui 	ZSWR15_BREAK_IE,
     96  1.1  tsutsui };
     97  1.1  tsutsui 
     98  1.1  tsutsui int zs_sbdio_match(struct device *, struct cfdata *, void *);
     99  1.1  tsutsui void zs_sbdio_attach(struct device *, struct device *, void *);
    100  1.1  tsutsui 
    101  1.1  tsutsui CFATTACH_DECL(zsc_sbdio, sizeof(struct zsc_softc),
    102  1.1  tsutsui     zs_sbdio_match, zs_sbdio_attach, NULL, NULL);
    103  1.1  tsutsui 
    104  1.1  tsutsui int
    105  1.1  tsutsui zs_sbdio_match(struct device *parent, struct cfdata *cf, void *aux)
    106  1.1  tsutsui {
    107  1.1  tsutsui 	struct sbdio_attach_args *sa = aux;
    108  1.1  tsutsui 
    109  1.1  tsutsui 	return strcmp(sa->sa_name, "zsc") ? 0 : 1;
    110  1.1  tsutsui }
    111  1.1  tsutsui 
    112  1.1  tsutsui void
    113  1.1  tsutsui zs_sbdio_attach(struct device *parent, struct device *self, void *aux)
    114  1.1  tsutsui {
    115  1.1  tsutsui 	struct sbdio_attach_args *sa = aux;
    116  1.1  tsutsui 	struct zsc_softc *zsc = (void *)self;
    117  1.1  tsutsui 	struct zsc_attach_args zsc_args;
    118  1.1  tsutsui 	struct zschan *zc;
    119  1.1  tsutsui 	struct zs_chanstate *cs;
    120  1.1  tsutsui 	struct zsdevice *zs_addr;
    121  1.1  tsutsui 	int s, zs_unit, channel;
    122  1.1  tsutsui 
    123  1.1  tsutsui 	printf(" at %p irq %d\n", (void *)sa->sa_addr1, sa->sa_irq);
    124  1.1  tsutsui 
    125  1.2  thorpej 	zs_unit = device_unit(&zsc->zsc_dev);
    126  1.1  tsutsui 	zs_addr = (void *)MIPS_PHYS_TO_KSEG1(sa->sa_addr1);
    127  1.1  tsutsui 	zsc->zsc_flags = sa->sa_flags;
    128  1.1  tsutsui 
    129  1.1  tsutsui 	/*
    130  1.1  tsutsui 	 * Initialize software state for each channel.
    131  1.1  tsutsui 	 */
    132  1.1  tsutsui 	for (channel = 0; channel < 2; channel++) {
    133  1.1  tsutsui 		zsc_args.channel = channel;
    134  1.1  tsutsui 		zsc_args.hwflags = 0;
    135  1.1  tsutsui 		cs = &zsc->zsc_cs_store[channel];
    136  1.1  tsutsui 		zsc->zsc_cs[channel] = cs;
    137  1.1  tsutsui 
    138  1.1  tsutsui 		cs->cs_channel = channel;
    139  1.1  tsutsui 		cs->cs_private = NULL;
    140  1.1  tsutsui 		cs->cs_ops = &zsops_null;
    141  1.1  tsutsui 
    142  1.1  tsutsui 		if (channel == 0)
    143  1.1  tsutsui 			zc = &zs_addr->zs_chan_a;
    144  1.1  tsutsui 		else
    145  1.1  tsutsui 			zc = &zs_addr->zs_chan_b;
    146  1.1  tsutsui 
    147  1.1  tsutsui 		if (zc == zs_consaddr) {
    148  1.1  tsutsui 			memcpy(cs, zs_conscs, sizeof(struct zs_chanstate));
    149  1.1  tsutsui 			zs_conscs = cs;
    150  1.1  tsutsui 			zsc_args.hwflags = ZS_HWFLAG_CONSOLE;
    151  1.1  tsutsui 		} else {
    152  1.1  tsutsui 			cs->cs_reg_csr  = &zc->zc_csr;
    153  1.1  tsutsui 			cs->cs_reg_data = &zc->zc_data;
    154  1.1  tsutsui 			memcpy(cs->cs_creg, zs_init_reg, 16);
    155  1.1  tsutsui 			memcpy(cs->cs_preg, zs_init_reg, 16);
    156  1.1  tsutsui 			cs->cs_defspeed = ZS_DEFSPEED;
    157  1.1  tsutsui 			zsc_args.hwflags = 0;
    158  1.1  tsutsui 		}
    159  1.1  tsutsui 
    160  1.6       ad 		zs_lock_init(cs);
    161  1.1  tsutsui 		cs->cs_brg_clk = PCLK / 16;
    162  1.1  tsutsui 		cs->cs_defcflag = zs_def_cflag;
    163  1.1  tsutsui 
    164  1.1  tsutsui 		/* Make these correspond to cs_defcflag (-crtscts) */
    165  1.1  tsutsui 		cs->cs_rr0_dcd = ZSRR0_DCD;
    166  1.1  tsutsui 		cs->cs_rr0_cts = 0;
    167  1.1  tsutsui 		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
    168  1.1  tsutsui 		cs->cs_wr5_rts = 0;
    169  1.1  tsutsui 
    170  1.1  tsutsui 		/*
    171  1.1  tsutsui 		 * Clear the master interrupt enable.
    172  1.1  tsutsui 		 * The INTENA is common to both channels,
    173  1.1  tsutsui 		 * so just do it on the A channel.
    174  1.1  tsutsui 		 */
    175  1.1  tsutsui 		if (channel == 0) {
    176  1.1  tsutsui 			zs_write_reg(cs, 9, 0);
    177  1.1  tsutsui 		}
    178  1.1  tsutsui 
    179  1.1  tsutsui 		/*
    180  1.1  tsutsui 		 * Look for a child driver for this channel.
    181  1.1  tsutsui 		 * The child attach will setup the hardware.
    182  1.1  tsutsui 		 */
    183  1.1  tsutsui 		if (!config_found(self, (void *)&zsc_args, zs_print)) {
    184  1.1  tsutsui 			/* No sub-driver.  Just reset it. */
    185  1.1  tsutsui 			uint8_t reset = (channel == 0) ?
    186  1.1  tsutsui 			    ZSWR9_A_RESET : ZSWR9_B_RESET;
    187  1.1  tsutsui 			s = splhigh();
    188  1.1  tsutsui 			zs_write_reg(cs, 9, reset);
    189  1.1  tsutsui 			splx(s);
    190  1.1  tsutsui 		}
    191  1.1  tsutsui 	}
    192  1.1  tsutsui 
    193  1.7       ad 	zsc->zsc_si = softint_establish(SOFTINT_SERIAL,
    194  1.3  tsutsui 	    (void (*)(void *))zsc_intr_soft, zsc);
    195  1.3  tsutsui 	intr_establish(sa->sa_irq, zshard, zsc);
    196  1.1  tsutsui 
    197  1.1  tsutsui 	/*
    198  1.1  tsutsui 	 * Set the master interrupt enable and interrupt vector.
    199  1.1  tsutsui 	 * (common to both channels, do it on A)
    200  1.1  tsutsui 	 */
    201  1.1  tsutsui 	cs = zsc->zsc_cs[0];
    202  1.1  tsutsui 	s = splhigh();
    203  1.1  tsutsui 	/* interrupt vector */
    204  1.1  tsutsui 	zs_write_reg(cs, 2, zs_init_reg[2]);
    205  1.1  tsutsui 	/* master interrupt control (enable) */
    206  1.1  tsutsui 	zs_write_reg(cs, 9, zs_init_reg[9]);
    207  1.1  tsutsui 	splx(s);
    208  1.1  tsutsui }
    209  1.1  tsutsui 
    210  1.1  tsutsui /*
    211  1.1  tsutsui  * console stuff
    212  1.1  tsutsui  */
    213  1.1  tsutsui 
    214  1.1  tsutsui static void zs_sbdio_cnprobe(struct consdev *);
    215  1.1  tsutsui static void zs_sbdio_cninit(struct consdev *);
    216  1.1  tsutsui 
    217  1.1  tsutsui struct consdev consdev_zs_sbdio = {
    218  1.1  tsutsui 	zs_sbdio_cnprobe,
    219  1.1  tsutsui 	zs_sbdio_cninit,
    220  1.1  tsutsui 	zscngetc,
    221  1.1  tsutsui 	zscnputc,
    222  1.1  tsutsui 	nullcnpollc,
    223  1.1  tsutsui 	NULL,
    224  1.1  tsutsui 	NULL,
    225  1.1  tsutsui 	NULL,
    226  1.1  tsutsui 	NODEV,
    227  1.1  tsutsui 	CN_DEAD
    228  1.1  tsutsui };
    229  1.1  tsutsui 
    230  1.1  tsutsui static void
    231  1.1  tsutsui zs_sbdio_cnprobe(struct consdev *cn)
    232  1.1  tsutsui {
    233  1.1  tsutsui 
    234  1.1  tsutsui 	/* not used */
    235  1.1  tsutsui }
    236  1.1  tsutsui 
    237  1.1  tsutsui static void
    238  1.1  tsutsui zs_sbdio_cninit(struct consdev *cn)
    239  1.1  tsutsui {
    240  1.1  tsutsui 	struct zs_chanstate *cs;
    241  1.1  tsutsui 	struct zschan *zc;
    242  1.1  tsutsui 
    243  1.1  tsutsui 	zc = zs_consaddr;
    244  1.1  tsutsui 	cs = zs_conscs;
    245  1.1  tsutsui 
    246  1.1  tsutsui 	/* Setup temporary chanstate. */
    247  1.1  tsutsui 	cs->cs_reg_csr  = &zc->zc_csr;
    248  1.1  tsutsui 	cs->cs_reg_data = &zc->zc_data;
    249  1.1  tsutsui 
    250  1.1  tsutsui 	/* Initialize the pending registers. */
    251  1.1  tsutsui 	memcpy(cs->cs_preg, zs_init_reg, 16);
    252  1.1  tsutsui 	cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
    253  1.1  tsutsui 
    254  1.1  tsutsui 	cs->cs_brg_clk = PCLK / 16;
    255  1.1  tsutsui 	cs->cs_defspeed = ZS_DEFSPEED;
    256  1.1  tsutsui 	zs_set_speed(cs, ZS_DEFSPEED);
    257  1.1  tsutsui 
    258  1.1  tsutsui 	/* Clear the master interrupt enable. */
    259  1.1  tsutsui 	zs_write_reg(cs, 9, 0);
    260  1.1  tsutsui 
    261  1.1  tsutsui 	/* Reset the whole SCC chip. */
    262  1.1  tsutsui 	zs_write_reg(cs, 9, ZSWR9_HARD_RESET);
    263  1.1  tsutsui 
    264  1.1  tsutsui 	/* Copy "pending" to "current" and H/W */
    265  1.1  tsutsui 	zs_loadchannelregs(cs);
    266  1.1  tsutsui }
    267