diff options
Diffstat (limited to 'arch/mips/mach-au1x00/au1x00_serial.c')
-rw-r--r-- | arch/mips/mach-au1x00/au1x00_serial.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/arch/mips/mach-au1x00/au1x00_serial.c b/arch/mips/mach-au1x00/au1x00_serial.c new file mode 100644 index 00000000000..046350826a9 --- /dev/null +++ b/arch/mips/mach-au1x00/au1x00_serial.c @@ -0,0 +1,131 @@ +/* + * AU1X00 UART support + * + * Hardcoded to UART 0 for now + * Speed and options also hardcoded to 115200 8N1 + * + * Copyright (c) 2003 Thomas.Lange@corelatus.se + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <common.h> +#include <asm/au1x00.h> +#include <serial.h> +#include <linux/compiler.h> + +/****************************************************************************** +* +* serial_init - initialize a channel +* +* This routine initializes the number of data bits, parity +* and set the selected baud rate. Interrupts are disabled. +* Set the modem control signals if the option is selected. +* +* RETURNS: N/A +*/ + +static int au1x00_serial_init(void) +{ + volatile u32 *uart_fifoctl = (volatile u32*)(UART0_ADDR+UART_FCR); + volatile u32 *uart_enable = (volatile u32*)(UART0_ADDR+UART_ENABLE); + + /* Enable clocks first */ + *uart_enable = UART_EN_CE; + + /* Then release reset */ + /* Must release reset before setting other regs */ + *uart_enable = UART_EN_CE|UART_EN_E; + + /* Activate fifos, reset tx and rx */ + /* Set tx trigger level to 12 */ + *uart_fifoctl = UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR| + UART_FCR_CLEAR_XMIT|UART_FCR_T_TRIGGER_12; + + serial_setbrg(); + + return 0; +} + + +static void au1x00_serial_setbrg(void) +{ + volatile u32 *uart_clk = (volatile u32*)(UART0_ADDR+UART_CLK); + volatile u32 *uart_lcr = (volatile u32*)(UART0_ADDR+UART_LCR); + volatile u32 *sys_powerctrl = (u32 *)SYS_POWERCTRL; + int sd; + int divisorx2; + + /* sd is system clock divisor */ + /* see section 10.4.5 in au1550 datasheet */ + sd = (*sys_powerctrl & 0x03) + 2; + + /* calulate 2x baudrate and round */ + divisorx2 = ((CONFIG_SYS_MIPS_TIMER_FREQ/(sd * 16 * CONFIG_BAUDRATE))); + + if (divisorx2 & 0x01) + divisorx2 = divisorx2 + 1; + + *uart_clk = divisorx2 / 2; + + /* Set parity, stop bits and word length to 8N1 */ + *uart_lcr = UART_LCR_WLEN8; +} + +static void au1x00_serial_putc(const char c) +{ + volatile u32 *uart_lsr = (volatile u32*)(UART0_ADDR+UART_LSR); + volatile u32 *uart_tx = (volatile u32*)(UART0_ADDR+UART_TX); + + if (c == '\n') + au1x00_serial_putc('\r'); + + /* Wait for fifo to shift out some bytes */ + while((*uart_lsr&UART_LSR_THRE)==0); + + *uart_tx = (u32)c; +} + +static int au1x00_serial_getc(void) +{ + volatile u32 *uart_rx = (volatile u32*)(UART0_ADDR+UART_RX); + char c; + + while (!serial_tstc()); + + c = (*uart_rx&0xFF); + return c; +} + +static int au1x00_serial_tstc(void) +{ + volatile u32 *uart_lsr = (volatile u32*)(UART0_ADDR+UART_LSR); + + if(*uart_lsr&UART_LSR_DR){ + /* Data in rfifo */ + return(1); + } + return 0; +} + +static struct serial_device au1x00_serial_drv = { + .name = "au1x00_serial", + .start = au1x00_serial_init, + .stop = NULL, + .setbrg = au1x00_serial_setbrg, + .putc = au1x00_serial_putc, + .puts = default_serial_puts, + .getc = au1x00_serial_getc, + .tstc = au1x00_serial_tstc, +}; + +void au1x00_serial_initialize(void) +{ + serial_register(&au1x00_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &au1x00_serial_drv; +} |