2005-10-20 10:59:11 +04:00
/*
* Copyright ( C ) 2001 , 2002 , 2005 Broadcom Corporation
* Copyright ( C ) 2004 by Ralf Baechle ( ralf @ linux - mips . org )
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
/*
* BCM1480 / 1455 - specific HT support ( looking like PCI )
*
* This module provides the glue between Linux ' s PCI subsystem
* and the hardware . We basically provide glue for accessing
* configuration space , and set up the translation for I / O
* space accesses .
*
* To access configuration space , we use ioremap . In the 32 - bit
* kernel , this consumes either 4 or 8 page table pages , and 16 MB of
* kernel mapped memory . Hopefully neither of these should be a huge
* problem .
*
*/
# include <linux/types.h>
# include <linux/pci.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/mm.h>
# include <linux/console.h>
# include <linux/tty.h>
# include <asm/sibyte/bcm1480_regs.h>
# include <asm/sibyte/bcm1480_scd.h>
# include <asm/sibyte/board.h>
# include <asm/io.h>
/*
* Macros for calculating offsets into config space given a device
* structure or dev / fun / reg
*/
2007-10-12 02:46:15 +04:00
# define CFGOFFSET(bus, devfn, where) (((bus)<<16)+((devfn)<<8)+(where))
# define CFGADDR(bus, devfn, where) CFGOFFSET((bus)->number, (devfn), where)
2005-10-20 10:59:11 +04:00
static void * ht_cfg_space ;
2013-01-22 15:59:30 +04:00
# define PCI_BUS_ENABLED 1
# define PCI_DEVICE_MODE 2
2005-10-20 10:59:11 +04:00
2009-09-17 04:25:07 +04:00
static int bcm1480ht_bus_status ;
2005-10-20 10:59:11 +04:00
# define PCI_BRIDGE_DEVICE 0
# define HT_BRIDGE_DEVICE 1
/*
* HT ' s level - sensitive interrupts require EOI , which is generated
* through a 4 MB memory - mapped region
*/
unsigned long ht_eoi_space ;
/*
* Read / write 32 - bit values in config space .
*/
static inline u32 READCFG32 ( u32 addr )
{
return * ( u32 * ) ( ht_cfg_space + ( addr & ~ 3 ) ) ;
}
static inline void WRITECFG32 ( u32 addr , u32 data )
{
* ( u32 * ) ( ht_cfg_space + ( addr & ~ 3 ) ) = data ;
}
/*
* Some checks before doing config cycles :
* In PCI Device Mode , hide everything on bus 0 except the LDT host
* bridge . Otherwise , access is controlled by bridge MasterEn bits .
*/
static int bcm1480ht_can_access ( struct pci_bus * bus , int devfn )
{
u32 devno ;
if ( ! ( bcm1480ht_bus_status & ( PCI_BUS_ENABLED | PCI_DEVICE_MODE ) ) )
return 0 ;
if ( bus - > number = = 0 ) {
devno = PCI_SLOT ( devfn ) ;
2006-03-11 11:18:41 +03:00
if ( bcm1480ht_bus_status & PCI_DEVICE_MODE )
2005-10-20 10:59:11 +04:00
return 0 ;
}
return 1 ;
}
/*
* Read / write access functions for various sizes of values
* in config space . Return all 1 ' s for disallowed accesses
* for a kludgy but adequate simulation of master aborts .
*/
static int bcm1480ht_pcibios_read ( struct pci_bus * bus , unsigned int devfn ,
int where , int size , u32 * val )
{
u32 data = 0 ;
if ( ( size = = 2 ) & & ( where & 1 ) )
return PCIBIOS_BAD_REGISTER_NUMBER ;
else if ( ( size = = 4 ) & & ( where & 3 ) )
return PCIBIOS_BAD_REGISTER_NUMBER ;
if ( bcm1480ht_can_access ( bus , devfn ) )
data = READCFG32 ( CFGADDR ( bus , devfn , where ) ) ;
else
data = 0xFFFFFFFF ;
if ( size = = 1 )
* val = ( data > > ( ( where & 3 ) < < 3 ) ) & 0xff ;
else if ( size = = 2 )
* val = ( data > > ( ( where & 3 ) < < 3 ) ) & 0xffff ;
else
* val = data ;
return PCIBIOS_SUCCESSFUL ;
}
static int bcm1480ht_pcibios_write ( struct pci_bus * bus , unsigned int devfn ,
int where , int size , u32 val )
{
u32 cfgaddr = CFGADDR ( bus , devfn , where ) ;
u32 data = 0 ;
if ( ( size = = 2 ) & & ( where & 1 ) )
return PCIBIOS_BAD_REGISTER_NUMBER ;
else if ( ( size = = 4 ) & & ( where & 3 ) )
return PCIBIOS_BAD_REGISTER_NUMBER ;
if ( ! bcm1480ht_can_access ( bus , devfn ) )
return PCIBIOS_BAD_REGISTER_NUMBER ;
data = READCFG32 ( cfgaddr ) ;
if ( size = = 1 )
data = ( data & ~ ( 0xff < < ( ( where & 3 ) < < 3 ) ) ) |
( val < < ( ( where & 3 ) < < 3 ) ) ;
else if ( size = = 2 )
data = ( data & ~ ( 0xffff < < ( ( where & 3 ) < < 3 ) ) ) |
( val < < ( ( where & 3 ) < < 3 ) ) ;
else
data = val ;
WRITECFG32 ( cfgaddr , data ) ;
return PCIBIOS_SUCCESSFUL ;
}
static int bcm1480ht_pcibios_get_busno ( void )
{
return 0 ;
}
struct pci_ops bcm1480ht_pci_ops = {
. read = bcm1480ht_pcibios_read ,
. write = bcm1480ht_pcibios_write ,
} ;
static struct resource bcm1480ht_mem_resource = {
. name = " BCM1480 HT MEM " ,
2008-01-29 13:14:59 +03:00
. start = A_BCM1480_PHYS_HT_MEM_MATCH_BYTES ,
. end = A_BCM1480_PHYS_HT_MEM_MATCH_BYTES + 0x1fffffffUL ,
2005-10-20 10:59:11 +04:00
. flags = IORESOURCE_MEM ,
} ;
static struct resource bcm1480ht_io_resource = {
. name = " BCM1480 HT I/O " ,
2008-03-16 20:14:16 +03:00
. start = A_BCM1480_PHYS_HT_IO_MATCH_BYTES ,
. end = A_BCM1480_PHYS_HT_IO_MATCH_BYTES + 0x01ffffffUL ,
2005-10-20 10:59:11 +04:00
. flags = IORESOURCE_IO ,
} ;
struct pci_controller bcm1480ht_controller = {
. pci_ops = & bcm1480ht_pci_ops ,
. mem_resource = & bcm1480ht_mem_resource ,
. io_resource = & bcm1480ht_io_resource ,
. index = 1 ,
. get_busno = bcm1480ht_pcibios_get_busno ,
2013-01-22 15:59:30 +04:00
. io_offset = A_BCM1480_PHYS_HT_IO_MATCH_BYTES ,
2005-10-20 10:59:11 +04:00
} ;
static int __init bcm1480ht_pcibios_init ( void )
{
ht_cfg_space = ioremap ( A_BCM1480_PHYS_HT_CFG_MATCH_BITS , 16 * 1024 * 1024 ) ;
2008-03-16 20:14:16 +03:00
/* CFE doesn't always init all HT paths, so we always scan */
2005-10-20 10:59:11 +04:00
bcm1480ht_bus_status | = PCI_BUS_ENABLED ;
ht_eoi_space = ( unsigned long )
ioremap ( A_BCM1480_PHYS_HT_SPECIAL_MATCH_BYTES ,
4 * 1024 * 1024 ) ;
2008-03-16 20:14:16 +03:00
bcm1480ht_controller . io_map_base = ( unsigned long )
ioremap ( A_BCM1480_PHYS_HT_IO_MATCH_BYTES , 65536 ) ;
bcm1480ht_controller . io_map_base - = bcm1480ht_controller . io_offset ;
2005-10-20 10:59:11 +04:00
register_pci_controller ( & bcm1480ht_controller ) ;
return 0 ;
}
arch_initcall ( bcm1480ht_pcibios_init ) ;