2007-09-23 18:59:26 +04:00
/*
2008-10-05 13:25:44 +04:00
* linux / arch / arm / mach - pxa / cm - x2xx - pci . c
2007-09-23 18:59:26 +04:00
*
* PCI bios - type initialisation for PCI machines
*
* Bits taken from various places .
*
2008-06-17 15:29:58 +04:00
* Copyright ( C ) 2007 , 2008 Compulab , Ltd .
2007-09-23 18:59:26 +04:00
* Mike Rapoport < mike @ compulab . co . il >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/device.h>
# include <linux/platform_device.h>
# include <linux/irq.h>
2008-06-17 15:29:58 +04:00
# include <linux/gpio.h>
2007-09-23 18:59:26 +04:00
# include <asm/mach/pci.h>
# include <asm/mach-types.h>
# include <asm/hardware/it8152.h>
2008-06-17 15:29:58 +04:00
unsigned long it8152_base_address ;
2008-10-05 13:25:44 +04:00
static int cmx2xx_it8152_irq_gpio ;
2007-09-23 18:59:26 +04:00
/*
* Only first 64 MB of memory can be accessed via PCI .
* We use GFP_DMA to allocate safe buffers to do map / unmap .
* This is really ugly and we need a better way of specifying
* DMA - capable regions of memory .
*/
2010-05-22 23:58:51 +04:00
void __init cmx2xx_pci_adjust_zones ( unsigned long * zone_size ,
2007-09-23 18:59:26 +04:00
unsigned long * zhole_size )
{
unsigned int sz = SZ_64M > > PAGE_SHIFT ;
2008-05-12 09:41:13 +04:00
if ( machine_is_armcore ( ) ) {
2008-10-05 13:25:44 +04:00
pr_info ( " Adjusting zones for CM-X2XX \n " ) ;
2008-05-12 09:41:13 +04:00
/*
* Only adjust if > 64 M on current system
*/
2010-05-22 23:58:51 +04:00
if ( zone_size [ 0 ] < = sz )
2008-05-12 09:41:13 +04:00
return ;
zone_size [ 1 ] = zone_size [ 0 ] - sz ;
zone_size [ 0 ] = sz ;
zhole_size [ 1 ] = zhole_size [ 0 ] ;
zhole_size [ 0 ] = 0 ;
}
2007-09-23 18:59:26 +04:00
}
2008-10-05 13:25:44 +04:00
static void cmx2xx_it8152_irq_demux ( unsigned int irq , struct irq_desc * desc )
2007-09-23 18:59:26 +04:00
{
/* clear our parent irq */
2010-11-29 13:18:26 +03:00
desc - > irq_data . chip - > irq_ack ( & desc - > irq_data ) ;
2007-09-23 18:59:26 +04:00
it8152_irq_demux ( irq , desc ) ;
}
2008-10-05 13:25:44 +04:00
void __cmx2xx_pci_init_irq ( int irq_gpio )
2007-09-23 18:59:26 +04:00
{
it8152_init_irq ( ) ;
2008-10-05 13:25:44 +04:00
cmx2xx_it8152_irq_gpio = irq_gpio ;
2008-06-17 15:29:58 +04:00
2008-07-27 07:23:31 +04:00
set_irq_type ( gpio_to_irq ( irq_gpio ) , IRQ_TYPE_EDGE_RISING ) ;
2008-06-17 15:29:58 +04:00
2008-10-05 13:25:44 +04:00
set_irq_chained_handler ( gpio_to_irq ( irq_gpio ) , cmx2xx_it8152_irq_demux ) ;
2007-09-23 18:59:26 +04:00
}
# ifdef CONFIG_PM
static unsigned long sleep_save_ite [ 10 ] ;
2008-10-05 13:25:44 +04:00
void __cmx2xx_pci_suspend ( void )
2007-09-23 18:59:26 +04:00
{
/* save ITE state */
sleep_save_ite [ 0 ] = __raw_readl ( IT8152_INTC_PDCNIMR ) ;
sleep_save_ite [ 1 ] = __raw_readl ( IT8152_INTC_LPCNIMR ) ;
sleep_save_ite [ 2 ] = __raw_readl ( IT8152_INTC_LPNIAR ) ;
/* Clear ITE IRQ's */
__raw_writel ( ( 0 ) , IT8152_INTC_PDCNIRR ) ;
__raw_writel ( ( 0 ) , IT8152_INTC_LPCNIRR ) ;
}
2008-10-05 13:25:44 +04:00
void __cmx2xx_pci_resume ( void )
2007-09-23 18:59:26 +04:00
{
/* restore IT8152 state */
__raw_writel ( ( sleep_save_ite [ 0 ] ) , IT8152_INTC_PDCNIMR ) ;
__raw_writel ( ( sleep_save_ite [ 1 ] ) , IT8152_INTC_LPCNIMR ) ;
__raw_writel ( ( sleep_save_ite [ 2 ] ) , IT8152_INTC_LPNIAR ) ;
}
# else
2008-10-05 13:25:44 +04:00
void cmx2xx_pci_suspend ( void ) { }
void cmx2xx_pci_resume ( void ) { }
2007-09-23 18:59:26 +04:00
# endif
/* PCI IRQ mapping*/
2008-10-05 13:25:44 +04:00
static int __init cmx2xx_pci_map_irq ( struct pci_dev * dev , u8 slot , u8 pin )
2007-09-23 18:59:26 +04:00
{
int irq ;
2008-03-05 02:08:02 +03:00
dev_dbg ( & dev - > dev , " %s: slot=%x, pin=%x \n " , __func__ , slot , pin ) ;
2007-09-23 18:59:26 +04:00
irq = it8152_pci_map_irq ( dev , slot , pin ) ;
if ( irq )
return irq ;
/*
Here comes the ugly part . The routing is baseboard specific ,
2008-10-05 13:25:44 +04:00
but defining a platform for each possible base of CM - X2XX is
unrealistic . Here we keep mapping for ATXBase and SB - X2XX .
2007-09-23 18:59:26 +04:00
*/
/* ATXBASE PCI slot */
if ( slot = = 7 )
return IT8152_PCI_INTA ;
2008-10-05 13:25:44 +04:00
/* ATXBase/SB-X2XX CardBus */
2007-09-23 18:59:26 +04:00
if ( slot = = 8 | | slot = = 0 )
return IT8152_PCI_INTB ;
/* ATXBase Ethernet */
if ( slot = = 9 )
return IT8152_PCI_INTA ;
2008-10-05 13:26:55 +04:00
/* CM-x255 Onboard Ethernet */
if ( slot = = 15 )
return IT8152_PCI_INTC ;
/* SB-x2xx Ethernet */
2007-09-23 18:59:26 +04:00
if ( slot = = 16 )
return IT8152_PCI_INTA ;
/* PC104+ interrupt routing */
if ( ( slot = = 17 ) | | ( slot = = 19 ) )
return IT8152_PCI_INTA ;
if ( ( slot = = 18 ) | | ( slot = = 20 ) )
return IT8152_PCI_INTB ;
return ( 0 ) ;
}
2008-10-05 13:25:44 +04:00
static void cmx2xx_pci_preinit ( void )
2007-09-23 18:59:26 +04:00
{
2008-10-05 13:25:44 +04:00
pr_info ( " Initializing CM-X2XX PCI subsystem \n " ) ;
2007-09-23 18:59:26 +04:00
__raw_writel ( 0x800 , IT8152_PCI_CFG_ADDR ) ;
if ( __raw_readl ( IT8152_PCI_CFG_DATA ) = = 0x81521283 ) {
2007-11-25 10:55:34 +03:00
pr_info ( " PCI Bridge found. \n " ) ;
2007-09-23 18:59:26 +04:00
/* set PCI I/O base at 0 */
writel ( 0x848 , IT8152_PCI_CFG_ADDR ) ;
writel ( 0 , IT8152_PCI_CFG_DATA ) ;
/* set PCI memory base at 0 */
writel ( 0x840 , IT8152_PCI_CFG_ADDR ) ;
writel ( 0 , IT8152_PCI_CFG_DATA ) ;
writel ( 0x20 , IT8152_GPIO_GPDR ) ;
/* CardBus Controller on ATXbase baseboard */
writel ( 0x4000 , IT8152_PCI_CFG_ADDR ) ;
if ( readl ( IT8152_PCI_CFG_DATA ) = = 0xAC51104C ) {
2007-11-25 10:55:34 +03:00
pr_info ( " CardBus Bridge found. \n " ) ;
2007-09-23 18:59:26 +04:00
/* Configure socket 0 */
writel ( 0x408C , IT8152_PCI_CFG_ADDR ) ;
writel ( 0x1022 , IT8152_PCI_CFG_DATA ) ;
writel ( 0x4080 , IT8152_PCI_CFG_ADDR ) ;
writel ( 0x3844d060 , IT8152_PCI_CFG_DATA ) ;
writel ( 0x4090 , IT8152_PCI_CFG_ADDR ) ;
writel ( ( ( readl ( IT8152_PCI_CFG_DATA ) & 0xffff ) |
0x60440000 ) ,
IT8152_PCI_CFG_DATA ) ;
writel ( 0x4018 , IT8152_PCI_CFG_ADDR ) ;
writel ( 0xb0000000 , IT8152_PCI_CFG_DATA ) ;
/* Configure socket 1 */
writel ( 0x418C , IT8152_PCI_CFG_ADDR ) ;
writel ( 0x1022 , IT8152_PCI_CFG_DATA ) ;
writel ( 0x4180 , IT8152_PCI_CFG_ADDR ) ;
writel ( 0x3844d060 , IT8152_PCI_CFG_DATA ) ;
writel ( 0x4190 , IT8152_PCI_CFG_ADDR ) ;
writel ( ( ( readl ( IT8152_PCI_CFG_DATA ) & 0xffff ) |
0x60440000 ) ,
IT8152_PCI_CFG_DATA ) ;
writel ( 0x4118 , IT8152_PCI_CFG_ADDR ) ;
writel ( 0xb0000000 , IT8152_PCI_CFG_DATA ) ;
}
}
}
2008-10-05 13:25:44 +04:00
static struct hw_pci cmx2xx_pci __initdata = {
2007-09-23 18:59:26 +04:00
. swizzle = pci_std_swizzle ,
2008-10-05 13:25:44 +04:00
. map_irq = cmx2xx_pci_map_irq ,
2007-09-23 18:59:26 +04:00
. nr_controllers = 1 ,
. setup = it8152_pci_setup ,
2007-11-25 10:55:34 +03:00
. scan = it8152_pci_scan_bus ,
2008-10-05 13:25:44 +04:00
. preinit = cmx2xx_pci_preinit ,
2007-09-23 18:59:26 +04:00
} ;
2008-10-05 13:25:44 +04:00
static int __init cmx2xx_init_pci ( void )
2007-09-23 18:59:26 +04:00
{
if ( machine_is_armcore ( ) )
2008-10-05 13:25:44 +04:00
pci_common_init ( & cmx2xx_pci ) ;
2007-09-23 18:59:26 +04:00
return 0 ;
}
2008-10-05 13:25:44 +04:00
subsys_initcall ( cmx2xx_init_pci ) ;