/* 
 | 
 * 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 <mach/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; 
 | 
} 
 |