10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4525Skchow * Common Development and Distribution License (the "License"). 6*4525Skchow * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*4525Skchow * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * Serial I/O driver for Z8530 chips 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/param.h> 340Sstevel@tonic-gate #include <sys/systm.h> 350Sstevel@tonic-gate #include <sys/sysmacros.h> 360Sstevel@tonic-gate #include <sys/stropts.h> 370Sstevel@tonic-gate #include <sys/stream.h> 380Sstevel@tonic-gate #include <sys/stat.h> 390Sstevel@tonic-gate #include <sys/mkdev.h> 400Sstevel@tonic-gate #include <sys/cmn_err.h> 410Sstevel@tonic-gate #include <sys/errno.h> 420Sstevel@tonic-gate #include <sys/kmem.h> 430Sstevel@tonic-gate #include <sys/zsdev.h> 440Sstevel@tonic-gate #include <sys/debug.h> 450Sstevel@tonic-gate #include <sys/machsystm.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate #include <sys/conf.h> 480Sstevel@tonic-gate #include <sys/sunddi.h> 490Sstevel@tonic-gate #include <sys/errno.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #define ZS_TRACING 520Sstevel@tonic-gate #ifdef ZS_TRACING 530Sstevel@tonic-gate #include <sys/vtrace.h> 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * Temp tracepoint definitions 570Sstevel@tonic-gate */ 580Sstevel@tonic-gate #define TR_FAC_ZS 51 590Sstevel@tonic-gate 600Sstevel@tonic-gate #define TR_ZS_H_INT_START 1 610Sstevel@tonic-gate #define TR_ZS_H_INT_END 2 620Sstevel@tonic-gate #define TR_ZS_INT_START 3 630Sstevel@tonic-gate #define TR_ZS_INT_END 4 640Sstevel@tonic-gate 650Sstevel@tonic-gate #define TR_FAC_ZS_INT 52 660Sstevel@tonic-gate #define TR_READ_START 1 670Sstevel@tonic-gate #define TR_READ_END 2 680Sstevel@tonic-gate 690Sstevel@tonic-gate #endif /* ZSH_TRACING */ 700Sstevel@tonic-gate 710Sstevel@tonic-gate #define KIOIP KSTAT_INTR_PTR(zs->intrstats) 720Sstevel@tonic-gate 730Sstevel@tonic-gate #ifndef MAXZS 740Sstevel@tonic-gate #define MAXZS 4 750Sstevel@tonic-gate #endif 760Sstevel@tonic-gate int maxzs = MAXZS; 770Sstevel@tonic-gate 780Sstevel@tonic-gate int nzs = 0; 790Sstevel@tonic-gate 800Sstevel@tonic-gate struct zscom *zscom; 810Sstevel@tonic-gate struct zscom *zscurr; 820Sstevel@tonic-gate struct zscom *zslast; 830Sstevel@tonic-gate struct zs_prog *zs_prog; 840Sstevel@tonic-gate char *zssoftCAR; 850Sstevel@tonic-gate int zs_watchdog_count = 10; /* countdown to determine if tx hung */ 860Sstevel@tonic-gate 870Sstevel@tonic-gate int zs_drain_check = 15000000; /* tunable: exit drain check time */ 880Sstevel@tonic-gate 890Sstevel@tonic-gate #ifdef ZS_DEBUG 900Sstevel@tonic-gate char zs_h_log[ZS_H_LOG_MAX +10]; 910Sstevel@tonic-gate int zs_h_log_n = 0; 920Sstevel@tonic-gate #define zs_h_log_add(c) \ 930Sstevel@tonic-gate { \ 940Sstevel@tonic-gate if (zs_h_log_n >= ZS_H_LOG_MAX) \ 950Sstevel@tonic-gate zs_h_log_n = 0; \ 960Sstevel@tonic-gate zs_h_log[zs_h_log_n++] = c; \ 970Sstevel@tonic-gate zs_h_log[zs_h_log_n] = '\0'; \ 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate #else /* NO_ZS_DEBUG */ 1010Sstevel@tonic-gate #define zs_h_log_add(c) 1020Sstevel@tonic-gate #endif /* ZS_DEBUG */ 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate /* 1060Sstevel@tonic-gate * Driver data 1070Sstevel@tonic-gate */ 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate #define GETPROP(dip, str, defval) \ 1100Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, (str), (defval)) 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate int zs_usec_delay = 1; 1130Sstevel@tonic-gate int zssoftpend; 1140Sstevel@tonic-gate ddi_softintr_t zs_softintr_id; 1150Sstevel@tonic-gate time_t default_dtrlow = 3; /* hold dtr low nearly this long on close */ 1160Sstevel@tonic-gate static ddi_iblock_cookie_t zs_iblock; 1170Sstevel@tonic-gate static ddi_iblock_cookie_t zs_hi_iblock; 1180Sstevel@tonic-gate static int zs_addedsoft = 0; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * Driver information for auto-configuration stuff. 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate static int zsprobe(dev_info_t *dev); 1260Sstevel@tonic-gate static int zsattach(dev_info_t *dev, ddi_attach_cmd_t cmd); 1270Sstevel@tonic-gate static int zsdetach(dev_info_t *dev, ddi_detach_cmd_t cmd); 1280Sstevel@tonic-gate void zsopinit(struct zscom *zs, struct zsops *zso); 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate static void zsnull_intr(struct zscom *zs); 1310Sstevel@tonic-gate static int zsnull_softint(struct zscom *zs); 1320Sstevel@tonic-gate static int zsnull_suspend(struct zscom *zs); 1330Sstevel@tonic-gate static int zsnull_resume(struct zscom *zs); 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate struct zsops zsops_null = { 1360Sstevel@tonic-gate zsnull_intr, 1370Sstevel@tonic-gate zsnull_intr, 1380Sstevel@tonic-gate zsnull_intr, 1390Sstevel@tonic-gate zsnull_intr, 1400Sstevel@tonic-gate zsnull_softint, 1410Sstevel@tonic-gate zsnull_suspend, 1420Sstevel@tonic-gate zsnull_resume 1430Sstevel@tonic-gate }; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate extern struct streamtab asynctab; /* default -- from zs_async.c */ 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate uint_t zs_high_intr(caddr_t argzs); 1480Sstevel@tonic-gate uint_t zsintr(caddr_t intarg); 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate extern int zsc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1510Sstevel@tonic-gate void **result); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate extern int ddi_create_internal_pathname(dev_info_t *dip, char *name, 1540Sstevel@tonic-gate int spec_type, minor_t minor_num); 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate extern struct streamtab zsstab; 1570Sstevel@tonic-gate int zssoftpend; /* soft interrupt pending */ 1580Sstevel@tonic-gate kmutex_t zs_soft_lock; /* adapt.lock,to use to protect data */ 1590Sstevel@tonic-gate /* common to sev. streams or ports */ 1600Sstevel@tonic-gate kmutex_t zs_curr_lock; /* lock protecting zscurr */ 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate extern kcondvar_t lbolt_cv; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate /* 1650Sstevel@tonic-gate * curently the only spin lock level 12 for all ocasions 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate #define ZSS_CONF_FLAG (D_NEW | D_MP) 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate static struct cb_ops cb_zs_ops = { 1710Sstevel@tonic-gate nulldev, /* cb_open */ 1720Sstevel@tonic-gate nulldev, /* cb_close */ 1730Sstevel@tonic-gate nodev, /* cb_strategy */ 1740Sstevel@tonic-gate nodev, /* cb_print */ 1750Sstevel@tonic-gate nodev, /* cb_dump */ 1760Sstevel@tonic-gate nodev, /* cb_read */ 1770Sstevel@tonic-gate nodev, /* cb_write */ 1780Sstevel@tonic-gate nodev, /* cb_ioctl */ 1790Sstevel@tonic-gate nodev, /* cb_devmap */ 1800Sstevel@tonic-gate nodev, /* cb_mmap */ 1810Sstevel@tonic-gate nodev, /* cb_segmap */ 1820Sstevel@tonic-gate nochpoll, /* cb_chpoll */ 1830Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1840Sstevel@tonic-gate &asynctab, /* cb_stream */ 1850Sstevel@tonic-gate (int)(ZSS_CONF_FLAG) /* cb_flag */ 1860Sstevel@tonic-gate }; 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate struct dev_ops zs_ops = { 1890Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 1900Sstevel@tonic-gate 0, /* devo_refcnt */ 1910Sstevel@tonic-gate zsc_info, /* devo_getinfo */ 1920Sstevel@tonic-gate nulldev, /* devo_identify */ 1930Sstevel@tonic-gate zsprobe, /* devo_probe */ 1940Sstevel@tonic-gate zsattach, /* devo_attach */ 1950Sstevel@tonic-gate zsdetach, /* devo_detach */ 1960Sstevel@tonic-gate nodev, /* devo_reset */ 1970Sstevel@tonic-gate &cb_zs_ops, /* devo_cb_ops */ 1980Sstevel@tonic-gate (struct bus_ops *)NULL, /* devo_bus_ops */ 1990Sstevel@tonic-gate ddi_power /* devo_power */ 2000Sstevel@tonic-gate }; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate /* 2040Sstevel@tonic-gate * This is the loadable module wrapper. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate #include <sys/modctl.h> 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate /* 2100Sstevel@tonic-gate * Module linkage information for the kernel. 2110Sstevel@tonic-gate */ 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate extern struct mod_ops mod_driverops; 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate static struct modldrv modldrv = { 2160Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 2170Sstevel@tonic-gate "Z8530 serial driver V%I%", 2180Sstevel@tonic-gate &zs_ops, /* driver ops */ 2190Sstevel@tonic-gate }; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate static struct modlinkage modlinkage = { 2220Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 2230Sstevel@tonic-gate }; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate int 2260Sstevel@tonic-gate _init(void) 2270Sstevel@tonic-gate { 2280Sstevel@tonic-gate return (mod_install(&modlinkage)); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate int 2320Sstevel@tonic-gate _fini(void) 2330Sstevel@tonic-gate { 2340Sstevel@tonic-gate return (EBUSY); 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate int 2380Sstevel@tonic-gate _info(struct modinfo *modinfop) 2390Sstevel@tonic-gate { 2400Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate static int 2440Sstevel@tonic-gate zsprobe(dev_info_t *dev) 2450Sstevel@tonic-gate { 2460Sstevel@tonic-gate struct zscc_device *zsaddr; 2470Sstevel@tonic-gate int rval; 2480Sstevel@tonic-gate auto char c; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate rval = DDI_PROBE_FAILURE; 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * temporarily map in registers 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate if (ddi_map_regs(dev, 0, (caddr_t *)&zsaddr, 0, 0)) { 2560Sstevel@tonic-gate cmn_err(CE_WARN, "zsprobe: unable to map registers"); 2570Sstevel@tonic-gate return (rval); 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * NON-DDI Compliant call 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate mon_clock_stop(); 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * get in sync with the chip 2670Sstevel@tonic-gate */ 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate if (ddi_peek8(dev, (char *)&zsaddr->zscc_control, &c) != DDI_SUCCESS) { 2700Sstevel@tonic-gate goto out; 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate drv_usecwait(2); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* 2750Sstevel@tonic-gate * The traditional test for the presence of an 8530 has been to write 2760Sstevel@tonic-gate * a 15 (octal 017) to its control register address, then read it back. 2770Sstevel@tonic-gate * A Z8530 will respond to this with the contents of Read-Register 15. 2780Sstevel@tonic-gate * If this address were memory, or something else, we would expect to 2790Sstevel@tonic-gate * see the 15 again. Normally, the contents of RR15 will be entirely 2800Sstevel@tonic-gate * different. A Z8530 does not use the D0 and D2 bits of register 15, 2810Sstevel@tonic-gate * so they should equal zero. Compatable chips should do the same. 2820Sstevel@tonic-gate * Beware of "enhanced" SCC's that do not guarantee this. 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate if (ddi_poke8(dev, (char *)&zsaddr->zscc_control, '\017') 2850Sstevel@tonic-gate != DDI_SUCCESS) { 2860Sstevel@tonic-gate goto out; 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate drv_usecwait(2); 2890Sstevel@tonic-gate if (ddi_peek8(dev, (char *)&zsaddr->zscc_control, &c) != DDI_SUCCESS) { 2900Sstevel@tonic-gate goto out; 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate drv_usecwait(2); 2930Sstevel@tonic-gate if (c & 5) { 2940Sstevel@tonic-gate goto out; 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate rval = DDI_PROBE_SUCCESS; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate out: 3000Sstevel@tonic-gate /* 3010Sstevel@tonic-gate * NON-DDI Compliant call 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate mon_clock_start(); 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate ddi_unmap_regs(dev, 0, (caddr_t *)&zsaddr, 0, 0); 3060Sstevel@tonic-gate return (rval); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate /*ARGSUSED*/ 3100Sstevel@tonic-gate static int 3110Sstevel@tonic-gate zsattach(dev_info_t *dev, ddi_attach_cmd_t cmd) 3120Sstevel@tonic-gate { 3130Sstevel@tonic-gate struct zscom *zs; 3140Sstevel@tonic-gate int loops, i; 3150Sstevel@tonic-gate uint_t s; 3160Sstevel@tonic-gate int rtsdtr_bits = 0; 3170Sstevel@tonic-gate char softcd; 3180Sstevel@tonic-gate uchar_t rr; 3190Sstevel@tonic-gate short speed[2]; 3200Sstevel@tonic-gate int current_chip = ddi_get_instance(dev); 3210Sstevel@tonic-gate struct zscc_device *tmpzs; /* for mapping purposes */ 3220Sstevel@tonic-gate char name[16]; 3230Sstevel@tonic-gate int keyboard_prop; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate switch (cmd) { 3260Sstevel@tonic-gate case DDI_ATTACH: 3270Sstevel@tonic-gate break; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate case DDI_RESUME: 3300Sstevel@tonic-gate zs = &zscom[current_chip*2]; 3310Sstevel@tonic-gate /* 3320Sstevel@tonic-gate * Try to resume first channel 3330Sstevel@tonic-gate */ 3340Sstevel@tonic-gate if (!zs->zs_resume || (zs->zs_resume)(zs) != DDI_SUCCESS) 3350Sstevel@tonic-gate return (DDI_FAILURE); 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * And the second channel 3380Sstevel@tonic-gate */ 3390Sstevel@tonic-gate zs++; 3400Sstevel@tonic-gate if (!zs->zs_resume || (zs->zs_resume)(zs) != DDI_SUCCESS) { 3410Sstevel@tonic-gate zs--; 3420Sstevel@tonic-gate if (!zs->zs_suspend || 3430Sstevel@tonic-gate (zs->zs_suspend)(zs) != DDI_SUCCESS) 3440Sstevel@tonic-gate cmn_err(CE_WARN, 3450Sstevel@tonic-gate "zs: inconsistent suspend/resume state"); 3460Sstevel@tonic-gate return (DDI_FAILURE); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate return (DDI_SUCCESS); 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate default: 3510Sstevel@tonic-gate return (DDI_FAILURE); 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate if (zscom == NULL) { 3550Sstevel@tonic-gate mutex_init(&zs_soft_lock, NULL, MUTEX_DRIVER, (void *)ZS_PL); 3560Sstevel@tonic-gate mutex_init(&zs_curr_lock, NULL, MUTEX_DRIVER, (void *)ZS_PL_HI); 3570Sstevel@tonic-gate zscom = kmem_zalloc(maxzs * sizeof (struct zscom), KM_SLEEP); 3580Sstevel@tonic-gate zs_prog = kmem_zalloc(maxzs * sizeof (struct zs_prog), 3590Sstevel@tonic-gate KM_SLEEP); 3600Sstevel@tonic-gate zssoftCAR = kmem_zalloc(maxzs, KM_SLEEP); 3610Sstevel@tonic-gate /* don't set nzs until arrays are allocated */ 3620Sstevel@tonic-gate membar_producer(); 3630Sstevel@tonic-gate nzs = maxzs; 3640Sstevel@tonic-gate zscurr = &zscom[(current_chip*2) + 1]; 3650Sstevel@tonic-gate zslast = &zscom[current_chip*2]; 3660Sstevel@tonic-gate i = GETPROP(dev, "zs-usec-delay", 0); 3670Sstevel@tonic-gate zs_usec_delay = (i <= 0) ? 1 : i; 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate if (2 * current_chip >= maxzs) { 3710Sstevel@tonic-gate cmn_err(CE_WARN, 3720Sstevel@tonic-gate "zs: unable to allocate resources for chip %d.", 3730Sstevel@tonic-gate current_chip); 3740Sstevel@tonic-gate cmn_err(CE_WARN, "Change zs:maxzs in /etc/system"); 3750Sstevel@tonic-gate return (DDI_FAILURE); 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate zs = &zscom[current_chip*2]; 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate /* 3800Sstevel@tonic-gate * map in the device registers 3810Sstevel@tonic-gate */ 3820Sstevel@tonic-gate if (ddi_map_regs(dev, 0, (caddr_t *)&zs->zs_addr, 0, 0)) { 3830Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d: unable to map registers\n", 3840Sstevel@tonic-gate current_chip); 3850Sstevel@tonic-gate return (DDI_FAILURE); 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate tmpzs = zs->zs_addr; 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate /* 3910Sstevel@tonic-gate * Non-DDI compliant Sun-Ness specfic call(s) 3920Sstevel@tonic-gate */ 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate /* 3950Sstevel@tonic-gate * Stop the monitor's polling interrupt. 3960Sstevel@tonic-gate * 3970Sstevel@tonic-gate * I know that this is not exactly obvious. On all sunmon PROM 3980Sstevel@tonic-gate * machines, the PROM has can have a high level periodic clock 3990Sstevel@tonic-gate * interrupt going at this time. It uses this periodic interrupt 4000Sstevel@tonic-gate * to poll the console tty or kbd uart to check for things like 4010Sstevel@tonic-gate * BREAK or L1-A (abort). While we're probing this device out we 4020Sstevel@tonic-gate * have to shut that off so the PROM won't get confused by what 4030Sstevel@tonic-gate * we're doing to the zs. This has caused some pretty funny bugs 4040Sstevel@tonic-gate * in its time. 4050Sstevel@tonic-gate * 4060Sstevel@tonic-gate * For OPENPROM machines, the prom takes level12 interrupts directly, 4070Sstevel@tonic-gate * but we call this routine anyway (I forget why). 4080Sstevel@tonic-gate */ 4090Sstevel@tonic-gate mon_clock_stop(); 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* 4120Sstevel@tonic-gate * Go critical to keep uart from urking. 4130Sstevel@tonic-gate */ 4140Sstevel@tonic-gate s = ddi_enter_critical(); 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate * We are about to issue a full reset to this chip. 4180Sstevel@tonic-gate * First, now that interrupts are blocked, we will delay up to a 4190Sstevel@tonic-gate * half-second, checking both channels for any stray activity. 4200Sstevel@tonic-gate * Next we will preserve the time constants from both channels, 4210Sstevel@tonic-gate * so that they can be restored after the reset. This is especially 4220Sstevel@tonic-gate * important for the console device. Finally, do the reset and 4230Sstevel@tonic-gate * follow it with an extended recovery while the chip settles down. 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate for (loops = 0; loops++ <= 500; DELAY(1000)) { 4260Sstevel@tonic-gate SCC_READA(1, rr); 4270Sstevel@tonic-gate if ((rr & ZSRR1_ALL_SENT) == 0) continue; 4280Sstevel@tonic-gate SCC_READB(1, rr); 4290Sstevel@tonic-gate if ((rr & ZSRR1_ALL_SENT) == 0) continue; 4300Sstevel@tonic-gate SCC_READA(0, rr); 4310Sstevel@tonic-gate if ((rr & ZSRR0_TX_READY) == 0) continue; 4320Sstevel@tonic-gate SCC_READB(0, rr); 4330Sstevel@tonic-gate if ((rr & ZSRR0_TX_READY) != 0) break; 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate SCC_READA(12, speed[0]); 4370Sstevel@tonic-gate SCC_READA(13, rr); 4380Sstevel@tonic-gate speed[0] |= rr << 8; 4390Sstevel@tonic-gate SCC_READB(12, speed[1]); 4400Sstevel@tonic-gate SCC_READB(13, rr); 4410Sstevel@tonic-gate speed[1] |= rr << 8; 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate SCC_WRITE(9, ZSWR9_RESET_WORLD); 4440Sstevel@tonic-gate DELAY(10); 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate /* 4470Sstevel@tonic-gate * Set up the other components of the zscom structs for this chip. 4480Sstevel@tonic-gate */ 4490Sstevel@tonic-gate for (i = 0; i < 2; i++) { 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * Property for ignoring DCD. 4520Sstevel@tonic-gate * We switch between 'a' and 'b' ports for this device. 4530Sstevel@tonic-gate */ 454*4525Skchow static char prop[] = "port-a-ignore-cd"; 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate /* 4570Sstevel@tonic-gate * For this channel, set the hardware address, allocate the 4580Sstevel@tonic-gate * high-level mutex, and update the zscurr pointer. 4590Sstevel@tonic-gate * The high-level lock is shared by both channels because 4600Sstevel@tonic-gate * 8530 register addressing is non-atomic and asymetrical. 4610Sstevel@tonic-gate * Multiple threads crossing paths during this operation 4620Sstevel@tonic-gate * could trash the chip, and thus, possibly the system console. 4630Sstevel@tonic-gate */ 4640Sstevel@tonic-gate if (i == 0) { /* port A */ 4650Sstevel@tonic-gate zs->zs_addr = (struct zscc_device *) 4660Sstevel@tonic-gate ((uintptr_t)tmpzs | ZSOFF); 4670Sstevel@tonic-gate (zs+1)->zs_excl_hi = zs->zs_excl_hi = &zs_curr_lock; 4680Sstevel@tonic-gate } else { /* port B */ 4690Sstevel@tonic-gate zs++; 4700Sstevel@tonic-gate zs->zs_addr = (struct zscc_device *) 4710Sstevel@tonic-gate ((uintptr_t)tmpzs & ~ZSOFF); 4720Sstevel@tonic-gate zscurr = zs; 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate zs->zs_unit = current_chip * 2 + i; 4750Sstevel@tonic-gate zs->zs_dip = dev; 4760Sstevel@tonic-gate zs->zs_excl = kmem_zalloc(sizeof (kmutex_t), KM_SLEEP); 4770Sstevel@tonic-gate mutex_init(zs->zs_excl, NULL, MUTEX_DRIVER, (void *)ZS_PL); 4780Sstevel@tonic-gate zs->zs_ocexcl = kmem_zalloc(sizeof (kmutex_t), KM_SLEEP); 4790Sstevel@tonic-gate mutex_init(zs->zs_ocexcl, NULL, MUTEX_DRIVER, (void *)ZS_PL); 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate zsopinit(zs, &zsops_null); 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate prop[5] = 'a' + i; 4840Sstevel@tonic-gate softcd = GETPROP((dev_info_t *)(dev), prop, 0); 4850Sstevel@tonic-gate zssoftCAR[zs->zs_unit] = softcd; 4860Sstevel@tonic-gate if (softcd) 4870Sstevel@tonic-gate rtsdtr_bits = ZSWR5_RTS | ZSWR5_DTR; 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate keyboard_prop = GETPROP((dev_info_t *)(zs->zs_dip), 4900Sstevel@tonic-gate "keyboard", 0); 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate mutex_enter(&zs_curr_lock); 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate /* 4950Sstevel@tonic-gate * Set up the default asynch modes 4960Sstevel@tonic-gate * so the monitor will still work 4970Sstevel@tonic-gate */ 4980Sstevel@tonic-gate SCC_WRITE(4, ZSWR4_PARITY_EVEN | ZSWR4_1_STOP | ZSWR4_X16_CLK); 4990Sstevel@tonic-gate SCC_WRITE(3, ZSWR3_RX_8); 5000Sstevel@tonic-gate SCC_WRITE(11, ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD); 5010Sstevel@tonic-gate SCC_WRITE(12, (speed[i] & 0xff)); 5020Sstevel@tonic-gate SCC_WRITE(13, (speed[i] >> 8) & 0xff); 5030Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_BAUD_FROM_PCLK); 5040Sstevel@tonic-gate SCC_WRITE(3, ZSWR3_RX_8 | ZSWR3_RX_ENABLE); 5050Sstevel@tonic-gate SCC_WRITE(5, ZSWR5_TX_ENABLE | ZSWR5_TX_8 | rtsdtr_bits); 5060Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate /* 5090Sstevel@tonic-gate * The SYNC pin on the second SCC (keyboard & mouse) may not 5100Sstevel@tonic-gate * be connected and noise creates transitions on this line. 5110Sstevel@tonic-gate * This floods the system with interrupts, unless the 5120Sstevel@tonic-gate * Sync/Hunt Interrupt Enable is cleared. So write 5130Sstevel@tonic-gate * register 15 with everything we need but that one. 5140Sstevel@tonic-gate */ 5150Sstevel@tonic-gate if (keyboard_prop) { 5160Sstevel@tonic-gate SCC_WRITE(15, ZSR15_BREAK | ZSR15_TX_UNDER | 5170Sstevel@tonic-gate ZSR15_CTS | ZSR15_CD); 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 5210Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 5220Sstevel@tonic-gate mutex_exit(&zs_curr_lock); 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate zs->zs_dtrlow = gethrestime_sec() - default_dtrlow; 5250Sstevel@tonic-gate cv_init(&zs->zs_flags_cv, NULL, CV_DEFAULT, NULL); 5260Sstevel@tonic-gate zsa_init(zs); 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate mutex_enter(&zs_curr_lock); 5300Sstevel@tonic-gate SCC_WRITE(9, ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT); 5310Sstevel@tonic-gate DELAY(4000); 5320Sstevel@tonic-gate mutex_exit(&zs_curr_lock); 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * Two levels of interrupt - chip interrupts at a high level (12), 5360Sstevel@tonic-gate * (which is seen below as zs_high_intr), and then as a secondary 5370Sstevel@tonic-gate * stage soft interrupt as seen in zsintr below. 5380Sstevel@tonic-gate * 5390Sstevel@tonic-gate * Because zs_high_intr does a window save, as well as calls to 5400Sstevel@tonic-gate * other functions, we cannot install it as a "fast" interrupt 5410Sstevel@tonic-gate * that would execute right out of the trap window. Too bad... 5420Sstevel@tonic-gate */ 5430Sstevel@tonic-gate if (ddi_add_intr(dev, (uint_t)0, &zs_hi_iblock, 5440Sstevel@tonic-gate (ddi_idevice_cookie_t *)0, zs_high_intr, 5450Sstevel@tonic-gate (caddr_t)0) != DDI_SUCCESS) { 5460Sstevel@tonic-gate cmn_err(CE_PANIC, "cannot set high level zs interrupt"); 5470Sstevel@tonic-gate /*NOTREACHED*/ 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate if (zs_addedsoft == 0) { 5510Sstevel@tonic-gate if (ddi_add_softintr(dev, DDI_SOFTINT_HIGH, &zs_softintr_id, 5520Sstevel@tonic-gate &zs_iblock, (ddi_idevice_cookie_t *)0, 5530Sstevel@tonic-gate zsintr, (caddr_t)0) != DDI_SUCCESS) { 5540Sstevel@tonic-gate cmn_err(CE_PANIC, 555*4525Skchow "cannot set second stage zs interrupt"); 5560Sstevel@tonic-gate /*NOTREACHED*/ 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate zs_addedsoft++; /* we only need one zsintr! */ 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate if (zs > zslast) 5630Sstevel@tonic-gate zslast = zs; 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate (void) ddi_exit_critical(s); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate /* 5680Sstevel@tonic-gate * Non-DDI compliant Sun-Ness specific call 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate mon_clock_start(); /* re-enable monitor's polling interrupt */ 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate if (!GETPROP(zs->zs_dip, "keyboard", 0)) { 5730Sstevel@tonic-gate static char *serial_line = DDI_NT_SERIAL_MB; 5740Sstevel@tonic-gate static char *dial_out = DDI_NT_SERIAL_MB_DO; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate /* 5770Sstevel@tonic-gate * Export names for channel a or b consconfig match... 5780Sstevel@tonic-gate * The names exported to the filesystem include the 5790Sstevel@tonic-gate * designated tty'a' type name and may not match the PROM 5800Sstevel@tonic-gate * pathname. 5810Sstevel@tonic-gate * Note the special name "obp-console-name" used in these calls. 5820Sstevel@tonic-gate * This keeps the ports and devlinks programs from seeing these 5830Sstevel@tonic-gate * names. (But allows ddi_pathname_to_dev_t to see them.) 5840Sstevel@tonic-gate * We don't need to do this if the instance number is zero, 5850Sstevel@tonic-gate * because we'll create them below, in this case. 5860Sstevel@tonic-gate */ 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate if (ddi_get_instance(dev) != 0) { 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate /* 5910Sstevel@tonic-gate * Select a node type unused by ddi/devfs 5920Sstevel@tonic-gate */ 5930Sstevel@tonic-gate static char *obp_type = "obp-console-name"; 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate (void) strcpy(name, "a"); 5960Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR, 5970Sstevel@tonic-gate ddi_get_instance(dev) * 2, 5980Sstevel@tonic-gate obp_type, NULL) == DDI_FAILURE) { 5990Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6000Sstevel@tonic-gate return (DDI_FAILURE); 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate (void) strcpy(name, "b"); 6030Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR, 6040Sstevel@tonic-gate (ddi_get_instance(dev) * 2) + 1, 6050Sstevel@tonic-gate obp_type, NULL) == DDI_FAILURE) { 6060Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6070Sstevel@tonic-gate return (DDI_FAILURE); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate /* 6120Sstevel@tonic-gate * Export normal device names... 6130Sstevel@tonic-gate */ 6140Sstevel@tonic-gate (void) sprintf(name, "%c", (ddi_get_instance(dev) + 'a')); 6150Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR, 6160Sstevel@tonic-gate ddi_get_instance(dev) * 2, 6170Sstevel@tonic-gate serial_line, NULL) == DDI_FAILURE) { 6180Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6190Sstevel@tonic-gate return (DDI_FAILURE); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate (void) sprintf(name, "%c", (ddi_get_instance(dev) + 'b')); 6220Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR, 6230Sstevel@tonic-gate (ddi_get_instance(dev) * 2) + 1, 6240Sstevel@tonic-gate serial_line, NULL) == DDI_FAILURE) { 6250Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6260Sstevel@tonic-gate return (DDI_FAILURE); 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate (void) sprintf(name, "%c,cu", (ddi_get_instance(dev) + 'a')); 6290Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR, 6300Sstevel@tonic-gate (ddi_get_instance(dev) * 2) | OUTLINE, 6310Sstevel@tonic-gate dial_out, NULL) == DDI_FAILURE) { 6320Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6330Sstevel@tonic-gate return (DDI_FAILURE); 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate (void) sprintf(name, "%c,cu", (ddi_get_instance(dev) + 'b')); 6360Sstevel@tonic-gate if (ddi_create_minor_node(dev, name, S_IFCHR, 6370Sstevel@tonic-gate ((ddi_get_instance(dev) * 2) + 1) | OUTLINE, 6380Sstevel@tonic-gate dial_out, NULL) == DDI_FAILURE) { 6390Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6400Sstevel@tonic-gate return (DDI_FAILURE); 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate } else { 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate /* 6450Sstevel@tonic-gate * Create keyboard and mouse nodes which devfs doesn't see 6460Sstevel@tonic-gate */ 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate /* 6490Sstevel@tonic-gate * This set of minor nodes is for use with the consconfig_dacf 6500Sstevel@tonic-gate * module for the sun4u platforms. (See PSARC/1998/212) 6510Sstevel@tonic-gate */ 6520Sstevel@tonic-gate if (ddi_create_internal_pathname(dev, "keyboard", S_IFCHR, 6530Sstevel@tonic-gate ddi_get_instance(dev) * 2) == DDI_FAILURE) { 6540Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6550Sstevel@tonic-gate return (DDI_FAILURE); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if (ddi_create_internal_pathname(dev, "mouse", S_IFCHR, 6590Sstevel@tonic-gate (ddi_get_instance(dev) * 2) + 1) == DDI_FAILURE) { 6600Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6610Sstevel@tonic-gate return (DDI_FAILURE); 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate /* 6650Sstevel@tonic-gate * These minor nodes are for use with pre-sun4u platforms. 6660Sstevel@tonic-gate * Either one set or the other will be opened by consconfig. 6670Sstevel@tonic-gate */ 6680Sstevel@tonic-gate (void) strcpy(name, "a"); 6690Sstevel@tonic-gate if (ddi_create_internal_pathname(dev, name, S_IFCHR, 670*4525Skchow ddi_get_instance(dev) * 2) == DDI_FAILURE) { 6710Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6720Sstevel@tonic-gate return (DDI_FAILURE); 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate (void) strcpy(name, "b"); 6760Sstevel@tonic-gate if (ddi_create_internal_pathname(dev, name, S_IFCHR, 677*4525Skchow (ddi_get_instance(dev) * 2) + 1) == DDI_FAILURE) { 6780Sstevel@tonic-gate ddi_remove_minor_node(dev, NULL); 6790Sstevel@tonic-gate return (DDI_FAILURE); 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate ddi_report_dev(dev); 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * Initialize power management bookkeeping; components are 6870Sstevel@tonic-gate * created idle. 6880Sstevel@tonic-gate */ 6890Sstevel@tonic-gate if (pm_create_components(dev, 3) == DDI_SUCCESS) { 6900Sstevel@tonic-gate (void) pm_busy_component(dev, 0); 6910Sstevel@tonic-gate pm_set_normal_power(dev, 0, 1); 6920Sstevel@tonic-gate pm_set_normal_power(dev, 1, 1); 6930Sstevel@tonic-gate pm_set_normal_power(dev, 2, 1); 6940Sstevel@tonic-gate } else { 6950Sstevel@tonic-gate return (DDI_FAILURE); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate (void) sprintf(name, "zsc%d", current_chip); 6990Sstevel@tonic-gate zs->intrstats = kstat_create("zs", current_chip, name, "controller", 700*4525Skchow KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 7010Sstevel@tonic-gate if (zs->intrstats) { 7020Sstevel@tonic-gate kstat_install(zs->intrstats); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate return (DDI_SUCCESS); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate static int 7090Sstevel@tonic-gate zsdetach(dev_info_t *dev, ddi_detach_cmd_t cmd) 7100Sstevel@tonic-gate { 7110Sstevel@tonic-gate struct zscom *zs; 7120Sstevel@tonic-gate int current_chip = ddi_get_instance(dev); 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate switch (cmd) { 7150Sstevel@tonic-gate case DDI_DETACH: 7160Sstevel@tonic-gate return (DDI_FAILURE); 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate case DDI_SUSPEND: 7190Sstevel@tonic-gate zs = &zscom[current_chip*2]; 7200Sstevel@tonic-gate /* 7210Sstevel@tonic-gate * Try to suspend first channel 7220Sstevel@tonic-gate */ 7230Sstevel@tonic-gate if (!zs->zs_suspend || (zs->zs_suspend)(zs) != DDI_SUCCESS) 7240Sstevel@tonic-gate return (DDI_FAILURE); 7250Sstevel@tonic-gate /* 7260Sstevel@tonic-gate * And the second channel 7270Sstevel@tonic-gate */ 7280Sstevel@tonic-gate zs++; 7290Sstevel@tonic-gate if (!zs->zs_suspend || (zs->zs_suspend)(zs) != DDI_SUCCESS) { 7300Sstevel@tonic-gate zs--; 7310Sstevel@tonic-gate if (!zs->zs_resume || 7320Sstevel@tonic-gate (zs->zs_resume)(zs) != DDI_SUCCESS) 7330Sstevel@tonic-gate cmn_err(CE_WARN, 7340Sstevel@tonic-gate "zs: inconsistent suspend/resume state"); 7350Sstevel@tonic-gate return (DDI_FAILURE); 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate return (DDI_SUCCESS); 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate default: 7400Sstevel@tonic-gate return (DDI_FAILURE); 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate /* 7450Sstevel@tonic-gate * SCC High Level Interrupt Handler 7460Sstevel@tonic-gate * 7470Sstevel@tonic-gate * This routine fields the level 12 interrupts generated by the 8530 chips. 7480Sstevel@tonic-gate * When the SCC interrupts the conditions that triggered it are available 7490Sstevel@tonic-gate * for reference in Read Register 3 of the A channel (RR3A). We process 7500Sstevel@tonic-gate * all the pending interrupts before returning. The maximum interrupts 7510Sstevel@tonic-gate * that will be processed before returning is set to 6, which is twice 7520Sstevel@tonic-gate * the size of RX-FIFO. 7530Sstevel@tonic-gate * We keep a pointer to the B side of the most recently interrupting chip 7540Sstevel@tonic-gate * in zscurr. 7550Sstevel@tonic-gate */ 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate /* 7580Sstevel@tonic-gate * 'argzs' actually 'struct zscom *argzs' 7590Sstevel@tonic-gate */ 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate #define ZSRR3_INT_PENDING (ZSRR3_IP_B_STAT | ZSRR3_IP_B_TX | ZSRR3_IP_B_RX |\ 7620Sstevel@tonic-gate ZSRR3_IP_A_STAT | ZSRR3_IP_A_TX | ZSRR3_IP_A_RX) 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate #define ZSRR1_ANY_ERRORS (ZSRR1_PE | ZSRR1_DO | ZSRR1_FE | ZSRR1_RXEOF) 7650Sstevel@tonic-gate #define ZS_HIGH_INTR_LOOPLIMIT 6 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate /*ARGSUSED*/ 7680Sstevel@tonic-gate uint_t 7690Sstevel@tonic-gate zs_high_intr(caddr_t argzs) 7700Sstevel@tonic-gate { 7710Sstevel@tonic-gate struct zscom *zs; 7720Sstevel@tonic-gate uchar_t stat, isource, count; 7730Sstevel@tonic-gate int unit; 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_H_INT_START, "zs_h_int start"); 7760Sstevel@tonic-gate mutex_enter(&zs_curr_lock); 7770Sstevel@tonic-gate zs = zscurr; /* Points at Channel B */ 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate ZSNEXTPOLL(zs, zscurr); 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate SCC_READA(3, isource); 7820Sstevel@tonic-gate start_zs_h: 7830Sstevel@tonic-gate count = ZS_HIGH_INTR_LOOPLIMIT; 7840Sstevel@tonic-gate while ((isource & ZSRR3_INT_PENDING) && (count--)) { 7850Sstevel@tonic-gate if (isource & ZSRR3_IP_B_STAT) 7860Sstevel@tonic-gate (zs->zs_xsint)(zs); 7870Sstevel@tonic-gate else { 7880Sstevel@tonic-gate if (isource & ZSRR3_IP_B_TX) 7890Sstevel@tonic-gate (zs->zs_txint)(zs); 7900Sstevel@tonic-gate if (isource & ZSRR3_IP_B_RX) { 7910Sstevel@tonic-gate SCC_READ(1, stat); 7920Sstevel@tonic-gate if (stat & ZSRR1_ANY_ERRORS) 7930Sstevel@tonic-gate (zs->zs_srint)(zs); 7940Sstevel@tonic-gate else if ((SCC_READ0()) & ZSRR0_RX_READY) 7950Sstevel@tonic-gate (zs->zs_rxint)(zs); 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate zs -= 1; 8000Sstevel@tonic-gate if (isource & ZSRR3_IP_A_STAT) 8010Sstevel@tonic-gate (zs->zs_xsint)(zs); 8020Sstevel@tonic-gate else { 8030Sstevel@tonic-gate if (isource & ZSRR3_IP_A_TX) 8040Sstevel@tonic-gate (zs->zs_txint)(zs); 8050Sstevel@tonic-gate if (isource & ZSRR3_IP_A_RX) { 8060Sstevel@tonic-gate SCC_READ(1, stat); 8070Sstevel@tonic-gate if (stat & ZSRR1_ANY_ERRORS) 8080Sstevel@tonic-gate (zs->zs_srint)(zs); 8090Sstevel@tonic-gate else if ((SCC_READ0()) & ZSRR0_RX_READY) 8100Sstevel@tonic-gate (zs->zs_rxint)(zs); 8110Sstevel@tonic-gate } 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate zs = zscurr; 8150Sstevel@tonic-gate SCC_READA(3, isource); 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate if (count == ZS_HIGH_INTR_LOOPLIMIT) { 8190Sstevel@tonic-gate unit = (nzs >> 1) - 1; 8200Sstevel@tonic-gate while (unit--) { 8210Sstevel@tonic-gate zs += 2; /* Always Channel B */ 8220Sstevel@tonic-gate if (zs > zslast) 8230Sstevel@tonic-gate zs = &zscom[1]; 8240Sstevel@tonic-gate if (!zs->zs_ops) 8250Sstevel@tonic-gate continue; 8260Sstevel@tonic-gate SCC_READA(3, isource); 8270Sstevel@tonic-gate if (isource & ZSRR3_INT_PENDING) { 8280Sstevel@tonic-gate zscurr = zs; /* update zscurr and */ 8290Sstevel@tonic-gate goto start_zs_h; 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate if (zs->intrstats) { 8330Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate mutex_exit(&zs_curr_lock); 8360Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_H_INT_END, "zs_h_int end"); 8370Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); /* Must not be for us. */ 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate if (zs->intrstats) { 8400Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_HARD]++; 8410Sstevel@tonic-gate } 8420Sstevel@tonic-gate mutex_exit(&zs_curr_lock); /* we're done with zscurr */ 8430Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_H_INT_END, "zs_h_int end"); 8440Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate /* 8480Sstevel@tonic-gate * Handle a second-stage interrupt. 8490Sstevel@tonic-gate */ 8500Sstevel@tonic-gate /*ARGSUSED*/ 8510Sstevel@tonic-gate uint_t 8520Sstevel@tonic-gate zsintr(caddr_t intarg) 8530Sstevel@tonic-gate { 8540Sstevel@tonic-gate struct zscom *zs; 8550Sstevel@tonic-gate int rv; 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate /* 8580Sstevel@tonic-gate * Test and clear soft interrupt. 8590Sstevel@tonic-gate */ 8600Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_INT_START, 8610Sstevel@tonic-gate "zs_int start"); 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate mutex_enter(&zs_curr_lock); 8640Sstevel@tonic-gate rv = zssoftpend; 8650Sstevel@tonic-gate if (rv != 0) { 8660Sstevel@tonic-gate zssoftpend = 0; 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate mutex_exit(&zs_curr_lock); 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate if (rv) { 8710Sstevel@tonic-gate for (zs = &zscom[0]; zs <= zslast; zs++) { 8720Sstevel@tonic-gate if (zs->zs_flags & ZS_NEEDSOFT) { 8730Sstevel@tonic-gate zs->zs_flags &= ~ZS_NEEDSOFT; 8740Sstevel@tonic-gate (*zs->zs_ops->zsop_softint)(zs); 8750Sstevel@tonic-gate if (zs->intrstats) { 8760Sstevel@tonic-gate KIOIP->intrs[KSTAT_INTR_SOFT]++; 8770Sstevel@tonic-gate } 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate } 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate TRACE_0(TR_FAC_ZS, TR_ZS_INT_END, 8820Sstevel@tonic-gate "zs_int end"); 8830Sstevel@tonic-gate return (rv); 8840Sstevel@tonic-gate } 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate void 8870Sstevel@tonic-gate setzssoft(void) 8880Sstevel@tonic-gate { 8890Sstevel@tonic-gate ddi_trigger_softintr(zs_softintr_id); 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate /* 8930Sstevel@tonic-gate * Install a new ops vector into low level vector routine addresses 8940Sstevel@tonic-gate */ 8950Sstevel@tonic-gate void 8960Sstevel@tonic-gate zsopinit(struct zscom *zs, struct zsops *zso) 8970Sstevel@tonic-gate { 8980Sstevel@tonic-gate zs->zs_txint = zso->zsop_txint; 8990Sstevel@tonic-gate zs->zs_xsint = zso->zsop_xsint; 9000Sstevel@tonic-gate zs->zs_rxint = zso->zsop_rxint; 9010Sstevel@tonic-gate zs->zs_srint = zso->zsop_srint; 9020Sstevel@tonic-gate zs->zs_suspend = zso->zsop_suspend; 9030Sstevel@tonic-gate zs->zs_resume = zso->zsop_resume; 9040Sstevel@tonic-gate zs->zs_ops = zso; 9050Sstevel@tonic-gate zs->zs_flags = 0; 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate /* 9090Sstevel@tonic-gate * Set or get the modem control status. 9100Sstevel@tonic-gate * 9110Sstevel@tonic-gate * This routine relies on the fact that the bits of interest in RR0 (CD and 9120Sstevel@tonic-gate * CTS) do not overlap the bits of interest in WR5 (RTS and DTR). Thus, they 9130Sstevel@tonic-gate * can be combined into a single 'int' without harm. 9140Sstevel@tonic-gate */ 9150Sstevel@tonic-gate int 9160Sstevel@tonic-gate zsmctl(struct zscom *zs, int bits, int how) 9170Sstevel@tonic-gate { 9180Sstevel@tonic-gate int mbits, obits; 9190Sstevel@tonic-gate time_t now, held; 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate ASSERT(mutex_owned(zs->zs_excl_hi)); 9220Sstevel@tonic-gate ASSERT(mutex_owned(zs->zs_excl)); 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate again: 9250Sstevel@tonic-gate mbits = zs->zs_wreg[5] & (ZSWR5_RTS|ZSWR5_DTR); 9260Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 9270Sstevel@tonic-gate mbits |= SCC_READ0() & (ZSRR0_CD|ZSRR0_CTS); 9280Sstevel@tonic-gate ZSDELAY(); 9290Sstevel@tonic-gate obits = mbits; 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate switch (how) { 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate case DMSET: 9340Sstevel@tonic-gate mbits = bits; 9350Sstevel@tonic-gate break; 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate case DMBIS: 9380Sstevel@tonic-gate mbits |= bits; 9390Sstevel@tonic-gate break; 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate case DMBIC: 9420Sstevel@tonic-gate mbits &= ~bits; 9430Sstevel@tonic-gate break; 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate case DMGET: 9460Sstevel@tonic-gate return (mbits); 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate now = gethrestime_sec(); 9500Sstevel@tonic-gate held = now - zs->zs_dtrlow; 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate /* 9530Sstevel@tonic-gate * if DTR is going low, stash current time away 9540Sstevel@tonic-gate */ 9550Sstevel@tonic-gate if (~mbits & obits & ZSWR5_DTR) 9560Sstevel@tonic-gate zs->zs_dtrlow = now; 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate /* 9590Sstevel@tonic-gate * if DTR is going high, sleep until it has been low a bit 9600Sstevel@tonic-gate */ 9610Sstevel@tonic-gate if ((mbits & ~obits & ZSWR5_DTR) && (held < default_dtrlow)) { 9620Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 9630Sstevel@tonic-gate cv_wait(&lbolt_cv, zs->zs_excl); 9640Sstevel@tonic-gate if (zs->zs_suspended) 9650Sstevel@tonic-gate (void) ddi_dev_is_needed(zs->zs_dip, 0, 1); 9660Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 9670Sstevel@tonic-gate goto again; 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate zs->zs_wreg[5] &= ~(ZSWR5_RTS|ZSWR5_DTR); 9710Sstevel@tonic-gate SCC_BIS(5, mbits & (ZSWR5_RTS|ZSWR5_DTR)); 9720Sstevel@tonic-gate return (mbits); 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate /* 9760Sstevel@tonic-gate * Program the Z8530 registers. 9770Sstevel@tonic-gate */ 9780Sstevel@tonic-gate void 9790Sstevel@tonic-gate zs_program(struct zs_prog *zspp) 9800Sstevel@tonic-gate { 9810Sstevel@tonic-gate struct zscom *zs = zspp->zs; 9820Sstevel@tonic-gate int loops; 9830Sstevel@tonic-gate uchar_t c; 9840Sstevel@tonic-gate uchar_t wr10 = 0, wr14 = 0; 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate ASSERT(mutex_owned(zs->zs_excl)); 9870Sstevel@tonic-gate ASSERT(mutex_owned(zs->zs_excl_hi)); 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate /* 9900Sstevel@tonic-gate * There are some special cases to account for before reprogramming. 9910Sstevel@tonic-gate * We might be transmitting, so delay 100,000 usec (worst case at 110 9920Sstevel@tonic-gate * baud) for this to finish, then disable the receiver until later, 9930Sstevel@tonic-gate * reset the External Status Change latches and the error bits, and 9940Sstevel@tonic-gate * drain the receive FIFO. 9950Sstevel@tonic-gate * XXX: Doing any kind of reset (WR9) here causes trouble! 9960Sstevel@tonic-gate */ 9970Sstevel@tonic-gate if (zspp->flags & ZSP_SYNC) { 9980Sstevel@tonic-gate SCC_WRITE(7, SDLCFLAG); 9990Sstevel@tonic-gate wr10 = ZSWR10_PRESET_ONES; 10000Sstevel@tonic-gate if (zspp->flags & ZSP_NRZI) 10010Sstevel@tonic-gate wr10 |= ZSWR10_NRZI; 10020Sstevel@tonic-gate SCC_WRITE(10, wr10); 10030Sstevel@tonic-gate } else { 10040Sstevel@tonic-gate for (loops = 1000; loops > 0; --loops) { 10050Sstevel@tonic-gate SCC_READ(1, c); 10060Sstevel@tonic-gate if (c & ZSRR1_ALL_SENT) 10070Sstevel@tonic-gate break; 10080Sstevel@tonic-gate DELAY(100); 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate SCC_WRITE(3, 0); 10110Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 10120Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 10130Sstevel@tonic-gate c = SCC_READDATA(); /* Empty the FIFO */ 10140Sstevel@tonic-gate c = SCC_READDATA(); 10150Sstevel@tonic-gate c = SCC_READDATA(); 10160Sstevel@tonic-gate } 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate /* 10190Sstevel@tonic-gate * Programming the SCC is done in three phases. 10200Sstevel@tonic-gate * Phase one sets operating modes: 10210Sstevel@tonic-gate */ 10220Sstevel@tonic-gate SCC_WRITE(4, zspp->wr4); 10230Sstevel@tonic-gate SCC_WRITE(11, zspp->wr11); 10240Sstevel@tonic-gate SCC_WRITE(12, zspp->wr12); 10250Sstevel@tonic-gate SCC_WRITE(13, zspp->wr13); 10260Sstevel@tonic-gate if (zspp->flags & ZSP_PLL) { 10270Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_DPLL_SRC_BAUD); 10280Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_DPLL_NRZI); 10290Sstevel@tonic-gate } else 10300Sstevel@tonic-gate SCC_WRITE(14, ZSWR14_DPLL_DISABLE); 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate /* 10330Sstevel@tonic-gate * Phase two enables special hardware functions: 10340Sstevel@tonic-gate */ 10350Sstevel@tonic-gate wr14 = ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA; 10360Sstevel@tonic-gate if (zspp->flags & ZSP_LOOP) 10370Sstevel@tonic-gate wr14 |= ZSWR14_LOCAL_LOOPBACK; 10380Sstevel@tonic-gate if (zspp->flags & ZSP_ECHO) 10390Sstevel@tonic-gate wr14 |= ZSWR14_AUTO_ECHO; 10400Sstevel@tonic-gate SCC_WRITE(14, wr14); 10410Sstevel@tonic-gate SCC_WRITE(3, zspp->wr3); 10420Sstevel@tonic-gate SCC_WRITE(5, zspp->wr5); 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXCRC); 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate if (zspp->flags & ZSP_PARITY_SPECIAL) { 10470Sstevel@tonic-gate SCC_WRITE(1, ZSWR1_PARITY_SPECIAL); 10480Sstevel@tonic-gate } else { 10490Sstevel@tonic-gate SCC_WRITE(1, 0); 10500Sstevel@tonic-gate } 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate /* 10530Sstevel@tonic-gate * Phase three enables interrupt sources: 10540Sstevel@tonic-gate */ 10550Sstevel@tonic-gate SCC_WRITE(15, zspp->wr15); 10560Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 10570Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 10580Sstevel@tonic-gate SCC_BIS(1, ZSWR1_INIT); 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate static void 10620Sstevel@tonic-gate zsnull_intr(struct zscom *zs) 10630Sstevel@tonic-gate { 10640Sstevel@tonic-gate short c; 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_TXINT); 10670Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_STATUS); 10680Sstevel@tonic-gate c = SCC_READDATA(); 10690Sstevel@tonic-gate ZSDELAY(); 10700Sstevel@tonic-gate #ifdef lint 10710Sstevel@tonic-gate c = c; 10720Sstevel@tonic-gate #endif /* lint */ 10730Sstevel@tonic-gate SCC_WRITE0(ZSWR0_RESET_ERRORS); 10740Sstevel@tonic-gate } 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate static int 10770Sstevel@tonic-gate zsnull_softint(struct zscom *zs) 10780Sstevel@tonic-gate { 10790Sstevel@tonic-gate cmn_err(CE_WARN, "zs%d: unexpected soft int\n", zs->zs_unit); 10800Sstevel@tonic-gate return (0); 10810Sstevel@tonic-gate } 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate /* 10840Sstevel@tonic-gate * These will be called on suspend/resume for un-opened zs ports. 10850Sstevel@tonic-gate */ 10860Sstevel@tonic-gate static int 10870Sstevel@tonic-gate zsnull_suspend(struct zscom *zs) 10880Sstevel@tonic-gate { 10890Sstevel@tonic-gate struct zs_prog *zspp = &zs_prog[zs->zs_unit]; 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate /* 10920Sstevel@tonic-gate * Get a copy of the current registers 10930Sstevel@tonic-gate */ 10940Sstevel@tonic-gate mutex_enter(zs->zs_excl); 10950Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 10960Sstevel@tonic-gate zspp->zs = zs; 10970Sstevel@tonic-gate zspp->flags = 0; 10980Sstevel@tonic-gate zspp->wr3 = zs->zs_wreg[3]; 10990Sstevel@tonic-gate zspp->wr4 = zs->zs_wreg[4]; 11000Sstevel@tonic-gate zspp->wr5 = zs->zs_wreg[5]; 11010Sstevel@tonic-gate zspp->wr11 = zs->zs_wreg[11]; 11020Sstevel@tonic-gate zspp->wr12 = zs->zs_wreg[12]; 11030Sstevel@tonic-gate zspp->wr13 = zs->zs_wreg[13]; 11040Sstevel@tonic-gate zspp->wr15 = zs->zs_wreg[15]; 11050Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 11060Sstevel@tonic-gate mutex_exit(zs->zs_excl); 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate return (DDI_SUCCESS); 11090Sstevel@tonic-gate } 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate static int 11120Sstevel@tonic-gate zsnull_resume(struct zscom *zs) 11130Sstevel@tonic-gate { 11140Sstevel@tonic-gate struct zs_prog *zspp = &zs_prog[zs->zs_unit]; 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate /* 11170Sstevel@tonic-gate * Restore registers 11180Sstevel@tonic-gate */ 11190Sstevel@tonic-gate mutex_enter(zs->zs_excl); 11200Sstevel@tonic-gate mutex_enter(zs->zs_excl_hi); 11210Sstevel@tonic-gate zs_program(zspp); 11220Sstevel@tonic-gate SCC_WRITE(9, ZSWR9_MASTER_IE); 11230Sstevel@tonic-gate DELAY(4000); 11240Sstevel@tonic-gate mutex_exit(zs->zs_excl_hi); 11250Sstevel@tonic-gate mutex_exit(zs->zs_excl); 11260Sstevel@tonic-gate return (DDI_SUCCESS); 11270Sstevel@tonic-gate } 1128