2005-10-26 21:45:56 +10:00
/*
* CHRP pci routines .
*/
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/delay.h>
# include <linux/string.h>
# include <linux/init.h>
# include <asm/io.h>
# include <asm/pgtable.h>
# include <asm/irq.h>
# include <asm/hydra.h>
# include <asm/prom.h>
# include <asm/machdep.h>
# include <asm/sections.h>
# include <asm/pci-bridge.h>
# include <asm/grackle.h>
# include <asm/rtas.h>
2006-04-03 16:37:23 +10:00
# include "chrp.h"
2007-08-20 08:50:28 -05:00
# include "gg2.h"
2006-04-03 16:37:23 +10:00
2005-10-26 21:45:56 +10:00
/* LongTrail */
void __iomem * gg2_pci_config_base ;
/*
* The VLSI Golden Gate II has only 512 K of PCI configuration space , so we
* limit the bus number to 3 bits
*/
int gg2_read_config ( struct pci_bus * bus , unsigned int devfn , int off ,
int len , u32 * val )
{
volatile void __iomem * cfg_data ;
2009-04-30 03:10:11 +00:00
struct pci_controller * hose = pci_bus_to_host ( bus ) ;
2005-10-26 21:45:56 +10:00
if ( bus - > number > 7 )
return PCIBIOS_DEVICE_NOT_FOUND ;
/*
* Note : the caller has already checked that off is
* suitably aligned and that len is 1 , 2 or 4.
*/
cfg_data = hose - > cfg_data + ( ( bus - > number < < 16 ) | ( devfn < < 8 ) | off ) ;
switch ( len ) {
case 1 :
* val = in_8 ( cfg_data ) ;
break ;
case 2 :
* val = in_le16 ( cfg_data ) ;
break ;
default :
* val = in_le32 ( cfg_data ) ;
break ;
}
return PCIBIOS_SUCCESSFUL ;
}
int gg2_write_config ( struct pci_bus * bus , unsigned int devfn , int off ,
int len , u32 val )
{
volatile void __iomem * cfg_data ;
2009-04-30 03:10:11 +00:00
struct pci_controller * hose = pci_bus_to_host ( bus ) ;
2005-10-26 21:45:56 +10:00
if ( bus - > number > 7 )
return PCIBIOS_DEVICE_NOT_FOUND ;
/*
* Note : the caller has already checked that off is
* suitably aligned and that len is 1 , 2 or 4.
*/
cfg_data = hose - > cfg_data + ( ( bus - > number < < 16 ) | ( devfn < < 8 ) | off ) ;
switch ( len ) {
case 1 :
out_8 ( cfg_data , val ) ;
break ;
case 2 :
out_le16 ( cfg_data , val ) ;
break ;
default :
out_le32 ( cfg_data , val ) ;
break ;
}
return PCIBIOS_SUCCESSFUL ;
}
static struct pci_ops gg2_pci_ops =
{
2007-08-10 05:18:44 +10:00
. read = gg2_read_config ,
. write = gg2_write_config ,
2005-10-26 21:45:56 +10:00
} ;
/*
* Access functions for PCI config space using RTAS calls .
*/
int rtas_read_config ( struct pci_bus * bus , unsigned int devfn , int offset ,
int len , u32 * val )
{
2009-04-30 03:10:11 +00:00
struct pci_controller * hose = pci_bus_to_host ( bus ) ;
2005-10-26 21:45:56 +10:00
unsigned long addr = ( offset & 0xff ) | ( ( devfn & 0xff ) < < 8 )
| ( ( ( bus - > number - hose - > first_busno ) & 0xff ) < < 16 )
2007-06-27 01:17:57 -05:00
| ( hose - > global_number < < 24 ) ;
2005-10-26 21:45:56 +10:00
int ret = - 1 ;
int rval ;
rval = rtas_call ( rtas_token ( " read-pci-config " ) , 2 , 2 , & ret , addr , len ) ;
* val = ret ;
return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL ;
}
int rtas_write_config ( struct pci_bus * bus , unsigned int devfn , int offset ,
int len , u32 val )
{
2009-04-30 03:10:11 +00:00
struct pci_controller * hose = pci_bus_to_host ( bus ) ;
2005-10-26 21:45:56 +10:00
unsigned long addr = ( offset & 0xff ) | ( ( devfn & 0xff ) < < 8 )
| ( ( ( bus - > number - hose - > first_busno ) & 0xff ) < < 16 )
2007-06-27 01:17:57 -05:00
| ( hose - > global_number < < 24 ) ;
2005-10-26 21:45:56 +10:00
int rval ;
rval = rtas_call ( rtas_token ( " write-pci-config " ) , 3 , 1 , NULL ,
addr , len , val ) ;
return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL ;
}
static struct pci_ops rtas_pci_ops =
{
2007-08-10 05:18:44 +10:00
. read = rtas_read_config ,
. write = rtas_write_config ,
2005-10-26 21:45:56 +10:00
} ;
volatile struct Hydra __iomem * Hydra = NULL ;
int __init
hydra_init ( void )
{
struct device_node * np ;
2006-01-14 00:13:49 +00:00
struct resource r ;
2005-10-26 21:45:56 +10:00
2007-04-24 13:53:04 +10:00
np = of_find_node_by_name ( NULL , " mac-io " ) ;
if ( np = = NULL | | of_address_to_resource ( np , 0 , & r ) ) {
of_node_put ( np ) ;
2005-10-26 21:45:56 +10:00
return 0 ;
2007-04-24 13:53:04 +10:00
}
2008-12-02 03:34:46 +00:00
of_node_put ( np ) ;
2006-01-14 00:13:49 +00:00
Hydra = ioremap ( r . start , r . end - r . start ) ;
2006-06-12 15:18:31 -07:00
printk ( " Hydra Mac I/O at %llx \n " , ( unsigned long long ) r . start ) ;
2005-10-26 21:45:56 +10:00
printk ( " Hydra Feature_Control was %x " ,
in_le32 ( & Hydra - > Feature_Control ) ) ;
out_le32 ( & Hydra - > Feature_Control , ( HYDRA_FC_SCC_CELL_EN |
HYDRA_FC_SCSI_CELL_EN |
HYDRA_FC_SCCA_ENABLE |
HYDRA_FC_SCCB_ENABLE |
HYDRA_FC_ARB_BYPASS |
HYDRA_FC_MPIC_ENABLE |
HYDRA_FC_SLOW_SCC_PCLK |
HYDRA_FC_MPIC_IS_MASTER ) ) ;
printk ( " , now %x \n " , in_le32 ( & Hydra - > Feature_Control ) ) ;
return 1 ;
}
# define PRG_CL_RESET_VALID 0x00010000
static void __init
setup_python ( struct pci_controller * hose , struct device_node * dev )
{
u32 __iomem * reg ;
u32 val ;
2006-01-14 00:13:49 +00:00
struct resource r ;
2005-10-26 21:45:56 +10:00
2006-01-14 00:13:49 +00:00
if ( of_address_to_resource ( dev , 0 , & r ) ) {
printk ( KERN_ERR " No address for Python PCI controller \n " ) ;
return ;
}
2005-10-26 21:45:56 +10:00
/* Clear the magic go-slow bit */
2006-01-14 00:13:49 +00:00
reg = ioremap ( r . start + 0xf6000 , 0x40 ) ;
BUG_ON ( ! reg ) ;
2005-10-26 21:45:56 +10:00
val = in_be32 ( & reg [ 12 ] ) ;
if ( val & PRG_CL_RESET_VALID ) {
out_be32 ( & reg [ 12 ] , val & ~ PRG_CL_RESET_VALID ) ;
in_be32 ( & reg [ 12 ] ) ;
}
iounmap ( reg ) ;
2006-01-14 00:13:49 +00:00
2007-07-19 16:07:35 -05:00
setup_indirect_pci ( hose , r . start + 0xf8000 , r . start + 0xf8010 , 0 ) ;
2005-10-26 21:45:56 +10:00
}
/* Marvell Discovery II based Pegasos 2 */
static void __init setup_peg2 ( struct pci_controller * hose , struct device_node * dev )
{
2007-04-24 13:50:55 +10:00
struct device_node * root = of_find_node_by_path ( " / " ) ;
2005-10-26 21:45:56 +10:00
struct device_node * rtas ;
rtas = of_find_node_by_name ( root , " rtas " ) ;
if ( rtas ) {
hose - > ops = & rtas_pci_ops ;
2006-02-04 12:55:41 +01:00
of_node_put ( rtas ) ;
2005-10-26 21:45:56 +10:00
} else {
printk ( " RTAS supporting Pegasos OF not found, please upgrade "
" your firmware \n " ) ;
}
2008-12-11 09:46:44 +00:00
ppc_pci_add_flags ( PPC_PCI_REASSIGN_ALL_BUS ) ;
2007-04-24 13:50:55 +10:00
/* keep the reference to the root node */
2005-10-26 21:45:56 +10:00
}
void __init
chrp_find_bridges ( void )
{
struct device_node * dev ;
2006-07-12 15:40:05 +10:00
const int * bus_range ;
2005-10-26 21:45:56 +10:00
int len , index = - 1 ;
struct pci_controller * hose ;
2006-07-12 15:40:05 +10:00
const unsigned int * dma ;
const char * model , * machine ;
2005-10-26 21:45:56 +10:00
int is_longtrail = 0 , is_mot = 0 , is_pegasos = 0 ;
2007-04-24 13:50:55 +10:00
struct device_node * root = of_find_node_by_path ( " / " ) ;
2006-01-14 00:13:49 +00:00
struct resource r ;
2005-10-26 21:45:56 +10:00
/*
* The PCI host bridge nodes on some machines don ' t have
* properties to adequately identify them , so we have to
* look at what sort of machine this is as well .
*/
2007-04-03 22:26:41 +10:00
machine = of_get_property ( root , " model " , NULL ) ;
2005-10-26 21:45:56 +10:00
if ( machine ! = NULL ) {
is_longtrail = strncmp ( machine , " IBM,LongTrail " , 13 ) = = 0 ;
is_mot = strncmp ( machine , " MOT " , 3 ) = = 0 ;
if ( strncmp ( machine , " Pegasos2 " , 8 ) = = 0 )
is_pegasos = 2 ;
else if ( strncmp ( machine , " Pegasos " , 7 ) = = 0 )
is_pegasos = 1 ;
}
for ( dev = root - > child ; dev ! = NULL ; dev = dev - > sibling ) {
if ( dev - > type = = NULL | | strcmp ( dev - > type , " pci " ) ! = 0 )
continue ;
+ + index ;
/* The GG2 bridge on the LongTrail doesn't have an address */
2006-01-14 00:13:49 +00:00
if ( of_address_to_resource ( dev , 0 , & r ) & & ! is_longtrail ) {
2005-10-26 21:45:56 +10:00
printk ( KERN_WARNING " Can't use %s: no address \n " ,
dev - > full_name ) ;
continue ;
}
2007-04-03 22:26:41 +10:00
bus_range = of_get_property ( dev , " bus-range " , & len ) ;
2005-10-26 21:45:56 +10:00
if ( bus_range = = NULL | | len < 2 * sizeof ( int ) ) {
printk ( KERN_WARNING " Can't get bus-range for %s \n " ,
dev - > full_name ) ;
continue ;
}
if ( bus_range [ 1 ] = = bus_range [ 0 ] )
printk ( KERN_INFO " PCI bus %d " , bus_range [ 0 ] ) ;
else
printk ( KERN_INFO " PCI buses %d..%d " ,
bus_range [ 0 ] , bus_range [ 1 ] ) ;
2006-07-04 14:16:28 +10:00
printk ( " controlled by %s " , dev - > full_name ) ;
2006-01-14 00:13:49 +00:00
if ( ! is_longtrail )
2006-06-12 15:18:31 -07:00
printk ( " at %llx " , ( unsigned long long ) r . start ) ;
2005-10-26 21:45:56 +10:00
printk ( " \n " ) ;
2007-06-27 01:56:50 -05:00
hose = pcibios_alloc_controller ( dev ) ;
2005-10-26 21:45:56 +10:00
if ( ! hose ) {
printk ( " Can't allocate PCI controller structure for %s \n " ,
dev - > full_name ) ;
continue ;
}
2008-10-13 20:49:47 +00:00
hose - > first_busno = hose - > self_busno = bus_range [ 0 ] ;
2005-10-26 21:45:56 +10:00
hose - > last_busno = bus_range [ 1 ] ;
2007-04-03 22:26:41 +10:00
model = of_get_property ( dev , " model " , NULL ) ;
2005-10-26 21:45:56 +10:00
if ( model = = NULL )
model = " <none> " ;
2008-10-13 20:14:09 +00:00
if ( strncmp ( model , " IBM, Python " , 11 ) = = 0 ) {
2005-10-26 21:45:56 +10:00
setup_python ( hose , dev ) ;
} else if ( is_mot
| | strncmp ( model , " Motorola, Grackle " , 17 ) = = 0 ) {
setup_grackle ( hose ) ;
} else if ( is_longtrail ) {
void __iomem * p = ioremap ( GG2_PCI_CONFIG_BASE , 0x80000 ) ;
hose - > ops = & gg2_pci_ops ;
hose - > cfg_data = p ;
gg2_pci_config_base = p ;
} else if ( is_pegasos = = 1 ) {
2007-07-19 16:07:35 -05:00
setup_indirect_pci ( hose , 0xfec00cf8 , 0xfee00cfc , 0 ) ;
2005-10-26 21:45:56 +10:00
} else if ( is_pegasos = = 2 ) {
setup_peg2 ( hose , dev ) ;
2006-07-04 14:16:28 +10:00
} else if ( ! strncmp ( model , " IBM,CPC710 " , 10 ) ) {
setup_indirect_pci ( hose ,
r . start + 0x000f8000 ,
2007-07-19 16:07:35 -05:00
r . start + 0x000f8010 ,
0 ) ;
2006-07-04 14:16:28 +10:00
if ( index = = 0 ) {
2007-04-03 22:26:41 +10:00
dma = of_get_property ( dev , " system-dma-base " ,
& len ) ;
2006-07-04 14:16:28 +10:00
if ( dma & & len > = sizeof ( * dma ) ) {
dma = ( unsigned int * )
( ( ( unsigned long ) dma ) +
len - sizeof ( * dma ) ) ;
pci_dram_offset = * dma ;
}
}
2005-10-26 21:45:56 +10:00
} else {
printk ( " No methods for %s (model %s), using RTAS \n " ,
dev - > full_name , model ) ;
hose - > ops = & rtas_pci_ops ;
}
pci_process_bridge_OF_ranges ( hose , dev , index = = 0 ) ;
/* check the first bridge for a property that we can
use to set pci_dram_offset */
2007-04-03 22:26:41 +10:00
dma = of_get_property ( dev , " ibm,dma-ranges " , & len ) ;
2005-10-26 21:45:56 +10:00
if ( index = = 0 & & dma ! = NULL & & len > = 6 * sizeof ( * dma ) ) {
pci_dram_offset = dma [ 2 ] - dma [ 3 ] ;
printk ( " pci_dram_offset = %lx \n " , pci_dram_offset ) ;
}
}
2007-04-24 13:50:55 +10:00
of_node_put ( root ) ;
2006-07-04 14:16:28 +10:00
}
/* SL82C105 IDE Control/Status Register */
# define SL82C105_IDECSR 0x40
2007-12-10 15:29:22 +11:00
/* Fixup for Winbond ATA quirk, required for briq mostly because the
* 8259 is configured for level sensitive IRQ 14 and so wants the
* ATA controller to be set to fully native mode or bad things
* will happen .
*/
static void __devinit chrp_pci_fixup_winbond_ata ( struct pci_dev * sl82c105 )
2006-07-04 14:16:28 +10:00
{
u8 progif ;
2005-10-26 21:45:56 +10:00
2006-07-04 14:16:28 +10:00
/* If non-briq machines need that fixup too, please speak up */
if ( ! machine_is ( chrp ) | | _chrp_type ! = _CHRP_briq )
return ;
if ( ( sl82c105 - > class & 5 ) ! = 5 ) {
printk ( " W83C553: Switching SL82C105 IDE to PCI native mode \n " ) ;
/* Enable SL82C105 PCI native IDE mode */
pci_read_config_byte ( sl82c105 , PCI_CLASS_PROG , & progif ) ;
pci_write_config_byte ( sl82c105 , PCI_CLASS_PROG , progif | 0x05 ) ;
sl82c105 - > class | = 0x05 ;
/* Disable SL82C105 second port */
pci_write_config_word ( sl82c105 , SL82C105_IDECSR , 0x0003 ) ;
2007-12-10 15:29:22 +11:00
/* Clear IO BARs, they will be reassigned */
pci_write_config_dword ( sl82c105 , PCI_BASE_ADDRESS_0 , 0 ) ;
pci_write_config_dword ( sl82c105 , PCI_BASE_ADDRESS_1 , 0 ) ;
pci_write_config_dword ( sl82c105 , PCI_BASE_ADDRESS_2 , 0 ) ;
pci_write_config_dword ( sl82c105 , PCI_BASE_ADDRESS_3 , 0 ) ;
2006-07-04 14:16:28 +10:00
}
2005-10-26 21:45:56 +10:00
}
2007-12-10 15:29:22 +11:00
DECLARE_PCI_FIXUP_EARLY ( PCI_VENDOR_ID_WINBOND , PCI_DEVICE_ID_WINBOND_82C105 ,
chrp_pci_fixup_winbond_ata ) ;
2007-08-18 04:27:17 +10:00
/* Pegasos2 firmware version 20040810 configures the built-in IDE controller
* in legacy mode , but sets the PCI registers to PCI native mode .
* The chip can only operate in legacy mode , so force the PCI class into legacy
* mode as well . The same fixup must be done to the class - code property in
* the IDE node / pci @ 80000000 / ide @ C , 1
*/
2008-01-21 20:39:30 +11:00
static void chrp_pci_fixup_vt8231_ata ( struct pci_dev * viaide )
2007-08-18 04:27:17 +10:00
{
u8 progif ;
struct pci_dev * viaisa ;
if ( ! machine_is ( chrp ) | | _chrp_type ! = _CHRP_Pegasos )
return ;
if ( viaide - > irq ! = 14 )
return ;
viaisa = pci_get_device ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8231 , NULL ) ;
if ( ! viaisa )
return ;
2008-05-02 06:02:41 +02:00
dev_info ( & viaide - > dev , " Fixing VIA IDE, force legacy mode on \n " ) ;
2007-08-18 04:27:17 +10:00
pci_read_config_byte ( viaide , PCI_CLASS_PROG , & progif ) ;
pci_write_config_byte ( viaide , PCI_CLASS_PROG , progif & ~ 0x5 ) ;
viaide - > class & = ~ 0x5 ;
pci_dev_put ( viaisa ) ;
}
2008-01-21 20:39:30 +11:00
DECLARE_PCI_FIXUP_FINAL ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_82C586_1 , chrp_pci_fixup_vt8231_ata ) ;