2005-09-06 11:56:02 +10:00
/*
* udbg for for NS16550 compatable serial ports
*
* Copyright ( C ) 2001 - 2005 PPC 64 Team , IBM Corp
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/types.h>
2005-09-06 11:57:00 +10:00
# include <asm/udbg.h>
2005-09-06 11:56:02 +10:00
# include <asm/io.h>
extern u8 real_readb ( volatile u8 __iomem * addr ) ;
extern void real_writeb ( u8 data , volatile u8 __iomem * addr ) ;
2007-02-04 16:36:49 -06:00
extern u8 real_205_readb ( volatile u8 __iomem * addr ) ;
extern void real_205_writeb ( u8 data , volatile u8 __iomem * addr ) ;
2005-09-06 11:56:02 +10:00
struct NS16550 {
/* this struct must be packed */
unsigned char rbr ; /* 0 */
unsigned char ier ; /* 1 */
unsigned char fcr ; /* 2 */
unsigned char lcr ; /* 3 */
unsigned char mcr ; /* 4 */
unsigned char lsr ; /* 5 */
unsigned char msr ; /* 6 */
unsigned char scr ; /* 7 */
} ;
# define thr rbr
# define iir fcr
# define dll rbr
# define dlm ier
# define dlab lcr
# 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 17:56:06 +11:00
# define LCR_DLAB 0x80
2005-09-06 11:56:02 +10:00
static volatile struct NS16550 __iomem * udbg_comport ;
2005-11-23 17:57:25 +11:00
static void udbg_550_putc ( char c )
2005-09-06 11:56:02 +10:00
{
if ( udbg_comport ) {
while ( ( in_8 ( & udbg_comport - > lsr ) & LSR_THRE ) = = 0 )
/* wait for idle */ ;
out_8 ( & udbg_comport - > thr , c ) ;
if ( c = = ' \n ' )
udbg_550_putc ( ' \r ' ) ;
}
}
static int udbg_550_getc_poll ( void )
{
if ( udbg_comport ) {
if ( ( in_8 ( & udbg_comport - > lsr ) & LSR_DR ) ! = 0 )
return in_8 ( & udbg_comport - > rbr ) ;
else
return - 1 ;
}
return - 1 ;
}
2005-11-30 16:54:12 +11:00
static int udbg_550_getc ( void )
2005-09-06 11:56:02 +10:00
{
if ( udbg_comport ) {
while ( ( in_8 ( & udbg_comport - > lsr ) & LSR_DR ) = = 0 )
/* wait for char */ ;
return in_8 ( & udbg_comport - > rbr ) ;
}
2005-11-30 16:54:12 +11:00
return - 1 ;
2005-09-06 11:56:02 +10:00
}
2005-11-23 17:56:06 +11:00
void udbg_init_uart ( void __iomem * comport , unsigned int speed ,
unsigned int clock )
2005-09-06 11:56:02 +10:00
{
2006-07-04 14:11:23 +10:00
unsigned int dll , base_bauds ;
2005-11-23 17:56:06 +11:00
2006-07-04 14:11:23 +10:00
if ( clock = = 0 )
clock = 1843200 ;
2005-11-23 17:56:06 +11:00
if ( speed = = 0 )
speed = 9600 ;
2006-07-04 14:11:23 +10:00
base_bauds = clock / 16 ;
2005-11-23 17:56:06 +11:00
dll = base_bauds / speed ;
2005-09-06 11:56:02 +10:00
if ( comport ) {
udbg_comport = ( struct NS16550 __iomem * ) comport ;
out_8 ( & udbg_comport - > lcr , 0x00 ) ;
out_8 ( & udbg_comport - > ier , 0xff ) ;
out_8 ( & udbg_comport - > ier , 0x00 ) ;
2005-11-23 17:56:06 +11:00
out_8 ( & udbg_comport - > lcr , LCR_DLAB ) ;
out_8 ( & udbg_comport - > dll , dll & 0xff ) ;
out_8 ( & udbg_comport - > dlm , dll > > 8 ) ;
/* 8 data, 1 stop, no parity */
out_8 ( & udbg_comport - > lcr , 0x03 ) ;
/* RTS/DTR */
out_8 ( & udbg_comport - > mcr , 0x03 ) ;
/* Clear & enable FIFOs */
out_8 ( & udbg_comport - > fcr , 0x07 ) ;
2005-09-06 11:56:42 +10:00
udbg_putc = udbg_550_putc ;
udbg_getc = udbg_550_getc ;
udbg_getc_poll = udbg_550_getc_poll ;
2005-09-06 11:56:02 +10:00
}
}
2005-11-23 17:56:06 +11:00
unsigned int udbg_probe_uart_speed ( void __iomem * comport , unsigned int clock )
{
unsigned int dll , dlm , divisor , prescaler , speed ;
u8 old_lcr ;
volatile struct NS16550 __iomem * port = comport ;
old_lcr = in_8 ( & port - > lcr ) ;
/* select divisor latch registers. */
out_8 ( & port - > lcr , LCR_DLAB ) ;
/* now, read the divisor */
dll = in_8 ( & port - > dll ) ;
dlm = in_8 ( & port - > dlm ) ;
divisor = dlm < < 8 | dll ;
/* check prescaling */
if ( in_8 ( & port - > mcr ) & 0x80 )
prescaler = 4 ;
else
prescaler = 1 ;
/* restore the LCR */
out_8 ( & port - > lcr , old_lcr ) ;
/* calculate speed */
speed = ( clock / prescaler ) / ( divisor * 16 ) ;
/* sanity check */
2005-12-20 16:16:26 -06:00
if ( speed < 0 | | speed > ( clock / 16 ) )
2005-11-23 17:56:06 +11:00
speed = 9600 ;
return speed ;
}
2005-09-06 11:56:02 +10:00
# ifdef CONFIG_PPC_MAPLE
2006-02-04 13:33:46 +01:00
void udbg_maple_real_putc ( char c )
2005-09-06 11:56:02 +10:00
{
if ( udbg_comport ) {
while ( ( real_readb ( & udbg_comport - > lsr ) & LSR_THRE ) = = 0 )
/* wait for idle */ ;
real_writeb ( c , & udbg_comport - > thr ) ; eieio ( ) ;
if ( c = = ' \n ' )
udbg_maple_real_putc ( ' \r ' ) ;
}
}
2006-01-11 11:54:09 +11:00
void __init udbg_init_maple_realmode ( void )
2005-09-06 11:56:02 +10:00
{
udbg_comport = ( volatile struct NS16550 __iomem * ) 0xf40003f8 ;
2005-09-06 11:56:42 +10:00
udbg_putc = udbg_maple_real_putc ;
udbg_getc = NULL ;
udbg_getc_poll = NULL ;
2005-09-06 11:56:02 +10:00
}
# endif /* CONFIG_PPC_MAPLE */
2007-02-04 16:36:49 -06:00
# ifdef CONFIG_PPC_PASEMI
void udbg_pas_real_putc ( char c )
{
if ( udbg_comport ) {
while ( ( real_205_readb ( & udbg_comport - > lsr ) & LSR_THRE ) = = 0 )
/* wait for idle */ ;
real_205_writeb ( c , & udbg_comport - > thr ) ; eieio ( ) ;
if ( c = = ' \n ' )
udbg_pas_real_putc ( ' \r ' ) ;
}
}
void udbg_init_pas_realmode ( void )
{
2007-03-14 09:18:30 +00:00
udbg_comport = ( volatile struct NS16550 __iomem * ) 0xfcff03f8UL ;
2007-02-04 16:36:49 -06:00
udbg_putc = udbg_pas_real_putc ;
udbg_getc = NULL ;
udbg_getc_poll = NULL ;
}
# endif /* CONFIG_PPC_MAPLE */
2007-05-08 12:59:31 +10:00
# ifdef CONFIG_PPC_EARLY_DEBUG_44x
# include <platforms/44x/44x.h>
static void udbg_44x_as1_putc ( char c )
{
if ( udbg_comport ) {
while ( ( as1_readb ( & udbg_comport - > lsr ) & LSR_THRE ) = = 0 )
/* wait for idle */ ;
as1_writeb ( c , & udbg_comport - > thr ) ; eieio ( ) ;
if ( c = = ' \n ' )
udbg_44x_as1_putc ( ' \r ' ) ;
}
}
void __init udbg_init_44x_as1 ( void )
{
udbg_comport =
( volatile struct NS16550 __iomem * ) PPC44x_EARLY_DEBUG_VIRTADDR ;
udbg_putc = udbg_44x_as1_putc ;
}
# endif /* CONFIG_PPC_EARLY_DEBUG_44x */