From 3a2ac88e4052d8ec513ff5d54882f1885fd6ad36 Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Mon, 9 Feb 2015 19:39:39 -0800 Subject: console: copy ns16550 driver from u-boot BUG=chrome-os-partner:35807 BRANCH=broadcom-firmware TEST=none Change-Id: I40623e92f290e5c584a451d99071316b6fc35431 Signed-off-by: Patrick Georgi Original-Commit-Id: 505720f734da7a4cdfaff8b2531385644141ba83 Original-Change-Id: I655c7065047971ab05a13e90ab911d7464a37552 Original-Signed-off-by: Daisuke Nojiri Original-Reviewed-on: https://chromium-review.googlesource.com/251300 Original-Reviewed-by: Julius Werner Reviewed-on: http://review.coreboot.org/9764 Tested-by: build bot (Jenkins) Reviewed-by: Edward O'Callaghan --- src/soc/broadcom/cygnus/include/soc/ns16550.h | 178 +++++++++++++++ src/soc/broadcom/cygnus/ns16550.c | 301 ++++++++++++++++++++++++++ 2 files changed, 479 insertions(+) create mode 100644 src/soc/broadcom/cygnus/include/soc/ns16550.h create mode 100644 src/soc/broadcom/cygnus/ns16550.c (limited to 'src/soc/broadcom') diff --git a/src/soc/broadcom/cygnus/include/soc/ns16550.h b/src/soc/broadcom/cygnus/include/soc/ns16550.h new file mode 100644 index 0000000000..51cb5b4a66 --- /dev/null +++ b/src/soc/broadcom/cygnus/include/soc/ns16550.h @@ -0,0 +1,178 @@ +/* + * NS16550 Serial Port + * originally from linux source (arch/powerpc/boot/ns16550.h) + * + * Cleanup and unification + * (C) 2009 by Detlev Zundel, DENX Software Engineering GmbH + * + * modified slightly to + * have addresses as offsets from CONFIG_SYS_ISA_BASE + * added a few more definitions + * added prototypes for ns16550.c + * reduced no of com ports to 2 + * modifications (c) Rob Taylor, Flying Pig Systems. 2000. + * + * added support for port on 64-bit bus + * by Richard Danter (richard.danter@windriver.com), (C) 2005 Wind River Systems + */ + +/* + * Note that the following macro magic uses the fact that the compiler + * will not allocate storage for arrays of size 0 + */ + +#include + +#if !defined(CONFIG_SYS_NS16550_REG_SIZE) || (CONFIG_SYS_NS16550_REG_SIZE == 0) +#error "Please define NS16550 registers size." +#elif defined(CONFIG_SYS_NS16550_MEM32) +#define UART_REG(x) u32 x +#elif (CONFIG_SYS_NS16550_REG_SIZE > 0) +#define UART_REG(x) \ + unsigned char prepad_##x[CONFIG_SYS_NS16550_REG_SIZE - 1]; \ + unsigned char x; +#elif (CONFIG_SYS_NS16550_REG_SIZE < 0) +#define UART_REG(x) \ + unsigned char x; \ + unsigned char postpad_##x[-CONFIG_SYS_NS16550_REG_SIZE - 1]; +#endif + +struct NS16550 { + UART_REG(rbr); /* 0 */ + UART_REG(ier); /* 1 */ + UART_REG(fcr); /* 2 */ + UART_REG(lcr); /* 3 */ + UART_REG(mcr); /* 4 */ + UART_REG(lsr); /* 5 */ + UART_REG(msr); /* 6 */ + UART_REG(spr); /* 7 */ +#ifdef CONFIG_SOC_DA8XX + UART_REG(reg8); /* 8 */ + UART_REG(reg9); /* 9 */ + UART_REG(revid1); /* A */ + UART_REG(revid2); /* B */ + UART_REG(pwr_mgmt); /* C */ + UART_REG(mdr1); /* D */ +#else + UART_REG(mdr1); /* 8 */ + UART_REG(reg9); /* 9 */ + UART_REG(regA); /* A */ + UART_REG(regB); /* B */ + UART_REG(regC); /* C */ + UART_REG(regD); /* D */ + UART_REG(regE); /* E */ + UART_REG(uasr); /* F */ + UART_REG(scr); /* 10*/ + UART_REG(ssr); /* 11*/ + UART_REG(reg12); /* 12*/ + UART_REG(osc_12m_sel); /* 13*/ +#endif +}; + +#define thr rbr +#define iir fcr +#define dll rbr +#define dlm ier + +typedef struct NS16550 *NS16550_t; + +/* + * These are the definitions for the FIFO Control Register + */ +#define UART_FCR_FIFO_EN 0x01 /* Fifo enable */ +#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */ +#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */ +#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */ +#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */ +#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */ +#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */ +#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */ +#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */ + +#define UART_FCR_RXSR 0x02 /* Receiver soft reset */ +#define UART_FCR_TXSR 0x04 /* Transmitter soft reset */ + +/* + * These are the definitions for the Modem Control Register + */ +#define UART_MCR_DTR 0x01 /* DTR */ +#define UART_MCR_RTS 0x02 /* RTS */ +#define UART_MCR_OUT1 0x04 /* Out 1 */ +#define UART_MCR_OUT2 0x08 /* Out 2 */ +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ + +#define UART_MCR_DMA_EN 0x04 +#define UART_MCR_TX_DFR 0x08 + +/* + * These are the definitions for the Line Control Register + * + * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting + * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits. + */ +#define UART_LCR_WLS_MSK 0x03 /* character length select mask */ +#define UART_LCR_WLS_5 0x00 /* 5 bit character length */ +#define UART_LCR_WLS_6 0x01 /* 6 bit character length */ +#define UART_LCR_WLS_7 0x02 /* 7 bit character length */ +#define UART_LCR_WLS_8 0x03 /* 8 bit character length */ +#define UART_LCR_STB 0x04 /* # stop Bits, off=1, on=1.5 or 2) */ +#define UART_LCR_PEN 0x08 /* Parity eneble */ +#define UART_LCR_EPS 0x10 /* Even Parity Select */ +#define UART_LCR_STKP 0x20 /* Stick Parity */ +#define UART_LCR_SBRK 0x40 /* Set Break */ +#define UART_LCR_BKSE 0x80 /* Bank select enable */ +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ + +/* + * These are the definitions for the Line Status Register + */ +#define UART_LSR_DR 0x01 /* Data ready */ +#define UART_LSR_OE 0x02 /* Overrun */ +#define UART_LSR_PE 0x04 /* Parity error */ +#define UART_LSR_FE 0x08 /* Framing error */ +#define UART_LSR_BI 0x10 /* Break */ +#define UART_LSR_THRE 0x20 /* Xmit holding register empty */ +#define UART_LSR_TEMT 0x40 /* Xmitter empty */ +#define UART_LSR_ERR 0x80 /* Error */ + +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ +#define UART_MSR_RI 0x40 /* Ring Indicator */ +#define UART_MSR_DSR 0x20 /* Data Set Ready */ +#define UART_MSR_CTS 0x10 /* Clear to Send */ +#define UART_MSR_DDCD 0x08 /* Delta DCD */ +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ +#define UART_MSR_DDSR 0x02 /* Delta DSR */ +#define UART_MSR_DCTS 0x01 /* Delta CTS */ + +/* + * These are the definitions for the Interrupt Identification Register + */ +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ + +#define UART_IIR_MSI 0x00 /* Modem status interrupt */ +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ + +/* + * These are the definitions for the Interrupt Enable Register + */ +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ + + +#ifdef CONFIG_OMAP1510 +#define OSC_12M_SEL 0x01 /* selects 6.5 * current clk div */ +#endif + +/* useful defaults for LCR */ +#define UART_LCR_8N1 0x03 + +void NS16550_init(NS16550_t com_port, int baud_divisor); +void NS16550_putc(NS16550_t com_port, char c); +char NS16550_getc(NS16550_t com_port); +int NS16550_tstc(NS16550_t com_port); +void NS16550_reinit(NS16550_t com_port, int baud_divisor); diff --git a/src/soc/broadcom/cygnus/ns16550.c b/src/soc/broadcom/cygnus/ns16550.c new file mode 100644 index 0000000000..cbb32e0155 --- /dev/null +++ b/src/soc/broadcom/cygnus/ns16550.c @@ -0,0 +1,301 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +#include +#ifdef CONFIG_NS87308 +#include +#endif + +#include + +#ifndef CONFIG_NS16550_MIN_FUNCTIONS + +DECLARE_GLOBAL_DATA_PTR; + +#if !defined(CONFIG_CONS_INDEX) +#elif (CONFIG_CONS_INDEX < 1) || (CONFIG_CONS_INDEX > 6) +#error "Invalid console index value." +#endif + +#if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1) +#error "Console port 1 defined but not configured." +#elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2) +#error "Console port 2 defined but not configured." +#elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3) +#error "Console port 3 defined but not configured." +#elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4) +#error "Console port 4 defined but not configured." +#elif CONFIG_CONS_INDEX == 5 && !defined(CONFIG_SYS_NS16550_COM5) +#error "Console port 5 defined but not configured." +#elif CONFIG_CONS_INDEX == 6 && !defined(CONFIG_SYS_NS16550_COM6) +#error "Console port 6 defined but not configured." +#endif + +/* Note: The port number specified in the functions is 1 based. + * the array is 0 based. + */ +static NS16550_t serial_ports[6] = { +#ifdef CONFIG_SYS_NS16550_COM1 + (NS16550_t)CONFIG_SYS_NS16550_COM1, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM2 + (NS16550_t)CONFIG_SYS_NS16550_COM2, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM3 + (NS16550_t)CONFIG_SYS_NS16550_COM3, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM4 + (NS16550_t)CONFIG_SYS_NS16550_COM4, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM5 + (NS16550_t)CONFIG_SYS_NS16550_COM5, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM6 + (NS16550_t)CONFIG_SYS_NS16550_COM6 +#else + NULL +#endif +}; + +#define PORT serial_ports[port-1] + +/* Multi serial device functions */ +#define DECLARE_ESERIAL_FUNCTIONS(port) \ + static int eserial##port##_init(void) \ + { \ + int clock_divisor; \ + clock_divisor = calc_divisor(serial_ports[port-1]); \ + NS16550_init(serial_ports[port-1], clock_divisor); \ + return 0 ; \ + } \ + static void eserial##port##_setbrg(void) \ + { \ + serial_setbrg_dev(port); \ + } \ + static int eserial##port##_getc(void) \ + { \ + return serial_getc_dev(port); \ + } \ + static int eserial##port##_tstc(void) \ + { \ + return serial_tstc_dev(port); \ + } \ + static void eserial##port##_putc(const char c) \ + { \ + serial_putc_dev(port, c); \ + } \ + static void eserial##port##_puts(const char *s) \ + { \ + serial_puts_dev(port, s); \ + } + +/* Serial device descriptor */ +#define INIT_ESERIAL_STRUCTURE(port, __name) { \ + .name = __name, \ + .start = eserial##port##_init, \ + .stop = NULL, \ + .setbrg = eserial##port##_setbrg, \ + .getc = eserial##port##_getc, \ + .tstc = eserial##port##_tstc, \ + .putc = eserial##port##_putc, \ + .puts = eserial##port##_puts, \ +} + +int calc_divisor(NS16550_t port) +{ +#ifdef CONFIG_OMAP1510 + /* If can't cleanly clock 115200 set div to 1 */ + if ((CONFIG_SYS_NS16550_CLK == 12000000) && (gd->baudrate == 115200)) { + port->osc_12m_sel = OSC_12M_SEL; /* enable 6.5 * divisor */ + return (1); /* return 1 for base divisor */ + } + port->osc_12m_sel = 0; /* clear if previsouly set */ +#endif +#ifdef CONFIG_OMAP1610 + /* If can't cleanly clock 115200 set div to 1 */ + if ((CONFIG_SYS_NS16550_CLK == 48000000) && (gd->baudrate == 115200)) { + return (26); /* return 26 for base divisor */ + } +#endif + +#define MODE_X_DIV 16 + /* Compute divisor value. Normally, we should simply return: + * CONFIG_SYS_NS16550_CLK) / MODE_X_DIV / gd->baudrate + * but we need to round that value by adding 0.5. + * Rounding is especially important at high baud rates. + */ + return (CONFIG_SYS_NS16550_CLK + (gd->baudrate * (MODE_X_DIV / 2))) / + (MODE_X_DIV * gd->baudrate); +} + +void +_serial_putc(const char c,const int port) +{ + if (c == '\n') + NS16550_putc(PORT, '\r'); + + NS16550_putc(PORT, c); +} + +void +_serial_putc_raw(const char c,const int port) +{ + NS16550_putc(PORT, c); +} + +void +_serial_puts (const char *s,const int port) +{ + while (*s) { + _serial_putc (*s++,port); + } +} + + +int +_serial_getc(const int port) +{ + return NS16550_getc(PORT); +} + +int +_serial_tstc(const int port) +{ + return NS16550_tstc(PORT); +} + +void +_serial_setbrg (const int port) +{ + int clock_divisor; + + clock_divisor = calc_divisor(PORT); + NS16550_reinit(PORT, clock_divisor); +} + +static inline void +serial_putc_dev(unsigned int dev_index,const char c) +{ + _serial_putc(c,dev_index); +} + +static inline void +serial_putc_raw_dev(unsigned int dev_index,const char c) +{ + _serial_putc_raw(c,dev_index); +} + +static inline void +serial_puts_dev(unsigned int dev_index,const char *s) +{ + _serial_puts(s,dev_index); +} + +static inline int +serial_getc_dev(unsigned int dev_index) +{ + return _serial_getc(dev_index); +} + +static inline int +serial_tstc_dev(unsigned int dev_index) +{ + return _serial_tstc(dev_index); +} + +static inline void +serial_setbrg_dev(unsigned int dev_index) +{ + _serial_setbrg(dev_index); +} + +#if defined(CONFIG_SYS_NS16550_COM1) +DECLARE_ESERIAL_FUNCTIONS(1); +struct serial_device eserial1_device = + INIT_ESERIAL_STRUCTURE(1, "eserial0"); +#endif +#if defined(CONFIG_SYS_NS16550_COM2) +DECLARE_ESERIAL_FUNCTIONS(2); +struct serial_device eserial2_device = + INIT_ESERIAL_STRUCTURE(2, "eserial1"); +#endif +#if defined(CONFIG_SYS_NS16550_COM3) +DECLARE_ESERIAL_FUNCTIONS(3); +struct serial_device eserial3_device = + INIT_ESERIAL_STRUCTURE(3, "eserial2"); +#endif +#if defined(CONFIG_SYS_NS16550_COM4) +DECLARE_ESERIAL_FUNCTIONS(4); +struct serial_device eserial4_device = + INIT_ESERIAL_STRUCTURE(4, "eserial3"); +#endif +#if defined(CONFIG_SYS_NS16550_COM5) +DECLARE_ESERIAL_FUNCTIONS(5); +struct serial_device eserial5_device = + INIT_ESERIAL_STRUCTURE(5, "eserial4"); +#endif +#if defined(CONFIG_SYS_NS16550_COM6) +DECLARE_ESERIAL_FUNCTIONS(6); +struct serial_device eserial6_device = + INIT_ESERIAL_STRUCTURE(6, "eserial5"); +#endif + +__weak struct serial_device *default_serial_console(void) +{ +#if CONFIG_CONS_INDEX == 1 + return &eserial1_device; +#elif CONFIG_CONS_INDEX == 2 + return &eserial2_device; +#elif CONFIG_CONS_INDEX == 3 + return &eserial3_device; +#elif CONFIG_CONS_INDEX == 4 + return &eserial4_device; +#elif CONFIG_CONS_INDEX == 5 + return &eserial5_device; +#elif CONFIG_CONS_INDEX == 6 + return &eserial6_device; +#else +#error "Bad CONFIG_CONS_INDEX." +#endif +} + +void ns16550_serial_initialize(void) +{ +#if defined(CONFIG_SYS_NS16550_COM1) + serial_register(&eserial1_device); +#endif +#if defined(CONFIG_SYS_NS16550_COM2) + serial_register(&eserial2_device); +#endif +#if defined(CONFIG_SYS_NS16550_COM3) + serial_register(&eserial3_device); +#endif +#if defined(CONFIG_SYS_NS16550_COM4) + serial_register(&eserial4_device); +#endif +#if defined(CONFIG_SYS_NS16550_COM5) + serial_register(&eserial5_device); +#endif +#if defined(CONFIG_SYS_NS16550_COM6) + serial_register(&eserial6_device); +#endif +} + +#endif /* !CONFIG_NS16550_MIN_FUNCTIONS */ -- cgit v1.2.3