1*78a91e64Smickey /* $OpenBSD: com_puc.c,v 1.3 2001/08/08 15:10:03 mickey Exp $ */ 25a7928a9Sdownsj 35a7928a9Sdownsj /* 45a7928a9Sdownsj * Copyright (c) 1997 - 1999, Jason Downs. All rights reserved. 55a7928a9Sdownsj * 65a7928a9Sdownsj * Redistribution and use in source and binary forms, with or without 75a7928a9Sdownsj * modification, are permitted provided that the following conditions 85a7928a9Sdownsj * are met: 95a7928a9Sdownsj * 1. Redistributions of source code must retain the above copyright 105a7928a9Sdownsj * notice, this list of conditions and the following disclaimer. 115a7928a9Sdownsj * 2. Redistributions in binary form must reproduce the above copyright 125a7928a9Sdownsj * notice, this list of conditions and the following disclaimer in the 135a7928a9Sdownsj * documentation and/or other materials provided with the distribution. 145a7928a9Sdownsj * 3. Neither the name(s) of the author(s) nor the name OpenBSD 155a7928a9Sdownsj * may be used to endorse or promote products derived from this software 165a7928a9Sdownsj * without specific prior written permission. 175a7928a9Sdownsj * 185a7928a9Sdownsj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 195a7928a9Sdownsj * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 205a7928a9Sdownsj * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 215a7928a9Sdownsj * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 225a7928a9Sdownsj * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 235a7928a9Sdownsj * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 245a7928a9Sdownsj * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 255a7928a9Sdownsj * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 265a7928a9Sdownsj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 275a7928a9Sdownsj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 285a7928a9Sdownsj * SUCH DAMAGE. 295a7928a9Sdownsj */ 305a7928a9Sdownsj 315a7928a9Sdownsj #include <sys/param.h> 325a7928a9Sdownsj #include <sys/systm.h> 335a7928a9Sdownsj #include <sys/ioctl.h> 345a7928a9Sdownsj #include <sys/select.h> 355a7928a9Sdownsj #include <sys/tty.h> 365a7928a9Sdownsj #include <sys/proc.h> 375a7928a9Sdownsj #include <sys/user.h> 385a7928a9Sdownsj #include <sys/conf.h> 395a7928a9Sdownsj #include <sys/file.h> 405a7928a9Sdownsj #include <sys/uio.h> 415a7928a9Sdownsj #include <sys/kernel.h> 425a7928a9Sdownsj #include <sys/syslog.h> 435a7928a9Sdownsj #include <sys/types.h> 445a7928a9Sdownsj #include <sys/device.h> 455a7928a9Sdownsj 465a7928a9Sdownsj #include <machine/intr.h> 475a7928a9Sdownsj #include <machine/bus.h> 485a7928a9Sdownsj 495a7928a9Sdownsj #include <dev/pci/pcivar.h> 505a7928a9Sdownsj #include <dev/pci/pucvar.h> 515a7928a9Sdownsj 525a7928a9Sdownsj #include <dev/isa/isavar.h> /* XXX */ 535a7928a9Sdownsj 545a7928a9Sdownsj #include "com.h" 555a7928a9Sdownsj #ifdef i386 565a7928a9Sdownsj #include "pccom.h" 575a7928a9Sdownsj #endif 585a7928a9Sdownsj 595a7928a9Sdownsj #include <dev/ic/comreg.h> 605a7928a9Sdownsj #if NPCCOM > 0 615a7928a9Sdownsj #include <i386/isa/pccomvar.h> 625a7928a9Sdownsj #endif 635a7928a9Sdownsj #if NCOM > 0 645a7928a9Sdownsj #include <dev/ic/comvar.h> 655a7928a9Sdownsj #endif 665a7928a9Sdownsj #include <dev/ic/ns16550reg.h> 675a7928a9Sdownsj 685a7928a9Sdownsj #define com_lcr com_cfcr 695a7928a9Sdownsj #define SET(t, f) (t) |= (f) 705a7928a9Sdownsj 715a7928a9Sdownsj int com_puc_match __P((struct device *, void *, void *)); 725a7928a9Sdownsj void com_puc_attach __P((struct device *, struct device *, void *)); 735a7928a9Sdownsj 745a7928a9Sdownsj #if NCOM_PUC 755a7928a9Sdownsj struct cfattach com_puc_ca = { 765a7928a9Sdownsj sizeof(struct com_softc), com_puc_match, com_puc_attach 775a7928a9Sdownsj }; 785a7928a9Sdownsj #endif 795a7928a9Sdownsj 805a7928a9Sdownsj #if NPCCOM_PUC 815a7928a9Sdownsj struct cfattach pccom_puc_ca = { 825a7928a9Sdownsj sizeof(struct com_softc), com_puc_match, com_puc_attach 835a7928a9Sdownsj }; 845a7928a9Sdownsj #endif 855a7928a9Sdownsj 865a7928a9Sdownsj void com_puc_attach2 __P((struct com_softc *)); 875a7928a9Sdownsj 885a7928a9Sdownsj int 895a7928a9Sdownsj com_puc_match(parent, match, aux) 905a7928a9Sdownsj struct device *parent; 915a7928a9Sdownsj void *match, *aux; 925a7928a9Sdownsj { 935a7928a9Sdownsj struct puc_attach_args *pa = aux; 945a7928a9Sdownsj 955a7928a9Sdownsj if (pa->type == PUC_PORT_TYPE_COM) 965a7928a9Sdownsj return(1); 975a7928a9Sdownsj 985a7928a9Sdownsj return(0); 995a7928a9Sdownsj } 1005a7928a9Sdownsj 1015a7928a9Sdownsj void 1025a7928a9Sdownsj com_puc_attach(parent, self, aux) 1035a7928a9Sdownsj struct device *parent, *self; 1045a7928a9Sdownsj void *aux; 1055a7928a9Sdownsj { 1065a7928a9Sdownsj struct com_softc *sc = (void *)self; 1075a7928a9Sdownsj struct puc_attach_args *pa = aux; 1085a7928a9Sdownsj const char *intrstr; 1095a7928a9Sdownsj 1105a7928a9Sdownsj /* Grab a PCI interrupt. */ 1115a7928a9Sdownsj intrstr = pci_intr_string(pa->pc, pa->intrhandle); 1125a7928a9Sdownsj sc->sc_ih = pci_intr_establish(pa->pc, pa->intrhandle, 1135a7928a9Sdownsj IPL_HIGH, comintr, sc, 1145a7928a9Sdownsj sc->sc_dev.dv_xname); 1155a7928a9Sdownsj if (sc->sc_ih == NULL) { 1165a7928a9Sdownsj printf(": couldn't establish interrupt"); 1175a7928a9Sdownsj if (intrstr != NULL) 1185a7928a9Sdownsj printf(" at %s", intrstr); 1195a7928a9Sdownsj printf("\n"); 1205a7928a9Sdownsj return; 1215a7928a9Sdownsj } 1225a7928a9Sdownsj printf(" %s", intrstr); 1235a7928a9Sdownsj 1245a7928a9Sdownsj sc->sc_iot = pa->t; 1255a7928a9Sdownsj sc->sc_ioh = pa->h; 1265a7928a9Sdownsj sc->sc_iobase = pa->a; 12798e273d3Sderaadt sc->sc_frequency = COM_FREQ; 128*78a91e64Smickey 12998e273d3Sderaadt if (pa->flags) 13098e273d3Sderaadt sc->sc_frequency = pa->flags & PUC_COM_CLOCKMASK; 1315a7928a9Sdownsj 1325a7928a9Sdownsj com_puc_attach2(sc); 1335a7928a9Sdownsj } 1345a7928a9Sdownsj 1355a7928a9Sdownsj /* 1365a7928a9Sdownsj * XXX This should be handled by a generic attach 1375a7928a9Sdownsj */ 1385a7928a9Sdownsj void 1395a7928a9Sdownsj com_puc_attach2(sc) 1405a7928a9Sdownsj struct com_softc *sc; 1415a7928a9Sdownsj { 1425a7928a9Sdownsj bus_space_tag_t iot = sc->sc_iot; 1435a7928a9Sdownsj bus_space_handle_t ioh = sc->sc_ioh; 1445a7928a9Sdownsj u_int8_t lcr; 1455a7928a9Sdownsj 1465a7928a9Sdownsj sc->sc_hwflags = 0; 1475a7928a9Sdownsj sc->sc_swflags = 0; 1485a7928a9Sdownsj 149*78a91e64Smickey timeout_set(&sc->sc_dtr_tmo, com_raisedtr, sc); 150*78a91e64Smickey timeout_set(&sc->sc_diag_tmo, comdiag, sc); 151*78a91e64Smickey 1525a7928a9Sdownsj /* 1535a7928a9Sdownsj * Probe for all known forms of UART. 1545a7928a9Sdownsj */ 1555a7928a9Sdownsj lcr = bus_space_read_1(iot, ioh, com_lcr); 1565a7928a9Sdownsj 1575a7928a9Sdownsj bus_space_write_1(iot, ioh, com_lcr, LCR_EFR); 1585a7928a9Sdownsj bus_space_write_1(iot, ioh, com_efr, 0); 1595a7928a9Sdownsj bus_space_write_1(iot, ioh, com_lcr, 0); 1605a7928a9Sdownsj 1615a7928a9Sdownsj bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE); 1625a7928a9Sdownsj delay(100); 1635a7928a9Sdownsj 1645a7928a9Sdownsj switch(bus_space_read_1(iot, ioh, com_iir) >> 6) { 1655a7928a9Sdownsj case 0: 1665a7928a9Sdownsj sc->sc_uarttype = COM_UART_16450; 1675a7928a9Sdownsj break; 1685a7928a9Sdownsj case 2: 1695a7928a9Sdownsj sc->sc_uarttype = COM_UART_16550; 1705a7928a9Sdownsj break; 1715a7928a9Sdownsj case 3: 1725a7928a9Sdownsj sc->sc_uarttype = COM_UART_16550A; 1735a7928a9Sdownsj break; 1745a7928a9Sdownsj default: 1755a7928a9Sdownsj sc->sc_uarttype = COM_UART_UNKNOWN; 1765a7928a9Sdownsj break; 1775a7928a9Sdownsj } 1785a7928a9Sdownsj 1795a7928a9Sdownsj if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for ST16650s */ 1805a7928a9Sdownsj bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); 1815a7928a9Sdownsj if (bus_space_read_1(iot, ioh, com_efr) == 0) { 1825a7928a9Sdownsj sc->sc_uarttype = COM_UART_ST16650; 1835a7928a9Sdownsj } else { 1845a7928a9Sdownsj bus_space_write_1(iot, ioh, com_lcr, LCR_EFR); 1855a7928a9Sdownsj if (bus_space_read_1(iot, ioh, com_efr) == 0) 1865a7928a9Sdownsj sc->sc_uarttype = COM_UART_ST16650V2; 1875a7928a9Sdownsj } 1885a7928a9Sdownsj } 1895a7928a9Sdownsj 1905a7928a9Sdownsj #if NPCCOM > 0 1915a7928a9Sdownsj #ifdef i386 1925a7928a9Sdownsj if (sc->sc_uarttype == COM_UART_ST16650V2) { /* Probe for XR16850s */ 1935a7928a9Sdownsj u_int8_t dlbl, dlbh; 1945a7928a9Sdownsj 1955a7928a9Sdownsj /* Enable latch access and get the current values. */ 1965a7928a9Sdownsj bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); 1975a7928a9Sdownsj dlbl = bus_space_read_1(iot, ioh, com_dlbl); 1985a7928a9Sdownsj dlbh = bus_space_read_1(iot, ioh, com_dlbh); 1995a7928a9Sdownsj 2005a7928a9Sdownsj /* Zero out the latch divisors */ 2015a7928a9Sdownsj bus_space_write_1(iot, ioh, com_dlbl, 0); 2025a7928a9Sdownsj bus_space_write_1(iot, ioh, com_dlbh, 0); 2035a7928a9Sdownsj 2045a7928a9Sdownsj if (bus_space_read_1(iot, ioh, com_dlbh) == 0x10) { 2055a7928a9Sdownsj sc->sc_uarttype = COM_UART_XR16850; 2065a7928a9Sdownsj sc->sc_uartrev = bus_space_read_1(iot, ioh, com_dlbl); 2075a7928a9Sdownsj } 2085a7928a9Sdownsj 2095a7928a9Sdownsj /* Reset to original. */ 2105a7928a9Sdownsj bus_space_write_1(iot, ioh, com_dlbl, dlbl); 2115a7928a9Sdownsj bus_space_write_1(iot, ioh, com_dlbh, dlbh); 2125a7928a9Sdownsj } 2135a7928a9Sdownsj #endif 2145a7928a9Sdownsj #endif 2155a7928a9Sdownsj 2165a7928a9Sdownsj /* Reset the LCR (latch access is probably enabled). */ 2175a7928a9Sdownsj bus_space_write_1(iot, ioh, com_lcr, lcr); 2185a7928a9Sdownsj if (sc->sc_uarttype == COM_UART_16450) { /* Probe for 8250 */ 2195a7928a9Sdownsj u_int8_t scr0, scr1, scr2; 2205a7928a9Sdownsj 2215a7928a9Sdownsj scr0 = bus_space_read_1(iot, ioh, com_scratch); 2225a7928a9Sdownsj bus_space_write_1(iot, ioh, com_scratch, 0xa5); 2235a7928a9Sdownsj scr1 = bus_space_read_1(iot, ioh, com_scratch); 2245a7928a9Sdownsj bus_space_write_1(iot, ioh, com_scratch, 0x5a); 2255a7928a9Sdownsj scr2 = bus_space_read_1(iot, ioh, com_scratch); 2265a7928a9Sdownsj bus_space_write_1(iot, ioh, com_scratch, scr0); 2275a7928a9Sdownsj 2285a7928a9Sdownsj if ((scr1 != 0xa5) || (scr2 != 0x5a)) 2295a7928a9Sdownsj sc->sc_uarttype = COM_UART_8250; 2305a7928a9Sdownsj } 2315a7928a9Sdownsj 2325a7928a9Sdownsj /* 2335a7928a9Sdownsj * Print UART type and initialize ourself. 2345a7928a9Sdownsj */ 2355a7928a9Sdownsj sc->sc_fifolen = 1; /* default */ 2365a7928a9Sdownsj switch (sc->sc_uarttype) { 2375a7928a9Sdownsj case COM_UART_UNKNOWN: 2385a7928a9Sdownsj printf(": unknown uart\n"); 2395a7928a9Sdownsj break; 2405a7928a9Sdownsj case COM_UART_8250: 2415a7928a9Sdownsj printf(": ns8250, no fifo\n"); 2425a7928a9Sdownsj break; 2435a7928a9Sdownsj case COM_UART_16450: 2445a7928a9Sdownsj printf(": ns16450, no fifo\n"); 2455a7928a9Sdownsj break; 2465a7928a9Sdownsj case COM_UART_16550: 2475a7928a9Sdownsj printf(": ns16550, no working fifo\n"); 2485a7928a9Sdownsj break; 2495a7928a9Sdownsj case COM_UART_16550A: 2505a7928a9Sdownsj printf(": ns16550a, 16 byte fifo\n"); 2515a7928a9Sdownsj SET(sc->sc_hwflags, COM_HW_FIFO); 2525a7928a9Sdownsj sc->sc_fifolen = 16; 2535a7928a9Sdownsj break; 2545a7928a9Sdownsj case COM_UART_ST16650: 2555a7928a9Sdownsj printf(": st16650, no working fifo\n"); 2565a7928a9Sdownsj break; 2575a7928a9Sdownsj case COM_UART_ST16650V2: 2585a7928a9Sdownsj printf(": st16650, 32 byte fifo\n"); 2595a7928a9Sdownsj SET(sc->sc_hwflags, COM_HW_FIFO); 2605a7928a9Sdownsj sc->sc_fifolen = 32; 2615a7928a9Sdownsj break; 2625a7928a9Sdownsj #if NPCCOM > 0 2635a7928a9Sdownsj #ifdef i386 2645a7928a9Sdownsj case COM_UART_XR16850: 2655a7928a9Sdownsj printf(": xr16850 (rev %d), 128 byte fifo\n", sc->sc_uartrev); 2665a7928a9Sdownsj SET(sc->sc_hwflags, COM_HW_FIFO); 2675a7928a9Sdownsj sc->sc_fifolen = 128; 2685a7928a9Sdownsj break; 2695a7928a9Sdownsj #endif 2705a7928a9Sdownsj #endif 2715a7928a9Sdownsj default: 2725a7928a9Sdownsj panic("comattach: bad fifo type"); 2735a7928a9Sdownsj } 2745a7928a9Sdownsj 2755a7928a9Sdownsj /* clear and disable fifo */ 2765a7928a9Sdownsj bus_space_write_1(iot, ioh, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST); 2775a7928a9Sdownsj (void)bus_space_read_1(iot, ioh, com_data); 2785a7928a9Sdownsj bus_space_write_1(iot, ioh, com_fifo, 0); 2795a7928a9Sdownsj } 280