1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011-2012 Robert N. M. Watson 5 * All rights reserved. 6 * 7 * This software was developed by SRI International and the University of 8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 9 * ("CTSRD"), as part of the DARPA CRASH research programme. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 #include <sys/param.h> 35 #include <sys/bus.h> 36 #include <sys/cons.h> 37 #include <sys/endian.h> 38 #include <sys/kdb.h> 39 #include <sys/kernel.h> 40 #include <sys/lock.h> 41 #include <sys/mutex.h> 42 #include <sys/reboot.h> 43 #include <sys/sysctl.h> 44 #include <sys/systm.h> 45 #include <sys/tty.h> 46 47 #include <ddb/ddb.h> 48 49 #include <dev/altera/jtag_uart/altera_jtag_uart.h> 50 51 static SYSCTL_NODE(_hw, OID_AUTO, altera_jtag_uart, 52 CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 53 "Altera JTAG UART configuration knobs"); 54 55 /* 56 * One-byte buffer as we can't check whether the UART is readable without 57 * actually reading from it, synchronised by a spinlock; this lock also 58 * synchronises access to the I/O ports for non-atomic sequences. These 59 * symbols are public so that the TTY layer can use them when working on an 60 * instance of the UART that is also a low-level console. 61 */ 62 char aju_cons_buffer_data; 63 int aju_cons_buffer_valid; 64 int aju_cons_jtag_present; 65 u_int aju_cons_jtag_missed; 66 struct mtx aju_cons_lock; 67 68 /* 69 * Low-level console driver functions. 70 */ 71 static cn_probe_t aju_cnprobe; 72 static cn_init_t aju_cninit; 73 static cn_term_t aju_cnterm; 74 static cn_getc_t aju_cngetc; 75 static cn_putc_t aju_cnputc; 76 static cn_grab_t aju_cngrab; 77 static cn_ungrab_t aju_cnungrab; 78 79 /* 80 * JTAG sets the ALTERA_JTAG_UART_CONTROL_AC bit whenever it accesses the 81 * FIFO. This allows us to (sort of) tell when JTAG is present, so that we 82 * can adopt lossy, rather than blocking, behaviour when JTAG isn't there. 83 * When it is present, we do full flow control. This delay is how long we 84 * wait to see if JTAG has really disappeared when finding a full buffer and 85 * no AC bit set. 86 */ 87 #define ALTERA_JTAG_UART_AC_POLL_DELAY 10000 88 static u_int altera_jtag_uart_ac_poll_delay = 89 ALTERA_JTAG_UART_AC_POLL_DELAY; 90 SYSCTL_UINT(_hw_altera_jtag_uart, OID_AUTO, ac_poll_delay, 91 CTLFLAG_RW, &altera_jtag_uart_ac_poll_delay, 0, 92 "Maximum delay waiting for JTAG present flag when buffer is full"); 93 94 /* 95 * I/O routines lifted from Deimos. This is not only MIPS-specific, but also 96 * BERI-specific, as we're hard coding the address at which we expect to 97 * find the Altera JTAG UART and using it unconditionally. We use these 98 * low-level routines so that we can perform console I/O long before newbus 99 * has initialised and devices have attached. The TTY layer of the driver 100 * knows about this, and uses the console-layer spinlock instead of the 101 * TTY-layer lock to avoid confusion between layers for the console UART. 102 * 103 * XXXRW: The only place this inter-layer behaviour breaks down is if the 104 * low-level console is used for polled read while the TTY driver is also 105 * looking for input. Probably we should also share buffers between layers. 106 */ 107 #define MIPS_XKPHYS_UNCACHED_BASE 0x9000000000000000 108 109 typedef uint64_t paddr_t; 110 typedef uint64_t vaddr_t; 111 112 static inline vaddr_t 113 mips_phys_to_uncached(paddr_t phys) 114 { 115 116 return (phys | MIPS_XKPHYS_UNCACHED_BASE); 117 } 118 119 static inline uint32_t 120 mips_ioread_uint32(vaddr_t vaddr) 121 { 122 uint32_t v; 123 124 __asm__ __volatile__ ("lw %0, 0(%1)" : "=r" (v) : "r" (vaddr)); 125 return (v); 126 } 127 128 static inline void 129 mips_iowrite_uint32(vaddr_t vaddr, uint32_t v) 130 { 131 132 __asm__ __volatile__ ("sw %0, 0(%1)" : : "r" (v), "r" (vaddr)); 133 } 134 135 /* 136 * Little-endian versions of 32-bit I/O routines. 137 */ 138 static inline uint32_t 139 mips_ioread_uint32le(vaddr_t vaddr) 140 { 141 142 return (le32toh(mips_ioread_uint32(vaddr))); 143 } 144 145 static inline void 146 mips_iowrite_uint32le(vaddr_t vaddr, uint32_t v) 147 { 148 149 mips_iowrite_uint32(vaddr, htole32(v)); 150 } 151 152 /* 153 * Low-level read and write register routines; the Altera UART is little 154 * endian, so we byte swap 32-bit reads and writes. 155 */ 156 static inline uint32_t 157 aju_cons_data_read(void) 158 { 159 160 return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE + 161 ALTERA_JTAG_UART_DATA_OFF))); 162 } 163 164 static inline void 165 aju_cons_data_write(uint32_t v) 166 { 167 168 mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE + 169 ALTERA_JTAG_UART_DATA_OFF), v); 170 } 171 172 static inline uint32_t 173 aju_cons_control_read(void) 174 { 175 176 return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE + 177 ALTERA_JTAG_UART_CONTROL_OFF))); 178 } 179 180 static inline void 181 aju_cons_control_write(uint32_t v) 182 { 183 184 mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE + 185 ALTERA_JTAG_UART_CONTROL_OFF), v); 186 } 187 188 /* 189 * Slightly higher-level routines aware of buffering and flow control. 190 */ 191 static int 192 aju_cons_readable(void) 193 { 194 uint32_t v; 195 196 AJU_CONSOLE_LOCK_ASSERT(); 197 198 if (aju_cons_buffer_valid) 199 return (1); 200 v = aju_cons_data_read(); 201 if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) { 202 aju_cons_buffer_valid = 1; 203 aju_cons_buffer_data = (v & ALTERA_JTAG_UART_DATA_DATA); 204 return (1); 205 } 206 return (0); 207 } 208 209 static void 210 aju_cons_write(char ch) 211 { 212 uint32_t v; 213 214 AJU_CONSOLE_LOCK_ASSERT(); 215 216 /* 217 * The flow control logic here is somewhat subtle: we want to wait for 218 * write buffer space only while JTAG is present. However, we can't 219 * directly ask if JTAG is present -- just whether it's been seen 220 * since we last cleared the ALTERA_JTAG_UART_CONTROL_AC bit. As 221 * such, implement a polling loop in which we both wait for space and 222 * try to decide whether JTAG has disappeared on us. We will have to 223 * wait one complete polling delay to detect that JTAG has gone away, 224 * but otherwise shouldn't wait any further once it has gone. And we 225 * had to wait for buffer space anyway, if it was there. 226 * 227 * If JTAG is spotted, reset the TTY-layer miss counter so console- 228 * layer clearing of the bit doesn't trigger a TTY-layer 229 * disconnection. 230 * 231 * XXXRW: Notice the inherent race with hardware: in clearing the 232 * bit, we may race with hardware setting the same bit. This can 233 * cause real-world reliability problems due to lost output on the 234 * console. 235 */ 236 v = aju_cons_control_read(); 237 if (v & ALTERA_JTAG_UART_CONTROL_AC) { 238 aju_cons_jtag_present = 1; 239 aju_cons_jtag_missed = 0; 240 v &= ~ALTERA_JTAG_UART_CONTROL_AC; 241 aju_cons_control_write(v); 242 } 243 while ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) == 0) { 244 if (!aju_cons_jtag_present) 245 return; 246 DELAY(altera_jtag_uart_ac_poll_delay); 247 v = aju_cons_control_read(); 248 if (v & ALTERA_JTAG_UART_CONTROL_AC) { 249 aju_cons_jtag_present = 1; 250 v &= ~ALTERA_JTAG_UART_CONTROL_AC; 251 aju_cons_control_write(v); 252 } else 253 aju_cons_jtag_present = 0; 254 } 255 aju_cons_data_write(ch); 256 } 257 258 static char 259 aju_cons_read(void) 260 { 261 262 AJU_CONSOLE_LOCK_ASSERT(); 263 264 while (!aju_cons_readable()); 265 aju_cons_buffer_valid = 0; 266 return (aju_cons_buffer_data); 267 } 268 269 /* 270 * Implementation of a FreeBSD low-level, polled console driver. 271 */ 272 static void 273 aju_cnprobe(struct consdev *cp) 274 { 275 276 sprintf(cp->cn_name, "%s%d", AJU_TTYNAME, 0); 277 cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL; 278 } 279 280 static void 281 aju_cninit(struct consdev *cp) 282 { 283 uint32_t v; 284 285 AJU_CONSOLE_LOCK_INIT(); 286 287 AJU_CONSOLE_LOCK(); 288 v = aju_cons_control_read(); 289 v &= ~ALTERA_JTAG_UART_CONTROL_AC; 290 aju_cons_control_write(v); 291 AJU_CONSOLE_UNLOCK(); 292 } 293 294 static void 295 aju_cnterm(struct consdev *cp) 296 { 297 298 } 299 300 static int 301 aju_cngetc(struct consdev *cp) 302 { 303 int ret; 304 305 AJU_CONSOLE_LOCK(); 306 ret = aju_cons_read(); 307 AJU_CONSOLE_UNLOCK(); 308 return (ret); 309 } 310 311 static void 312 aju_cnputc(struct consdev *cp, int c) 313 { 314 315 AJU_CONSOLE_LOCK(); 316 aju_cons_write(c); 317 AJU_CONSOLE_UNLOCK(); 318 } 319 320 static void 321 aju_cngrab(struct consdev *cp) 322 { 323 324 } 325 326 static void 327 aju_cnungrab(struct consdev *cp) 328 { 329 330 } 331 332 CONSOLE_DRIVER(aju); 333