2007-05-15 05:52:22 +10:00
/*
* udbg serial input / output routines for the Marvell MV64x60 ( Discovery ) .
*
* Author : Dale Farnsworth < dale @ farnsworth . org >
*
* 2007 ( c ) MontaVista Software , Inc . This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed " as is " without any warranty of any kind , whether express
* or implied .
*/
# include <asm/io.h>
# include <asm/prom.h>
# include <asm/udbg.h>
# include <sysdev/mv64x60.h>
# define MPSC_0_CR1_OFFSET 0x000c
# define MPSC_0_CR2_OFFSET 0x0010
# define MPSC_CHR_2_TCS (1 << 9)
# define MPSC_0_CHR_10_OFFSET 0x0030
# define MPSC_INTR_CAUSE_OFF_0 0x0004
# define MPSC_INTR_CAUSE_OFF_1 0x000c
# define MPSC_INTR_CAUSE_RCC (1<<6)
static void __iomem * mpsc_base ;
static void __iomem * mpsc_intr_cause ;
static void mv64x60_udbg_putc ( char c )
{
if ( c = = ' \n ' )
mv64x60_udbg_putc ( ' \r ' ) ;
while ( in_le32 ( mpsc_base + MPSC_0_CR2_OFFSET ) & MPSC_CHR_2_TCS )
;
out_le32 ( mpsc_base + MPSC_0_CR1_OFFSET , c ) ;
out_le32 ( mpsc_base + MPSC_0_CR2_OFFSET , MPSC_CHR_2_TCS ) ;
}
static int mv64x60_udbg_testc ( void )
{
return ( in_le32 ( mpsc_intr_cause ) & MPSC_INTR_CAUSE_RCC ) ! = 0 ;
}
static int mv64x60_udbg_getc ( void )
{
int cause = 0 ;
int c ;
while ( ! mv64x60_udbg_testc ( ) )
;
c = in_8 ( mpsc_base + MPSC_0_CHR_10_OFFSET + 2 ) ;
out_8 ( mpsc_base + MPSC_0_CHR_10_OFFSET + 2 , c ) ;
out_le32 ( mpsc_intr_cause , cause & ~ MPSC_INTR_CAUSE_RCC ) ;
return c ;
}
static int mv64x60_udbg_getc_poll ( void )
{
if ( ! mv64x60_udbg_testc ( ) )
return - 1 ;
return mv64x60_udbg_getc ( ) ;
}
static void mv64x60_udbg_init ( void )
{
struct device_node * np , * mpscintr , * stdout = NULL ;
const char * path ;
const phandle * ph ;
struct resource r [ 2 ] ;
const int * block_index ;
int intr_cause_offset ;
int err ;
path = of_get_property ( of_chosen , " linux,stdout-path " , NULL ) ;
if ( ! path )
return ;
stdout = of_find_node_by_path ( path ) ;
if ( ! stdout )
return ;
2013-12-11 10:48:45 +00:00
for_each_compatible_node ( np , NULL , " marvell,mv64360-mpsc " ) {
2007-05-15 05:52:22 +10:00
if ( np = = stdout )
break ;
2007-11-30 06:44:36 +11:00
}
2007-05-15 05:52:22 +10:00
of_node_put ( stdout ) ;
if ( ! np )
return ;
2008-04-22 07:02:56 +10:00
block_index = of_get_property ( np , " cell-index " , NULL ) ;
2007-05-15 05:52:22 +10:00
if ( ! block_index )
goto error ;
switch ( * block_index ) {
case 0 :
intr_cause_offset = MPSC_INTR_CAUSE_OFF_0 ;
break ;
case 1 :
intr_cause_offset = MPSC_INTR_CAUSE_OFF_1 ;
break ;
default :
goto error ;
}
err = of_address_to_resource ( np , 0 , & r [ 0 ] ) ;
if ( err )
goto error ;
ph = of_get_property ( np , " mpscintr " , NULL ) ;
mpscintr = of_find_node_by_phandle ( * ph ) ;
if ( ! mpscintr )
goto error ;
err = of_address_to_resource ( mpscintr , 0 , & r [ 1 ] ) ;
of_node_put ( mpscintr ) ;
if ( err )
goto error ;
of_node_put ( np ) ;
2011-06-09 09:13:32 -07:00
mpsc_base = ioremap ( r [ 0 ] . start , resource_size ( & r [ 0 ] ) ) ;
2007-05-15 05:52:22 +10:00
if ( ! mpsc_base )
return ;
2011-06-09 09:13:32 -07:00
mpsc_intr_cause = ioremap ( r [ 1 ] . start , resource_size ( & r [ 1 ] ) ) ;
2007-05-15 05:52:22 +10:00
if ( ! mpsc_intr_cause ) {
iounmap ( mpsc_base ) ;
return ;
}
mpsc_intr_cause + = intr_cause_offset ;
udbg_putc = mv64x60_udbg_putc ;
udbg_getc = mv64x60_udbg_getc ;
udbg_getc_poll = mv64x60_udbg_getc_poll ;
return ;
error :
of_node_put ( np ) ;
}
void mv64x60_init_early ( void )
{
mv64x60_udbg_init ( ) ;
}