2005-04-16 15:20:36 -07:00
/*
* Copyright 2001 MontaVista Software Inc .
* Author : MontaVista Software , Inc .
* ahennessy @ mvista . com
*
* Copyright ( C ) 2000 - 2001 Toshiba Corporation
* Copyright ( C ) 2004 by Ralf Baechle ( ralf @ linux - mips . org )
*
* Based on arch / mips / ddb5xxx / ddb5477 / pci_ops . c
*
2008-07-11 00:33:08 +09:00
* Define the pci_ops for TX3927 .
2005-04-16 15:20:36 -07:00
*
* Much of the code is derived from the original DDB5074 port by
2014-04-22 12:51:13 +02:00
* Geert Uytterhoeven < geert @ linux - m68k . org >
2005-04-16 15:20:36 -07:00
*
* 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>
2008-07-25 23:01:35 +09:00
# include <linux/interrupt.h>
2010-10-07 14:08:54 +01:00
# include <linux/irq.h>
2005-04-16 15:20:36 -07:00
# include <asm/addrspace.h>
2008-07-25 23:01:35 +09:00
# include <asm/txx9irq.h>
# include <asm/txx9/pci.h>
2008-07-11 00:33:08 +09:00
# include <asm/txx9/tx3927.h>
2005-04-16 15:20:36 -07:00
2008-07-24 00:25:13 +09:00
static int mkaddr ( struct pci_bus * bus , unsigned char devfn , unsigned char where )
2005-04-16 15:20:36 -07:00
{
2008-07-24 00:25:13 +09:00
if ( bus - > parent = = NULL & &
devfn > = PCI_DEVFN ( TX3927_PCIC_MAX_DEVNU , 0 ) )
return - 1 ;
tx3927_pcicptr - > ica =
( ( bus - > number & 0xff ) < < 0x10 ) |
( ( devfn & 0xff ) < < 0x08 ) |
( where & 0xfc ) | ( bus - > parent ? 1 : 0 ) ;
2005-04-16 15:20:36 -07:00
/* clear M_ABORT and Disable M_ABORT Int. */
tx3927_pcicptr - > pcistat | = PCI_STATUS_REC_MASTER_ABORT ;
tx3927_pcicptr - > pcistatim & = ~ PCI_STATUS_REC_MASTER_ABORT ;
2008-07-24 00:25:13 +09:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
static inline int check_abort ( void )
{
2008-07-24 00:25:13 +09:00
if ( tx3927_pcicptr - > pcistat & PCI_STATUS_REC_MASTER_ABORT ) {
2005-04-16 15:20:36 -07:00
tx3927_pcicptr - > pcistat | = PCI_STATUS_REC_MASTER_ABORT ;
tx3927_pcicptr - > pcistatim | = PCI_STATUS_REC_MASTER_ABORT ;
2008-07-24 00:25:13 +09:00
/* flush write buffer */
iob ( ) ;
2005-04-16 15:20:36 -07:00
return PCIBIOS_DEVICE_NOT_FOUND ;
2008-07-24 00:25:13 +09:00
}
2005-04-16 15:20:36 -07:00
return PCIBIOS_SUCCESSFUL ;
}
2008-07-11 00:33:08 +09:00
static int tx3927_pci_read_config ( struct pci_bus * bus , unsigned int devfn ,
2005-04-16 15:20:36 -07:00
int where , int size , u32 * val )
{
2008-07-24 00:25:13 +09:00
if ( mkaddr ( bus , devfn , where ) ) {
* val = 0xffffffff ;
return PCIBIOS_DEVICE_NOT_FOUND ;
}
2005-04-16 15:20:36 -07:00
switch ( size ) {
case 1 :
* val = * ( volatile u8 * ) ( ( unsigned long ) & tx3927_pcicptr - > icd | ( where & 3 ) ) ;
break ;
case 2 :
* val = le16_to_cpu ( * ( volatile u16 * ) ( ( unsigned long ) & tx3927_pcicptr - > icd | ( where & 3 ) ) ) ;
break ;
case 4 :
* val = le32_to_cpu ( tx3927_pcicptr - > icd ) ;
break ;
}
return check_abort ( ) ;
}
2008-07-11 00:33:08 +09:00
static int tx3927_pci_write_config ( struct pci_bus * bus , unsigned int devfn ,
2005-04-16 15:20:36 -07:00
int where , int size , u32 val )
{
2008-07-24 00:25:13 +09:00
if ( mkaddr ( bus , devfn , where ) )
return PCIBIOS_DEVICE_NOT_FOUND ;
2005-04-16 15:20:36 -07:00
switch ( size ) {
case 1 :
* ( volatile u8 * ) ( ( unsigned long ) & tx3927_pcicptr - > icd | ( where & 3 ) ) = val ;
break ;
case 2 :
2005-11-15 13:55:06 +00:00
* ( volatile u16 * ) ( ( unsigned long ) & tx3927_pcicptr - > icd | ( where & 2 ) ) =
2005-04-16 15:20:36 -07:00
cpu_to_le16 ( val ) ;
break ;
case 4 :
tx3927_pcicptr - > icd = cpu_to_le32 ( val ) ;
}
return check_abort ( ) ;
}
2008-07-11 00:33:08 +09:00
static struct pci_ops tx3927_pci_ops = {
. read = tx3927_pci_read_config ,
. write = tx3927_pci_write_config ,
2005-04-16 15:20:36 -07:00
} ;
2008-07-11 00:33:08 +09:00
void __init tx3927_pcic_setup ( struct pci_controller * channel ,
unsigned long sdram_size , int extarb )
{
unsigned long flags ;
unsigned long io_base =
channel - > io_resource - > start + mips_io_port_base - IO_BASE ;
unsigned long io_size =
channel - > io_resource - > end - channel - > io_resource - > start ;
unsigned long io_pciaddr =
channel - > io_resource - > start - channel - > io_offset ;
unsigned long mem_base =
channel - > mem_resource - > start ;
unsigned long mem_size =
channel - > mem_resource - > end - channel - > mem_resource - > start ;
unsigned long mem_pciaddr =
channel - > mem_resource - > start - channel - > mem_offset ;
printk ( KERN_INFO " TX3927 PCIC -- DID:%04x VID:%04x RID:%02x Arbiter:%s " ,
tx3927_pcicptr - > did , tx3927_pcicptr - > vid ,
tx3927_pcicptr - > rid ,
extarb ? " External " : " Internal " ) ;
channel - > pci_ops = & tx3927_pci_ops ;
local_irq_save ( flags ) ;
/* Disable External PCI Config. Access */
tx3927_pcicptr - > lbc = TX3927_PCIC_LBC_EPCAD ;
# ifdef __BIG_ENDIAN
tx3927_pcicptr - > lbc | = TX3927_PCIC_LBC_IBSE |
TX3927_PCIC_LBC_TIBSE |
TX3927_PCIC_LBC_TMFBSE | TX3927_PCIC_LBC_MSDSE ;
# endif
/* LB->PCI mappings */
tx3927_pcicptr - > iomas = ~ ( io_size - 1 ) ;
tx3927_pcicptr - > ilbioma = io_base ;
tx3927_pcicptr - > ipbioma = io_pciaddr ;
tx3927_pcicptr - > mmas = ~ ( mem_size - 1 ) ;
tx3927_pcicptr - > ilbmma = mem_base ;
tx3927_pcicptr - > ipbmma = mem_pciaddr ;
/* PCI->LB mappings */
tx3927_pcicptr - > iobas = 0xffffffff ;
tx3927_pcicptr - > ioba = 0 ;
tx3927_pcicptr - > tlbioma = 0 ;
tx3927_pcicptr - > mbas = ~ ( sdram_size - 1 ) ;
tx3927_pcicptr - > mba = 0 ;
tx3927_pcicptr - > tlbmma = 0 ;
/* Enable Direct mapping Address Space Decoder */
tx3927_pcicptr - > lbc | = TX3927_PCIC_LBC_ILMDE | TX3927_PCIC_LBC_ILIDE ;
/* Clear All Local Bus Status */
tx3927_pcicptr - > lbstat = TX3927_PCIC_LBIM_ALL ;
/* Enable All Local Bus Interrupts */
tx3927_pcicptr - > lbim = TX3927_PCIC_LBIM_ALL ;
/* Clear All PCI Status Error */
tx3927_pcicptr - > pcistat = TX3927_PCIC_PCISTATIM_ALL ;
/* Enable All PCI Status Error Interrupts */
tx3927_pcicptr - > pcistatim = TX3927_PCIC_PCISTATIM_ALL ;
/* PCIC Int => IRC IRQ10 */
tx3927_pcicptr - > il = TX3927_IR_PCI ;
/* Target Control (per errata) */
tx3927_pcicptr - > tc = TX3927_PCIC_TC_OF8E | TX3927_PCIC_TC_IF8E ;
/* Enable Bus Arbiter */
if ( ! extarb )
tx3927_pcicptr - > pbapmc = TX3927_PCIC_PBAPMC_PBAEN ;
tx3927_pcicptr - > pcicmd = PCI_COMMAND_MASTER |
PCI_COMMAND_MEMORY |
PCI_COMMAND_IO |
PCI_COMMAND_PARITY | PCI_COMMAND_SERR ;
local_irq_restore ( flags ) ;
}
2008-07-25 23:01:35 +09:00
static irqreturn_t tx3927_pcierr_interrupt ( int irq , void * dev_id )
{
struct pt_regs * regs = get_irq_regs ( ) ;
if ( txx9_pci_err_action ! = TXX9_PCI_ERR_IGNORE ) {
printk ( KERN_WARNING " PCI error interrupt at 0x%08lx. \n " ,
regs - > cp0_epc ) ;
printk ( KERN_WARNING " pcistat:%02x, lbstat:%04lx \n " ,
tx3927_pcicptr - > pcistat , tx3927_pcicptr - > lbstat ) ;
}
if ( txx9_pci_err_action ! = TXX9_PCI_ERR_PANIC ) {
/* clear all pci errors */
tx3927_pcicptr - > pcistat | = TX3927_PCIC_PCISTATIM_ALL ;
tx3927_pcicptr - > istat = TX3927_PCIC_IIM_ALL ;
tx3927_pcicptr - > tstat = TX3927_PCIC_TIM_ALL ;
tx3927_pcicptr - > lbstat = TX3927_PCIC_LBIM_ALL ;
return IRQ_HANDLED ;
}
console_verbose ( ) ;
panic ( " PCI error. " ) ;
}
void __init tx3927_setup_pcierr_irq ( void )
{
if ( request_irq ( TXX9_IRQ_BASE + TX3927_IR_PCI ,
tx3927_pcierr_interrupt ,
2011-11-22 14:38:03 +00:00
0 , " PCI error " ,
2008-07-25 23:01:35 +09:00
( void * ) TX3927_PCIC_REG ) )
printk ( KERN_WARNING " Failed to request irq for PCIERR \n " ) ;
}