2005-04-16 15:20:36 -07:00
/*
* Copyright ( C ) 2004 Benjamin Herrenschmuidt ( benh @ kernel . crashing . org ) ,
* IBM Corp .
*
* 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 .
*/
2006-10-09 13:25:15 +10:00
# undef DEBUG
2005-04-16 15:20:36 -07:00
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/delay.h>
# include <linux/string.h>
# include <linux/init.h>
# include <linux/bootmem.h>
2006-10-09 13:25:15 +10:00
# include <linux/irq.h>
2005-04-16 15:20:36 -07:00
# include <asm/sections.h>
# include <asm/io.h>
# include <asm/prom.h>
# include <asm/pci-bridge.h>
# include <asm/machdep.h>
# include <asm/iommu.h>
2005-09-28 02:50:25 +10:00
# include <asm/ppc-pci.h>
2005-04-16 15:20:36 -07:00
2005-10-29 22:07:56 +10:00
# include "maple.h"
2005-04-16 15:20:36 -07:00
# ifdef DEBUG
# define DBG(x...) printk(x)
# else
# define DBG(x...)
# endif
2006-10-09 13:25:15 +10:00
static struct pci_controller * u3_agp , * u3_ht , * u4_pcie ;
2005-04-16 15:20:36 -07:00
static int __init fixup_one_level_bus_range ( struct device_node * node , int higher )
{
for ( ; node ! = 0 ; node = node - > sibling ) {
2006-07-12 15:40:17 +10:00
const int * bus_range ;
const unsigned int * class_code ;
2005-04-16 15:20:36 -07:00
int len ;
/* For PCI<->PCI bridges or CardBus bridges, we go down */
2007-04-03 22:26:41 +10:00
class_code = of_get_property ( node , " class-code " , NULL ) ;
2005-04-16 15:20:36 -07:00
if ( ! class_code | | ( ( * class_code > > 8 ) ! = PCI_CLASS_BRIDGE_PCI & &
( * class_code > > 8 ) ! = PCI_CLASS_BRIDGE_CARDBUS ) )
continue ;
2007-04-03 22:26:41 +10:00
bus_range = of_get_property ( node , " bus-range " , & len ) ;
2005-04-16 15:20:36 -07:00
if ( bus_range ! = NULL & & len > 2 * sizeof ( int ) ) {
if ( bus_range [ 1 ] > higher )
higher = bus_range [ 1 ] ;
}
higher = fixup_one_level_bus_range ( node - > child , higher ) ;
}
return higher ;
}
/* This routine fixes the "bus-range" property of all bridges in the
* system since they tend to have their " last " member wrong on macs
*
* Note that the bus numbers manipulated here are OF bus numbers , they
* are not Linux bus numbers .
*/
static void __init fixup_bus_range ( struct device_node * bridge )
{
2006-07-12 15:40:17 +10:00
int * bus_range ;
struct property * prop ;
2005-04-16 15:20:36 -07:00
int len ;
/* Lookup the "bus-range" property for the hose */
2006-07-12 15:40:17 +10:00
prop = of_find_property ( bridge , " bus-range " , & len ) ;
if ( prop = = NULL | | prop - > value = = NULL | | len < 2 * sizeof ( int ) ) {
2005-04-16 15:20:36 -07:00
printk ( KERN_WARNING " Can't get bus-range for %s \n " ,
bridge - > full_name ) ;
return ;
}
2007-04-03 10:58:52 +10:00
bus_range = prop - > value ;
2005-04-16 15:20:36 -07:00
bus_range [ 1 ] = fixup_one_level_bus_range ( bridge - > child , bus_range [ 1 ] ) ;
}
2006-09-21 14:31:13 -05:00
static unsigned long u3_agp_cfa0 ( u8 devfn , u8 off )
{
return ( 1 < < ( unsigned long ) PCI_SLOT ( devfn ) ) |
( ( unsigned long ) PCI_FUNC ( devfn ) < < 8 ) |
( ( unsigned long ) off & 0xFCUL ) ;
}
2005-04-16 15:20:36 -07:00
2006-09-21 14:31:13 -05:00
static unsigned long u3_agp_cfa1 ( u8 bus , u8 devfn , u8 off )
{
return ( ( unsigned long ) bus < < 16 ) |
( ( unsigned long ) devfn < < 8 ) |
( ( unsigned long ) off & 0xFCUL ) |
1UL ;
}
2005-04-16 15:20:36 -07:00
2006-09-23 01:37:41 +01:00
static volatile void __iomem * u3_agp_cfg_access ( struct pci_controller * hose ,
2005-04-16 15:20:36 -07:00
u8 bus , u8 dev_fn , u8 offset )
{
unsigned int caddr ;
if ( bus = = hose - > first_busno ) {
if ( dev_fn < ( 11 < < 3 ) )
2006-09-23 01:37:41 +01:00
return NULL ;
2006-09-21 14:31:13 -05:00
caddr = u3_agp_cfa0 ( dev_fn , offset ) ;
2005-04-16 15:20:36 -07:00
} else
2006-09-21 14:31:13 -05:00
caddr = u3_agp_cfa1 ( bus , dev_fn , offset ) ;
2005-04-16 15:20:36 -07:00
/* Uninorth will return garbage if we don't read back the value ! */
do {
out_le32 ( hose - > cfg_addr , caddr ) ;
} while ( in_le32 ( hose - > cfg_addr ) ! = caddr ) ;
offset & = 0x07 ;
2006-09-23 01:37:41 +01:00
return hose - > cfg_data + offset ;
2005-04-16 15:20:36 -07:00
}
static int u3_agp_read_config ( struct pci_bus * bus , unsigned int devfn ,
int offset , int len , u32 * val )
{
struct pci_controller * hose ;
2006-09-23 01:37:41 +01:00
volatile void __iomem * addr ;
2005-04-16 15:20:36 -07:00
hose = pci_bus_to_host ( bus ) ;
if ( hose = = NULL )
return PCIBIOS_DEVICE_NOT_FOUND ;
addr = u3_agp_cfg_access ( hose , bus - > number , devfn , offset ) ;
if ( ! addr )
return PCIBIOS_DEVICE_NOT_FOUND ;
/*
* Note : the caller has already checked that offset is
* suitably aligned and that len is 1 , 2 or 4.
*/
switch ( len ) {
case 1 :
2006-09-23 01:37:41 +01:00
* val = in_8 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
case 2 :
2006-09-23 01:37:41 +01:00
* val = in_le16 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
default :
2006-09-23 01:37:41 +01:00
* val = in_le32 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
}
return PCIBIOS_SUCCESSFUL ;
}
static int u3_agp_write_config ( struct pci_bus * bus , unsigned int devfn ,
int offset , int len , u32 val )
{
struct pci_controller * hose ;
2006-09-23 01:37:41 +01:00
volatile void __iomem * addr ;
2005-04-16 15:20:36 -07:00
hose = pci_bus_to_host ( bus ) ;
if ( hose = = NULL )
return PCIBIOS_DEVICE_NOT_FOUND ;
addr = u3_agp_cfg_access ( hose , bus - > number , devfn , offset ) ;
if ( ! addr )
return PCIBIOS_DEVICE_NOT_FOUND ;
/*
* Note : the caller has already checked that offset is
* suitably aligned and that len is 1 , 2 or 4.
*/
switch ( len ) {
case 1 :
2006-09-23 01:37:41 +01:00
out_8 ( addr , val ) ;
( void ) in_8 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
case 2 :
2006-09-23 01:37:41 +01:00
out_le16 ( addr , val ) ;
( void ) in_le16 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
default :
2006-09-23 01:37:41 +01:00
out_le32 ( addr , val ) ;
( void ) in_le32 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
}
return PCIBIOS_SUCCESSFUL ;
}
static struct pci_ops u3_agp_pci_ops =
{
u3_agp_read_config ,
u3_agp_write_config
} ;
2006-09-21 14:31:13 -05:00
static unsigned long u3_ht_cfa0 ( u8 devfn , u8 off )
{
return ( devfn < < 8 ) | off ;
}
2005-04-16 15:20:36 -07:00
2006-09-21 14:31:13 -05:00
static unsigned long u3_ht_cfa1 ( u8 bus , u8 devfn , u8 off )
{
return u3_ht_cfa0 ( devfn , off ) + ( bus < < 16 ) + 0x01000000UL ;
}
2005-04-16 15:20:36 -07:00
2006-09-23 01:37:41 +01:00
static volatile void __iomem * u3_ht_cfg_access ( struct pci_controller * hose ,
2005-04-16 15:20:36 -07:00
u8 bus , u8 devfn , u8 offset )
{
if ( bus = = hose - > first_busno ) {
if ( PCI_SLOT ( devfn ) = = 0 )
2006-09-23 01:37:41 +01:00
return NULL ;
return hose - > cfg_data + u3_ht_cfa0 ( devfn , offset ) ;
2005-04-16 15:20:36 -07:00
} else
2006-09-23 01:37:41 +01:00
return hose - > cfg_data + u3_ht_cfa1 ( bus , devfn , offset ) ;
2005-04-16 15:20:36 -07:00
}
static int u3_ht_read_config ( struct pci_bus * bus , unsigned int devfn ,
int offset , int len , u32 * val )
{
struct pci_controller * hose ;
2006-09-23 01:37:41 +01:00
volatile void __iomem * addr ;
2005-04-16 15:20:36 -07:00
hose = pci_bus_to_host ( bus ) ;
if ( hose = = NULL )
return PCIBIOS_DEVICE_NOT_FOUND ;
2006-09-21 14:25:34 -05:00
if ( offset > 0xff )
return PCIBIOS_BAD_REGISTER_NUMBER ;
2005-04-16 15:20:36 -07:00
addr = u3_ht_cfg_access ( hose , bus - > number , devfn , offset ) ;
if ( ! addr )
return PCIBIOS_DEVICE_NOT_FOUND ;
/*
* Note : the caller has already checked that offset is
* suitably aligned and that len is 1 , 2 or 4.
*/
switch ( len ) {
case 1 :
2006-09-23 01:37:41 +01:00
* val = in_8 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
case 2 :
2006-09-23 01:37:41 +01:00
* val = in_le16 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
default :
2006-09-23 01:37:41 +01:00
* val = in_le32 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
}
return PCIBIOS_SUCCESSFUL ;
}
static int u3_ht_write_config ( struct pci_bus * bus , unsigned int devfn ,
int offset , int len , u32 val )
{
struct pci_controller * hose ;
2006-09-23 01:37:41 +01:00
volatile void __iomem * addr ;
2005-04-16 15:20:36 -07:00
hose = pci_bus_to_host ( bus ) ;
if ( hose = = NULL )
return PCIBIOS_DEVICE_NOT_FOUND ;
2006-09-21 14:25:34 -05:00
if ( offset > 0xff )
return PCIBIOS_BAD_REGISTER_NUMBER ;
2005-04-16 15:20:36 -07:00
addr = u3_ht_cfg_access ( hose , bus - > number , devfn , offset ) ;
if ( ! addr )
return PCIBIOS_DEVICE_NOT_FOUND ;
/*
* Note : the caller has already checked that offset is
* suitably aligned and that len is 1 , 2 or 4.
*/
switch ( len ) {
case 1 :
2006-09-23 01:37:41 +01:00
out_8 ( addr , val ) ;
( void ) in_8 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
case 2 :
2006-09-23 01:37:41 +01:00
out_le16 ( addr , val ) ;
( void ) in_le16 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
default :
2006-09-23 01:37:41 +01:00
out_le32 ( addr , val ) ;
( void ) in_le32 ( addr ) ;
2005-04-16 15:20:36 -07:00
break ;
}
return PCIBIOS_SUCCESSFUL ;
}
static struct pci_ops u3_ht_pci_ops =
{
u3_ht_read_config ,
u3_ht_write_config
} ;
2006-10-09 13:25:15 +10:00
static unsigned int u4_pcie_cfa0 ( unsigned int devfn , unsigned int off )
{
return ( 1 < < PCI_SLOT ( devfn ) ) |
( PCI_FUNC ( devfn ) < < 8 ) |
( ( off > > 8 ) < < 28 ) |
( off & 0xfcu ) ;
}
static unsigned int u4_pcie_cfa1 ( unsigned int bus , unsigned int devfn ,
unsigned int off )
{
return ( bus < < 16 ) |
( devfn < < 8 ) |
( ( off > > 8 ) < < 28 ) |
( off & 0xfcu ) | 1u ;
}
static volatile void __iomem * u4_pcie_cfg_access ( struct pci_controller * hose ,
u8 bus , u8 dev_fn , int offset )
{
unsigned int caddr ;
if ( bus = = hose - > first_busno )
caddr = u4_pcie_cfa0 ( dev_fn , offset ) ;
else
caddr = u4_pcie_cfa1 ( bus , dev_fn , offset ) ;
/* Uninorth will return garbage if we don't read back the value ! */
do {
out_le32 ( hose - > cfg_addr , caddr ) ;
} while ( in_le32 ( hose - > cfg_addr ) ! = caddr ) ;
offset & = 0x03 ;
return hose - > cfg_data + offset ;
}
static int u4_pcie_read_config ( struct pci_bus * bus , unsigned int devfn ,
int offset , int len , u32 * val )
{
struct pci_controller * hose ;
volatile void __iomem * addr ;
hose = pci_bus_to_host ( bus ) ;
if ( hose = = NULL )
return PCIBIOS_DEVICE_NOT_FOUND ;
if ( offset > = 0x1000 )
return PCIBIOS_BAD_REGISTER_NUMBER ;
addr = u4_pcie_cfg_access ( hose , bus - > number , devfn , offset ) ;
if ( ! addr )
return PCIBIOS_DEVICE_NOT_FOUND ;
/*
* Note : the caller has already checked that offset is
* suitably aligned and that len is 1 , 2 or 4.
*/
switch ( len ) {
case 1 :
* val = in_8 ( addr ) ;
break ;
case 2 :
* val = in_le16 ( addr ) ;
break ;
default :
* val = in_le32 ( addr ) ;
break ;
}
return PCIBIOS_SUCCESSFUL ;
}
static int u4_pcie_write_config ( struct pci_bus * bus , unsigned int devfn ,
int offset , int len , u32 val )
{
struct pci_controller * hose ;
volatile void __iomem * addr ;
hose = pci_bus_to_host ( bus ) ;
if ( hose = = NULL )
return PCIBIOS_DEVICE_NOT_FOUND ;
if ( offset > = 0x1000 )
return PCIBIOS_BAD_REGISTER_NUMBER ;
addr = u4_pcie_cfg_access ( hose , bus - > number , devfn , offset ) ;
if ( ! addr )
return PCIBIOS_DEVICE_NOT_FOUND ;
/*
* Note : the caller has already checked that offset is
* suitably aligned and that len is 1 , 2 or 4.
*/
switch ( len ) {
case 1 :
out_8 ( addr , val ) ;
( void ) in_8 ( addr ) ;
break ;
case 2 :
out_le16 ( addr , val ) ;
( void ) in_le16 ( addr ) ;
break ;
default :
out_le32 ( addr , val ) ;
( void ) in_le32 ( addr ) ;
break ;
}
return PCIBIOS_SUCCESSFUL ;
}
static struct pci_ops u4_pcie_pci_ops =
{
u4_pcie_read_config ,
u4_pcie_write_config
} ;
2005-04-16 15:20:36 -07:00
static void __init setup_u3_agp ( struct pci_controller * hose )
{
/* On G5, we move AGP up to high bus number so we don't need
* to reassign bus numbers for HT . If we ever have P2P bridges
2005-10-20 20:57:05 +10:00
* on AGP , we ' ll have to move pci_assign_all_buses to the
2005-04-16 15:20:36 -07:00
* pci_controller structure so we enable it for AGP and not for
* HT childs .
* We hard code the address because of the different size of
* the reg address cell , we shall fix that by killing struct
* reg_property and using some accessor functions instead
*/
2005-09-12 13:14:26 +10:00
hose - > first_busno = 0xf0 ;
2005-04-16 15:20:36 -07:00
hose - > last_busno = 0xff ;
hose - > ops = & u3_agp_pci_ops ;
hose - > cfg_addr = ioremap ( 0xf0000000 + 0x800000 , 0x1000 ) ;
hose - > cfg_data = ioremap ( 0xf0000000 + 0xc00000 , 0x1000 ) ;
u3_agp = hose ;
}
2006-10-09 13:25:15 +10:00
static void __init setup_u4_pcie ( struct pci_controller * hose )
{
/* We currently only implement the "non-atomic" config space, to
* be optimised later .
*/
hose - > ops = & u4_pcie_pci_ops ;
hose - > cfg_addr = ioremap ( 0xf0000000 + 0x800000 , 0x1000 ) ;
hose - > cfg_data = ioremap ( 0xf0000000 + 0xc00000 , 0x1000 ) ;
u4_pcie = hose ;
}
2005-04-16 15:20:36 -07:00
static void __init setup_u3_ht ( struct pci_controller * hose )
{
hose - > ops = & u3_ht_pci_ops ;
/* We hard code the address because of the different size of
* the reg address cell , we shall fix that by killing struct
* reg_property and using some accessor functions instead
*/
2006-09-23 01:37:41 +01:00
hose - > cfg_data = ioremap ( 0xf2000000 , 0x02000000 ) ;
2005-04-16 15:20:36 -07:00
hose - > first_busno = 0 ;
hose - > last_busno = 0xef ;
u3_ht = hose ;
}
2007-06-18 01:06:54 +02:00
static int __init maple_add_bridge ( struct device_node * dev )
2005-04-16 15:20:36 -07:00
{
int len ;
struct pci_controller * hose ;
char * disp_name ;
2006-07-12 15:40:17 +10:00
const int * bus_range ;
2005-04-16 15:20:36 -07:00
int primary = 1 ;
DBG ( " Adding PCI host bridge %s \n " , dev - > full_name ) ;
2007-04-03 22:26:41 +10:00
bus_range = of_get_property ( dev , " bus-range " , & len ) ;
2005-09-12 13:14:26 +10:00
if ( bus_range = = NULL | | len < 2 * sizeof ( int ) ) {
printk ( KERN_WARNING " Can't get bus-range for %s, assume bus 0 \n " ,
dev - > full_name ) ;
}
2005-04-16 15:20:36 -07:00
2005-11-15 16:05:33 +11:00
hose = pcibios_alloc_controller ( dev ) ;
2005-04-16 15:20:36 -07:00
if ( hose = = NULL )
return - ENOMEM ;
2005-09-12 13:14:26 +10:00
hose - > first_busno = bus_range ? bus_range [ 0 ] : 0 ;
hose - > last_busno = bus_range ? bus_range [ 1 ] : 0xff ;
2005-04-16 15:20:36 -07:00
disp_name = NULL ;
2007-05-03 17:26:52 +10:00
if ( of_device_is_compatible ( dev , " u3-agp " ) ) {
2005-09-12 13:14:26 +10:00
setup_u3_agp ( hose ) ;
disp_name = " U3-AGP " ;
primary = 0 ;
2007-05-03 17:26:52 +10:00
} else if ( of_device_is_compatible ( dev , " u3-ht " ) ) {
2005-09-12 13:14:26 +10:00
setup_u3_ht ( hose ) ;
disp_name = " U3-HT " ;
primary = 1 ;
2007-05-03 17:26:52 +10:00
} else if ( of_device_is_compatible ( dev , " u4-pcie " ) ) {
2006-10-09 13:25:15 +10:00
setup_u4_pcie ( hose ) ;
disp_name = " U4-PCIE " ;
primary = 0 ;
2005-09-12 13:14:26 +10:00
}
printk ( KERN_INFO " Found %s PCI host bridge. Firmware bus number: %d->%d \n " ,
disp_name , hose - > first_busno , hose - > last_busno ) ;
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
2005-10-22 15:03:21 +10:00
pci_process_bridge_OF_ranges ( hose , dev , primary ) ;
2005-04-16 15:20:36 -07:00
2005-09-12 13:14:26 +10:00
/* Fixup "bus-range" OF property */
fixup_bus_range ( dev ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2006-11-11 17:24:51 +11:00
void __devinit maple_pci_irq_fixup ( struct pci_dev * dev )
2005-04-16 15:20:36 -07:00
{
2006-11-11 17:24:51 +11:00
DBG ( " -> maple_pci_irq_fixup \n " ) ;
/* Fixup IRQ for PCIe host */
if ( u4_pcie ! = NULL & & dev - > bus - > number = = 0 & &
pci_bus_to_host ( dev - > bus ) = = u4_pcie ) {
printk ( KERN_DEBUG " Fixup U4 PCIe IRQ \n " ) ;
dev - > irq = irq_create_mapping ( NULL , 1 ) ;
if ( dev - > irq ! = NO_IRQ )
set_irq_type ( dev - > irq , IRQ_TYPE_LEVEL_LOW ) ;
}
2006-10-09 13:27:28 +10:00
2006-11-11 17:24:51 +11:00
/* Hide AMD8111 IDE interrupt when in legacy mode so
* the driver calls pci_get_legacy_ide_irq ( )
*/
if ( dev - > vendor = = PCI_VENDOR_ID_AMD & &
dev - > device = = PCI_DEVICE_ID_AMD_8111_IDE & &
( dev - > class & 5 ) ! = 5 ) {
dev - > irq = NO_IRQ ;
2006-10-09 13:25:15 +10:00
}
2005-04-16 15:20:36 -07:00
2006-11-11 17:24:51 +11:00
DBG ( " <- maple_pci_irq_fixup \n " ) ;
2005-04-16 15:20:36 -07:00
}
void __init maple_pci_init ( void )
{
struct device_node * np , * root ;
struct device_node * ht = NULL ;
/* Probe root PCI hosts, that is on U3 the AGP host and the
* HyperTransport host . That one is actually " kept " around
* and actually added last as it ' s resource management relies
* on the AGP resources to have been setup first
*/
root = of_find_node_by_path ( " / " ) ;
if ( root = = NULL ) {
printk ( KERN_CRIT " maple_find_bridges: can't find root of device tree \n " ) ;
return ;
}
for ( np = NULL ; ( np = of_get_next_child ( root , np ) ) ! = NULL ; ) {
2007-01-03 12:56:28 -06:00
if ( ! np - > type )
2005-04-16 15:20:36 -07:00
continue ;
2007-01-03 12:56:28 -06:00
if ( strcmp ( np - > type , " pci " ) & & strcmp ( np - > type , " ht " ) )
continue ;
2007-05-03 17:26:52 +10:00
if ( ( of_device_is_compatible ( np , " u4-pcie " ) | |
of_device_is_compatible ( np , " u3-agp " ) ) & &
2007-06-18 01:06:54 +02:00
maple_add_bridge ( np ) = = 0 )
2007-01-03 12:56:28 -06:00
of_node_get ( np ) ;
2007-05-03 17:26:52 +10:00
if ( of_device_is_compatible ( np , " u3-ht " ) ) {
2005-04-16 15:20:36 -07:00
of_node_get ( np ) ;
ht = np ;
}
}
of_node_put ( root ) ;
/* Now setup the HyperTransport host if we found any
*/
2007-06-18 01:06:54 +02:00
if ( ht & & maple_add_bridge ( ht ) ! = 0 )
2005-04-16 15:20:36 -07:00
of_node_put ( ht ) ;
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init ( ) ;
/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We
* assume there is no P2P bridge on the AGP bus , which should be a
* safe assumptions hopefully .
*/
if ( u3_agp ) {
struct device_node * np = u3_agp - > arch_data ;
2005-09-06 13:17:54 +10:00
PCI_DN ( np ) - > busno = 0xf0 ;
2005-04-16 15:20:36 -07:00
for ( np = np - > child ; np ; np = np - > sibling )
2005-09-06 13:17:54 +10:00
PCI_DN ( np ) - > busno = 0xf0 ;
2005-04-16 15:20:36 -07:00
}
2006-02-17 11:30:30 +01:00
/* Tell pci.c to not change any resource allocations. */
pci_probe_only = 1 ;
2005-04-16 15:20:36 -07:00
}
int maple_pci_get_legacy_ide_irq ( struct pci_dev * pdev , int channel )
{
struct device_node * np ;
2006-07-03 21:36:01 +10:00
unsigned int defirq = channel ? 15 : 14 ;
unsigned int irq ;
2005-04-16 15:20:36 -07:00
if ( pdev - > vendor ! = PCI_VENDOR_ID_AMD | |
pdev - > device ! = PCI_DEVICE_ID_AMD_8111_IDE )
2006-07-03 21:36:01 +10:00
return defirq ;
2005-04-16 15:20:36 -07:00
np = pci_device_to_OF_node ( pdev ) ;
2006-10-09 13:25:15 +10:00
if ( np = = NULL ) {
printk ( " Failed to locate OF node for IDE %s \n " ,
pci_name ( pdev ) ) ;
2006-07-03 21:36:01 +10:00
return defirq ;
2006-10-09 13:25:15 +10:00
}
2006-07-03 21:36:01 +10:00
irq = irq_of_parse_and_map ( np , channel & 0x1 ) ;
if ( irq = = NO_IRQ ) {
printk ( " Failed to map onboard IDE interrupt for channel %d \n " ,
channel ) ;
return defirq ;
}
return irq ;
2005-04-16 15:20:36 -07:00
}
/* XXX: To remove once all firmwares are ok */
static void fixup_maple_ide ( struct pci_dev * dev )
{
2006-10-09 13:25:15 +10:00
if ( ! machine_is ( maple ) )
return ;
2005-04-16 15:20:36 -07:00
#if 0 /* Enable this to enable IDE port 0 */
{
u8 v ;
pci_read_config_byte ( dev , 0x40 , & v ) ;
v | = 2 ;
pci_write_config_byte ( dev , 0x40 , v ) ;
}
# endif
#if 0 /* fix bus master base */
pci_write_config_dword ( dev , 0x20 , 0xcc01 ) ;
printk ( " old ide resource: %lx -> %lx \n " ,
dev - > resource [ 4 ] . start , dev - > resource [ 4 ] . end ) ;
dev - > resource [ 4 ] . start = 0xcc00 ;
dev - > resource [ 4 ] . end = 0xcc10 ;
# endif
2006-10-09 13:25:15 +10:00
#if 0 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */
2005-04-16 15:20:36 -07:00
{
struct pci_dev * apicdev ;
u32 v ;
apicdev = pci_get_slot ( dev - > bus , PCI_DEVFN ( 5 , 0 ) ) ;
if ( apicdev = = NULL )
printk ( " IDE Fixup IRQ: Can't find IO-APIC ! \n " ) ;
else {
pci_write_config_byte ( apicdev , 0xf2 , 0x10 + 2 * 14 ) ;
pci_read_config_dword ( apicdev , 0xf4 , & v ) ;
v & = ~ 0x00000022 ;
pci_write_config_dword ( apicdev , 0xf4 , v ) ;
pci_write_config_byte ( apicdev , 0xf2 , 0x10 + 2 * 15 ) ;
pci_read_config_dword ( apicdev , 0xf4 , & v ) ;
v & = ~ 0x00000022 ;
pci_write_config_dword ( apicdev , 0xf4 , v ) ;
pci_dev_put ( apicdev ) ;
}
}
# endif
}
DECLARE_PCI_FIXUP_HEADER ( PCI_VENDOR_ID_AMD , PCI_DEVICE_ID_AMD_8111_IDE ,
fixup_maple_ide ) ;