1 /* $OpenBSD: cn30xxuart.c,v 1.9 2016/04/14 13:51:58 visa Exp $ */ 2 3 /* 4 * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/device.h> 32 #include <sys/tty.h> 33 #include <sys/conf.h> 34 35 #include <machine/octeonvar.h> 36 #include <machine/autoconf.h> 37 #include <machine/bus.h> 38 39 #include <dev/ic/comreg.h> 40 #include <dev/ic/comvar.h> 41 #include <dev/cons.h> 42 43 #include <octeon/dev/iobusvar.h> 44 #include <octeon/dev/uartbusvar.h> 45 #include <octeon/dev/cn30xxuartreg.h> 46 47 #define OCTEON_UART_FIFO_SIZE 64 48 49 int cn30xxuart_probe(struct device *, void *, void *); 50 void cn30xxuart_attach(struct device *, struct device *, void *); 51 int cn30xxuart_intr(void *); 52 53 struct cfattach cn30xxuart_ca = { 54 sizeof(struct com_softc), cn30xxuart_probe, cn30xxuart_attach 55 }; 56 57 extern struct cfdriver com_cd; 58 59 cons_decl(cn30xxuart); 60 61 #define USR_TXFIFO_NOTFULL 2 62 63 /* XXX: What is this used for? Removed from stand/boot/uart.c -r1.2 */ 64 static int delay_changed = 1; 65 int cn30xxuart_delay(void); 66 void cn30xxuart_wait_txhr_empty(int); 67 68 int 69 cn30xxuart_probe(struct device *parent, void *match, void *aux) 70 { 71 struct cfdata *cf = match; 72 struct uartbus_attach_args *uba = aux; 73 bus_space_tag_t iot = uba->uba_memt; 74 bus_space_handle_t ioh; 75 int rv = 0, console; 76 77 if (strcmp(uba->uba_name, com_cd.cd_name) != 0) 78 return 0; 79 80 console = 1; 81 82 /* if it's in use as console, it's there. */ 83 if (!(console && !comconsattached)) { 84 if (bus_space_map(iot, uba->uba_baseaddr, COM_NPORTS, 0, &ioh)) { 85 printf(": can't map uart registers\n"); 86 return 1; 87 } 88 rv = comprobe1(iot, ioh); 89 } else 90 rv = 1; 91 92 /* make a config stanza with exact locators match over a generic line */ 93 if (cf->cf_loc[0] != -1) 94 rv += rv; 95 96 return rv; 97 } 98 99 void 100 cn30xxuart_attach(struct device *parent, struct device *self, void *aux) 101 { 102 struct com_softc *sc = (void *)self; 103 struct uartbus_attach_args *uba = aux; 104 int console; 105 106 console = 1; 107 108 sc->sc_iot = uba->uba_memt; 109 sc->sc_iobase = uba->uba_baseaddr; 110 sc->sc_hwflags = 0; 111 sc->sc_swflags = 0; 112 sc->sc_frequency = octeon_ioclock_speed(); 113 sc->sc_uarttype = COM_UART_16550A; 114 sc->sc_fifolen = OCTEON_UART_FIFO_SIZE; 115 116 /* if it's in use as console, it's there. */ 117 if (bus_space_map(sc->sc_iot, sc->sc_iobase, COM_NPORTS, 0, &sc->sc_ioh)) { 118 printf(": can't map uart registers\n"); 119 return; 120 } 121 122 if (console && !comconsattached) { 123 /* 124 * If we are the console, reuse the existing bus_space 125 * information, so that comcnattach() invokes bus_space_map() 126 * with correct parameters. 127 */ 128 129 if (comcnattach(sc->sc_iot, sc->sc_iobase, 115200, 130 sc->sc_frequency, (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8)) 131 panic("can't setup serial console"); 132 } 133 134 com_attach_subr(sc); 135 136 octeon_intr_establish(uba->uba_intr, IPL_TTY, cn30xxuart_intr, 137 (void *)sc, sc->sc_dev.dv_xname); 138 } 139 140 int 141 cn30xxuart_intr(void *arg) 142 { 143 comintr(arg); 144 145 /* 146 * Always return non-zero to prevent console clutter about spurious 147 * interrupts. comstart() enables the transmitter holding register 148 * empty interrupt before adding data to the FIFO, which can trigger 149 * a premature interrupt on the primary CPU in a multiprocessor system. 150 */ 151 return 1; 152 } 153 154 /* 155 * Early console routines. 156 */ 157 int 158 cn30xxuart_delay(void) 159 { 160 int divisor; 161 u_char lcr; 162 static int d = 0; 163 164 if (!delay_changed) 165 return d; 166 delay_changed = 0; 167 lcr = octeon_xkphys_read_8(MIO_UART0_LCR); 168 octeon_xkphys_write_8(MIO_UART0_LCR, lcr | LCR_DLAB); 169 divisor = octeon_xkphys_read_8(MIO_UART0_DLL) | 170 octeon_xkphys_read_8(MIO_UART0_DLH) << 8; 171 octeon_xkphys_write_8(MIO_UART0_LCR, lcr); 172 173 return 10; /* return an approx delay value */ 174 } 175 176 void 177 cn30xxuart_wait_txhr_empty(int d) 178 { 179 while (((octeon_xkphys_read_8(MIO_UART0_LSR) & LSR_TXRDY) == 0) && 180 ((octeon_xkphys_read_8(MIO_UART0_USR) & USR_TXFIFO_NOTFULL) == 0)) 181 delay(d); 182 } 183 184 void 185 cn30xxuartcninit(struct consdev *consdev) 186 { 187 } 188 189 void 190 cn30xxuartcnprobe(struct consdev *consdev) 191 { 192 } 193 194 void 195 cn30xxuartcnpollc(dev_t dev, int c) 196 { 197 } 198 199 void 200 cn30xxuartcnputc(dev_t dev, int c) 201 { 202 int d; 203 204 /* 1/10th the time to transmit 1 character (estimate). */ 205 d = cn30xxuart_delay(); 206 cn30xxuart_wait_txhr_empty(d); 207 octeon_xkphys_write_8(MIO_UART0_RBR, (uint8_t)c); 208 cn30xxuart_wait_txhr_empty(d); 209 } 210 211 int 212 cn30xxuartcngetc(dev_t dev) 213 { 214 int c, d; 215 216 /* 1/10th the time to transmit 1 character (estimate). */ 217 d = cn30xxuart_delay(); 218 219 while ((octeon_xkphys_read_8(MIO_UART0_LSR) & LSR_RXRDY) == 0) 220 delay(d); 221 222 c = (uint8_t)octeon_xkphys_read_8(MIO_UART0_RBR); 223 224 return (c); 225 } 226