2007-08-20 21:40:02 +04:00
/*
* Old U - boot compatibility for PowerQUICC II
* ( a . k . a . 82 xx with CPM , not the 8240 family of chips )
*
* Author : Scott Wood < scottwood @ freescale . com >
*
* Copyright ( c ) 2007 Freescale Semiconductor , Inc .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation .
*/
# include "ops.h"
# include "stdio.h"
# include "cuboot.h"
# include "io.h"
2007-09-01 02:18:28 +04:00
# include "fsl-soc.h"
2007-08-20 21:40:02 +04:00
# define TARGET_CPM2
# define TARGET_HAS_ETH1
# include "ppcboot.h"
static bd_t bd ;
struct cs_range {
u32 csnum ;
u32 base ; /* must be zero */
u32 addr ;
u32 size ;
} ;
struct pci_range {
u32 flags ;
u32 pci_addr [ 2 ] ;
u32 phys_addr ;
u32 size [ 2 ] ;
} ;
struct cs_range cs_ranges_buf [ MAX_PROP_LEN / sizeof ( struct cs_range ) ] ;
struct pci_range pci_ranges_buf [ MAX_PROP_LEN / sizeof ( struct pci_range ) ] ;
/* Different versions of u-boot put the BCSR in different places, and
* some don ' t set up the PCI PIC at all , so we assume the device tree is
* sane and update the BRx registers appropriately .
*
2007-09-14 22:24:02 +04:00
* For any node defined as compatible with fsl , pq2 - localbus ,
* # address / # size must be 2 / 1 for the localbus , and 1 / 1 for the parent bus .
* Ranges must be for whole chip selects .
2007-08-20 21:40:02 +04:00
*/
static void update_cs_ranges ( void )
{
2007-09-14 22:24:02 +04:00
void * bus_node , * parent_node ;
2007-08-20 21:40:02 +04:00
u32 * ctrl_addr ;
unsigned long ctrl_size ;
u32 naddr , nsize ;
int len ;
int i ;
2007-09-14 22:24:02 +04:00
bus_node = finddevice ( " /localbus " ) ;
if ( ! bus_node | | ! dt_is_compatible ( bus_node , " fsl,pq2-localbus " ) )
2007-08-20 21:40:02 +04:00
return ;
dt_get_reg_format ( bus_node , & naddr , & nsize ) ;
if ( naddr ! = 2 | | nsize ! = 1 )
goto err ;
parent_node = get_parent ( bus_node ) ;
if ( ! parent_node )
goto err ;
dt_get_reg_format ( parent_node , & naddr , & nsize ) ;
if ( naddr ! = 1 | | nsize ! = 1 )
goto err ;
2007-09-14 22:24:02 +04:00
if ( ! dt_xlate_reg ( bus_node , 0 , ( unsigned long * ) & ctrl_addr ,
2007-08-20 21:40:02 +04:00
& ctrl_size ) )
goto err ;
len = getprop ( bus_node , " ranges " , cs_ranges_buf , sizeof ( cs_ranges_buf ) ) ;
for ( i = 0 ; i < len / sizeof ( struct cs_range ) ; i + + ) {
u32 base , option ;
int cs = cs_ranges_buf [ i ] . csnum ;
if ( cs > = ctrl_size / 8 )
goto err ;
if ( cs_ranges_buf [ i ] . base ! = 0 )
goto err ;
base = in_be32 ( & ctrl_addr [ cs * 2 ] ) ;
/* If CS is already valid, use the existing flags.
* Otherwise , guess a sane default .
*/
if ( base & 1 ) {
base & = 0x7fff ;
option = in_be32 ( & ctrl_addr [ cs * 2 + 1 ] ) & 0x7fff ;
} else {
base = 0x1801 ;
option = 0x10 ;
}
out_be32 ( & ctrl_addr [ cs * 2 ] , 0 ) ;
out_be32 ( & ctrl_addr [ cs * 2 + 1 ] ,
option | ~ ( cs_ranges_buf [ i ] . size - 1 ) ) ;
out_be32 ( & ctrl_addr [ cs * 2 ] , base | cs_ranges_buf [ i ] . addr ) ;
}
return ;
err :
2007-09-14 22:24:02 +04:00
printf ( " Bad /localbus node \r \n " ) ;
2007-08-20 21:40:02 +04:00
}
/* Older u-boots don't set PCI up properly. Update the hardware to match
* the device tree . The prefetch mem region and non - prefetch mem region
* must be contiguous in the host bus . As required by the PCI binding ,
* PCI # addr / # size must be 3 / 2. The parent bus must be 1 / 1. Only
* 32 - bit PCI is supported . All three region types ( prefetchable mem ,
* non - prefetchable mem , and I / O ) must be present .
*/
static void fixup_pci ( void )
{
struct pci_range * mem = NULL , * mmio = NULL ,
* io = NULL , * mem_base = NULL ;
u32 * pci_regs [ 3 ] ;
u8 * soc_regs ;
int i , len ;
2007-09-01 02:18:28 +04:00
void * node , * parent_node ;
2008-04-15 20:02:31 +04:00
u32 naddr , nsize , mem_pow2 , mem_mask ;
2007-08-20 21:40:02 +04:00
2007-08-30 21:06:21 +04:00
node = finddevice ( " /pci " ) ;
if ( ! node | | ! dt_is_compatible ( node , " fsl,pq2-pci " ) )
2007-08-20 21:40:02 +04:00
return ;
for ( i = 0 ; i < 3 ; i + + )
2007-08-30 21:06:21 +04:00
if ( ! dt_xlate_reg ( node , i ,
2007-08-20 21:40:02 +04:00
( unsigned long * ) & pci_regs [ i ] , NULL ) )
goto err ;
2007-09-01 02:18:28 +04:00
soc_regs = ( u8 * ) fsl_get_immr ( ) ;
if ( ! soc_regs )
2008-04-15 20:02:31 +04:00
goto unhandled ;
2007-08-20 21:40:02 +04:00
2007-08-30 21:06:21 +04:00
dt_get_reg_format ( node , & naddr , & nsize ) ;
2007-08-20 21:40:02 +04:00
if ( naddr ! = 3 | | nsize ! = 2 )
goto err ;
2007-08-30 21:06:21 +04:00
parent_node = get_parent ( node ) ;
2007-08-20 21:40:02 +04:00
if ( ! parent_node )
goto err ;
dt_get_reg_format ( parent_node , & naddr , & nsize ) ;
if ( naddr ! = 1 | | nsize ! = 1 )
2008-04-15 20:02:31 +04:00
goto unhandled ;
2007-08-20 21:40:02 +04:00
2007-08-30 21:06:21 +04:00
len = getprop ( node , " ranges " , pci_ranges_buf ,
2007-08-20 21:40:02 +04:00
sizeof ( pci_ranges_buf ) ) ;
for ( i = 0 ; i < len / sizeof ( struct pci_range ) ; i + + ) {
u32 flags = pci_ranges_buf [ i ] . flags & 0x43000000 ;
if ( flags = = 0x42000000 )
mem = & pci_ranges_buf [ i ] ;
else if ( flags = = 0x02000000 )
mmio = & pci_ranges_buf [ i ] ;
else if ( flags = = 0x01000000 )
io = & pci_ranges_buf [ i ] ;
}
if ( ! mem | | ! mmio | | ! io )
2008-04-15 20:02:31 +04:00
goto unhandled ;
if ( mem - > size [ 1 ] ! = mmio - > size [ 1 ] )
goto unhandled ;
if ( mem - > size [ 1 ] & ( mem - > size [ 1 ] - 1 ) )
goto unhandled ;
if ( io - > size [ 1 ] & ( io - > size [ 1 ] - 1 ) )
goto unhandled ;
2007-08-20 21:40:02 +04:00
if ( mem - > phys_addr + mem - > size [ 1 ] = = mmio - > phys_addr )
mem_base = mem ;
else if ( mmio - > phys_addr + mmio - > size [ 1 ] = = mem - > phys_addr )
mem_base = mmio ;
else
2008-04-15 20:02:31 +04:00
goto unhandled ;
2007-08-20 21:40:02 +04:00
out_be32 ( & pci_regs [ 1 ] [ 0 ] , mem_base - > phys_addr | 1 ) ;
out_be32 ( & pci_regs [ 2 ] [ 0 ] , ~ ( mem - > size [ 1 ] + mmio - > size [ 1 ] - 1 ) ) ;
out_be32 ( & pci_regs [ 1 ] [ 1 ] , io - > phys_addr | 1 ) ;
out_be32 ( & pci_regs [ 2 ] [ 1 ] , ~ ( io - > size [ 1 ] - 1 ) ) ;
out_le32 ( & pci_regs [ 0 ] [ 0 ] , mem - > pci_addr [ 1 ] > > 12 ) ;
out_le32 ( & pci_regs [ 0 ] [ 2 ] , mem - > phys_addr > > 12 ) ;
out_le32 ( & pci_regs [ 0 ] [ 4 ] , ( ~ ( mem - > size [ 1 ] - 1 ) > > 12 ) | 0xa0000000 ) ;
out_le32 ( & pci_regs [ 0 ] [ 6 ] , mmio - > pci_addr [ 1 ] > > 12 ) ;
out_le32 ( & pci_regs [ 0 ] [ 8 ] , mmio - > phys_addr > > 12 ) ;
out_le32 ( & pci_regs [ 0 ] [ 10 ] , ( ~ ( mmio - > size [ 1 ] - 1 ) > > 12 ) | 0x80000000 ) ;
out_le32 ( & pci_regs [ 0 ] [ 12 ] , io - > pci_addr [ 1 ] > > 12 ) ;
out_le32 ( & pci_regs [ 0 ] [ 14 ] , io - > phys_addr > > 12 ) ;
out_le32 ( & pci_regs [ 0 ] [ 16 ] , ( ~ ( io - > size [ 1 ] - 1 ) > > 12 ) | 0xc0000000 ) ;
/* Inbound translation */
out_le32 ( & pci_regs [ 0 ] [ 58 ] , 0 ) ;
out_le32 ( & pci_regs [ 0 ] [ 60 ] , 0 ) ;
2008-04-15 20:02:31 +04:00
mem_pow2 = 1 < < ( __ilog2_u32 ( bd . bi_memsize - 1 ) + 1 ) ;
mem_mask = ~ ( mem_pow2 - 1 ) > > 12 ;
out_le32 ( & pci_regs [ 0 ] [ 62 ] , 0xa0000000 | mem_mask ) ;
2007-08-20 21:40:02 +04:00
/* If PCI is disabled, drive RST high to enable. */
if ( ! ( in_le32 ( & pci_regs [ 0 ] [ 32 ] ) & 1 ) ) {
/* Tpvrh (Power valid to RST# high) 100 ms */
udelay ( 100000 ) ;
out_le32 ( & pci_regs [ 0 ] [ 32 ] , 1 ) ;
/* Trhfa (RST# high to first cfg access) 2^25 clocks */
udelay ( 1020000 ) ;
}
/* Enable bus master and memory access */
out_le32 ( & pci_regs [ 0 ] [ 64 ] , 0x80000004 ) ;
out_le32 ( & pci_regs [ 0 ] [ 65 ] , in_le32 ( & pci_regs [ 0 ] [ 65 ] ) | 6 ) ;
/* Park the bus on PCI, and elevate PCI's arbitration priority,
* as required by section 9.6 of the user ' s manual .
*/
out_8 ( & soc_regs [ 0x10028 ] , 3 ) ;
out_be32 ( ( u32 * ) & soc_regs [ 0x1002c ] , 0x01236745 ) ;
return ;
err :
2008-04-15 20:02:31 +04:00
printf ( " Bad PCI node -- using existing firmware setup. \r \n " ) ;
return ;
unhandled :
printf ( " Unsupported PCI node -- using existing firmware setup. \r \n " ) ;
2007-08-20 21:40:02 +04:00
}
static void pq2_platform_fixups ( void )
{
void * node ;
dt_fixup_memory ( bd . bi_memstart , bd . bi_memsize ) ;
dt_fixup_mac_addresses ( bd . bi_enetaddr , bd . bi_enet1addr ) ;
dt_fixup_cpu_clocks ( bd . bi_intfreq , bd . bi_busfreq / 4 , bd . bi_busfreq ) ;
node = finddevice ( " /soc/cpm " ) ;
2007-08-30 00:08:40 +04:00
if ( node )
2007-08-20 21:40:02 +04:00
setprop ( node , " clock-frequency " , & bd . bi_cpmfreq , 4 ) ;
2007-08-30 00:08:40 +04:00
node = finddevice ( " /soc/cpm/brg " ) ;
if ( node )
setprop ( node , " clock-frequency " , & bd . bi_brgfreq , 4 ) ;
2007-08-20 21:40:02 +04:00
update_cs_ranges ( ) ;
fixup_pci ( ) ;
}
void platform_init ( unsigned long r3 , unsigned long r4 , unsigned long r5 ,
unsigned long r6 , unsigned long r7 )
{
CUBOOT_INIT ( ) ;
2007-12-10 06:28:39 +03:00
fdt_init ( _dtb_start ) ;
2007-08-20 21:40:02 +04:00
serial_console_init ( ) ;
platform_ops . fixups = pq2_platform_fixups ;
}