1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * NS16550 UART driver File: dev_ns16550.c 5 * 6 * This is a console device driver for an NS16550 UART, either 7 * on-board or as a PCI-device. In the case of a PCI device, 8 * our probe routine is called from the PCI probe code 9 * over in dev_ns16550_pci.c 10 * 11 * Author: Mitch Lichtenberg (mpl@broadcom.com) 12 * 13 ********************************************************************* 14 * 15 * Copyright 2000,2001,2002,2003 16 * Broadcom Corporation. All rights reserved. 17 * 18 * This software is furnished under license and may be used and 19 * copied only in accordance with the following terms and 20 * conditions. Subject to these conditions, you may download, 21 * copy, install, use, modify and distribute modified or unmodified 22 * copies of this software in source and/or binary form. No title 23 * or ownership is transferred hereby. 24 * 25 * 1) Any source code used, modified or distributed must reproduce 26 * and retain this copyright notice and list of conditions 27 * as they appear in the source file. 28 * 29 * 2) No right is granted to use any trade name, trademark, or 30 * logo of Broadcom Corporation. The "Broadcom Corporation" 31 * name may not be used to endorse or promote products derived 32 * from this software without the prior written permission of 33 * Broadcom Corporation. 34 * 35 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 36 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 37 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 38 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 39 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 40 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 41 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 42 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 43 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 44 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 46 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 47 * THE POSSIBILITY OF SUCH DAMAGE. 48 ********************************************************************* */ 49 50#if CFG_SIM && CFG_SIM_CONSOLE 51#include <typedefs.h> 52#include <cfe_osl.h> 53#endif /* CFG_SIM && CFG_SIM_CONSOLE */ 54 55#include "lib_types.h" 56#include "lib_malloc.h" 57#include "lib_printf.h" 58#include "cfe_iocb.h" 59#include "cfe_device.h" 60#include "cfe_ioctl.h" 61 62#include "lib_physio.h" 63 64#include "bsp_config.h" 65 66#include "ns16550.h" 67 68#ifdef BCM4704 69#define WRITECSR(softc, offset, value) do { \ 70 phys_write8((softc)->uart_base + ((offset) << (softc)->reg_shift), (value)); \ 71 phys_read8(0x18000000); \ 72} while (0) 73#else 74#define WRITECSR(softc, offset, value) \ 75 phys_write8((softc)->uart_base + ((offset) << (softc)->reg_shift), (value)) 76#endif 77 78#define READCSR(softc, offset) \ 79 phys_read8((softc)->uart_base + ((offset) << (softc)->reg_shift)) 80 81static int ns16550_uart_open(cfe_devctx_t *ctx); 82static int ns16550_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 83static int ns16550_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 84static int ns16550_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 85static int ns16550_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 86static int ns16550_uart_close(cfe_devctx_t *ctx); 87 88void ns16550_uart_probe(cfe_driver_t *drv, 89 unsigned long probe_a, unsigned long probe_b, 90 void *probe_ptr); 91 92 93const cfe_devdisp_t ns16550_uart_dispatch = { 94 ns16550_uart_open, 95 ns16550_uart_read, 96 ns16550_uart_inpstat, 97 ns16550_uart_write, 98 ns16550_uart_ioctl, 99 ns16550_uart_close, 100 NULL, 101 NULL 102}; 103 104const cfe_driver_t ns16550_uart = { 105 "NS16550 UART", 106 "uart", 107 CFE_DEV_SERIAL, 108 &ns16550_uart_dispatch, 109 ns16550_uart_probe 110}; 111 112typedef struct ns16550_uart_s { 113 physaddr_t uart_base; 114 int uart_flowcontrol; 115 int baud_base; 116 int reg_shift; 117 int uart_speed; 118} ns16550_uart_t; 119 120 121/* 122 * NS16550-compatible UART. 123 * probe_a: physical address of UART 124 */ 125 126void ns16550_uart_probe(cfe_driver_t *drv, 127 unsigned long probe_a, unsigned long probe_b, 128 void *probe_ptr) 129{ 130 ns16550_uart_t *softc; 131 char descr[80]; 132 133 softc = (ns16550_uart_t *) KMALLOC(sizeof(ns16550_uart_t),0); 134 if (softc) { 135 softc->uart_base = probe_a; 136 softc->baud_base = probe_b ? : NS16550_HZ; 137 softc->reg_shift = probe_ptr ? *(int*)probe_ptr : 0; 138 softc->uart_speed = CFG_SERIAL_BAUD_RATE; 139 softc->uart_flowcontrol = SERIAL_FLOW_NONE; 140 xsprintf(descr, "%s at 0x%X", drv->drv_description, (uint32_t)probe_a); 141 142 cfe_attach(drv, softc, NULL, descr); 143 } 144} 145 146#if !defined(MIPS33xx) 147 148#define DELAY(n) delay(n) 149extern int32_t _getticks(void); 150static void delay(int ticks) 151{ 152 int32_t t; 153 154 t = _getticks() + ticks; 155 while (_getticks() < t) 156 ; /* NULL LOOP */ 157} 158#endif /* !MIPS33xx */ 159 160static void ns16550_uart_setflow(ns16550_uart_t *softc) 161{ 162 /* noop for now */ 163} 164 165 166static int ns16550_uart_open(cfe_devctx_t *ctx) 167{ 168 ns16550_uart_t *softc = ctx->dev_softc; 169 unsigned int brtc; 170 171 brtc = BRTC(softc->baud_base, softc->uart_speed); 172 173 WRITECSR(softc,R_UART_CFCR,CFCR_DLAB); 174 WRITECSR(softc,R_UART_DATA,brtc & 0xFF); 175 WRITECSR(softc,R_UART_IER,brtc>>8); 176 WRITECSR(softc,R_UART_CFCR,CFCR_8BITS); 177 178#if !defined(NS16550_NO_FLOW) 179 180 WRITECSR(softc,R_UART_CFCR,CFCR_DLAB); 181 WRITECSR(softc,R_UART_DATA,brtc & 0xFF); 182 WRITECSR(softc,R_UART_IER,brtc>>8); 183 WRITECSR(softc,R_UART_CFCR,CFCR_8BITS); 184#if !defined(_BCM94702_CPCI_) 185 WRITECSR(softc,R_UART_MCR,MCR_DTR | MCR_RTS | MCR_IENABLE); 186#endif 187 WRITECSR(softc,R_UART_IER,0); 188 189 WRITECSR(softc,R_UART_FIFO,FIFO_ENABLE); 190 DELAY(100); 191 WRITECSR(softc,R_UART_FIFO, 192 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1); 193 DELAY(100); 194 195 if ((READCSR(softc,R_UART_IIR) & IIR_FIFO_MASK) != 196 IIR_FIFO_MASK) { 197 WRITECSR(softc,R_UART_FIFO,0); 198 } 199#endif /* !NS16550_NO_FLOW */ 200 201 ns16550_uart_setflow(softc); 202 203 return 0; 204} 205 206static int ns16550_uart_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer) 207{ 208 ns16550_uart_t *softc = ctx->dev_softc; 209 unsigned char *bptr; 210 int blen; 211 212 bptr = buffer->buf_ptr; 213 blen = buffer->buf_length; 214 215 while ((blen > 0) && (READCSR(softc,R_UART_LSR) & LSR_RXRDY)) { 216 *bptr++ = (READCSR(softc,R_UART_DATA) & 0xFF); 217 blen--; 218 } 219 220 buffer->buf_retlen = buffer->buf_length - blen; 221 return 0; 222} 223 224static int ns16550_uart_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat) 225{ 226 ns16550_uart_t *softc = ctx->dev_softc; 227 228 inpstat->inp_status = (READCSR(softc,R_UART_LSR) & LSR_RXRDY) ? 1 : 0; 229 230 return 0; 231} 232 233#if CFG_SIM || CFG_BUFLOG 234#define LOG_BUF_LEN (4096) 235#define LOG_BUF_MASK (LOG_BUF_LEN-1) 236char log_buf[LOG_BUF_LEN]; 237unsigned long log_start; 238#define KSEG1ADDR(a) (((unsigned long)(a) & 0x1fffffff) | 0xa0000000) 239 240#define WRITEBUF(c) \ 241do { \ 242 *((char*)KSEG1ADDR(&log_buf[log_start])) = c; \ 243 log_start = (log_start + 1) & LOG_BUF_MASK; \ 244} \ 245while (0) 246 247extern int logbuf_write(const char *str); 248extern void logbuf_dump(void); 249 250int logbuf_write(const char *str) 251{ 252 int count = 0; 253 char c; 254 255 /* Convert CR to CRLF as we write things out */ 256 while ((c = *str ++)) { 257 if (c == '\n') { 258 WRITEBUF('\r'); 259 count ++; 260 } 261 WRITEBUF(c); 262 count ++; 263 } 264 265 return count; 266} 267 268void logbuf_dump(void) 269{ 270 xprintf(log_buf); 271} 272#endif 273 274static int ns16550_uart_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer) 275{ 276 ns16550_uart_t *softc = ctx->dev_softc; 277 unsigned char *bptr; 278 int blen; 279 280 bptr = buffer->buf_ptr; 281 blen = buffer->buf_length; 282 while ((blen > 0) && (READCSR(softc,R_UART_LSR) & LSR_TXRDY)) { 283#if CFG_SIM 284 WRITEBUF(*bptr); 285#endif 286 WRITECSR(softc,R_UART_DATA, *bptr++); 287 blen--; 288#if CFG_SIM && CFG_SIM_CONSOLE 289 OSL_DELAY(100); 290#endif /* CFG_SIM && CFG_SIM_CONSOLE */ 291 } 292 293 buffer->buf_retlen = buffer->buf_length - blen; 294 return 0; 295} 296 297static int ns16550_uart_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer) 298{ 299 ns16550_uart_t *softc = ctx->dev_softc; 300 301 unsigned int *info = (unsigned int *) buffer->buf_ptr; 302 303 switch ((int)buffer->buf_ioctlcmd) { 304 case IOCTL_SERIAL_GETSPEED: 305 *info = softc->uart_speed; 306 break; 307 case IOCTL_SERIAL_SETSPEED: 308 softc->uart_speed = *info; 309 /* NYI */ 310 break; 311 case IOCTL_SERIAL_GETFLOW: 312 *info = softc->uart_flowcontrol; 313 break; 314 case IOCTL_SERIAL_SETFLOW: 315 softc->uart_flowcontrol = *info; 316 ns16550_uart_setflow(softc); 317 break; 318 default: 319 return -1; 320 } 321 322 return 0; 323} 324 325static int ns16550_uart_close(cfe_devctx_t *ctx) 326{ 327 ns16550_uart_t *softc = ctx->dev_softc; 328 329 WRITECSR(softc,R_UART_MCR,0); 330 331 return 0; 332} 333 334 335