@ -6,6 +6,8 @@
*/
# include <common.h>
# include <debug_uart.h>
# include <dm.h>
# include <errno.h>
# include <fdtdec.h>
# include <watchdog.h>
@ -18,6 +20,7 @@
DECLARE_GLOBAL_DATA_PTR ;
# define ZYNQ_UART_SR_TXFULL 0x00000010 /* TX FIFO full */
# define ZYNQ_UART_SR_TXACTIVE (1 << 11) /* TX active */
# define ZYNQ_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
# define ZYNQ_UART_CR_TX_EN 0x00000010 /* TX enabled */
@ -38,9 +41,8 @@ struct uart_zynq {
u32 baud_rate_divider ; /* 0x34 - Baud Rate Divider [7:0] */
} ;
static struct uart_zynq * uart_zynq_ports [ 2 ] = {
[ 0 ] = ( struct uart_zynq * ) ZYNQ_SERIAL_BASEADDR0 ,
[ 1 ] = ( struct uart_zynq * ) ZYNQ_SERIAL_BASEADDR1 ,
struct zynq_uart_priv {
struct uart_zynq * regs ;
} ;
/* Set up the baud rate in gd struct */
@ -84,15 +86,6 @@ static void _uart_zynq_serial_setbrg(struct uart_zynq *regs,
writel ( bgen , & regs - > baud_rate_gen ) ;
}
/* Set up the baud rate in gd struct */
static void uart_zynq_serial_setbrg ( const int port )
{
unsigned long clock = get_uart_clk ( port ) ;
struct uart_zynq * regs = uart_zynq_ports [ port ] ;
return _uart_zynq_serial_setbrg ( regs , clock , gd - > baudrate ) ;
}
/* Initialize the UART, with...some settings. */
static void _uart_zynq_serial_init ( struct uart_zynq * regs )
{
@ -102,20 +95,6 @@ static void _uart_zynq_serial_init(struct uart_zynq *regs)
writel ( ZYNQ_UART_MR_PARITY_NONE , & regs - > mode ) ; /* 8 bit, no parity */
}
/* Initialize the UART, with...some settings. */
static int uart_zynq_serial_init ( const int port )
{
struct uart_zynq * regs = uart_zynq_ports [ port ] ;
if ( ! regs )
return - 1 ;
_uart_zynq_serial_init ( regs ) ;
uart_zynq_serial_setbrg ( port ) ;
return 0 ;
}
static int _uart_zynq_serial_putc ( struct uart_zynq * regs , const char c )
{
if ( readl ( & regs - > channel_sts ) & ZYNQ_UART_SR_TXFULL )
@ -126,103 +105,91 @@ static int _uart_zynq_serial_putc(struct uart_zynq *regs, const char c)
return 0 ;
}
static void uart_zynq_serial_putc ( const char c , const int port )
int zynq_serial_setbrg ( struct udevice * dev , int baudrate )
{
struct uart_zynq * regs = uart_zynq_ports [ port ] ;
struct zynq_uart_priv * priv = dev_get_priv ( dev ) ;
unsigned long clock = get_uart_clk ( 0 ) ;
while ( _uart_zynq_serial_putc ( regs , c ) = = - EAGAIN )
WATCHDOG_RESET ( ) ;
_uart_zynq_serial_setbrg ( priv - > regs , clock , baudrate ) ;
if ( c = = ' \n ' ) {
while ( _uart_zynq_serial_putc ( regs , ' \r ' ) = = - EAGAIN )
WATCHDOG_RESET ( ) ;
}
return 0 ;
}
static void uart_zynq_serial_puts ( const char * s , const int port )
static int zynq_serial_probe ( struct udevice * dev )
{
while ( * s )
uart_zynq_serial_putc ( * s + + , port ) ;
}
struct zynq_uart_priv * priv = dev_get_priv ( dev ) ;
static int uart_zynq_serial_tstc ( const int port )
{
struct uart_zynq * regs = uart_zynq_ports [ port ] ;
_uart_zynq_serial_init ( priv - > regs ) ;
return ( readl ( & regs - > channel_sts ) & ZYNQ_UART_SR_RXEMPTY ) = = 0 ;
return 0 ;
}
static int uart_ zynq_serial_getc( const int port )
static int zynq_serial_getc ( struct udevice * dev )
{
struct uart_zynq * regs = uart_zynq_ports [ port ] ;
struct zynq_uart_priv * priv = dev_get_priv ( dev ) ;
struct uart_zynq * regs = priv - > regs ;
if ( readl ( & regs - > channel_sts ) & ZYNQ_UART_SR_RXEMPTY )
return - EAGAIN ;
while ( ! uart_zynq_serial_tstc ( port ) )
WATCHDOG_RESET ( ) ;
return readl ( & regs - > tx_rx_fifo ) ;
}
/* Multi serial device functions */
# define DECLARE_PSSERIAL_FUNCTIONS(port) \
static int uart_zynq # # port # # _init ( void ) \
{ return uart_zynq_serial_init ( port ) ; } \
static void uart_zynq # # port # # _setbrg ( void ) \
{ return uart_zynq_serial_setbrg ( port ) ; } \
static int uart_zynq # # port # # _getc ( void ) \
{ return uart_zynq_serial_getc ( port ) ; } \
static int uart_zynq # # port # # _tstc ( void ) \
{ return uart_zynq_serial_tstc ( port ) ; } \
static void uart_zynq # # port # # _putc ( const char c ) \
{ uart_zynq_serial_putc ( c , port ) ; } \
static void uart_zynq # # port # # _puts ( const char * s ) \
{ uart_zynq_serial_puts ( s , port ) ; }
/* Serial device descriptor */
# define INIT_PSSERIAL_STRUCTURE(port, __name) { \
. name = __name , \
. start = uart_zynq # # port # # _init , \
. stop = NULL , \
. setbrg = uart_zynq # # port # # _setbrg , \
. getc = uart_zynq # # port # # _getc , \
. tstc = uart_zynq # # port # # _tstc , \
. putc = uart_zynq # # port # # _putc , \
. puts = uart_zynq # # port # # _puts , \
}
static int zynq_serial_putc ( struct udevice * dev , const char ch )
{
struct zynq_uart_priv * priv = dev_get_priv ( dev ) ;
DECLARE_PSSERIAL_FUNCTIONS ( 0 ) ;
static struct serial_device uart_zynq_serial0_device =
INIT_PSSERIAL_STRUCTURE ( 0 , " ttyPS0 " ) ;
DECLARE_PSSERIAL_FUNCTIONS ( 1 ) ;
static struct serial_device uart_zynq_serial1_device =
INIT_PSSERIAL_STRUCTURE ( 1 , " ttyPS1 " ) ;
return _uart_zynq_serial_putc ( priv - > regs , ch ) ;
}
__weak struct serial_device * default_serial_console ( void )
static int zynq_serial_pending ( struct udevice * dev , bool input )
{
const void * blob = gd - > fdt_blob ;
int node ;
unsigned int base_addr ;
struct zynq_uart_priv * priv = dev_get_priv ( dev ) ;
struct uart_zynq * regs = priv - > regs ;
node = fdt_path_offset ( blob , " serial0 " ) ;
if ( node < 0 )
return NULL ;
if ( input )
return ! ( readl ( & regs - > channel_sts ) & ZYNQ_UART_SR_RXEMPTY ) ;
else
return ! ! ( readl ( & regs - > channel_sts ) & ZYNQ_UART_SR_TXACTIVE ) ;
}
base_addr = fdtdec_get_addr ( blob , node , " reg " ) ;
if ( base_addr = = FDT_ADDR_T_NONE )
return NULL ;
static int zynq_serial_ofdata_to_platdata ( struct udevice * dev )
{
struct zynq_uart_priv * priv = dev_get_priv ( dev ) ;
fdt_addr_t addr ;
if ( base_addr = = ZYNQ_SERIAL_BASEADDR0 )
return & uart_zynq_serial0_device ;
addr = fdtdec_get_addr ( gd - > fdt_blob , dev - > of_offset , " reg " ) ;
if ( addr = = FDT_ADDR_T_NONE )
return - EINVAL ;
if ( base_addr = = ZYNQ_SERIAL_BASEADDR1 )
return & uart_zynq_serial1_device ;
priv - > regs = ( struct uart_zynq * ) addr ;
return NULL ;
return 0 ;
}
void zynq_serial_initialize ( void )
{
serial_register ( & uart_zynq_serial0_device ) ;
serial_register ( & uart_zynq_serial1_device ) ;
}
static const struct dm_serial_ops zynq_serial_ops = {
. putc = zynq_serial_putc ,
. pending = zynq_serial_pending ,
. getc = zynq_serial_getc ,
. setbrg = zynq_serial_setbrg ,
} ;
static const struct udevice_id zynq_serial_ids [ ] = {
{ . compatible = " xlnx,xuartps " } ,
{ . compatible = " cdns,uart-r1p8 " } ,
{ }
} ;
U_BOOT_DRIVER ( serial_s5p ) = {
. name = " serial_zynq " ,
. id = UCLASS_SERIAL ,
. of_match = zynq_serial_ids ,
. ofdata_to_platdata = zynq_serial_ofdata_to_platdata ,
. priv_auto_alloc_size = sizeof ( struct zynq_uart_priv ) ,
. probe = zynq_serial_probe ,
. ops = & zynq_serial_ops ,
. flags = DM_FLAG_PRE_RELOC ,
} ;
# ifdef CONFIG_DEBUG_UART_ZYNQ