2005-07-25 22:45:45 +00:00
/*
* Define the pci_ops for the Toshiba rbtx4938
* Copyright ( C ) 2000 - 2001 Toshiba Corporation
*
* 2003 - 2005 ( 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 .
*
* Support for TX4938 in 2.6 - Manish Lachwani ( mlachwani @ mvista . com )
*/
# include <linux/types.h>
# include <linux/pci.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <asm/addrspace.h>
# include <asm/tx4938/rbtx4938.h>
/* initialize in setup */
struct resource pci_io_resource = {
. name = " pci IO space " ,
. start = 0 ,
. end = 0 ,
. flags = IORESOURCE_IO
} ;
/* initialize in setup */
struct resource pci_mem_resource = {
. name = " pci memory space " ,
. start = 0 ,
. end = 0 ,
. flags = IORESOURCE_MEM
} ;
struct resource tx4938_pcic1_pci_io_resource = {
2006-03-11 08:18:41 +00:00
. name = " PCI1 IO " ,
. start = 0 ,
. end = 0 ,
. flags = IORESOURCE_IO
2005-07-25 22:45:45 +00:00
} ;
struct resource tx4938_pcic1_pci_mem_resource = {
2006-03-11 08:18:41 +00:00
. name = " PCI1 mem " ,
. start = 0 ,
. end = 0 ,
. flags = IORESOURCE_MEM
2005-07-25 22:45:45 +00:00
} ;
2007-07-02 22:43:06 +09:00
static int mkaddr ( int bus , int dev_fn , int where ,
struct tx4938_pcic_reg * pcicptr )
2005-07-25 22:45:45 +00:00
{
if ( bus > 0 ) {
/* Type 1 configuration */
2007-07-02 22:43:06 +09:00
pcicptr - > g2pcfgadrs = ( ( bus & 0xff ) < < 0x10 ) |
2005-07-25 22:45:45 +00:00
( ( dev_fn & 0xff ) < < 0x08 ) | ( where & 0xfc ) | 1 ;
} else {
if ( dev_fn > = PCI_DEVFN ( TX4938_PCIC_MAX_DEVNU , 0 ) )
return - 1 ;
/* Type 0 configuration */
2007-07-02 22:43:06 +09:00
pcicptr - > g2pcfgadrs = ( ( bus & 0xff ) < < 0x10 ) |
2005-07-25 22:45:45 +00:00
( ( dev_fn & 0xff ) < < 0x08 ) | ( where & 0xfc ) ;
}
/* clear M_ABORT and Disable M_ABORT Int. */
2007-07-02 22:43:06 +09:00
pcicptr - > pcistatus =
( pcicptr - > pcistatus & 0x0000ffff ) |
2005-07-25 22:45:45 +00:00
( PCI_STATUS_REC_MASTER_ABORT < < 16 ) ;
2007-07-02 22:43:06 +09:00
pcicptr - > pcimask & = ~ PCI_STATUS_REC_MASTER_ABORT ;
2005-07-25 22:45:45 +00:00
return 0 ;
}
2007-07-02 22:43:06 +09:00
static int check_abort ( struct tx4938_pcic_reg * pcicptr )
2005-07-25 22:45:45 +00:00
{
int code = PCIBIOS_SUCCESSFUL ;
/* wait write cycle completion before checking error status */
2007-07-02 22:43:06 +09:00
while ( pcicptr - > pcicstatus & TX4938_PCIC_PCICSTATUS_IWB )
2005-07-25 22:45:45 +00:00
;
2007-07-02 22:43:06 +09:00
if ( pcicptr - > pcistatus & ( PCI_STATUS_REC_MASTER_ABORT < < 16 ) ) {
pcicptr - > pcistatus =
( pcicptr - >
2005-07-25 22:45:45 +00:00
pcistatus & 0x0000ffff ) | ( PCI_STATUS_REC_MASTER_ABORT
< < 16 ) ;
2007-07-02 22:43:06 +09:00
pcicptr - > pcimask | = PCI_STATUS_REC_MASTER_ABORT ;
2005-07-25 22:45:45 +00:00
code = PCIBIOS_DEVICE_NOT_FOUND ;
}
return code ;
}
2007-07-02 22:43:06 +09:00
extern struct pci_controller tx4938_pci_controller [ ] ;
extern struct tx4938_pcic_reg * get_tx4938_pcicptr ( int ch ) ;
static struct tx4938_pcic_reg * pci_bus_to_pcicptr ( struct pci_bus * bus )
{
struct pci_controller * channel = bus - > sysdata ;
return get_tx4938_pcicptr ( channel - & tx4938_pci_controller [ 0 ] ) ;
}
2005-07-25 22:45:45 +00:00
static int tx4938_pcibios_read_config ( struct pci_bus * bus , unsigned int devfn ,
int where , int size , u32 * val )
{
2007-07-02 22:43:06 +09:00
int retval , dev , busno , func ;
struct tx4938_pcic_reg * pcicptr = pci_bus_to_pcicptr ( bus ) ;
void __iomem * cfgdata =
( void __iomem * ) ( unsigned long ) & pcicptr - > g2pcfgdata ;
2005-07-25 22:45:45 +00:00
dev = PCI_SLOT ( devfn ) ;
func = PCI_FUNC ( devfn ) ;
/* check if the bus is top-level */
if ( bus - > parent ! = NULL )
busno = bus - > number ;
else {
busno = 0 ;
}
2007-07-02 22:43:06 +09:00
if ( mkaddr ( busno , devfn , where , pcicptr ) )
2005-07-25 22:45:45 +00:00
return - 1 ;
switch ( size ) {
case 1 :
# ifdef __BIG_ENDIAN
2007-07-02 22:43:06 +09:00
cfgdata + = ( where & 3 ) ^ 3 ;
2005-07-25 22:45:45 +00:00
# else
2007-07-02 22:43:06 +09:00
cfgdata + = where & 3 ;
2005-07-25 22:45:45 +00:00
# endif
2007-07-02 22:43:06 +09:00
* val = __raw_readb ( cfgdata ) ;
2005-07-25 22:45:45 +00:00
break ;
case 2 :
# ifdef __BIG_ENDIAN
2007-07-02 22:43:06 +09:00
cfgdata + = ( where & 2 ) ^ 2 ;
2005-07-25 22:45:45 +00:00
# else
2007-07-02 22:43:06 +09:00
cfgdata + = where & 2 ;
2005-07-25 22:45:45 +00:00
# endif
2007-07-02 22:43:06 +09:00
* val = __raw_readw ( cfgdata ) ;
2005-07-25 22:45:45 +00:00
break ;
case 4 :
2007-07-02 22:43:06 +09:00
* val = __raw_readl ( cfgdata ) ;
2005-07-25 22:45:45 +00:00
break ;
}
2007-07-02 22:43:06 +09:00
retval = check_abort ( pcicptr ) ;
2005-07-25 22:45:45 +00:00
if ( retval = = PCIBIOS_DEVICE_NOT_FOUND )
* val = 0xffffffff ;
return retval ;
}
static int tx4938_pcibios_write_config ( struct pci_bus * bus , unsigned int devfn , int where ,
int size , u32 val )
{
2007-07-02 22:43:06 +09:00
int dev , busno , func ;
struct tx4938_pcic_reg * pcicptr = pci_bus_to_pcicptr ( bus ) ;
void __iomem * cfgdata =
( void __iomem * ) ( unsigned long ) & pcicptr - > g2pcfgdata ;
2005-07-25 22:45:45 +00:00
busno = bus - > number ;
dev = PCI_SLOT ( devfn ) ;
func = PCI_FUNC ( devfn ) ;
/* check if the bus is top-level */
if ( bus - > parent ! = NULL ) {
busno = bus - > number ;
} else {
busno = 0 ;
}
2007-07-02 22:43:06 +09:00
if ( mkaddr ( busno , devfn , where , pcicptr ) )
2005-07-25 22:45:45 +00:00
return - 1 ;
switch ( size ) {
case 1 :
# ifdef __BIG_ENDIAN
2007-07-02 22:43:06 +09:00
cfgdata + = ( where & 3 ) ^ 3 ;
2005-07-25 22:45:45 +00:00
# else
2007-07-02 22:43:06 +09:00
cfgdata + = where & 3 ;
2005-07-25 22:45:45 +00:00
# endif
2007-07-02 22:43:06 +09:00
__raw_writeb ( val , cfgdata ) ;
2005-07-25 22:45:45 +00:00
break ;
case 2 :
# ifdef __BIG_ENDIAN
2007-07-02 22:43:06 +09:00
cfgdata + = ( where & 2 ) ^ 2 ;
2005-07-25 22:45:45 +00:00
# else
2007-07-02 22:43:06 +09:00
cfgdata + = where & 2 ;
2005-07-25 22:45:45 +00:00
# endif
2007-07-02 22:43:06 +09:00
__raw_writew ( val , cfgdata ) ;
2005-07-25 22:45:45 +00:00
break ;
case 4 :
2007-07-02 22:43:06 +09:00
__raw_writel ( val , cfgdata ) ;
2005-07-25 22:45:45 +00:00
break ;
}
2007-07-02 22:43:06 +09:00
return check_abort ( pcicptr ) ;
2005-07-25 22:45:45 +00:00
}
struct pci_ops tx4938_pci_ops = {
tx4938_pcibios_read_config ,
tx4938_pcibios_write_config
} ;
struct pci_controller tx4938_pci_controller [ ] = {
/* h/w only supports devices 0x00 to 0x14 */
{
. pci_ops = & tx4938_pci_ops ,
. io_resource = & pci_io_resource ,
. mem_resource = & pci_mem_resource ,
} ,
/* h/w only supports devices 0x00 to 0x14 */
{
. pci_ops = & tx4938_pci_ops ,
. io_resource = & tx4938_pcic1_pci_io_resource ,
. mem_resource = & tx4938_pcic1_pci_mem_resource ,
}
} ;