2010-12-16 21:34:51 +01:00
/*
* linux / arch / arm / mach - sa1100 / pci - nanoengine . c
*
* PCI functions for BSE nanoEngine PCI
*
* Copyright ( C ) 2010 Marcelo Roberto Jimenez < mroberto @ cpti . cetuc . puc - rio . br >
*
* 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 program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/kernel.h>
# include <linux/irq.h>
# include <linux/pci.h>
# include <asm/mach/pci.h>
# include <asm/mach-types.h>
# include <mach/nanoengine.h>
2011-08-05 12:24:44 +02:00
# include <mach/hardware.h>
2010-12-16 21:34:51 +01:00
2015-01-09 20:34:42 -06:00
static void __iomem * nanoengine_pci_map_bus ( struct pci_bus * bus ,
unsigned int devfn , int where )
2010-12-16 21:34:51 +01:00
{
2015-01-09 20:34:42 -06:00
if ( bus - > number ! = 0 | | ( devfn > > 3 ) ! = 0 )
return NULL ;
2010-12-16 21:34:51 +01:00
2015-01-09 20:34:42 -06:00
return ( void __iomem * ) NANO_PCI_CONFIG_SPACE_VIRT +
2010-12-16 21:34:51 +01:00
( ( bus - > number < < 16 ) | ( devfn < < 8 ) | ( where & ~ 3 ) ) ;
}
static struct pci_ops pci_nano_ops = {
2015-01-09 20:34:42 -06:00
. map_bus = nanoengine_pci_map_bus ,
. read = pci_generic_config_read32 ,
. write = pci_generic_config_write32 ,
2010-12-16 21:34:51 +01:00
} ;
2011-06-10 15:30:21 +01:00
static int __init pci_nanoengine_map_irq ( const struct pci_dev * dev , u8 slot ,
u8 pin )
2010-12-16 21:34:51 +01:00
{
return NANOENGINE_IRQ_GPIO_PCI ;
}
2012-01-12 10:25:29 +00:00
static struct resource pci_io_ports =
DEFINE_RES_IO_NAMED ( 0x400 , 0x400 , " PCI IO " ) ;
2010-12-16 21:34:51 +01:00
static struct resource pci_non_prefetchable_memory = {
. name = " PCI non-prefetchable " ,
. start = NANO_PCI_MEM_RW_PHYS ,
/* nanoEngine documentation says there is a 1 Megabyte window here,
* but PCI reports just 128 + 8 kbytes . */
. end = NANO_PCI_MEM_RW_PHYS + NANO_PCI_MEM_RW_SIZE - 1 ,
/* .end = NANO_PCI_MEM_RW_PHYS + SZ_128K + SZ_8K - 1,*/
. flags = IORESOURCE_MEM ,
} ;
/*
* nanoEngine PCI reports 1 Megabyte of prefetchable memory , but it
* overlaps with previously defined memory .
*
* Here is what happens :
*
# dmesg
. . .
pci 0000 : 00 : 00.0 : [ 8086 : 1209 ] type 0 class 0x000200
pci 0000 : 00 : 00.0 : reg 10 : [ mem 0x00021000 - 0x00021fff ]
pci 0000 : 00 : 00.0 : reg 14 : [ io 0x0000 - 0x003f ]
pci 0000 : 00 : 00.0 : reg 18 : [ mem 0x00000000 - 0x0001ffff ]
pci 0000 : 00 : 00.0 : reg 30 : [ mem 0x00000000 - 0x000fffff pref ]
pci 0000 : 00 : 00.0 : supports D1 D2
pci 0000 : 00 : 00.0 : PME # supported from D0 D1 D2 D3hot
pci 0000 : 00 : 00.0 : PME # disabled
PCI : bus0 : Fast back to back transfers enabled
pci 0000 : 00 : 00.0 : BAR 6 : can ' t assign mem pref ( size 0x100000 )
pci 0000 : 00 : 00.0 : BAR 2 : assigned [ mem 0x18600000 - 0x1861ffff ]
pci 0000 : 00 : 00.0 : BAR 2 : set to [ mem 0x18600000 - 0x1861ffff ] ( PCI address [ 0x0 - 0x1ffff ] )
pci 0000 : 00 : 00.0 : BAR 0 : assigned [ mem 0x18620000 - 0x18620fff ]
pci 0000 : 00 : 00.0 : BAR 0 : set to [ mem 0x18620000 - 0x18620fff ] ( PCI address [ 0x20000 - 0x20fff ] )
pci 0000 : 00 : 00.0 : BAR 1 : assigned [ io 0x0400 - 0x043f ]
pci 0000 : 00 : 00.0 : BAR 1 : set to [ io 0x0400 - 0x043f ] ( PCI address [ 0x0 - 0x3f ] )
*
* On the other hand , if we do not request the prefetchable memory resource ,
* linux will alloc it first and the two non - prefetchable memory areas that
* are our real interest will not be mapped . So we choose to map it to an
* unused area . It gets recognized as expansion ROM , but becomes disabled .
*
* Here is what happens then :
*
# dmesg
. . .
pci 0000 : 00 : 00.0 : [ 8086 : 1209 ] type 0 class 0x000200
pci 0000 : 00 : 00.0 : reg 10 : [ mem 0x00021000 - 0x00021fff ]
pci 0000 : 00 : 00.0 : reg 14 : [ io 0x0000 - 0x003f ]
pci 0000 : 00 : 00.0 : reg 18 : [ mem 0x00000000 - 0x0001ffff ]
pci 0000 : 00 : 00.0 : reg 30 : [ mem 0x00000000 - 0x000fffff pref ]
pci 0000 : 00 : 00.0 : supports D1 D2
pci 0000 : 00 : 00.0 : PME # supported from D0 D1 D2 D3hot
pci 0000 : 00 : 00.0 : PME # disabled
PCI : bus0 : Fast back to back transfers enabled
pci 0000 : 00 : 00.0 : BAR 6 : assigned [ mem 0x78000000 - 0x780fffff pref ]
pci 0000 : 00 : 00.0 : BAR 2 : assigned [ mem 0x18600000 - 0x1861ffff ]
pci 0000 : 00 : 00.0 : BAR 2 : set to [ mem 0x18600000 - 0x1861ffff ] ( PCI address [ 0x0 - 0x1ffff ] )
pci 0000 : 00 : 00.0 : BAR 0 : assigned [ mem 0x18620000 - 0x18620fff ]
pci 0000 : 00 : 00.0 : BAR 0 : set to [ mem 0x18620000 - 0x18620fff ] ( PCI address [ 0x20000 - 0x20fff ] )
pci 0000 : 00 : 00.0 : BAR 1 : assigned [ io 0x0400 - 0x043f ]
pci 0000 : 00 : 00.0 : BAR 1 : set to [ io 0x0400 - 0x043f ] ( PCI address [ 0x0 - 0x3f ] )
# lspci -vv -s 0000:00:00.0
00 : 00.0 Class 0200 : Device 8086 : 1209 ( rev 09 )
Control : I / O + Mem + BusMaster + SpecCycle - MemWINV - VGASnoop - ParErr + Stepping - SERR + FastB2B - DisINTx -
Status : Cap + 66 MHz - UDF - FastB2B + ParErr - DEVSEL = medium > TAbort - < TAbort - < MAbort - > SERR + < PERR + INTx -
Latency : 0 ( 2000 ns min , 14000 ns max ) , Cache Line Size : 32 bytes
Interrupt : pin A routed to IRQ 0
Region 0 : Memory at 18620000 ( 32 - bit , non - prefetchable ) [ size = 4 K ]
Region 1 : I / O ports at 0400 [ size = 64 ]
Region 2 : [ virtual ] Memory at 18600000 ( 32 - bit , non - prefetchable ) [ size = 128 K ]
[ virtual ] Expansion ROM at 78000000 [ disabled ] [ size = 1 M ]
Capabilities : [ dc ] Power Management version 2
Flags : PMEClk - DSI + D1 + D2 + AuxCurrent = 0 mA PME ( D0 + , D1 + , D2 + , D3hot + , D3cold - )
Status : D0 NoSoftRst - PME - Enable - DSel = 0 DScale = 2 PME -
Kernel driver in use : e100
Kernel modules : e100
*
*/
static struct resource pci_prefetchable_memory = {
. name = " PCI prefetchable " ,
. start = 0x78000000 ,
. end = 0x78000000 + NANO_PCI_MEM_RW_SIZE - 1 ,
. flags = IORESOURCE_MEM | IORESOURCE_PREFETCH ,
} ;
2011-10-28 16:26:16 -06:00
static int __init pci_nanoengine_setup_resources ( struct pci_sys_data * sys )
2010-12-16 21:34:51 +01:00
{
if ( request_resource ( & ioport_resource , & pci_io_ports ) ) {
printk ( KERN_ERR " PCI: unable to allocate io port region \n " ) ;
return - EBUSY ;
}
if ( request_resource ( & iomem_resource , & pci_non_prefetchable_memory ) ) {
release_resource ( & pci_io_ports ) ;
printk ( KERN_ERR " PCI: unable to allocate non prefetchable \n " ) ;
return - EBUSY ;
}
if ( request_resource ( & iomem_resource , & pci_prefetchable_memory ) ) {
release_resource ( & pci_io_ports ) ;
release_resource ( & pci_non_prefetchable_memory ) ;
printk ( KERN_ERR " PCI: unable to allocate prefetchable \n " ) ;
return - EBUSY ;
}
2012-02-23 20:19:01 -07:00
pci_add_resource_offset ( & sys - > resources , & pci_io_ports , sys - > io_offset ) ;
pci_add_resource_offset ( & sys - > resources ,
& pci_non_prefetchable_memory , sys - > mem_offset ) ;
pci_add_resource_offset ( & sys - > resources ,
& pci_prefetchable_memory , sys - > mem_offset ) ;
2010-12-16 21:34:51 +01:00
return 1 ;
}
int __init pci_nanoengine_setup ( int nr , struct pci_sys_data * sys )
{
int ret = 0 ;
2011-06-28 21:16:13 -05:00
pcibios_min_io = 0 ;
pcibios_min_mem = 0 ;
2010-12-16 21:34:51 +01:00
if ( nr = = 0 ) {
sys - > mem_offset = NANO_PCI_MEM_RW_PHYS ;
sys - > io_offset = 0x400 ;
2011-10-28 16:26:16 -06:00
ret = pci_nanoengine_setup_resources ( sys ) ;
2010-12-16 21:34:51 +01:00
/* Enable alternate memory bus master mode, see
* " Intel StrongARM SA1110 Developer's Manual " ,
* section 10.8 , " Alternate Memory Bus Master Mode " . */
GPDR = ( GPDR & ~ GPIO_MBREQ ) | GPIO_MBGNT ;
GAFR | = GPIO_MBGNT | GPIO_MBREQ ;
TUCR | = TUCR_MBGPIO ;
}
return ret ;
}
static struct hw_pci nanoengine_pci __initdata = {
. map_irq = pci_nanoengine_map_irq ,
. nr_controllers = 1 ,
2012-03-10 12:49:16 +00:00
. ops = & pci_nano_ops ,
2010-12-16 21:34:51 +01:00
. setup = pci_nanoengine_setup ,
} ;
static int __init nanoengine_pci_init ( void )
{
if ( machine_is_nanoengine ( ) )
pci_common_init ( & nanoengine_pci ) ;
return 0 ;
}
subsys_initcall ( nanoengine_pci_init ) ;