uart_dev_oct16550.c revision 262649
116234Smichaelm/*- 216234Smichaelm * Copyright (c) 2003 Marcel Moolenaar 316234Smichaelm * All rights reserved. 416234Smichaelm * 516234Smichaelm * Redistribution and use in source and binary forms, with or without 616234Smichaelm * modification, are permitted provided that the following conditions 716234Smichaelm * are met: 816234Smichaelm * 916234Smichaelm * 1. Redistributions of source code must retain the above copyright 1016234Smichaelm * notice, this list of conditions and the following disclaimer. 1116234Smichaelm * 2. Redistributions in binary form must reproduce the above copyright 1216234Smichaelm * notice, this list of conditions and the following disclaimer in the 1316234Smichaelm * documentation and/or other materials provided with the distribution. 1416234Smichaelm * 1516234Smichaelm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1616234Smichaelm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1716234Smichaelm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1816234Smichaelm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1916234Smichaelm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2016234Smichaelm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2116234Smichaelm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2216234Smichaelm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2316234Smichaelm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2416234Smichaelm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2516234Smichaelm */ 2616234Smichaelm 2716234Smichaelm/* 2816234Smichaelm * uart_dev_oct16550.c 2916234Smichaelm * 3016234Smichaelm * Derived from uart_dev_ns8250.c 3116234Smichaelm * 3216234Smichaelm * Redistribution and use in source and binary forms, with or without 3316234Smichaelm * modification, are permitted provided that the following conditions 3416234Smichaelm * are met: 3516234Smichaelm * 3616234Smichaelm * 1. Redistributions of source code must retain the above copyright 3716234Smichaelm * notice, this list of conditions and the following disclaimer. 3816234Smichaelm * 2. Redistributions in binary form must reproduce the above copyright 3916234Smichaelm * notice, this list of conditions and the following disclaimer in the 4016234Smichaelm * documentation and/or other materials provided with the distribution. 4116234Smichaelm * 4216234Smichaelm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 4316234Smichaelm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4416234Smichaelm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 4516234Smichaelm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 4616234Smichaelm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4716234Smichaelm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 4816234Smichaelm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 4916234Smichaelm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 5016234Smichaelm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 5116234Smichaelm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5216234Smichaelm * 5316234Smichaelm * 5416234Smichaelm */ 5516234Smichaelm 5616234Smichaelm 5716234Smichaelm#include <sys/cdefs.h> 5816234Smichaelm__FBSDID("$FreeBSD: stable/10/sys/mips/cavium/uart_dev_oct16550.c 262649 2014-03-01 04:16:54Z imp $"); 5916234Smichaelm 6016234Smichaelm#include <sys/param.h> 6116234Smichaelm#include <sys/systm.h> 6216234Smichaelm#include <sys/bus.h> 6316234Smichaelm#include <sys/conf.h> 6416234Smichaelm#include <machine/bus.h> 6516234Smichaelm#include <machine/pcpu.h> 6616234Smichaelm 6716234Smichaelm#include <dev/uart/uart.h> 6816234Smichaelm#include <dev/uart/uart_cpu.h> 6916234Smichaelm#include <dev/uart/uart_bus.h> 7016234Smichaelm 7116234Smichaelm#include <dev/ic/ns16550.h> 7216234Smichaelm 7316234Smichaelm#include <mips/cavium/octeon_pcmap_regs.h> 7416234Smichaelm 7516234Smichaelm#include <contrib/octeon-sdk/cvmx.h> 7616234Smichaelm 7716234Smichaelm#include "uart_if.h" 7816234Smichaelm 7916234Smichaelm/* 8016234Smichaelm * Clear pending interrupts. THRE is cleared by reading IIR. Data 8116234Smichaelm * that may have been received gets lost here. 8216234Smichaelm */ 8316234Smichaelmstatic void 8416234Smichaelmoct16550_clrint (struct uart_bas *bas) 8516234Smichaelm{ 8616234Smichaelm uint8_t iir; 8716234Smichaelm 8816234Smichaelm iir = uart_getreg(bas, REG_IIR); 8916234Smichaelm while ((iir & IIR_NOPEND) == 0) { 9016234Smichaelm iir &= IIR_IMASK; 9116234Smichaelm if (iir == IIR_RLS) 9216234Smichaelm (void)uart_getreg(bas, REG_LSR); 9316234Smichaelm else if (iir == IIR_RXRDY || iir == IIR_RXTOUT) 9416234Smichaelm (void)uart_getreg(bas, REG_DATA); 9516234Smichaelm else if (iir == IIR_MLSC) 9616234Smichaelm (void)uart_getreg(bas, REG_MSR); 9716234Smichaelm else if (iir == IIR_BUSY) 9816234Smichaelm (void) uart_getreg(bas, REG_USR); 9916234Smichaelm uart_barrier(bas); 10016234Smichaelm iir = uart_getreg(bas, REG_IIR); 10116234Smichaelm } 10216234Smichaelm} 10316234Smichaelm 10416234Smichaelmstatic int delay_changed = 1; 10516234Smichaelm 10616234Smichaelmstatic int 10716234Smichaelmoct16550_delay (struct uart_bas *bas) 10816234Smichaelm{ 10916234Smichaelm int divisor; 11016234Smichaelm u_char lcr; 11116234Smichaelm static int delay = 0; 11216234Smichaelm 11316234Smichaelm if (!delay_changed) return delay; 11416234Smichaelm delay_changed = 0; 11516234Smichaelm lcr = uart_getreg(bas, REG_LCR); 11616234Smichaelm uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); 11716234Smichaelm uart_barrier(bas); 11816234Smichaelm divisor = uart_getreg(bas, REG_DLL) | (uart_getreg(bas, REG_DLH) << 8); 11916234Smichaelm uart_barrier(bas); 12016234Smichaelm uart_setreg(bas, REG_LCR, lcr); 12116234Smichaelm uart_barrier(bas); 12216234Smichaelm 12316234Smichaelm if(!bas->rclk) 12416234Smichaelm return 10; /* return an approx delay value */ 12516234Smichaelm 12616234Smichaelm /* 1/10th the time to transmit 1 character (estimate). */ 12716234Smichaelm if (divisor <= 134) 12816234Smichaelm return (16000000 * divisor / bas->rclk); 12916234Smichaelm return (16000 * divisor / (bas->rclk / 1000)); 13016234Smichaelm 13116234Smichaelm} 13216234Smichaelm 13316234Smichaelmstatic int 13416234Smichaelmoct16550_divisor (int rclk, int baudrate) 13516234Smichaelm{ 13616234Smichaelm int actual_baud, divisor; 13716234Smichaelm int error; 13816234Smichaelm 13916234Smichaelm if (baudrate == 0) 14016234Smichaelm return (0); 14116234Smichaelm 14216234Smichaelm divisor = (rclk / (baudrate << 3) + 1) >> 1; 14316234Smichaelm if (divisor == 0 || divisor >= 65536) 14416234Smichaelm return (0); 14516234Smichaelm actual_baud = rclk / (divisor << 4); 14616234Smichaelm 14716234Smichaelm /* 10 times error in percent: */ 14816234Smichaelm error = ((actual_baud - baudrate) * 2000 / baudrate + 1) >> 1; 14916234Smichaelm 15016234Smichaelm /* 3.0% maximum error tolerance: */ 15116234Smichaelm if (error < -30 || error > 30) 15216234Smichaelm return (0); 15316234Smichaelm 15416234Smichaelm return (divisor); 15516234Smichaelm} 15616234Smichaelm 15716234Smichaelmstatic int 15816234Smichaelmoct16550_drain (struct uart_bas *bas, int what) 15916234Smichaelm{ 16016234Smichaelm int delay, limit; 16116234Smichaelm 16216234Smichaelm delay = oct16550_delay(bas); 16316234Smichaelm 16416234Smichaelm if (what & UART_DRAIN_TRANSMITTER) { 16516234Smichaelm /* 16616234Smichaelm * Pick an arbitrary high limit to avoid getting stuck in 16716234Smichaelm * an infinite loop when the hardware is broken. Make the 16816234Smichaelm * limit high enough to handle large FIFOs. 16916234Smichaelm */ 17016234Smichaelm limit = 10*10*10*1024; 17116234Smichaelm while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit) 17216234Smichaelm DELAY(delay); 17316234Smichaelm if (limit == 0) { 17416234Smichaelm /* printf("oct16550: transmitter appears stuck... "); */ 17516234Smichaelm return (0); 17616234Smichaelm } 17716234Smichaelm } 17816234Smichaelm 17916234Smichaelm if (what & UART_DRAIN_RECEIVER) { 18016234Smichaelm /* 18116234Smichaelm * Pick an arbitrary high limit to avoid getting stuck in 18216234Smichaelm * an infinite loop when the hardware is broken. Make the 18316234Smichaelm * limit high enough to handle large FIFOs and integrated 18416234Smichaelm * UARTs. The HP rx2600 for example has 3 UARTs on the 18516234Smichaelm * management board that tend to get a lot of data send 18616234Smichaelm * to it when the UART is first activated. 18716234Smichaelm */ 18816234Smichaelm limit=10*4096; 18916234Smichaelm while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) && --limit) { 19016234Smichaelm (void)uart_getreg(bas, REG_DATA); 19116234Smichaelm uart_barrier(bas); 19216234Smichaelm DELAY(delay << 2); 19316234Smichaelm } 19416234Smichaelm if (limit == 0) { 19516234Smichaelm /* printf("oct16550: receiver appears broken... "); */ 19616234Smichaelm return (EIO); 19716234Smichaelm } 19816234Smichaelm } 19916234Smichaelm 20016234Smichaelm return (0); 20116234Smichaelm} 20216234Smichaelm 20316234Smichaelm/* 20416234Smichaelm * We can only flush UARTs with FIFOs. UARTs without FIFOs should be 20516234Smichaelm * drained. WARNING: this function clobbers the FIFO setting! 20616234Smichaelm */ 20716234Smichaelmstatic void 20816234Smichaelmoct16550_flush (struct uart_bas *bas, int what) 20916234Smichaelm{ 21016234Smichaelm uint8_t fcr; 21116234Smichaelm 21216234Smichaelm fcr = FCR_ENABLE; 21316234Smichaelm if (what & UART_FLUSH_TRANSMITTER) 21416234Smichaelm fcr |= FCR_XMT_RST; 21516234Smichaelm if (what & UART_FLUSH_RECEIVER) 21616234Smichaelm fcr |= FCR_RCV_RST; 21716234Smichaelm uart_setreg(bas, REG_FCR, fcr); 21816234Smichaelm uart_barrier(bas); 21916234Smichaelm} 22016234Smichaelm 22116234Smichaelmstatic int 22216234Smichaelmoct16550_param (struct uart_bas *bas, int baudrate, int databits, int stopbits, 22316234Smichaelm int parity) 22416234Smichaelm{ 22516234Smichaelm int divisor; 22616234Smichaelm uint8_t lcr; 22716234Smichaelm 22816234Smichaelm lcr = 0; 22916234Smichaelm if (databits >= 8) 23016234Smichaelm lcr |= LCR_8BITS; 23116234Smichaelm else if (databits == 7) 23216234Smichaelm lcr |= LCR_7BITS; 23316234Smichaelm else if (databits == 6) 23416234Smichaelm lcr |= LCR_6BITS; 23516234Smichaelm else 23616234Smichaelm lcr |= LCR_5BITS; 23716234Smichaelm if (stopbits > 1) 23816234Smichaelm lcr |= LCR_STOPB; 23916234Smichaelm lcr |= parity << 3; 24016234Smichaelm 24116234Smichaelm /* Set baudrate. */ 24216234Smichaelm if (baudrate > 0) { 24316234Smichaelm divisor = oct16550_divisor(bas->rclk, baudrate); 24416234Smichaelm if (divisor == 0) 24516234Smichaelm return (EINVAL); 24616234Smichaelm uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); 24716234Smichaelm uart_barrier(bas); 24816234Smichaelm uart_setreg(bas, REG_DLL, divisor & 0xff); 24916234Smichaelm uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff); 25016234Smichaelm uart_barrier(bas); 25116234Smichaelm delay_changed = 1; 25216234Smichaelm } 25316234Smichaelm 25416234Smichaelm /* Set LCR and clear DLAB. */ 25516234Smichaelm uart_setreg(bas, REG_LCR, lcr); 25616234Smichaelm uart_barrier(bas); 25716234Smichaelm return (0); 25816234Smichaelm} 25916234Smichaelm 26016234Smichaelm/* 26116234Smichaelm * Low-level UART interface. 26216234Smichaelm */ 26316234Smichaelmstatic int oct16550_probe(struct uart_bas *bas); 26416234Smichaelmstatic void oct16550_init(struct uart_bas *bas, int, int, int, int); 26516234Smichaelmstatic void oct16550_term(struct uart_bas *bas); 26616234Smichaelmstatic void oct16550_putc(struct uart_bas *bas, int); 26716234Smichaelmstatic int oct16550_rxready(struct uart_bas *bas); 26816234Smichaelmstatic int oct16550_getc(struct uart_bas *bas, struct mtx *); 26916234Smichaelm 27016234Smichaelmstruct uart_ops uart_oct16550_ops = { 27116234Smichaelm .probe = oct16550_probe, 27216234Smichaelm .init = oct16550_init, 27316234Smichaelm .term = oct16550_term, 27416234Smichaelm .putc = oct16550_putc, 27516234Smichaelm .rxready = oct16550_rxready, 27616234Smichaelm .getc = oct16550_getc, 27716234Smichaelm}; 27816234Smichaelm 27916234Smichaelmstatic int 28016234Smichaelmoct16550_probe (struct uart_bas *bas) 28116234Smichaelm{ 28216234Smichaelm u_char val; 28316234Smichaelm 28416234Smichaelm /* Check known 0 bits that don't depend on DLAB. */ 28516234Smichaelm val = uart_getreg(bas, REG_IIR); 28616234Smichaelm if (val & 0x30) 28716234Smichaelm return (ENXIO); 28816234Smichaelm val = uart_getreg(bas, REG_MCR); 28916234Smichaelm if (val & 0xc0) 29016234Smichaelm return (ENXIO); 29116234Smichaelm val = uart_getreg(bas, REG_USR); 29216234Smichaelm if (val & 0xe0) 29316234Smichaelm return (ENXIO); 29416234Smichaelm return (0); 29516234Smichaelm} 29616234Smichaelm 29716234Smichaelmstatic void 29816234Smichaelmoct16550_init (struct uart_bas *bas, int baudrate, int databits, int stopbits, 29916234Smichaelm int parity) 30016234Smichaelm{ 30116234Smichaelm u_char ier; 30216234Smichaelm 30316234Smichaelm oct16550_param(bas, baudrate, databits, stopbits, parity); 30416234Smichaelm 30516234Smichaelm /* Disable all interrupt sources. */ 30616234Smichaelm ier = uart_getreg(bas, REG_IER) & 0x0; 30716234Smichaelm uart_setreg(bas, REG_IER, ier); 30816234Smichaelm uart_barrier(bas); 30916234Smichaelm 31016234Smichaelm /* Disable the FIFO (if present). */ 31116234Smichaelm// uart_setreg(bas, REG_FCR, 0); 31216234Smichaelm uart_barrier(bas); 31316234Smichaelm 31416234Smichaelm /* Set RTS & DTR. */ 31516234Smichaelm uart_setreg(bas, REG_MCR, MCR_RTS | MCR_DTR); 31616234Smichaelm uart_barrier(bas); 31716234Smichaelm 31816234Smichaelm oct16550_clrint(bas); 31916234Smichaelm} 32016234Smichaelm 32116234Smichaelmstatic void 32216234Smichaelmoct16550_term (struct uart_bas *bas) 32316234Smichaelm{ 32416234Smichaelm 32516234Smichaelm /* Clear RTS & DTR. */ 32616234Smichaelm uart_setreg(bas, REG_MCR, 0); 32716234Smichaelm uart_barrier(bas); 32816234Smichaelm} 32916234Smichaelm 33016234Smichaelmstatic inline void oct16550_wait_txhr_empty (struct uart_bas *bas, int limit, int delay) 33116234Smichaelm{ 33216234Smichaelm while (((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) && 33316234Smichaelm ((uart_getreg(bas, REG_USR) & USR_TXFIFO_NOTFULL) == 0)) 33416234Smichaelm DELAY(delay); 33516234Smichaelm} 33616234Smichaelm 33716234Smichaelmstatic void 33816234Smichaelmoct16550_putc (struct uart_bas *bas, int c) 33916234Smichaelm{ 34016234Smichaelm int delay; 34116234Smichaelm 34216234Smichaelm /* 1/10th the time to transmit 1 character (estimate). */ 34316234Smichaelm delay = oct16550_delay(bas); 34416234Smichaelm oct16550_wait_txhr_empty(bas, 100, delay); 34516234Smichaelm uart_setreg(bas, REG_DATA, c); 34616234Smichaelm uart_barrier(bas); 34716234Smichaelm oct16550_wait_txhr_empty(bas, 100, delay); 34816234Smichaelm} 34916234Smichaelm 35016234Smichaelmstatic int 35116234Smichaelmoct16550_rxready (struct uart_bas *bas) 35216234Smichaelm{ 35316234Smichaelm 35416234Smichaelm return ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) != 0 ? 1 : 0); 35516234Smichaelm} 35616234Smichaelm 35716234Smichaelmstatic int 35816234Smichaelmoct16550_getc (struct uart_bas *bas, struct mtx *hwmtx) 35916234Smichaelm{ 36016234Smichaelm int c, delay; 36116234Smichaelm 36216234Smichaelm uart_lock(hwmtx); 36316234Smichaelm 36416234Smichaelm /* 1/10th the time to transmit 1 character (estimate). */ 36516234Smichaelm delay = oct16550_delay(bas); 36616234Smichaelm 36716234Smichaelm while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) == 0) { 36816234Smichaelm uart_unlock(hwmtx); 36916234Smichaelm DELAY(delay); 37016234Smichaelm uart_lock(hwmtx); 37116234Smichaelm } 37216234Smichaelm 37316234Smichaelm c = uart_getreg(bas, REG_DATA); 37416234Smichaelm 37516234Smichaelm uart_unlock(hwmtx); 37616234Smichaelm 37716234Smichaelm return (c); 37816234Smichaelm} 37916234Smichaelm 38016234Smichaelm/* 38116234Smichaelm * High-level UART interface. 38216234Smichaelm */ 38316234Smichaelmstruct oct16550_softc { 38416234Smichaelm struct uart_softc base; 38516234Smichaelm uint8_t fcr; 38616234Smichaelm uint8_t ier; 38716234Smichaelm uint8_t mcr; 38816234Smichaelm}; 38916234Smichaelm 39016234Smichaelmstatic int oct16550_bus_attach(struct uart_softc *); 39116234Smichaelmstatic int oct16550_bus_detach(struct uart_softc *); 39216234Smichaelmstatic int oct16550_bus_flush(struct uart_softc *, int); 39316234Smichaelmstatic int oct16550_bus_getsig(struct uart_softc *); 39416234Smichaelmstatic int oct16550_bus_ioctl(struct uart_softc *, int, intptr_t); 39516234Smichaelmstatic int oct16550_bus_ipend(struct uart_softc *); 39616234Smichaelmstatic int oct16550_bus_param(struct uart_softc *, int, int, int, int); 39716234Smichaelmstatic int oct16550_bus_probe(struct uart_softc *); 39816234Smichaelmstatic int oct16550_bus_receive(struct uart_softc *); 39916234Smichaelmstatic int oct16550_bus_setsig(struct uart_softc *, int); 40016234Smichaelmstatic int oct16550_bus_transmit(struct uart_softc *); 40116234Smichaelmstatic void oct16550_bus_grab(struct uart_softc *); 40216234Smichaelmstatic void oct16550_bus_ungrab(struct uart_softc *); 40316234Smichaelm 40416234Smichaelmstatic kobj_method_t oct16550_methods[] = { 40516234Smichaelm KOBJMETHOD(uart_attach, oct16550_bus_attach), 40616234Smichaelm KOBJMETHOD(uart_detach, oct16550_bus_detach), 40716234Smichaelm KOBJMETHOD(uart_flush, oct16550_bus_flush), 40816234Smichaelm KOBJMETHOD(uart_getsig, oct16550_bus_getsig), 40916234Smichaelm KOBJMETHOD(uart_ioctl, oct16550_bus_ioctl), 41016234Smichaelm KOBJMETHOD(uart_ipend, oct16550_bus_ipend), 41116234Smichaelm KOBJMETHOD(uart_param, oct16550_bus_param), 41216234Smichaelm KOBJMETHOD(uart_probe, oct16550_bus_probe), 41316234Smichaelm KOBJMETHOD(uart_receive, oct16550_bus_receive), 41416234Smichaelm KOBJMETHOD(uart_setsig, oct16550_bus_setsig), 41516234Smichaelm KOBJMETHOD(uart_transmit, oct16550_bus_transmit), 41616234Smichaelm KOBJMETHOD(uart_grab, oct16550_bus_grab), 41716234Smichaelm KOBJMETHOD(uart_ungrab, oct16550_bus_ungrab), 41816234Smichaelm { 0, 0 } 41916234Smichaelm}; 42016234Smichaelm 42116234Smichaelmstruct uart_class uart_oct16550_class = { 42216234Smichaelm "oct16550 class", 42316234Smichaelm oct16550_methods, 42416234Smichaelm sizeof(struct oct16550_softc), 42516234Smichaelm .uc_ops = &uart_oct16550_ops, 42616234Smichaelm .uc_range = 8 << 3, 42716234Smichaelm .uc_rclk = 0 42816234Smichaelm}; 42916234Smichaelm 43016234Smichaelm#define SIGCHG(c, i, s, d) \ 43116234Smichaelm if (c) { \ 43216234Smichaelm i |= (i & s) ? s : s | d; \ 43316234Smichaelm } else { \ 43416234Smichaelm i = (i & s) ? (i & ~s) | d : i; \ 43516234Smichaelm } 43616234Smichaelm 43716234Smichaelmstatic int 43816234Smichaelmoct16550_bus_attach (struct uart_softc *sc) 43916234Smichaelm{ 44016234Smichaelm struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; 44116234Smichaelm struct uart_bas *bas; 44216234Smichaelm int unit; 44316234Smichaelm 44416234Smichaelm unit = device_get_unit(sc->sc_dev); 44516234Smichaelm bas = &sc->sc_bas; 44616234Smichaelm 44716234Smichaelm oct16550_drain(bas, UART_DRAIN_TRANSMITTER); 44816234Smichaelm oct16550->mcr = uart_getreg(bas, REG_MCR); 44916234Smichaelm oct16550->fcr = FCR_ENABLE | FCR_RX_HIGH; 45016234Smichaelm uart_setreg(bas, REG_FCR, oct16550->fcr); 45116234Smichaelm uart_barrier(bas); 45216234Smichaelm oct16550_bus_flush(sc, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); 45316234Smichaelm 45416234Smichaelm if (oct16550->mcr & MCR_DTR) 45516234Smichaelm sc->sc_hwsig |= SER_DTR; 45616234Smichaelm if (oct16550->mcr & MCR_RTS) 45716234Smichaelm sc->sc_hwsig |= SER_RTS; 45816234Smichaelm oct16550_bus_getsig(sc); 45916234Smichaelm 46016234Smichaelm oct16550_clrint(bas); 46116234Smichaelm oct16550->ier = uart_getreg(bas, REG_IER) & 0xf0; 46216234Smichaelm oct16550->ier |= IER_EMSC | IER_ERLS | IER_ERXRDY; 46316234Smichaelm uart_setreg(bas, REG_IER, oct16550->ier); 46416234Smichaelm uart_barrier(bas); 46516234Smichaelm 46616234Smichaelm return (0); 46716234Smichaelm} 46816234Smichaelm 46916234Smichaelmstatic int 47016234Smichaelmoct16550_bus_detach (struct uart_softc *sc) 47116234Smichaelm{ 47216234Smichaelm struct uart_bas *bas; 47316234Smichaelm u_char ier; 47416234Smichaelm 47516234Smichaelm bas = &sc->sc_bas; 47616234Smichaelm ier = uart_getreg(bas, REG_IER) & 0xf0; 47716234Smichaelm uart_setreg(bas, REG_IER, ier); 47816234Smichaelm uart_barrier(bas); 47916234Smichaelm oct16550_clrint(bas); 48016234Smichaelm return (0); 48116234Smichaelm} 48216234Smichaelm 48316234Smichaelmstatic int 48416234Smichaelmoct16550_bus_flush (struct uart_softc *sc, int what) 48516234Smichaelm{ 48616234Smichaelm struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; 48716234Smichaelm struct uart_bas *bas; 48816234Smichaelm int error; 48916234Smichaelm 49016234Smichaelm bas = &sc->sc_bas; 49116234Smichaelm uart_lock(sc->sc_hwmtx); 49216234Smichaelm if (sc->sc_rxfifosz > 1) { 49316234Smichaelm oct16550_flush(bas, what); 49416234Smichaelm uart_setreg(bas, REG_FCR, oct16550->fcr); 49516234Smichaelm uart_barrier(bas); 49616234Smichaelm error = 0; 49716234Smichaelm } else 49816234Smichaelm error = oct16550_drain(bas, what); 49916234Smichaelm uart_unlock(sc->sc_hwmtx); 50016234Smichaelm return (error); 50116234Smichaelm} 50216234Smichaelm 50316234Smichaelmstatic int 50416234Smichaelmoct16550_bus_getsig (struct uart_softc *sc) 50516234Smichaelm{ 50616234Smichaelm uint32_t new, old, sig; 50716234Smichaelm uint8_t msr; 50816234Smichaelm 50916234Smichaelm do { 51016234Smichaelm old = sc->sc_hwsig; 51116234Smichaelm sig = old; 51216234Smichaelm uart_lock(sc->sc_hwmtx); 51316234Smichaelm msr = uart_getreg(&sc->sc_bas, REG_MSR); 51416234Smichaelm uart_unlock(sc->sc_hwmtx); 51516234Smichaelm SIGCHG(msr & MSR_DSR, sig, SER_DSR, SER_DDSR); 51616234Smichaelm SIGCHG(msr & MSR_CTS, sig, SER_CTS, SER_DCTS); 51716234Smichaelm SIGCHG(msr & MSR_DCD, sig, SER_DCD, SER_DDCD); 51816234Smichaelm SIGCHG(msr & MSR_RI, sig, SER_RI, SER_DRI); 51916234Smichaelm new = sig & ~SER_MASK_DELTA; 52016234Smichaelm } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 52116234Smichaelm return (sig); 52216234Smichaelm} 52316234Smichaelm 52416234Smichaelmstatic int 52516234Smichaelmoct16550_bus_ioctl (struct uart_softc *sc, int request, intptr_t data) 52616234Smichaelm{ 52716234Smichaelm struct uart_bas *bas; 52816234Smichaelm int baudrate, divisor, error; 52916234Smichaelm uint8_t efr, lcr; 53016234Smichaelm 53116234Smichaelm bas = &sc->sc_bas; 53216234Smichaelm error = 0; 53316234Smichaelm uart_lock(sc->sc_hwmtx); 53416234Smichaelm switch (request) { 53516234Smichaelm case UART_IOCTL_BREAK: 536 lcr = uart_getreg(bas, REG_LCR); 537 if (data) 538 lcr |= LCR_SBREAK; 539 else 540 lcr &= ~LCR_SBREAK; 541 uart_setreg(bas, REG_LCR, lcr); 542 uart_barrier(bas); 543 break; 544 case UART_IOCTL_IFLOW: 545 lcr = uart_getreg(bas, REG_LCR); 546 uart_barrier(bas); 547 uart_setreg(bas, REG_LCR, 0xbf); 548 uart_barrier(bas); 549 efr = uart_getreg(bas, REG_EFR); 550 if (data) 551 efr |= EFR_RTS; 552 else 553 efr &= ~EFR_RTS; 554 uart_setreg(bas, REG_EFR, efr); 555 uart_barrier(bas); 556 uart_setreg(bas, REG_LCR, lcr); 557 uart_barrier(bas); 558 break; 559 case UART_IOCTL_OFLOW: 560 lcr = uart_getreg(bas, REG_LCR); 561 uart_barrier(bas); 562 uart_setreg(bas, REG_LCR, 0xbf); 563 uart_barrier(bas); 564 efr = uart_getreg(bas, REG_EFR); 565 if (data) 566 efr |= EFR_CTS; 567 else 568 efr &= ~EFR_CTS; 569 uart_setreg(bas, REG_EFR, efr); 570 uart_barrier(bas); 571 uart_setreg(bas, REG_LCR, lcr); 572 uart_barrier(bas); 573 break; 574 case UART_IOCTL_BAUD: 575 lcr = uart_getreg(bas, REG_LCR); 576 uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); 577 uart_barrier(bas); 578 divisor = uart_getreg(bas, REG_DLL) | 579 (uart_getreg(bas, REG_DLH) << 8); 580 uart_barrier(bas); 581 uart_setreg(bas, REG_LCR, lcr); 582 uart_barrier(bas); 583 baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0; 584 delay_changed = 1; 585 if (baudrate > 0) 586 *(int*)data = baudrate; 587 else 588 error = ENXIO; 589 break; 590 default: 591 error = EINVAL; 592 break; 593 } 594 uart_unlock(sc->sc_hwmtx); 595 return (error); 596} 597 598 599static int 600oct16550_bus_ipend(struct uart_softc *sc) 601{ 602 struct uart_bas *bas; 603 int ipend = 0; 604 uint8_t iir, lsr; 605 606 bas = &sc->sc_bas; 607 uart_lock(sc->sc_hwmtx); 608 609 iir = uart_getreg(bas, REG_IIR) & IIR_IMASK; 610 if (iir != IIR_NOPEND) { 611 612 if (iir == IIR_RLS) { 613 lsr = uart_getreg(bas, REG_LSR); 614 if (lsr & LSR_OE) 615 ipend |= SER_INT_OVERRUN; 616 if (lsr & LSR_BI) 617 ipend |= SER_INT_BREAK; 618 if (lsr & LSR_RXRDY) 619 ipend |= SER_INT_RXREADY; 620 621 } else if (iir == IIR_RXRDY) { 622 ipend |= SER_INT_RXREADY; 623 624 } else if (iir == IIR_RXTOUT) { 625 ipend |= SER_INT_RXREADY; 626 627 } else if (iir == IIR_TXRDY) { 628 ipend |= SER_INT_TXIDLE; 629 630 } else if (iir == IIR_MLSC) { 631 ipend |= SER_INT_SIGCHG; 632 633 } else if (iir == IIR_BUSY) { 634 (void) uart_getreg(bas, REG_USR); 635 } 636 } 637 uart_unlock(sc->sc_hwmtx); 638 639 return (ipend); 640} 641 642static int 643oct16550_bus_param (struct uart_softc *sc, int baudrate, int databits, 644 int stopbits, int parity) 645{ 646 struct uart_bas *bas; 647 int error; 648 649 bas = &sc->sc_bas; 650 uart_lock(sc->sc_hwmtx); 651 error = oct16550_param(bas, baudrate, databits, stopbits, parity); 652 uart_unlock(sc->sc_hwmtx); 653 return (error); 654} 655 656static int 657oct16550_bus_probe (struct uart_softc *sc) 658{ 659 struct uart_bas *bas; 660 int error; 661 662 bas = &sc->sc_bas; 663 bas->rclk = uart_oct16550_class.uc_rclk = cvmx_clock_get_rate(CVMX_CLOCK_SCLK); 664 665 error = oct16550_probe(bas); 666 if (error) { 667 return (error); 668 } 669 670 uart_setreg(bas, REG_MCR, (MCR_DTR | MCR_RTS)); 671 672 /* 673 * Enable FIFOs. And check that the UART has them. If not, we're 674 * done. Since this is the first time we enable the FIFOs, we reset 675 * them. 676 */ 677 oct16550_drain(bas, UART_DRAIN_TRANSMITTER); 678#define ENABLE_OCTEON_FIFO 1 679#ifdef ENABLE_OCTEON_FIFO 680 uart_setreg(bas, REG_FCR, FCR_ENABLE | FCR_XMT_RST | FCR_RCV_RST); 681#endif 682 uart_barrier(bas); 683 684 oct16550_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); 685 686 if (device_get_unit(sc->sc_dev)) { 687 device_set_desc(sc->sc_dev, "Octeon-16550 channel 1"); 688 } else { 689 device_set_desc(sc->sc_dev, "Octeon-16550 channel 0"); 690 } 691#ifdef ENABLE_OCTEON_FIFO 692 sc->sc_rxfifosz = 64; 693 sc->sc_txfifosz = 64; 694#else 695 sc->sc_rxfifosz = 1; 696 sc->sc_txfifosz = 1; 697#endif 698 699 700#if 0 701 /* 702 * XXX there are some issues related to hardware flow control and 703 * it's likely that uart(4) is the cause. This basicly needs more 704 * investigation, but we avoid using for hardware flow control 705 * until then. 706 */ 707 /* 16650s or higher have automatic flow control. */ 708 if (sc->sc_rxfifosz > 16) { 709 sc->sc_hwiflow = 1; 710 sc->sc_hwoflow = 1; 711 } 712#endif 713 714 return (0); 715} 716 717static int 718oct16550_bus_receive (struct uart_softc *sc) 719{ 720 struct uart_bas *bas; 721 int xc; 722 uint8_t lsr; 723 724 bas = &sc->sc_bas; 725 uart_lock(sc->sc_hwmtx); 726 lsr = uart_getreg(bas, REG_LSR); 727 728 while (lsr & LSR_RXRDY) { 729 if (uart_rx_full(sc)) { 730 sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 731 break; 732 } 733 xc = uart_getreg(bas, REG_DATA); 734 if (lsr & LSR_FE) 735 xc |= UART_STAT_FRAMERR; 736 if (lsr & LSR_PE) 737 xc |= UART_STAT_PARERR; 738 uart_rx_put(sc, xc); 739 lsr = uart_getreg(bas, REG_LSR); 740 } 741 /* Discard everything left in the Rx FIFO. */ 742 /* 743 * First do a dummy read/discard anyway, in case the UART was lying to us. 744 * This problem was seen on board, when IIR said RBR, but LSR said no RXRDY 745 * Results in a stuck ipend loop. 746 */ 747 (void)uart_getreg(bas, REG_DATA); 748 while (lsr & LSR_RXRDY) { 749 (void)uart_getreg(bas, REG_DATA); 750 uart_barrier(bas); 751 lsr = uart_getreg(bas, REG_LSR); 752 } 753 uart_unlock(sc->sc_hwmtx); 754 return (0); 755} 756 757static int 758oct16550_bus_setsig (struct uart_softc *sc, int sig) 759{ 760 struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; 761 struct uart_bas *bas; 762 uint32_t new, old; 763 764 bas = &sc->sc_bas; 765 do { 766 old = sc->sc_hwsig; 767 new = old; 768 if (sig & SER_DDTR) { 769 SIGCHG(sig & SER_DTR, new, SER_DTR, 770 SER_DDTR); 771 } 772 if (sig & SER_DRTS) { 773 SIGCHG(sig & SER_RTS, new, SER_RTS, 774 SER_DRTS); 775 } 776 } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 777 uart_lock(sc->sc_hwmtx); 778 oct16550->mcr &= ~(MCR_DTR|MCR_RTS); 779 if (new & SER_DTR) 780 oct16550->mcr |= MCR_DTR; 781 if (new & SER_RTS) 782 oct16550->mcr |= MCR_RTS; 783 uart_setreg(bas, REG_MCR, oct16550->mcr); 784 uart_barrier(bas); 785 uart_unlock(sc->sc_hwmtx); 786 return (0); 787} 788 789static int 790oct16550_bus_transmit (struct uart_softc *sc) 791{ 792 struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; 793 struct uart_bas *bas; 794 int i; 795 796 bas = &sc->sc_bas; 797 uart_lock(sc->sc_hwmtx); 798#ifdef NO_UART_INTERRUPTS 799 for (i = 0; i < sc->sc_txdatasz; i++) { 800 oct16550_putc(bas, sc->sc_txbuf[i]); 801 } 802#else 803 804 oct16550_wait_txhr_empty(bas, 100, oct16550_delay(bas)); 805 uart_setreg(bas, REG_IER, oct16550->ier | IER_ETXRDY); 806 uart_barrier(bas); 807 808 for (i = 0; i < sc->sc_txdatasz; i++) { 809 uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]); 810 uart_barrier(bas); 811 } 812 sc->sc_txbusy = 1; 813#endif 814 uart_unlock(sc->sc_hwmtx); 815 return (0); 816} 817 818static void 819oct16550_bus_grab(struct uart_softc *sc) 820{ 821 struct uart_bas *bas = &sc->sc_bas; 822 823 /* 824 * turn off all interrupts to enter polling mode. Leave the 825 * saved mask alone. We'll restore whatever it was in ungrab. 826 * All pending interupt signals are reset when IER is set to 0. 827 */ 828 uart_lock(sc->sc_hwmtx); 829 uart_setreg(bas, REG_IER, 0); 830 uart_barrier(bas); 831 uart_unlock(sc->sc_hwmtx); 832} 833 834static void 835oct16550_bus_ungrab(struct uart_softc *sc) 836{ 837 struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; 838 struct uart_bas *bas = &sc->sc_bas; 839 840 /* 841 * Restore previous interrupt mask 842 */ 843 uart_lock(sc->sc_hwmtx); 844 uart_setreg(bas, REG_IER, oct16550->ier); 845 uart_barrier(bas); 846 uart_unlock(sc->sc_hwmtx); 847} 848