blob: 897c0cd967d4195323961788769204f9da0ad882 [file] [log] [blame]
/*******************************************************************
*
* Copyright C 2010 by Amlogic, Inc. All Rights Reserved.
*
* Description: Serial driver.
*
* Author: Jerry Yu
* Created: 2009-3-12
*
*******************************************************************/
#include <config.h>
#include <common.h>
//#include <asm/arch/io.h>
//#include <asm/arch/cpu.h>
#include <asm/io.h>
#include <asm/arch/uart.h>
#include <serial.h>
DECLARE_GLOBAL_DATA_PTR;
int serial_set_pin_port(unsigned long port_base);
static void serial_putc_port (unsigned long port_base,const char c);
//static unsigned port_base_addrs[]={UART_PORT_0,UART_PORT_1};
#if 0 // due to errror
static void serial_clr_err (unsigned port_base)
{
/* write to the register */
if (readl(P_UART_STATUS(port_base))&(UART_STAT_MASK_PRTY_ERR|UART_STAT_MASK_FRAM_ERR))
writel((readl(P_UART_CONTROL(port_base)) | UART_CNTL_MASK_CLR_ERR), P_UART_CONTROL(port_base));
}
#endif
/*
* Sets baudarate
*/
static void serial_setbrg_port (unsigned long port_base)
{
unsigned long baud_para;
int clk81=clk_get_rate(UART_CLK_SRC);
if (clk81<0)
return;
/* baud rate */
baud_para=clk81/(gd->baudrate*4) -1;
baud_para &= UART_CNTL_MASK_BAUD_RATE;
/* write to the register */
writel((readl(P_UART_CONTROL(port_base)) & ~UART_CNTL_MASK_BAUD_RATE) | baud_para, P_UART_CONTROL(port_base));
}
/*
* Sets stop bits
* input[0]: stop_bits (1, 2)
*/
static void serial_set_stop_port (unsigned long port_base,int stop_bits)
{
unsigned long uart_config;
uart_config = readl(P_UART_CONTROL(port_base)) & ~UART_CNTL_MASK_STP_BITS;
/* stop bits */
switch (stop_bits)
{
case 2:
uart_config |= UART_CNTL_MASK_STP_2BIT;
break;
case 1:
default:
uart_config |= UART_CNTL_MASK_STP_1BIT;
break;
}
/* write to the register */
writel(uart_config, P_UART_CONTROL(port_base));
}
/*
* Sets parity type
* input[0]: 1 -- enable parity, 0 -- disable;
* input[1]: 1 -- odd parity, 0 -- even parity;
*/
static void serial_set_parity_port(unsigned long port_base,int type)
{
unsigned long uart_config;
uart_config = readl(P_UART_CONTROL(port_base)) & ~(UART_CNTL_MASK_PRTY_TYPE | UART_CNTL_MASK_PRTY_EN);
#if 0 //changed by Elvis --- disable parity
uart_config |= UART_CNTL_MASK_PRTY_EN;
/* parity bits */
if (type&2)
uart_config |= UART_CNTL_MASK_PRTY_EN;
if (type&1)
uart_config |= UART_CNTL_MASK_PRTY_ODD;
else
uart_config |= UART_CNTL_MASK_PRTY_EVEN;
#endif
/* write to the register */
writel(uart_config, P_UART_CONTROL(port_base));
}
/*
* Sets data length
* input[0]: Character length [5, 6, 7, 8]
*/
static void serial_set_dlen_port (unsigned long port_base,int data_len)
{
unsigned long uart_config;
uart_config = readl(P_UART_CONTROL(port_base)) & ~UART_CNTL_MASK_CHAR_LEN;
/* data bits */
switch (data_len)
{
case 5:
uart_config |= UART_CNTL_MASK_CHAR_5BIT;
break;
case 6:
uart_config |= UART_CNTL_MASK_CHAR_6BIT;
break;
case 7:
uart_config |= UART_CNTL_MASK_CHAR_7BIT;
break;
case 8:
default:
uart_config |= UART_CNTL_MASK_CHAR_8BIT;
break;
}
/* write to the register */
writel(uart_config, P_UART_CONTROL(port_base));
}
/*
* reset the uart state machine
*/
static void serial_reset_port(unsigned long port_base) {
/* write to the register */
writel(readl(P_UART_CONTROL(port_base)) | UART_CNTL_MASK_RST_TX | UART_CNTL_MASK_RST_RX | UART_CNTL_MASK_CLR_ERR, P_UART_CONTROL(port_base));
writel(readl(P_UART_CONTROL(port_base)) & ~(UART_CNTL_MASK_RST_TX | UART_CNTL_MASK_RST_RX | UART_CNTL_MASK_CLR_ERR), P_UART_CONTROL(port_base));
}
/*
* Intialise the serial port with given baudrate
*/
static int serial_init_port (unsigned long port_base)
{
int ret;
#ifdef CONFIG_M3
while ((readl(P_UART_STATUS(port_base)) & (UART_STAT_MASK_XMIT_BUSY))) ;
#endif
writel(0,P_UART_CONTROL(port_base));
ret = serial_set_pin_port(port_base);
if (ret < 0)
return -1;
serial_setbrg_port(port_base);
#ifndef CONFIG_SERIAL_STP_BITS
#define CONFIG_SERIAL_STP_BITS 1
#endif
serial_set_stop_port(port_base,CONFIG_SERIAL_STP_BITS);
#ifndef CONFIG_SERIAL_PRTY_TYPE
#define CONFIG_SERIAL_PRTY_TYPE 0
#endif
serial_set_parity_port(port_base,CONFIG_SERIAL_PRTY_TYPE);
#ifndef CONFIG_SERIAL_CHAR_LEN
#define CONFIG_SERIAL_CHAR_LEN 8
#endif
serial_set_dlen_port(port_base,CONFIG_SERIAL_CHAR_LEN);
writel(readl(P_UART_CONTROL(port_base)) | UART_CNTL_MASK_TX_EN | UART_CNTL_MASK_RX_EN, P_UART_CONTROL(port_base));
while (!(readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_TFIFO_EMPTY)) ;
serial_reset_port(port_base);
#ifdef CONFIG_M3
while ((readl(P_UART_STATUS(port_base)) & (UART_STAT_MASK_XMIT_BUSY))) ;
#endif
serial_putc_port(port_base,'\n');
return 0;
}
/*
* Output a single byte to the serial port.
*/
static void serial_putc_port (unsigned long port_base,const char c)
{
if (c == '\n')
serial_putc_port(port_base,'\r');
/* Wait till dataTx register is not full */
while ((readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_TFIFO_FULL));
// while(!(readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_TFIFO_EMPTY));
writel(c, P_UART_WFIFO(port_base));
/* Wait till dataTx register is empty */
#if !defined (CONFIG_VLSI_EMULATOR)
while (!(readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_TFIFO_EMPTY)) ;
#endif //CONFIG_VLSI_EMULATOR
}
/*
* Read a single byte from the serial port. Returns 1 on success, 0
* otherwise 0.
*/
static int serial_tstc_port (unsigned long port_base)
{
int i;
i=(readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_RFIFO_CNT);
return i;
}
/*
* Read a single byte from the serial port.
*/
static int serial_getc_port (unsigned long port_base)
{
unsigned char ch;
/* Wait till character is placed in fifo */
while ((readl(P_UART_STATUS(port_base)) & UART_STAT_MASK_RFIFO_CNT) == 0) ;
ch = readl(P_UART_RFIFO(port_base)) & 0x00ff;
/* Also check for overflow errors */
if (readl(P_UART_STATUS(port_base)) & (UART_STAT_MASK_PRTY_ERR | UART_STAT_MASK_FRAM_ERR))
{
writel(readl(P_UART_CONTROL(port_base)) |UART_CNTL_MASK_CLR_ERR,P_UART_CONTROL(port_base));//clear errors
writel(readl(P_UART_CONTROL(port_base)) & (~UART_CNTL_MASK_CLR_ERR),P_UART_CONTROL(port_base));
}
return ((int)ch);
}
static void serial_puts_port (unsigned long port_base,const char *s)
{
while (*s) {
serial_putc_port(port_base,*s++);
}
}
#if CONFIG_SERIAL_MULTI
#include <serial.h>
#define DECLARE_UART_FUNCTIONS(port) \
static int uart_##port##_init (void) {\
serial_init_port(port); return(0);}\
static void uart_##port##_setbrg (void) {\
serial_setbrg_port(port);}\
static int uart_##port##_getc (void) {\
return serial_getc_port(port);}\
static int uart_##port##_tstc (void) {\
return serial_tstc_port(port);}\
static void uart_##port##_putc (const char c) {\
serial_putc_port(port, c);}\
static void uart_##port##_puts (const char *s) {\
serial_puts_port(port, s);}
#define INIT_UART_STRUCTURE(port,_name,bus) static struct serial_device device_##port={\
.name = _name,\
/*bus,*/\
.start = uart_##port##_init,\
.stop = NULL,\
.setbrg = uart_##port##_setbrg,\
.getc = uart_##port##_getc,\
.tstc = uart_##port##_tstc,\
.putc = uart_##port##_putc,\
.puts = uart_##port##_puts, }
DECLARE_UART_FUNCTIONS(UART_PORT_0);
INIT_UART_STRUCTURE(UART_PORT_0,"uart0","UART0");
DECLARE_UART_FUNCTIONS(UART_PORT_1);
INIT_UART_STRUCTURE(UART_PORT_1,"uart1","UART1");
#ifdef UART_PORT_AO
DECLARE_UART_FUNCTIONS(UART_PORT_AO);
INIT_UART_STRUCTURE(UART_PORT_AO,"uart_ao","UART_AO");
#endif
struct serial_device * default_serial_console (void)
{
#if (UART_PORT_CONS==UART_PORT_0)
return &device_UART_PORT_0;
#elif (UART_PORT_CONS==UART_PORT_1)
return &device_UART_PORT_1;
#else
#ifdef UART_PORT_AO
#if (UART_PORT_CONS==UART_PORT_AO)
return &device_UART_PORT_AO;
#else
#error "invalid uart port index defined"
#endif
#endif
#endif
}
void serial_aml_register(void)
{
serial_register(&device_UART_PORT_0);
serial_register(&device_UART_PORT_1);
#ifdef UART_PORT_AO
serial_register(&device_UART_PORT_AO);
#endif
}
#endif
#if !(defined CONFIG_SERIAL_MULTI)
int serial_init(void){
return serial_init_port(UART_PORT_CONS);
}
void serial_putc(const char c){
serial_putc_port(UART_PORT_CONS,c);
}
int serial_tstc(void){
return serial_tstc_port(UART_PORT_CONS);
}
int serial_getc(void){
return serial_getc_port(UART_PORT_CONS);
}
void serial_puts(const char * s){
serial_puts_port(UART_PORT_CONS,s);
}
void serial_setbrg(void){
serial_setbrg_port(UART_PORT_CONS);
}
#ifdef CONFIG_CMD_KGDB
#if UART_PORT_CONS==UART_PORT_0
#define DEBUG_PORT UART_PORT_1
#else
#define DEBUG_PORT UART_PORT_0
#endif
int kgdb_serial_init(void){
int ret=serial_init_port(DEBUG_PORT);
return ret;
}
int getDebugChar(void){
return serial_getc_port(DEBUG_PORT);
}
void putDebugChar(const char c){
serial_putc_port(DEBUG_PORT,c);
}
void putDebugStr(const char * s){
serial_puts_port(DEBUG_PORT,s);
}
#endif /* CONFIG_CMD_KGDB */
#endif