2007-05-12 10:58:18 +10:00
/*
* Motorola ECC prpmc280 / f101 & prpmc2800 / f101e platform code .
*
* Author : Mark A . Greer < mgreer @ mvista . com >
*
* 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 <stdarg.h>
# include <stddef.h>
# include "types.h"
# include "elf.h"
# include "page.h"
# include "string.h"
# include "stdio.h"
# include "io.h"
# include "ops.h"
# include "gunzip_util.h"
# include "mv64x60.h"
# define KB 1024U
# define MB (KB*KB)
# define GB (KB*MB)
# define MHz (1000U*1000U)
# define GHz (1000U*MHz)
# define BOARD_MODEL "PrPMC2800"
# define BOARD_MODEL_MAX 32 /* max strlen(BOARD_MODEL) + 1 */
# define EEPROM2_ADDR 0xa4
# define EEPROM3_ADDR 0xa8
BSS_STACK ( 16 * KB ) ;
static u8 * bridge_base ;
typedef enum {
BOARD_MODEL_PRPMC280 ,
BOARD_MODEL_PRPMC2800 ,
} prpmc2800_board_model ;
typedef enum {
BRIDGE_TYPE_MV64360 ,
BRIDGE_TYPE_MV64362 ,
} prpmc2800_bridge_type ;
struct prpmc2800_board_info {
prpmc2800_board_model model ;
char variant ;
prpmc2800_bridge_type bridge_type ;
u8 subsys0 ;
u8 subsys1 ;
u8 vpd4 ;
u8 vpd4_mask ;
u32 core_speed ;
u32 mem_size ;
u32 boot_flash ;
u32 user_flash ;
} ;
static struct prpmc2800_board_info prpmc2800_board_info [ ] = {
{
. model = BOARD_MODEL_PRPMC280 ,
. variant = ' a ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xff ,
. subsys1 = 0xff ,
. vpd4 = 0x00 ,
. vpd4_mask = 0x0f ,
. core_speed = 1 * GHz ,
. mem_size = 512 * MB ,
. boot_flash = 1 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC280 ,
. variant = ' b ' ,
. bridge_type = BRIDGE_TYPE_MV64362 ,
. subsys0 = 0xff ,
. subsys1 = 0xff ,
. vpd4 = 0x01 ,
. vpd4_mask = 0x0f ,
. core_speed = 1 * GHz ,
. mem_size = 512 * MB ,
. boot_flash = 0 ,
. user_flash = 0 ,
} ,
{
. model = BOARD_MODEL_PRPMC280 ,
. variant = ' c ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xff ,
. subsys1 = 0xff ,
. vpd4 = 0x02 ,
. vpd4_mask = 0x0f ,
. core_speed = 733 * MHz ,
. mem_size = 512 * MB ,
. boot_flash = 1 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC280 ,
. variant = ' d ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xff ,
. subsys1 = 0xff ,
. vpd4 = 0x03 ,
. vpd4_mask = 0x0f ,
. core_speed = 1 * GHz ,
. mem_size = 1 * GB ,
. boot_flash = 1 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC280 ,
. variant = ' e ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xff ,
. subsys1 = 0xff ,
. vpd4 = 0x04 ,
. vpd4_mask = 0x0f ,
. core_speed = 1 * GHz ,
. mem_size = 512 * MB ,
. boot_flash = 1 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC280 ,
. variant = ' f ' ,
. bridge_type = BRIDGE_TYPE_MV64362 ,
. subsys0 = 0xff ,
. subsys1 = 0xff ,
. vpd4 = 0x05 ,
. vpd4_mask = 0x0f ,
. core_speed = 733 * MHz ,
. mem_size = 128 * MB ,
. boot_flash = 1 * MB ,
. user_flash = 0 ,
} ,
{
. model = BOARD_MODEL_PRPMC280 ,
. variant = ' g ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xff ,
. subsys1 = 0xff ,
. vpd4 = 0x06 ,
. vpd4_mask = 0x0f ,
. core_speed = 1 * GHz ,
. mem_size = 256 * MB ,
. boot_flash = 1 * MB ,
. user_flash = 0 ,
} ,
{
. model = BOARD_MODEL_PRPMC280 ,
. variant = ' h ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xff ,
. subsys1 = 0xff ,
. vpd4 = 0x07 ,
. vpd4_mask = 0x0f ,
. core_speed = 1 * GHz ,
. mem_size = 1 * GB ,
. boot_flash = 1 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC2800 ,
. variant = ' a ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xb2 ,
. subsys1 = 0x8c ,
. vpd4 = 0x00 ,
. vpd4_mask = 0x00 ,
. core_speed = 1 * GHz ,
. mem_size = 512 * MB ,
. boot_flash = 2 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC2800 ,
. variant = ' b ' ,
. bridge_type = BRIDGE_TYPE_MV64362 ,
. subsys0 = 0xb2 ,
. subsys1 = 0x8d ,
. vpd4 = 0x00 ,
. vpd4_mask = 0x00 ,
. core_speed = 1 * GHz ,
. mem_size = 512 * MB ,
. boot_flash = 0 ,
. user_flash = 0 ,
} ,
{
. model = BOARD_MODEL_PRPMC2800 ,
. variant = ' c ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xb2 ,
. subsys1 = 0x8e ,
. vpd4 = 0x00 ,
. vpd4_mask = 0x00 ,
. core_speed = 733 * MHz ,
. mem_size = 512 * MB ,
. boot_flash = 2 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC2800 ,
. variant = ' d ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xb2 ,
. subsys1 = 0x8f ,
. vpd4 = 0x00 ,
. vpd4_mask = 0x00 ,
. core_speed = 1 * GHz ,
. mem_size = 1 * GB ,
. boot_flash = 2 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC2800 ,
. variant = ' e ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xa2 ,
. subsys1 = 0x8a ,
. vpd4 = 0x00 ,
. vpd4_mask = 0x00 ,
. core_speed = 1 * GHz ,
. mem_size = 512 * MB ,
. boot_flash = 2 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC2800 ,
. variant = ' f ' ,
. bridge_type = BRIDGE_TYPE_MV64362 ,
. subsys0 = 0xa2 ,
. subsys1 = 0x8b ,
. vpd4 = 0x00 ,
. vpd4_mask = 0x00 ,
. core_speed = 733 * MHz ,
. mem_size = 128 * MB ,
. boot_flash = 2 * MB ,
. user_flash = 0 ,
} ,
{
. model = BOARD_MODEL_PRPMC2800 ,
. variant = ' g ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xa2 ,
. subsys1 = 0x8c ,
. vpd4 = 0x00 ,
. vpd4_mask = 0x00 ,
. core_speed = 1 * GHz ,
. mem_size = 2 * GB ,
. boot_flash = 2 * MB ,
. user_flash = 64 * MB ,
} ,
{
. model = BOARD_MODEL_PRPMC2800 ,
. variant = ' h ' ,
. bridge_type = BRIDGE_TYPE_MV64360 ,
. subsys0 = 0xa2 ,
. subsys1 = 0x8d ,
. vpd4 = 0x00 ,
. vpd4_mask = 0x00 ,
. core_speed = 733 * MHz ,
. mem_size = 1 * GB ,
. boot_flash = 2 * MB ,
. user_flash = 64 * MB ,
} ,
} ;
static struct prpmc2800_board_info * prpmc2800_get_board_info ( u8 * vpd )
{
struct prpmc2800_board_info * bip ;
int i ;
for ( i = 0 , bip = prpmc2800_board_info ; i < ARRAY_SIZE ( prpmc2800_board_info ) ;
i + + , bip + + )
if ( ( vpd [ 0 ] = = bip - > subsys0 ) & & ( vpd [ 1 ] = = bip - > subsys1 )
& & ( ( vpd [ 4 ] & bip - > vpd4_mask ) = = bip - > vpd4 ) )
return bip ;
return NULL ;
}
/* Get VPD from i2c eeprom 2, then match it to a board info entry */
static struct prpmc2800_board_info * prpmc2800_get_bip ( void )
{
struct prpmc2800_board_info * bip ;
u8 vpd [ 5 ] ;
int rc ;
if ( mv64x60_i2c_open ( ) )
fatal ( " Error: Can't open i2c device \n \r " ) ;
/* Get VPD from i2c eeprom-2 */
memset ( vpd , 0 , sizeof ( vpd ) ) ;
rc = mv64x60_i2c_read ( EEPROM2_ADDR , vpd , 0x1fde , 2 , sizeof ( vpd ) ) ;
if ( rc < 0 )
fatal ( " Error: Couldn't read eeprom2 \n \r " ) ;
mv64x60_i2c_close ( ) ;
/* Get board type & related info */
bip = prpmc2800_get_board_info ( vpd ) ;
if ( bip = = NULL ) {
printf ( " Error: Unsupported board or corrupted VPD: \n \r " ) ;
printf ( " 0x%x 0x%x 0x%x 0x%x 0x%x \n \r " ,
vpd [ 0 ] , vpd [ 1 ] , vpd [ 2 ] , vpd [ 3 ] , vpd [ 4 ] ) ;
printf ( " Using device tree defaults... \n \r " ) ;
}
return bip ;
}
static void prpmc2800_bridge_setup ( u32 mem_size )
{
u32 i , v [ 12 ] , enables , acc_bits ;
u32 pci_base_hi , pci_base_lo , size , buf [ 2 ] ;
unsigned long cpu_base ;
int rc ;
void * devp ;
u8 * bridge_pbase , is_coherent ;
struct mv64x60_cpu2pci_win * tbl ;
bridge_pbase = mv64x60_get_bridge_pbase ( ) ;
is_coherent = mv64x60_is_coherent ( ) ;
if ( is_coherent )
acc_bits = MV64x60_PCI_ACC_CNTL_SNOOP_WB
| MV64x60_PCI_ACC_CNTL_SWAP_NONE
| MV64x60_PCI_ACC_CNTL_MBURST_32_BYTES
| MV64x60_PCI_ACC_CNTL_RDSIZE_32_BYTES ;
else
acc_bits = MV64x60_PCI_ACC_CNTL_SNOOP_NONE
| MV64x60_PCI_ACC_CNTL_SWAP_NONE
| MV64x60_PCI_ACC_CNTL_MBURST_128_BYTES
| MV64x60_PCI_ACC_CNTL_RDSIZE_256_BYTES ;
mv64x60_config_ctlr_windows ( bridge_base , bridge_pbase , is_coherent ) ;
mv64x60_config_pci_windows ( bridge_base , bridge_pbase , 0 , 0 , mem_size ,
acc_bits ) ;
/* Get the cpu -> pci i/o & mem mappings from the device tree */
2008-04-08 08:09:51 +10:00
devp = find_node_by_compatible ( NULL , " marvell,mv64360-pci " ) ;
2007-05-12 10:58:18 +10:00
if ( devp = = NULL )
2008-04-08 08:09:51 +10:00
fatal ( " Error: Missing marvell,mv64360-pci "
2007-05-12 10:58:18 +10:00
" device tree node \n \r " ) ;
rc = getprop ( devp , " ranges " , v , sizeof ( v ) ) ;
if ( rc ! = sizeof ( v ) )
2008-04-08 08:09:51 +10:00
fatal ( " Error: Can't find marvell,mv64360-pci ranges "
2007-05-12 10:58:18 +10:00
" property \n \r " ) ;
/* Get the cpu -> pci i/o & mem mappings from the device tree */
2008-04-08 08:09:51 +10:00
devp = find_node_by_compatible ( NULL , " marvell,mv64360 " ) ;
2007-05-12 10:58:18 +10:00
if ( devp = = NULL )
2008-04-08 08:09:51 +10:00
fatal ( " Error: Missing marvell,mv64360 device tree node \n \r " ) ;
2007-05-12 10:58:18 +10:00
enables = in_le32 ( ( u32 * ) ( bridge_base + MV64x60_CPU_BAR_ENABLE ) ) ;
enables | = 0x0007fe00 ; /* Disable all cpu->pci windows */
out_le32 ( ( u32 * ) ( bridge_base + MV64x60_CPU_BAR_ENABLE ) , enables ) ;
for ( i = 0 ; i < 12 ; i + = 6 ) {
switch ( v [ i ] & 0xff000000 ) {
case 0x01000000 : /* PCI I/O Space */
tbl = mv64x60_cpu2pci_io ;
break ;
case 0x02000000 : /* PCI MEM Space */
tbl = mv64x60_cpu2pci_mem ;
break ;
default :
continue ;
}
pci_base_hi = v [ i + 1 ] ;
pci_base_lo = v [ i + 2 ] ;
cpu_base = v [ i + 3 ] ;
size = v [ i + 5 ] ;
buf [ 0 ] = cpu_base ;
buf [ 1 ] = size ;
if ( ! dt_xlate_addr ( devp , buf , sizeof ( buf ) , & cpu_base ) )
fatal ( " Error: Can't translate PCI address 0x%x \n \r " ,
( u32 ) cpu_base ) ;
mv64x60_config_cpu2pci_window ( bridge_base , 0 , pci_base_hi ,
pci_base_lo , cpu_base , size , tbl ) ;
}
enables & = ~ 0x00000600 ; /* Enable cpu->pci0 i/o, cpu->pci0 mem0 */
out_le32 ( ( u32 * ) ( bridge_base + MV64x60_CPU_BAR_ENABLE ) , enables ) ;
}
static void prpmc2800_fixups ( void )
{
u32 v [ 2 ] , l , mem_size ;
int rc ;
void * devp ;
char model [ BOARD_MODEL_MAX ] ;
struct prpmc2800_board_info * bip ;
bip = prpmc2800_get_bip ( ) ; /* Get board info based on VPD */
mem_size = ( bip ) ? bip - > mem_size : mv64x60_get_mem_size ( bridge_base ) ;
prpmc2800_bridge_setup ( mem_size ) ; /* Do necessary bridge setup */
/* If the VPD doesn't match what we know about, just use the
* defaults already in the device tree .
*/
if ( ! bip )
return ;
/* Know the board type so override device tree defaults */
/* Set /model appropriately */
devp = finddevice ( " / " ) ;
if ( devp = = NULL )
fatal ( " Error: Missing '/' device tree node \n \r " ) ;
memset ( model , 0 , BOARD_MODEL_MAX ) ;
strncpy ( model , BOARD_MODEL , BOARD_MODEL_MAX - 2 ) ;
l = strlen ( model ) ;
if ( bip - > model = = BOARD_MODEL_PRPMC280 )
l - - ;
model [ l + + ] = bip - > variant ;
model [ l + + ] = ' \0 ' ;
setprop ( devp , " model " , model , l ) ;
/* Set /cpus/PowerPC,7447/clock-frequency */
2008-04-08 08:09:51 +10:00
devp = find_node_by_prop_value_str ( NULL , " device_type " , " cpu " ) ;
2007-05-12 10:58:18 +10:00
if ( devp = = NULL )
2008-04-08 08:09:51 +10:00
fatal ( " Error: Missing proper cpu device tree node \n \r " ) ;
2007-05-12 10:58:18 +10:00
v [ 0 ] = bip - > core_speed ;
setprop ( devp , " clock-frequency " , & v [ 0 ] , sizeof ( v [ 0 ] ) ) ;
/* Set /memory/reg size */
devp = finddevice ( " /memory " ) ;
if ( devp = = NULL )
fatal ( " Error: Missing /memory device tree node \n \r " ) ;
v [ 0 ] = 0 ;
v [ 1 ] = bip - > mem_size ;
setprop ( devp , " reg " , v , sizeof ( v ) ) ;
2008-04-08 08:09:51 +10:00
/* Update model, if this is a mv64362 */
2007-05-12 10:58:18 +10:00
if ( bip - > bridge_type = = BRIDGE_TYPE_MV64362 ) {
2008-04-08 08:09:51 +10:00
devp = find_node_by_compatible ( NULL , " marvell,mv64360 " ) ;
2007-05-12 10:58:18 +10:00
if ( devp = = NULL )
2008-04-08 08:09:51 +10:00
fatal ( " Error: Missing marvell,mv64360 "
" device tree node \n \r " ) ;
2007-05-12 10:58:18 +10:00
setprop ( devp , " model " , " mv64362 " , strlen ( " mv64362 " ) + 1 ) ;
}
/* Set User FLASH size */
2008-04-08 08:09:51 +10:00
devp = find_node_by_compatible ( NULL , " direct-mapped " ) ;
2007-05-12 10:58:18 +10:00
if ( devp = = NULL )
fatal ( " Error: Missing User FLASH device tree node \n \r " ) ;
rc = getprop ( devp , " reg " , v , sizeof ( v ) ) ;
if ( rc ! = sizeof ( v ) )
fatal ( " Error: Can't find User FLASH reg property \n \r " ) ;
v [ 1 ] = bip - > user_flash ;
setprop ( devp , " reg " , v , sizeof ( v ) ) ;
}
# define MV64x60_MPP_CNTL_0 0xf000
# define MV64x60_MPP_CNTL_2 0xf008
# define MV64x60_GPP_IO_CNTL 0xf100
# define MV64x60_GPP_LEVEL_CNTL 0xf110
# define MV64x60_GPP_VALUE_SET 0xf118
static void prpmc2800_reset ( void )
{
u32 temp ;
udelay ( 5000000 ) ;
if ( bridge_base ! = 0 ) {
temp = in_le32 ( ( u32 * ) ( bridge_base + MV64x60_MPP_CNTL_0 ) ) ;
temp & = 0xFFFF0FFF ;
out_le32 ( ( u32 * ) ( bridge_base + MV64x60_MPP_CNTL_0 ) , temp ) ;
temp = in_le32 ( ( u32 * ) ( bridge_base + MV64x60_GPP_LEVEL_CNTL ) ) ;
temp | = 0x00000004 ;
out_le32 ( ( u32 * ) ( bridge_base + MV64x60_GPP_LEVEL_CNTL ) , temp ) ;
temp = in_le32 ( ( u32 * ) ( bridge_base + MV64x60_GPP_IO_CNTL ) ) ;
temp | = 0x00000004 ;
out_le32 ( ( u32 * ) ( bridge_base + MV64x60_GPP_IO_CNTL ) , temp ) ;
temp = in_le32 ( ( u32 * ) ( bridge_base + MV64x60_MPP_CNTL_2 ) ) ;
temp & = 0xFFFF0FFF ;
out_le32 ( ( u32 * ) ( bridge_base + MV64x60_MPP_CNTL_2 ) , temp ) ;
temp = in_le32 ( ( u32 * ) ( bridge_base + MV64x60_GPP_LEVEL_CNTL ) ) ;
temp | = 0x00080000 ;
out_le32 ( ( u32 * ) ( bridge_base + MV64x60_GPP_LEVEL_CNTL ) , temp ) ;
temp = in_le32 ( ( u32 * ) ( bridge_base + MV64x60_GPP_IO_CNTL ) ) ;
temp | = 0x00080000 ;
out_le32 ( ( u32 * ) ( bridge_base + MV64x60_GPP_IO_CNTL ) , temp ) ;
out_le32 ( ( u32 * ) ( bridge_base + MV64x60_GPP_VALUE_SET ) ,
0x00080004 ) ;
}
for ( ; ; ) ;
}
# define HEAP_SIZE (16*MB)
static struct gunzip_state gzstate ;
void platform_init ( unsigned long r3 , unsigned long r4 , unsigned long r5 ,
unsigned long r6 , unsigned long r7 )
{
struct elf_info ei ;
char * heap_start , * dtb ;
int dt_size = _dtb_end - _dtb_start ;
void * vmlinuz_addr = _vmlinux_start ;
unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start ;
char elfheader [ 256 ] ;
if ( dt_size < = 0 ) /* No fdt */
exit ( ) ;
/*
* Start heap after end of the kernel ( after decompressed to
* address 0 ) or the end of the zImage , whichever is higher .
* That ' s so things allocated by simple_alloc won ' t overwrite
* any part of the zImage and the kernel won ' t overwrite the dtb
* when decompressed & relocated .
*/
gunzip_start ( & gzstate , vmlinuz_addr , vmlinuz_size ) ;
gunzip_exactly ( & gzstate , elfheader , sizeof ( elfheader ) ) ;
if ( ! parse_elf32 ( elfheader , & ei ) )
exit ( ) ;
heap_start = ( char * ) ( ei . memsize + ei . elfoffset ) ; /* end of kernel*/
heap_start = max ( heap_start , ( char * ) _end ) ; /* end of zImage */
if ( ( unsigned ) simple_alloc_init ( heap_start , HEAP_SIZE , 2 * KB , 16 )
> ( 128 * MB ) )
exit ( ) ;
/* Relocate dtb to safe area past end of zImage & kernel */
dtb = malloc ( dt_size ) ;
if ( ! dtb )
exit ( ) ;
memmove ( dtb , _dtb_start , dt_size ) ;
2007-12-10 14:28:39 +11:00
fdt_init ( dtb ) ;
2007-05-12 10:58:18 +10:00
bridge_base = mv64x60_get_bridge_base ( ) ;
platform_ops . fixups = prpmc2800_fixups ;
platform_ops . exit = prpmc2800_reset ;
if ( serial_console_init ( ) < 0 )
exit ( ) ;
}
/* _zimage_start called very early--need to turn off external interrupts */
asm ( " .globl _zimage_start \n \
_zimage_start : \ n \
mfmsr 10 \ n \
rlwinm 10 , 10 , 0 , ~ ( 1 < < 15 ) /* Clear MSR_EE */ \ n \
sync \ n \
mtmsr 10 \ n \
isync \ n \
b _zimage_start_lib \ n \
" );