377 lines
9.2 KiB
C
377 lines
9.2 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* drivers/serial/serial_meson.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
|
|
#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 error
|
|
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 baud rate
|
|
*/
|
|
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));
|
|
}
|
|
|
|
/*
|
|
* Initialise 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)
|
|
{
|
|
|
|
//#ifndef CONFIG_SILENT_CONSOLE
|
|
#ifndef CONFIG_AML_PRODUCT_MODE
|
|
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
|
|
#endif
|
|
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
|
|
//#ifndef CONFIG_SILENT_CONSOLE
|
|
#ifndef CONFIG_AML_PRODUCT_MODE
|
|
/* 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);
|
|
#else
|
|
ch = 0;
|
|
return ((int)ch);
|
|
#endif
|
|
|
|
}
|
|
|
|
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
|
|
|