2006-12-28 20:22:32 +03:00
/*
* PCI Tower specific code
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 2006 Thomas Bogendoerfer ( tsbogend @ alpha . franken . de )
*/
# include <linux/init.h>
# include <linux/interrupt.h>
2010-10-07 17:08:54 +04:00
# include <linux/irq.h>
2006-12-28 20:22:32 +03:00
# include <linux/pci.h>
# include <linux/serial_8250.h>
# include <asm/sni.h>
# include <asm/time.h>
# include <asm/irq_cpu.h>
# define PORT(_base,_irq) \
{ \
. iobase = _base , \
. irq = _irq , \
. uartclk = 1843200 , \
. iotype = UPIO_PORT , \
. flags = UPF_BOOT_AUTOCONF , \
}
static struct plat_serial8250_port pcit_data [ ] = {
PORT ( 0x3f8 , 0 ) ,
PORT ( 0x2f8 , 3 ) ,
{ } ,
} ;
static struct platform_device pcit_serial8250_device = {
. name = " serial8250 " ,
. id = PLAT8250_DEV_PLATFORM ,
. dev = {
. platform_data = pcit_data ,
} ,
} ;
static struct plat_serial8250_port pcit_cplus_data [ ] = {
2007-04-08 15:34:57 +04:00
PORT ( 0x3f8 , 0 ) ,
2006-12-28 20:22:32 +03:00
PORT ( 0x2f8 , 3 ) ,
PORT ( 0x3e8 , 4 ) ,
PORT ( 0x2e8 , 3 ) ,
{ } ,
} ;
static struct platform_device pcit_cplus_serial8250_device = {
. name = " serial8250 " ,
. id = PLAT8250_DEV_PLATFORM ,
. dev = {
. platform_data = pcit_cplus_data ,
} ,
} ;
2007-06-21 01:36:47 +04:00
static struct resource pcit_cmos_rsrc [ ] = {
2013-01-22 15:59:30 +04:00
{
. start = 0x70 ,
. end = 0x71 ,
. flags = IORESOURCE_IO
} ,
{
. start = 8 ,
. end = 8 ,
. flags = IORESOURCE_IRQ
}
2007-06-21 01:36:47 +04:00
} ;
static struct platform_device pcit_cmos_device = {
2013-01-22 15:59:30 +04:00
. name = " rtc_cmos " ,
. num_resources = ARRAY_SIZE ( pcit_cmos_rsrc ) ,
. resource = pcit_cmos_rsrc
2007-06-21 01:36:47 +04:00
} ;
2008-01-29 13:14:57 +03:00
static struct platform_device pcit_pcspeaker_pdev = {
. name = " pcspkr " ,
. id = - 1 ,
} ;
2006-12-28 20:22:32 +03:00
static struct resource sni_io_resource = {
2007-04-08 15:34:57 +04:00
. start = 0x00000000UL ,
2006-12-28 20:22:32 +03:00
. end = 0x03bfffffUL ,
2007-04-08 15:34:57 +04:00
. name = " PCIT IO " ,
2006-12-28 20:22:32 +03:00
. flags = IORESOURCE_IO ,
} ;
static struct resource pcit_io_resources [ ] = {
{
. start = 0x00 ,
. end = 0x1f ,
. name = " dma1 " ,
. flags = IORESOURCE_BUSY
} , {
. start = 0x40 ,
. end = 0x5f ,
. name = " timer " ,
. flags = IORESOURCE_BUSY
} , {
. start = 0x60 ,
. end = 0x6f ,
. name = " keyboard " ,
. flags = IORESOURCE_BUSY
} , {
. start = 0x80 ,
. end = 0x8f ,
. name = " dma page reg " ,
. flags = IORESOURCE_BUSY
} , {
. start = 0xc0 ,
. end = 0xdf ,
. name = " dma2 " ,
. flags = IORESOURCE_BUSY
2007-04-08 15:34:57 +04:00
} , {
. start = 0xcf8 ,
. end = 0xcfb ,
. name = " PCI config addr " ,
. flags = IORESOURCE_BUSY
2006-12-28 20:22:32 +03:00
} , {
. start = 0xcfc ,
. end = 0xcff ,
. name = " PCI config data " ,
. flags = IORESOURCE_BUSY
}
} ;
static void __init sni_pcit_resource_init ( void )
{
int i ;
/* request I/O space for devices used on all i[345]86 PCs */
for ( i = 0 ; i < ARRAY_SIZE ( pcit_io_resources ) ; i + + )
2007-04-08 15:34:57 +04:00
request_resource ( & sni_io_resource , pcit_io_resources + i ) ;
2006-12-28 20:22:32 +03:00
}
extern struct pci_ops sni_pcit_ops ;
2013-06-25 19:10:28 +04:00
# ifdef CONFIG_PCI
static struct resource sni_mem_resource = {
. start = 0x18000000UL ,
. end = 0x1fbfffffUL ,
. name = " PCIT PCI MEM " ,
. flags = IORESOURCE_MEM
} ;
2006-12-28 20:22:32 +03:00
static struct pci_controller sni_pcit_controller = {
. pci_ops = & sni_pcit_ops ,
. mem_resource = & sni_mem_resource ,
2007-04-08 15:34:57 +04:00
. mem_offset = 0x00000000UL ,
2006-12-28 20:22:32 +03:00
. io_resource = & sni_io_resource ,
2007-04-08 15:34:57 +04:00
. io_offset = 0x00000000UL ,
2013-01-22 15:59:30 +04:00
. io_map_base = SNI_PORT_BASE
2006-12-28 20:22:32 +03:00
} ;
2013-06-25 19:10:28 +04:00
# endif /* CONFIG_PCI */
2006-12-28 20:22:32 +03:00
2011-03-24 00:09:15 +03:00
static void enable_pcit_irq ( struct irq_data * d )
2006-12-28 20:22:32 +03:00
{
2011-03-24 00:09:15 +03:00
u32 mask = 1 < < ( d - > irq - SNI_PCIT_INT_START + 24 ) ;
2006-12-28 20:22:32 +03:00
* ( volatile u32 * ) SNI_PCIT_INT_REG | = mask ;
}
2011-03-24 00:09:15 +03:00
void disable_pcit_irq ( struct irq_data * d )
2006-12-28 20:22:32 +03:00
{
2011-03-24 00:09:15 +03:00
u32 mask = 1 < < ( d - > irq - SNI_PCIT_INT_START + 24 ) ;
2006-12-28 20:22:32 +03:00
* ( volatile u32 * ) SNI_PCIT_INT_REG & = ~ mask ;
}
static struct irq_chip pcit_irq_type = {
2009-11-18 01:51:03 +03:00
. name = " PCIT " ,
2011-03-24 00:09:15 +03:00
. irq_mask = disable_pcit_irq ,
. irq_unmask = enable_pcit_irq ,
2006-12-28 20:22:32 +03:00
} ;
static void pcit_hwint1 ( void )
{
u32 pending = * ( volatile u32 * ) SNI_PCIT_INT_REG ;
int irq ;
clear_c0_status ( IE_IRQ1 ) ;
irq = ffs ( ( pending > > 16 ) & 0x7f ) ;
if ( likely ( irq > 0 ) )
2007-10-12 02:46:15 +04:00
do_IRQ ( irq + SNI_PCIT_INT_START - 1 ) ;
set_c0_status ( IE_IRQ1 ) ;
2006-12-28 20:22:32 +03:00
}
static void pcit_hwint0 ( void )
{
u32 pending = * ( volatile u32 * ) SNI_PCIT_INT_REG ;
int irq ;
clear_c0_status ( IE_IRQ0 ) ;
2007-04-08 15:34:57 +04:00
irq = ffs ( ( pending > > 16 ) & 0x3f ) ;
2006-12-28 20:22:32 +03:00
if ( likely ( irq > 0 ) )
2007-10-12 02:46:15 +04:00
do_IRQ ( irq + SNI_PCIT_INT_START - 1 ) ;
set_c0_status ( IE_IRQ0 ) ;
2006-12-28 20:22:32 +03:00
}
static void sni_pcit_hwint ( void )
{
2007-03-19 03:13:37 +03:00
u32 pending = read_c0_cause ( ) & read_c0_status ( ) ;
2006-12-28 20:22:32 +03:00
if ( pending & C_IRQ1 )
pcit_hwint1 ( ) ;
else if ( pending & C_IRQ2 )
2007-10-12 02:46:15 +04:00
do_IRQ ( MIPS_CPU_IRQ_BASE + 4 ) ;
2006-12-28 20:22:32 +03:00
else if ( pending & C_IRQ3 )
2007-10-12 02:46:15 +04:00
do_IRQ ( MIPS_CPU_IRQ_BASE + 5 ) ;
2006-12-28 20:22:32 +03:00
else if ( pending & C_IRQ5 )
2007-10-12 02:46:15 +04:00
do_IRQ ( MIPS_CPU_IRQ_BASE + 7 ) ;
2006-12-28 20:22:32 +03:00
}
static void sni_pcit_hwint_cplus ( void )
{
2007-03-19 03:13:37 +03:00
u32 pending = read_c0_cause ( ) & read_c0_status ( ) ;
2006-12-28 20:22:32 +03:00
if ( pending & C_IRQ0 )
pcit_hwint0 ( ) ;
2007-04-08 15:34:57 +04:00
else if ( pending & C_IRQ1 )
2007-10-12 02:46:15 +04:00
do_IRQ ( MIPS_CPU_IRQ_BASE + 3 ) ;
2006-12-28 20:22:32 +03:00
else if ( pending & C_IRQ2 )
2007-10-12 02:46:15 +04:00
do_IRQ ( MIPS_CPU_IRQ_BASE + 4 ) ;
2006-12-28 20:22:32 +03:00
else if ( pending & C_IRQ3 )
2007-10-12 02:46:15 +04:00
do_IRQ ( MIPS_CPU_IRQ_BASE + 5 ) ;
2006-12-28 20:22:32 +03:00
else if ( pending & C_IRQ5 )
2007-10-12 02:46:15 +04:00
do_IRQ ( MIPS_CPU_IRQ_BASE + 7 ) ;
2006-12-28 20:22:32 +03:00
}
void __init sni_pcit_irq_init ( void )
{
int i ;
mips_cpu_irq_init ( ) ;
for ( i = SNI_PCIT_INT_START ; i < = SNI_PCIT_INT_END ; i + + )
2011-03-27 17:19:28 +04:00
irq_set_chip_and_handler ( i , & pcit_irq_type , handle_level_irq ) ;
2006-12-28 20:22:32 +03:00
* ( volatile u32 * ) SNI_PCIT_INT_REG = 0 ;
sni_hwint = sni_pcit_hwint ;
change_c0_status ( ST0_IM , IE_IRQ1 ) ;
2007-10-12 02:46:15 +04:00
setup_irq ( SNI_PCIT_INT_START + 6 , & sni_isa_irq ) ;
2006-12-28 20:22:32 +03:00
}
void __init sni_pcit_cplus_irq_init ( void )
{
int i ;
mips_cpu_irq_init ( ) ;
for ( i = SNI_PCIT_INT_START ; i < = SNI_PCIT_INT_END ; i + + )
2011-03-27 17:19:28 +04:00
irq_set_chip_and_handler ( i , & pcit_irq_type , handle_level_irq ) ;
2007-04-08 15:34:57 +04:00
* ( volatile u32 * ) SNI_PCIT_INT_REG = 0x40000000 ;
2006-12-28 20:22:32 +03:00
sni_hwint = sni_pcit_hwint_cplus ;
change_c0_status ( ST0_IM , IE_IRQ0 ) ;
2007-10-12 02:46:15 +04:00
setup_irq ( MIPS_CPU_IRQ_BASE + 3 , & sni_isa_irq ) ;
2006-12-28 20:22:32 +03:00
}
2007-06-21 01:36:47 +04:00
void __init sni_pcit_init ( void )
2006-12-28 20:22:32 +03:00
{
2007-04-08 15:34:57 +04:00
ioport_resource . end = sni_io_resource . end ;
2006-12-28 20:22:32 +03:00
# ifdef CONFIG_PCI
2007-04-08 15:34:57 +04:00
PCIBIOS_MIN_IO = 0x9000 ;
2006-12-28 20:22:32 +03:00
register_pci_controller ( & sni_pcit_controller ) ;
# endif
2007-04-08 15:34:57 +04:00
sni_pcit_resource_init ( ) ;
2006-12-28 20:22:32 +03:00
}
static int __init snirm_pcit_setup_devinit ( void )
{
switch ( sni_brd_type ) {
case SNI_BRD_PCI_TOWER :
2013-01-22 15:59:30 +04:00
platform_device_register ( & pcit_serial8250_device ) ;
platform_device_register ( & pcit_cmos_device ) ;
2008-01-29 13:14:57 +03:00
platform_device_register ( & pcit_pcspeaker_pdev ) ;
2013-01-22 15:59:30 +04:00
break ;
2006-12-28 20:22:32 +03:00
case SNI_BRD_PCI_TOWER_CPLUS :
2013-01-22 15:59:30 +04:00
platform_device_register ( & pcit_cplus_serial8250_device ) ;
platform_device_register ( & pcit_cmos_device ) ;
2008-01-29 13:14:57 +03:00
platform_device_register ( & pcit_pcspeaker_pdev ) ;
2013-01-22 15:59:30 +04:00
break ;
2006-12-28 20:22:32 +03:00
}
return 0 ;
}
device_initcall ( snirm_pcit_setup_devinit ) ;