2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-09-06 05:56:02 +04:00
/*
2011-03-31 05:57:33 +04:00
* udbg for NS16550 compatible serial ports
2005-09-06 05:56:02 +04:00
*
* Copyright ( C ) 2001 - 2005 PPC 64 Team , IBM Corp
*/
# include <linux/types.h>
2005-09-06 05:57:00 +04:00
# include <asm/udbg.h>
2005-09-06 05:56:02 +04:00
# include <asm/io.h>
2011-04-15 02:32:08 +04:00
# include <asm/reg_a2.h>
2005-09-06 05:56:02 +04:00
extern u8 real_readb ( volatile u8 __iomem * addr ) ;
extern void real_writeb ( u8 data , volatile u8 __iomem * addr ) ;
2007-02-05 01:36:49 +03:00
extern u8 real_205_readb ( volatile u8 __iomem * addr ) ;
extern void real_205_writeb ( u8 data , volatile u8 __iomem * addr ) ;
2005-09-06 05:56:02 +04:00
2013-07-15 07:03:12 +04:00
# define UART_RBR 0
# define UART_IER 1
# define UART_FCR 2
# define UART_LCR 3
# define UART_MCR 4
# define UART_LSR 5
# define UART_MSR 6
# define UART_SCR 7
# define UART_THR UART_RBR
# define UART_IIR UART_FCR
# define UART_DLL UART_RBR
# define UART_DLM UART_IER
# define UART_DLAB UART_LCR
2005-09-06 05:56:02 +04:00
# define LSR_DR 0x01 /* Data ready */
# define LSR_OE 0x02 /* Overrun */
# define LSR_PE 0x04 /* Parity error */
# define LSR_FE 0x08 /* Framing error */
# define LSR_BI 0x10 /* Break */
# define LSR_THRE 0x20 /* Xmit holding register empty */
# define LSR_TEMT 0x40 /* Xmitter empty */
# define LSR_ERR 0x80 /* Error */
2005-11-23 09:56:06 +03:00
# define LCR_DLAB 0x80
2013-07-15 07:03:12 +04:00
static u8 ( * udbg_uart_in ) ( unsigned int reg ) ;
static void ( * udbg_uart_out ) ( unsigned int reg , u8 data ) ;
2005-09-06 05:56:02 +04:00
2013-07-15 07:03:12 +04:00
static void udbg_uart_flush ( void )
2005-09-06 05:56:02 +04:00
{
2013-07-15 07:03:12 +04:00
if ( ! udbg_uart_in )
return ;
/* wait for idle */
while ( ( udbg_uart_in ( UART_LSR ) & LSR_THRE ) = = 0 )
cpu_relax ( ) ;
2009-03-09 10:52:41 +03:00
}
2013-07-15 07:03:12 +04:00
static void udbg_uart_putc ( char c )
2009-03-09 10:52:41 +03:00
{
2013-07-15 07:03:12 +04:00
if ( ! udbg_uart_out )
return ;
if ( c = = ' \n ' )
udbg_uart_putc ( ' \r ' ) ;
udbg_uart_flush ( ) ;
udbg_uart_out ( UART_THR , c ) ;
2005-09-06 05:56:02 +04:00
}
2013-07-15 07:03:12 +04:00
static int udbg_uart_getc_poll ( void )
2005-09-06 05:56:02 +04:00
{
2014-11-11 01:12:28 +03:00
if ( ! udbg_uart_in )
return - 1 ;
if ( ! ( udbg_uart_in ( UART_LSR ) & LSR_DR ) )
2013-07-15 07:03:12 +04:00
return udbg_uart_in ( UART_RBR ) ;
2014-11-11 01:12:28 +03:00
2005-09-06 05:56:02 +04:00
return - 1 ;
}
2013-07-15 07:03:12 +04:00
static int udbg_uart_getc ( void )
2005-09-06 05:56:02 +04:00
{
2013-07-15 07:03:12 +04:00
if ( ! udbg_uart_in )
return - 1 ;
/* wait for char */
while ( ! ( udbg_uart_in ( UART_LSR ) & LSR_DR ) )
cpu_relax ( ) ;
return udbg_uart_in ( UART_RBR ) ;
}
static void udbg_use_uart ( void )
{
udbg_putc = udbg_uart_putc ;
udbg_flush = udbg_uart_flush ;
udbg_getc = udbg_uart_getc ;
udbg_getc_poll = udbg_uart_getc_poll ;
2005-09-06 05:56:02 +04:00
}
2013-07-15 07:03:12 +04:00
void udbg_uart_setup ( unsigned int speed , unsigned int clock )
2005-09-06 05:56:02 +04:00
{
2006-07-04 08:11:23 +04:00
unsigned int dll , base_bauds ;
2005-11-23 09:56:06 +03:00
2013-07-15 07:03:12 +04:00
if ( ! udbg_uart_out )
return ;
2006-07-04 08:11:23 +04:00
if ( clock = = 0 )
clock = 1843200 ;
2005-11-23 09:56:06 +03:00
if ( speed = = 0 )
speed = 9600 ;
2006-07-04 08:11:23 +04:00
base_bauds = clock / 16 ;
2005-11-23 09:56:06 +03:00
dll = base_bauds / speed ;
2005-09-06 05:56:02 +04:00
2013-07-15 07:03:12 +04:00
udbg_uart_out ( UART_LCR , 0x00 ) ;
udbg_uart_out ( UART_IER , 0xff ) ;
udbg_uart_out ( UART_IER , 0x00 ) ;
udbg_uart_out ( UART_LCR , LCR_DLAB ) ;
udbg_uart_out ( UART_DLL , dll & 0xff ) ;
udbg_uart_out ( UART_DLM , dll > > 8 ) ;
/* 8 data, 1 stop, no parity */
udbg_uart_out ( UART_LCR , 0x3 ) ;
/* RTS/DTR */
udbg_uart_out ( UART_MCR , 0x3 ) ;
/* Clear & enable FIFOs */
udbg_uart_out ( UART_FCR , 0x7 ) ;
2005-09-06 05:56:02 +04:00
}
2013-07-15 07:03:12 +04:00
unsigned int udbg_probe_uart_speed ( unsigned int clock )
2005-11-23 09:56:06 +03:00
{
unsigned int dll , dlm , divisor , prescaler , speed ;
u8 old_lcr ;
2013-07-15 07:03:12 +04:00
old_lcr = udbg_uart_in ( UART_LCR ) ;
2005-11-23 09:56:06 +03:00
/* select divisor latch registers. */
2013-07-15 07:03:12 +04:00
udbg_uart_out ( UART_LCR , old_lcr | LCR_DLAB ) ;
2005-11-23 09:56:06 +03:00
/* now, read the divisor */
2013-07-15 07:03:12 +04:00
dll = udbg_uart_in ( UART_DLL ) ;
dlm = udbg_uart_in ( UART_DLM ) ;
2005-11-23 09:56:06 +03:00
divisor = dlm < < 8 | dll ;
/* check prescaling */
2013-07-15 07:03:12 +04:00
if ( udbg_uart_in ( UART_MCR ) & 0x80 )
2005-11-23 09:56:06 +03:00
prescaler = 4 ;
else
prescaler = 1 ;
/* restore the LCR */
2013-07-15 07:03:12 +04:00
udbg_uart_out ( UART_LCR , old_lcr ) ;
2005-11-23 09:56:06 +03:00
/* calculate speed */
speed = ( clock / prescaler ) / ( divisor * 16 ) ;
/* sanity check */
2008-10-14 18:36:31 +04:00
if ( speed > ( clock / 16 ) )
2005-11-23 09:56:06 +03:00
speed = 9600 ;
return speed ;
}
2013-07-15 07:03:12 +04:00
static union {
unsigned char __iomem * mmio_base ;
unsigned long pio_base ;
} udbg_uart ;
static unsigned int udbg_uart_stride = 1 ;
static u8 udbg_uart_in_pio ( unsigned int reg )
2005-09-06 05:56:02 +04:00
{
2013-07-15 07:03:12 +04:00
return inb ( udbg_uart . pio_base + ( reg * udbg_uart_stride ) ) ;
2009-03-09 10:52:41 +03:00
}
2013-07-15 07:03:12 +04:00
static void udbg_uart_out_pio ( unsigned int reg , u8 data )
2009-03-09 10:52:41 +03:00
{
2013-07-15 07:03:12 +04:00
outb ( data , udbg_uart . pio_base + ( reg * udbg_uart_stride ) ) ;
2005-09-06 05:56:02 +04:00
}
2013-07-15 07:03:12 +04:00
void udbg_uart_init_pio ( unsigned long port , unsigned int stride )
2005-09-06 05:56:02 +04:00
{
2013-07-15 07:03:12 +04:00
if ( ! port )
return ;
udbg_uart . pio_base = port ;
udbg_uart_stride = stride ;
udbg_uart_in = udbg_uart_in_pio ;
udbg_uart_out = udbg_uart_out_pio ;
udbg_use_uart ( ) ;
}
2005-09-06 05:56:02 +04:00
2013-07-15 07:03:12 +04:00
static u8 udbg_uart_in_mmio ( unsigned int reg )
{
return in_8 ( udbg_uart . mmio_base + ( reg * udbg_uart_stride ) ) ;
2005-09-06 05:56:02 +04:00
}
2007-02-05 01:36:49 +03:00
2013-07-15 07:03:12 +04:00
static void udbg_uart_out_mmio ( unsigned int reg , u8 data )
2007-02-05 01:36:49 +03:00
{
2013-07-15 07:03:12 +04:00
out_8 ( udbg_uart . mmio_base + ( reg * udbg_uart_stride ) , data ) ;
}
void udbg_uart_init_mmio ( void __iomem * addr , unsigned int stride )
{
if ( ! addr )
return ;
udbg_uart . mmio_base = addr ;
udbg_uart_stride = stride ;
udbg_uart_in = udbg_uart_in_mmio ;
udbg_uart_out = udbg_uart_out_mmio ;
udbg_use_uart ( ) ;
2009-03-09 10:52:41 +03:00
}
2013-07-15 07:03:12 +04:00
# ifdef CONFIG_PPC_MAPLE
# define UDBG_UART_MAPLE_ADDR ((void __iomem *)0xf40003f8)
static u8 udbg_uart_in_maple ( unsigned int reg )
2009-03-09 10:52:41 +03:00
{
2013-07-15 07:03:12 +04:00
return real_readb ( UDBG_UART_MAPLE_ADDR + reg ) ;
2007-02-05 01:36:49 +03:00
}
2013-07-15 07:03:12 +04:00
static void udbg_uart_out_maple ( unsigned int reg , u8 val )
2007-02-05 01:36:49 +03:00
{
2013-07-15 07:03:12 +04:00
real_writeb ( val , UDBG_UART_MAPLE_ADDR + reg ) ;
}
2007-02-05 01:36:49 +03:00
2013-07-15 07:03:12 +04:00
void __init udbg_init_maple_realmode ( void )
{
udbg_uart_in = udbg_uart_in_maple ;
udbg_uart_out = udbg_uart_out_maple ;
udbg_use_uart ( ) ;
2007-02-05 01:36:49 +03:00
}
2013-07-15 07:03:12 +04:00
2007-02-05 01:36:49 +03:00
# endif /* CONFIG_PPC_MAPLE */
2007-05-08 06:59:31 +04:00
2013-07-15 07:03:12 +04:00
# ifdef CONFIG_PPC_PASEMI
# define UDBG_UART_PAS_ADDR ((void __iomem *)0xfcff03f8UL)
2007-05-08 06:59:31 +04:00
2013-07-15 07:03:12 +04:00
static u8 udbg_uart_in_pas ( unsigned int reg )
2007-05-08 06:59:31 +04:00
{
2013-07-15 07:03:12 +04:00
return real_205_readb ( UDBG_UART_PAS_ADDR + reg ) ;
2009-03-09 10:52:41 +03:00
}
2013-07-15 07:03:12 +04:00
static void udbg_uart_out_pas ( unsigned int reg , u8 val )
2009-03-09 10:52:41 +03:00
{
2013-07-15 07:03:12 +04:00
real_205_writeb ( val , UDBG_UART_PAS_ADDR + reg ) ;
2007-05-08 06:59:31 +04:00
}
2013-07-15 07:03:12 +04:00
void __init udbg_init_pas_realmode ( void )
2007-09-17 14:56:47 +04:00
{
2013-07-15 07:03:12 +04:00
udbg_uart_in = udbg_uart_in_pas ;
udbg_uart_out = udbg_uart_out_pas ;
udbg_use_uart ( ) ;
2007-09-17 14:56:47 +04:00
}
2013-07-15 07:03:12 +04:00
# endif /* CONFIG_PPC_PASEMI */
# ifdef CONFIG_PPC_EARLY_DEBUG_44x
# include <platforms/44x/44x.h>
static u8 udbg_uart_in_44x_as1 ( unsigned int reg )
2007-05-08 06:59:31 +04:00
{
2013-07-15 07:03:12 +04:00
return as1_readb ( ( void __iomem * ) PPC44x_EARLY_DEBUG_VIRTADDR + reg ) ;
}
2007-05-08 06:59:31 +04:00
2013-07-15 07:03:12 +04:00
static void udbg_uart_out_44x_as1 ( unsigned int reg , u8 val )
{
as1_writeb ( val , ( void __iomem * ) PPC44x_EARLY_DEBUG_VIRTADDR + reg ) ;
2007-05-08 06:59:31 +04:00
}
2007-12-21 07:39:26 +03:00
2013-07-15 07:03:12 +04:00
void __init udbg_init_44x_as1 ( void )
2007-12-21 07:39:26 +03:00
{
2013-07-15 07:03:12 +04:00
udbg_uart_in = udbg_uart_in_44x_as1 ;
udbg_uart_out = udbg_uart_out_44x_as1 ;
udbg_use_uart ( ) ;
2009-03-09 10:52:41 +03:00
}
2013-07-15 07:03:12 +04:00
# endif /* CONFIG_PPC_EARLY_DEBUG_44x */
# ifdef CONFIG_PPC_EARLY_DEBUG_40x
static u8 udbg_uart_in_40x ( unsigned int reg )
2009-03-09 10:52:41 +03:00
{
2013-07-15 07:03:12 +04:00
return real_readb ( ( void __iomem * ) CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
+ reg ) ;
2007-12-21 07:39:26 +03:00
}
2013-07-15 07:03:12 +04:00
static void udbg_uart_out_40x ( unsigned int reg , u8 val )
2007-12-21 07:39:26 +03:00
{
2013-07-15 07:03:12 +04:00
real_writeb ( val , ( void __iomem * ) CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
+ reg ) ;
2007-12-21 07:39:26 +03:00
}
void __init udbg_init_40x_realmode ( void )
{
2013-07-15 07:03:12 +04:00
udbg_uart_in = udbg_uart_in_40x ;
udbg_uart_out = udbg_uart_out_40x ;
udbg_use_uart ( ) ;
2007-12-21 07:39:26 +03:00
}
2013-07-15 07:03:12 +04:00
2007-12-21 07:39:26 +03:00
# endif /* CONFIG_PPC_EARLY_DEBUG_40x */