2005-04-16 15:20:36 -07:00
/*
* Copyright 2001 MontaVista Software Inc .
* Author : MontaVista Software , Inc .
2005-09-03 15:56:17 -07:00
* ahennessy @ mvista . com
2005-04-16 15:20:36 -07:00
*
2005-09-03 15:56:17 -07:00
* Copyright ( C ) 2000 - 2001 Toshiba Corporation
2005-04-16 15:20:36 -07:00
* Copyright ( C ) 2004 by Ralf Baechle ( ralf @ linux - mips . org )
*
* Based on arch / mips / ddb5xxx / ddb5477 / pci_ops . c
*
* Define the pci_ops for the Toshiba rbtx4927
*
2005-09-03 15:56:17 -07:00
* Much of the code is derived from the original DDB5074 port by
2005-04-16 15:20:36 -07:00
* Geert Uytterhoeven < geert @ sonycom . com >
*
* Copyright 2004 MontaVista Software Inc .
* Author : Manish Lachwani ( mlachwani @ mvista . com )
*
* 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 SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF
* USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* 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 . ,
* 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/types.h>
# include <linux/pci.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <asm/addrspace.h>
# include <asm/byteorder.h>
# include <asm/tx4927/tx4927_pci.h>
/* initialize in setup */
struct resource pci_io_resource = {
. name = " TX4927 PCI IO SPACE " ,
. start = 0x1000 ,
. end = ( 0x1000 + ( TX4927_PCIIO_SIZE ) ) - 1 ,
. flags = IORESOURCE_IO
} ;
/* initialize in setup */
struct resource pci_mem_resource = {
. name = " TX4927 PCI MEM SPACE " ,
. start = TX4927_PCIMEM ,
. end = TX4927_PCIMEM + TX4927_PCIMEM_SIZE - 1 ,
. flags = IORESOURCE_MEM
} ;
static int mkaddr ( int bus , int dev_fn , int where , int * flagsp )
{
if ( bus > 0 ) {
/* Type 1 configuration */
tx4927_pcicptr - > g2pcfgadrs = ( ( bus & 0xff ) < < 0x10 ) |
( ( dev_fn & 0xff ) < < 0x08 ) | ( where & 0xfc ) | 1 ;
} else {
if ( dev_fn > = PCI_DEVFN ( TX4927_PCIC_MAX_DEVNU , 0 ) )
return - 1 ;
/* Type 0 configuration */
tx4927_pcicptr - > g2pcfgadrs = ( ( bus & 0xff ) < < 0x10 ) |
( ( dev_fn & 0xff ) < < 0x08 ) | ( where & 0xfc ) ;
}
/* clear M_ABORT and Disable M_ABORT Int. */
tx4927_pcicptr - > pcistatus =
( tx4927_pcicptr - > pcistatus & 0x0000ffff ) |
( PCI_STATUS_REC_MASTER_ABORT < < 16 ) ;
tx4927_pcicptr - > pcimask & = ~ PCI_STATUS_REC_MASTER_ABORT ;
return 0 ;
}
static int check_abort ( int flags )
{
int code = PCIBIOS_SUCCESSFUL ;
if ( tx4927_pcicptr - >
pcistatus & ( PCI_STATUS_REC_MASTER_ABORT < < 16 ) ) {
tx4927_pcicptr - > pcistatus =
( tx4927_pcicptr - >
pcistatus & 0x0000ffff ) | ( PCI_STATUS_REC_MASTER_ABORT
< < 16 ) ;
tx4927_pcicptr - > pcimask | = PCI_STATUS_REC_MASTER_ABORT ;
code = PCIBIOS_DEVICE_NOT_FOUND ;
}
return code ;
}
static int tx4927_pcibios_read_config ( struct pci_bus * bus , unsigned int devfn , int where ,
int size , u32 * val )
{
int flags , retval , dev , busno , func ;
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 ;
}
if ( mkaddr ( busno , devfn , where , & flags ) )
return - 1 ;
switch ( size ) {
case 1 :
2006-06-28 11:24:12 +01:00
* val = * ( volatile u8 * ) ( ( unsigned long ) & tx4927_pcicptr - >
2005-04-16 15:20:36 -07:00
g2pcfgdata |
# ifdef __LITTLE_ENDIAN
( where & 3 ) ) ;
# else
( ( where & 0x3 ) ^ 0x3 ) ) ;
# endif
break ;
case 2 :
2006-06-28 11:24:12 +01:00
* val = * ( volatile u16 * ) ( ( unsigned long ) & tx4927_pcicptr - >
2005-04-16 15:20:36 -07:00
g2pcfgdata |
# ifdef __LITTLE_ENDIAN
( where & 3 ) ) ;
# else
( ( where & 0x3 ) ^ 0x2 ) ) ;
# endif
break ;
case 4 :
* val = tx4927_pcicptr - > g2pcfgdata ;
break ;
}
retval = check_abort ( flags ) ;
if ( retval = = PCIBIOS_DEVICE_NOT_FOUND )
* val = 0xffffffff ;
return retval ;
}
static int tx4927_pcibios_write_config ( struct pci_bus * bus , unsigned int devfn , int where ,
int size , u32 val )
{
int flags , dev , busno , func ;
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 ;
}
if ( mkaddr ( busno , devfn , where , & flags ) )
return - 1 ;
switch ( size ) {
case 1 :
2006-06-28 11:24:12 +01:00
* ( volatile u8 * ) ( ( unsigned long ) & tx4927_pcicptr - >
2005-04-16 15:20:36 -07:00
g2pcfgdata |
# ifdef __LITTLE_ENDIAN
( where & 3 ) ) = val ;
# else
( ( where & 0x3 ) ^ 0x3 ) ) = val ;
# endif
break ;
case 2 :
2006-06-28 11:24:12 +01:00
* ( volatile u16 * ) ( ( unsigned long ) & tx4927_pcicptr - >
2005-04-16 15:20:36 -07:00
g2pcfgdata |
# ifdef __LITTLE_ENDIAN
( where & 3 ) ) = val ;
# else
( ( where & 0x3 ) ^ 0x2 ) ) = val ;
# endif
break ;
case 4 :
tx4927_pcicptr - > g2pcfgdata = val ;
break ;
}
return check_abort ( flags ) ;
}
struct pci_ops tx4927_pci_ops = {
tx4927_pcibios_read_config ,
tx4927_pcibios_write_config
} ;
/*
* h / w only supports devices 0x00 to 0x14
*/
struct pci_controller tx4927_controller = {
. pci_ops = & tx4927_pci_ops ,
. io_resource = & pci_io_resource ,
. mem_resource = & pci_mem_resource ,
} ;