2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-09-06 11:56:02 +10:00
/*
2009-07-07 15:24:23 +05:30
* udbg for zilog scc ports as found on Apple PowerMacs
2005-09-06 11:56:02 +10:00
*
* Copyright ( C ) 2001 - 2005 PPC 64 Team , IBM Corp
*/
# 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/processor.h>
# include <asm/io.h>
# include <asm/prom.h>
# include <asm/pmac_feature.h>
extern u8 real_readb ( volatile u8 __iomem * addr ) ;
extern void real_writeb ( u8 data , volatile u8 __iomem * addr ) ;
# define SCC_TXRDY 4
# define SCC_RXRDY 1
static volatile u8 __iomem * sccc ;
static volatile u8 __iomem * sccd ;
2005-11-23 17:57:25 +11:00
static void udbg_scc_putc ( char c )
2005-09-06 11:56:02 +10:00
{
if ( sccc ) {
while ( ( in_8 ( sccc ) & SCC_TXRDY ) = = 0 )
;
out_8 ( sccd , c ) ;
if ( c = = ' \n ' )
udbg_scc_putc ( ' \r ' ) ;
}
}
static int udbg_scc_getc_poll ( void )
{
if ( sccc ) {
if ( ( in_8 ( sccc ) & SCC_RXRDY ) ! = 0 )
return in_8 ( sccd ) ;
else
return - 1 ;
}
return - 1 ;
}
2005-11-30 16:54:12 +11:00
static int udbg_scc_getc ( void )
2005-09-06 11:56:02 +10:00
{
if ( sccc ) {
while ( ( in_8 ( sccc ) & SCC_RXRDY ) = = 0 )
;
return in_8 ( sccd ) ;
}
2005-11-30 16:54:12 +11:00
return - 1 ;
2005-09-06 11:56:02 +10:00
}
static unsigned char scc_inittab [ ] = {
13 , 0 , /* set baud rate divisor */
12 , 0 ,
14 , 1 , /* baud rate gen enable, src=rtxc */
11 , 0x50 , /* clocks = br gen */
5 , 0xea , /* tx 8 bits, assert DTR & RTS */
4 , 0x46 , /* x16 clock, 1 stop */
3 , 0xc1 , /* rx enable, 8 bits */
} ;
2005-11-23 17:57:25 +11:00
void udbg_scc_init ( int force_scc )
2005-09-06 11:56:02 +10:00
{
2006-07-12 15:40:29 +10:00
const u32 * reg ;
2005-09-06 11:56:02 +10:00
unsigned long addr ;
2005-11-23 17:57:25 +11:00
struct device_node * stdout = NULL , * escc = NULL , * macio = NULL ;
struct device_node * ch , * ch_def = NULL , * ch_a = NULL ;
2006-07-12 15:40:29 +10:00
const char * path ;
2018-03-28 21:30:28 +02:00
int i ;
2005-09-06 11:56:02 +10:00
2005-11-23 17:57:25 +11:00
escc = of_find_node_by_name ( NULL , " escc " ) ;
if ( escc = = NULL )
goto bail ;
macio = of_get_parent ( escc ) ;
if ( macio = = NULL )
goto bail ;
2007-04-03 22:26:41 +10:00
path = of_get_property ( of_chosen , " linux,stdout-path " , NULL ) ;
2005-11-23 17:57:25 +11:00
if ( path ! = NULL )
stdout = of_find_node_by_path ( path ) ;
for ( ch = NULL ; ( ch = of_get_next_child ( escc , ch ) ) ! = NULL ; ) {
if ( ch = = stdout )
ch_def = of_node_get ( ch ) ;
2018-12-05 13:50:18 -06:00
if ( of_node_name_eq ( ch , " ch-a " ) )
2005-11-23 17:57:25 +11:00
ch_a = of_node_get ( ch ) ;
}
if ( ch_def = = NULL & & ! force_scc )
goto bail ;
ch = ch_def ? ch_def : ch_a ;
2005-09-06 11:56:02 +10:00
/* Get address within mac-io ASIC */
2007-04-03 22:26:41 +10:00
reg = of_get_property ( escc , " reg " , NULL ) ;
2005-09-06 11:56:02 +10:00
if ( reg = = NULL )
2005-11-23 17:57:25 +11:00
goto bail ;
2005-09-06 11:56:02 +10:00
addr = reg [ 0 ] ;
2005-11-23 17:57:25 +11:00
2005-09-06 11:56:02 +10:00
/* Get address of mac-io PCI itself */
2007-04-03 22:26:41 +10:00
reg = of_get_property ( macio , " assigned-addresses " , NULL ) ;
2005-09-06 11:56:02 +10:00
if ( reg = = NULL )
2005-11-23 17:57:25 +11:00
goto bail ;
2005-09-06 11:56:02 +10:00
addr + = reg [ 2 ] ;
2005-11-23 17:57:25 +11:00
/* Lock the serial port */
pmac_call_feature ( PMAC_FTR_SCC_ENABLE , ch ,
PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON , 1 ) ;
if ( ch = = ch_a )
addr + = 0x20 ;
2006-03-23 17:38:10 +11:00
sccc = ioremap ( addr & PAGE_MASK , PAGE_SIZE ) ;
2005-09-06 11:56:02 +10:00
sccc + = addr & ~ PAGE_MASK ;
sccd = sccc + 0x10 ;
mb ( ) ;
for ( i = 20000 ; i ! = 0 ; - - i )
2018-03-28 21:30:28 +02:00
in_8 ( sccc ) ;
2005-09-06 11:56:02 +10:00
out_8 ( sccc , 0x09 ) ; /* reset A or B side */
out_8 ( sccc , 0xc0 ) ;
2006-10-03 14:47:58 +10:00
/* If SCC was the OF output port, read the BRG value, else
2008-07-28 12:06:19 +10:00
* Setup for 38400 or 57600 8 N1 depending on the machine
2006-10-03 14:47:58 +10:00
*/
if ( ch_def ! = NULL ) {
out_8 ( sccc , 13 ) ;
scc_inittab [ 1 ] = in_8 ( sccc ) ;
out_8 ( sccc , 12 ) ;
scc_inittab [ 3 ] = in_8 ( sccc ) ;
2010-02-01 21:34:14 -07:00
} else if ( of_machine_is_compatible ( " RackMac1,1 " )
| | of_machine_is_compatible ( " RackMac1,2 " )
| | of_machine_is_compatible ( " MacRISC4 " ) ) {
2008-07-28 12:06:19 +10:00
/* Xserves and G5s default to 57600 */
scc_inittab [ 1 ] = 0 ;
scc_inittab [ 3 ] = 0 ;
} else {
/* Others default to 38400 */
scc_inittab [ 1 ] = 0 ;
scc_inittab [ 3 ] = 1 ;
2006-10-03 14:47:58 +10:00
}
2005-09-06 11:56:02 +10:00
for ( i = 0 ; i < sizeof ( scc_inittab ) ; + + i )
out_8 ( sccc , scc_inittab [ i ] ) ;
2006-10-03 14:47:58 +10:00
2005-09-06 11:56:42 +10:00
udbg_putc = udbg_scc_putc ;
udbg_getc = udbg_scc_getc ;
udbg_getc_poll = udbg_scc_getc_poll ;
2005-09-06 11:56:02 +10:00
udbg_puts ( " Hello World ! \n " ) ;
2005-11-23 17:57:25 +11:00
bail :
of_node_put ( macio ) ;
of_node_put ( escc ) ;
of_node_put ( stdout ) ;
of_node_put ( ch_def ) ;
of_node_put ( ch_a ) ;
2005-09-06 11:56:02 +10:00
}
2005-11-23 17:57:25 +11:00
# ifdef CONFIG_PPC64
static void udbg_real_scc_putc ( char c )
2005-09-06 11:56:02 +10:00
{
while ( ( real_readb ( sccc ) & SCC_TXRDY ) = = 0 )
;
real_writeb ( c , sccd ) ;
if ( c = = ' \n ' )
udbg_real_scc_putc ( ' \r ' ) ;
}
2006-01-11 11:54:09 +11:00
void __init udbg_init_pmac_realmode ( void )
2005-09-06 11:56:02 +10:00
{
sccc = ( volatile u8 __iomem * ) 0x80013020ul ;
sccd = ( volatile u8 __iomem * ) 0x80013030ul ;
2005-09-06 11:56:42 +10:00
udbg_putc = udbg_real_scc_putc ;
udbg_getc = NULL ;
udbg_getc_poll = NULL ;
2005-09-06 11:56:02 +10:00
}
2005-11-23 17:57:25 +11:00
# endif /* CONFIG_PPC64 */