2005-04-16 15:20:36 -07:00
/*
* Copyright ( C ) Paul Mackerras 1997.
*
* 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 <stdarg.h>
2005-08-08 13:24:38 +10:00
# include <stddef.h>
# include "string.h"
# include "stdio.h"
# include "prom.h"
2005-06-08 15:12:00 +10:00
2005-04-16 15:20:36 -07:00
int ( * prom ) ( void * ) ;
2006-01-14 15:04:06 +11:00
phandle chosen_handle ;
ihandle stdout ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
int call_prom ( const char * service , int nargs , int nret , . . . )
2005-04-16 15:20:36 -07:00
{
2006-01-14 15:04:06 +11:00
int i ;
2005-04-16 15:20:36 -07:00
struct prom_args {
2006-01-14 15:04:06 +11:00
const char * service ;
2005-04-16 15:20:36 -07:00
int nargs ;
int nret ;
2006-01-14 15:04:06 +11:00
unsigned int args [ 12 ] ;
2005-04-16 15:20:36 -07:00
} args ;
2006-01-14 15:04:06 +11:00
va_list list ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
args . service = service ;
args . nargs = nargs ;
args . nret = nret ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
va_start ( list , nret ) ;
for ( i = 0 ; i < nargs ; i + + )
args . args [ i ] = va_arg ( list , unsigned int ) ;
va_end ( list ) ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
for ( i = 0 ; i < nret ; i + + )
args . args [ nargs + i ] = 0 ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
if ( prom ( & args ) < 0 )
return - 1 ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
return ( nret > 0 ) ? args . args [ nargs ] : 0 ;
2005-04-16 15:20:36 -07:00
}
2006-01-14 15:04:06 +11:00
int call_prom_ret ( const char * service , int nargs , int nret ,
unsigned int * rets , . . . )
2005-04-16 15:20:36 -07:00
{
2006-01-14 15:04:06 +11:00
int i ;
2005-04-16 15:20:36 -07:00
struct prom_args {
2006-01-14 15:04:06 +11:00
const char * service ;
2005-04-16 15:20:36 -07:00
int nargs ;
int nret ;
2006-01-14 15:04:06 +11:00
unsigned int args [ 12 ] ;
2005-04-16 15:20:36 -07:00
} args ;
2006-01-14 15:04:06 +11:00
va_list list ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
args . service = service ;
args . nargs = nargs ;
args . nret = nret ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
va_start ( list , rets ) ;
for ( i = 0 ; i < nargs ; i + + )
args . args [ i ] = va_arg ( list , unsigned int ) ;
va_end ( list ) ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
for ( i = 0 ; i < nret ; i + + )
args . args [ nargs + i ] = 0 ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
if ( prom ( & args ) < 0 )
return - 1 ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
if ( rets ! = ( void * ) 0 )
for ( i = 1 ; i < nret ; + + i )
rets [ i - 1 ] = args . args [ nargs + i ] ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
return ( nret > 0 ) ? args . args [ nargs ] : 0 ;
2005-04-16 15:20:36 -07:00
}
2006-01-14 15:04:06 +11:00
int write ( void * handle , void * ptr , int nb )
2005-04-16 15:20:36 -07:00
{
2006-01-14 15:04:06 +11:00
return call_prom ( " write " , 3 , 1 , handle , ptr , nb ) ;
2005-04-16 15:20:36 -07:00
}
2006-01-14 15:04:06 +11:00
/*
* Older OF ' s require that when claiming a specific range of addresses ,
* we claim the physical space in the / memory node and the virtual
* space in the chosen mmu node , and then do a map operation to
* map virtual to physical .
2005-08-08 13:24:38 +10:00
*/
2006-01-14 15:04:06 +11:00
static int need_map = - 1 ;
static ihandle chosen_mmu ;
static phandle memory ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
/* returns true if s2 is a prefix of s1 */
static int string_match ( const char * s1 , const char * s2 )
2005-04-16 15:20:36 -07:00
{
2006-01-14 15:04:06 +11:00
for ( ; * s2 ; + + s2 )
if ( * s1 + + ! = * s2 )
return 0 ;
return 1 ;
2005-04-16 15:20:36 -07:00
}
2006-01-14 15:04:06 +11:00
static int check_of_version ( void )
2005-04-16 15:20:36 -07:00
{
2006-01-14 15:04:06 +11:00
phandle oprom , chosen ;
char version [ 64 ] ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
oprom = finddevice ( " /openprom " ) ;
if ( oprom = = ( phandle ) - 1 )
2005-04-16 15:20:36 -07:00
return 0 ;
2006-01-14 15:04:06 +11:00
if ( getprop ( oprom , " model " , version , sizeof ( version ) ) < = 0 )
return 0 ;
version [ sizeof ( version ) - 1 ] = 0 ;
printf ( " OF version = '%s' \r \n " , version ) ;
if ( ! string_match ( version , " Open Firmware, 1. " )
& & ! string_match ( version , " FirmWorks,3. " ) )
return 0 ;
chosen = finddevice ( " /chosen " ) ;
if ( chosen = = ( phandle ) - 1 ) {
chosen = finddevice ( " /chosen@0 " ) ;
if ( chosen = = ( phandle ) - 1 ) {
printf ( " no chosen \n " ) ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
}
2006-01-14 15:04:06 +11:00
if ( getprop ( chosen , " mmu " , & chosen_mmu , sizeof ( chosen_mmu ) ) < = 0 ) {
printf ( " no mmu \n " ) ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
2006-01-14 15:04:06 +11:00
memory = ( ihandle ) call_prom ( " open " , 1 , 1 , " /memory " ) ;
if ( memory = = ( ihandle ) - 1 ) {
memory = ( ihandle ) call_prom ( " open " , 1 , 1 , " /memory@0 " ) ;
if ( memory = = ( ihandle ) - 1 ) {
printf ( " no memory node \n " ) ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
}
2006-01-14 15:04:06 +11:00
printf ( " old OF detected \r \n " ) ;
return 1 ;
2005-04-16 15:20:36 -07:00
}
2006-01-14 15:04:06 +11:00
void * claim ( unsigned long virt , unsigned long size , unsigned long align )
2005-04-16 15:20:36 -07:00
{
2006-01-14 15:04:06 +11:00
int ret ;
unsigned int result ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
if ( need_map < 0 )
need_map = check_of_version ( ) ;
if ( align | | ! need_map )
return ( void * ) call_prom ( " claim " , 3 , 1 , virt , size , align ) ;
2005-04-16 15:20:36 -07:00
2006-01-14 15:04:06 +11:00
ret = call_prom_ret ( " call-method " , 5 , 2 , & result , " claim " , memory ,
align , size , virt ) ;
if ( ret ! = 0 | | result = = - 1 )
return ( void * ) - 1 ;
ret = call_prom_ret ( " call-method " , 5 , 2 , & result , " claim " , chosen_mmu ,
align , size , virt ) ;
/* 0x12 == coherent + read/write */
ret = call_prom ( " call-method " , 6 , 1 , " map " , chosen_mmu ,
0x12 , size , virt , virt ) ;
return ( void * ) virt ;
2005-04-16 15:20:36 -07:00
}