2011-03-23 02:33:58 +03:00
/*
* drivers / misc / spear13xx_pcie_gadget . c
*
* Copyright ( C ) 2010 ST Microelectronics
2015-06-26 01:01:08 +03:00
* Pratyush Anand < pratyush . anand @ gmail . com >
2011-03-23 02:33:58 +03:00
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
2014-08-07 16:13:28 +04:00
# include <linux/device.h>
2011-03-23 02:33:58 +03:00
# include <linux/clk.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/pci_regs.h>
# include <linux/configfs.h>
# include <mach/pcie.h>
# include <mach/misc_regs.h>
# define IN0_MEM_SIZE (200 * 1024 * 1024 - 1)
/* In current implementation address translation is done using IN0 only.
* So IN1 start address and IN0 end address has been kept same
*/
# define IN1_MEM_SIZE (0 * 1024 * 1024 - 1)
# define IN_IO_SIZE (20 * 1024 * 1024 - 1)
# define IN_CFG0_SIZE (12 * 1024 * 1024 - 1)
# define IN_CFG1_SIZE (12 * 1024 * 1024 - 1)
# define IN_MSG_SIZE (12 * 1024 * 1024 - 1)
/* Keep default BAR size as 4K*/
/* AORAM would be mapped by default*/
# define INBOUND_ADDR_MASK (SPEAR13XX_SYSRAM1_SIZE - 1)
# define INT_TYPE_NO_INT 0
# define INT_TYPE_INTX 1
# define INT_TYPE_MSI 2
struct spear_pcie_gadget_config {
void __iomem * base ;
void __iomem * va_app_base ;
void __iomem * va_dbi_base ;
char int_type [ 10 ] ;
ulong requested_msi ;
ulong configured_msi ;
ulong bar0_size ;
ulong bar0_rw_offset ;
void __iomem * va_bar0_address ;
} ;
struct pcie_gadget_target {
struct configfs_subsystem subsys ;
struct spear_pcie_gadget_config config ;
} ;
struct pcie_gadget_target_attr {
struct configfs_attribute attr ;
ssize_t ( * show ) ( struct spear_pcie_gadget_config * config ,
char * buf ) ;
ssize_t ( * store ) ( struct spear_pcie_gadget_config * config ,
const char * buf ,
size_t count ) ;
} ;
static void enable_dbi_access ( struct pcie_app_reg __iomem * app_reg )
{
/* Enable DBI access */
writel ( readl ( & app_reg - > slv_armisc ) | ( 1 < < AXI_OP_DBI_ACCESS_ID ) ,
& app_reg - > slv_armisc ) ;
writel ( readl ( & app_reg - > slv_awmisc ) | ( 1 < < AXI_OP_DBI_ACCESS_ID ) ,
& app_reg - > slv_awmisc ) ;
}
static void disable_dbi_access ( struct pcie_app_reg __iomem * app_reg )
{
/* disable DBI access */
writel ( readl ( & app_reg - > slv_armisc ) & ~ ( 1 < < AXI_OP_DBI_ACCESS_ID ) ,
& app_reg - > slv_armisc ) ;
writel ( readl ( & app_reg - > slv_awmisc ) & ~ ( 1 < < AXI_OP_DBI_ACCESS_ID ) ,
& app_reg - > slv_awmisc ) ;
}
static void spear_dbi_read_reg ( struct spear_pcie_gadget_config * config ,
int where , int size , u32 * val )
{
struct pcie_app_reg __iomem * app_reg = config - > va_app_base ;
ulong va_address ;
/* Enable DBI access */
enable_dbi_access ( app_reg ) ;
va_address = ( ulong ) config - > va_dbi_base + ( where & ~ 0x3 ) ;
* val = readl ( va_address ) ;
if ( size = = 1 )
* val = ( * val > > ( 8 * ( where & 3 ) ) ) & 0xff ;
else if ( size = = 2 )
* val = ( * val > > ( 8 * ( where & 3 ) ) ) & 0xffff ;
/* Disable DBI access */
disable_dbi_access ( app_reg ) ;
}
static void spear_dbi_write_reg ( struct spear_pcie_gadget_config * config ,
int where , int size , u32 val )
{
struct pcie_app_reg __iomem * app_reg = config - > va_app_base ;
ulong va_address ;
/* Enable DBI access */
enable_dbi_access ( app_reg ) ;
va_address = ( ulong ) config - > va_dbi_base + ( where & ~ 0x3 ) ;
if ( size = = 4 )
writel ( val , va_address ) ;
else if ( size = = 2 )
writew ( val , va_address + ( where & 2 ) ) ;
else if ( size = = 1 )
writeb ( val , va_address + ( where & 3 ) ) ;
/* Disable DBI access */
disable_dbi_access ( app_reg ) ;
}
# define PCI_FIND_CAP_TTL 48
static int pci_find_own_next_cap_ttl ( struct spear_pcie_gadget_config * config ,
u32 pos , int cap , int * ttl )
{
u32 id ;
while ( ( * ttl ) - - ) {
spear_dbi_read_reg ( config , pos , 1 , & pos ) ;
if ( pos < 0x40 )
break ;
pos & = ~ 3 ;
spear_dbi_read_reg ( config , pos + PCI_CAP_LIST_ID , 1 , & id ) ;
if ( id = = 0xff )
break ;
if ( id = = cap )
return pos ;
pos + = PCI_CAP_LIST_NEXT ;
}
return 0 ;
}
static int pci_find_own_next_cap ( struct spear_pcie_gadget_config * config ,
u32 pos , int cap )
{
int ttl = PCI_FIND_CAP_TTL ;
return pci_find_own_next_cap_ttl ( config , pos , cap , & ttl ) ;
}
static int pci_find_own_cap_start ( struct spear_pcie_gadget_config * config ,
u8 hdr_type )
{
u32 status ;
spear_dbi_read_reg ( config , PCI_STATUS , 2 , & status ) ;
if ( ! ( status & PCI_STATUS_CAP_LIST ) )
return 0 ;
switch ( hdr_type ) {
case PCI_HEADER_TYPE_NORMAL :
case PCI_HEADER_TYPE_BRIDGE :
return PCI_CAPABILITY_LIST ;
case PCI_HEADER_TYPE_CARDBUS :
return PCI_CB_CAPABILITY_LIST ;
default :
return 0 ;
}
return 0 ;
}
/*
* Tell if a device supports a given PCI capability .
* Returns the address of the requested capability structure within the
* device ' s PCI configuration space or 0 in case the device does not
* support it . Possible values for @ cap :
*
* % PCI_CAP_ID_PM Power Management
* % PCI_CAP_ID_AGP Accelerated Graphics Port
* % PCI_CAP_ID_VPD Vital Product Data
* % PCI_CAP_ID_SLOTID Slot Identification
* % PCI_CAP_ID_MSI Message Signalled Interrupts
* % PCI_CAP_ID_CHSWP CompactPCI HotSwap
* % PCI_CAP_ID_PCIX PCI - X
* % PCI_CAP_ID_EXP PCI Express
*/
static int pci_find_own_capability ( struct spear_pcie_gadget_config * config ,
int cap )
{
u32 pos ;
u32 hdr_type ;
spear_dbi_read_reg ( config , PCI_HEADER_TYPE , 1 , & hdr_type ) ;
pos = pci_find_own_cap_start ( config , hdr_type ) ;
if ( pos )
pos = pci_find_own_next_cap ( config , pos , cap ) ;
return pos ;
}
static irqreturn_t spear_pcie_gadget_irq ( int irq , void * dev_id )
{
return 0 ;
}
/*
* configfs interfaces show / store functions
*/
2015-10-03 16:32:54 +03:00
static struct pcie_gadget_target * to_target ( struct config_item * item )
2011-03-23 02:33:58 +03:00
{
2015-10-03 16:32:54 +03:00
return item ?
container_of ( to_configfs_subsystem ( to_config_group ( item ) ) ,
struct pcie_gadget_target , subsys ) : NULL ;
}
static ssize_t pcie_gadget_link_show ( struct config_item * item , char * buf )
{
struct pcie_app_reg __iomem * app_reg = to_target ( item ) - > va_app_base ;
2011-03-23 02:33:58 +03:00
if ( readl ( & app_reg - > app_status_1 ) & ( ( u32 ) 1 < < XMLH_LINK_UP_ID ) )
return sprintf ( buf , " UP " ) ;
else
return sprintf ( buf , " DOWN " ) ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_link_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
2015-10-03 16:32:54 +03:00
struct pcie_app_reg __iomem * app_reg = to_target ( item ) - > va_app_base ;
2011-03-23 02:33:58 +03:00
if ( sysfs_streq ( buf , " UP " ) )
writel ( readl ( & app_reg - > app_ctrl_0 ) | ( 1 < < APP_LTSSM_ENABLE_ID ) ,
& app_reg - > app_ctrl_0 ) ;
else if ( sysfs_streq ( buf , " DOWN " ) )
writel ( readl ( & app_reg - > app_ctrl_0 )
& ~ ( 1 < < APP_LTSSM_ENABLE_ID ) ,
& app_reg - > app_ctrl_0 ) ;
else
return - EINVAL ;
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_int_type_show ( struct config_item * item , char * buf )
2011-03-23 02:33:58 +03:00
{
2015-10-03 16:32:54 +03:00
return sprintf ( buf , " %s " , to_target ( item ) - > int_type ) ;
2011-03-23 02:33:58 +03:00
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_int_type_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
2015-10-03 16:32:54 +03:00
struct spear_pcie_gadget_config * config = to_target ( item )
2011-03-23 02:33:58 +03:00
u32 cap , vec , flags ;
ulong vector ;
if ( sysfs_streq ( buf , " INTA " ) )
spear_dbi_write_reg ( config , PCI_INTERRUPT_LINE , 1 , 1 ) ;
else if ( sysfs_streq ( buf , " MSI " ) ) {
vector = config - > requested_msi ;
vec = 0 ;
while ( vector > 1 ) {
vector / = 2 ;
vec + + ;
}
spear_dbi_write_reg ( config , PCI_INTERRUPT_LINE , 1 , 0 ) ;
cap = pci_find_own_capability ( config , PCI_CAP_ID_MSI ) ;
spear_dbi_read_reg ( config , cap + PCI_MSI_FLAGS , 1 , & flags ) ;
flags & = ~ PCI_MSI_FLAGS_QMASK ;
flags | = vec < < 1 ;
spear_dbi_write_reg ( config , cap + PCI_MSI_FLAGS , 1 , flags ) ;
} else
return - EINVAL ;
strcpy ( config - > int_type , buf ) ;
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_no_of_msi_show ( struct config_item * item , char * buf )
2011-03-23 02:33:58 +03:00
{
2015-10-03 16:32:54 +03:00
struct spear_pcie_gadget_config * config = to_target ( item )
struct pcie_app_reg __iomem * app_reg = to_target ( item ) - > va_app_base ;
2011-03-23 02:33:58 +03:00
u32 cap , vec , flags ;
ulong vector ;
if ( ( readl ( & app_reg - > msg_status ) & ( 1 < < CFG_MSI_EN_ID ) )
! = ( 1 < < CFG_MSI_EN_ID ) )
vector = 0 ;
else {
cap = pci_find_own_capability ( config , PCI_CAP_ID_MSI ) ;
spear_dbi_read_reg ( config , cap + PCI_MSI_FLAGS , 1 , & flags ) ;
flags & = ~ PCI_MSI_FLAGS_QSIZE ;
vec = flags > > 4 ;
vector = 1 ;
while ( vec - - )
vector * = 2 ;
}
config - > configured_msi = vector ;
return sprintf ( buf , " %lu " , vector ) ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_no_of_msi_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
2013-06-04 08:15:16 +04:00
int ret ;
2015-10-03 16:32:54 +03:00
ret = kstrtoul ( buf , 0 , & to_target ( item ) - > requested_msi ) ;
2013-06-04 08:15:16 +04:00
if ( ret )
return ret ;
2011-03-23 02:33:58 +03:00
if ( config - > requested_msi > 32 )
config - > requested_msi = 32 ;
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_inta_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
2015-10-03 16:32:54 +03:00
struct pcie_app_reg __iomem * app_reg = to_target ( item ) - > va_app_base ;
2011-03-23 02:33:58 +03:00
ulong en ;
2013-06-04 08:15:16 +04:00
int ret ;
2011-03-23 02:33:58 +03:00
2013-06-04 08:15:16 +04:00
ret = kstrtoul ( buf , 0 , & en ) ;
if ( ret )
return ret ;
2011-03-23 02:33:58 +03:00
if ( en )
writel ( readl ( & app_reg - > app_ctrl_0 ) | ( 1 < < SYS_INT_ID ) ,
& app_reg - > app_ctrl_0 ) ;
else
writel ( readl ( & app_reg - > app_ctrl_0 ) & ~ ( 1 < < SYS_INT_ID ) ,
& app_reg - > app_ctrl_0 ) ;
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_send_msi_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
2015-10-03 16:32:54 +03:00
struct spear_pcie_gadget_config * config = to_target ( item )
2011-03-23 02:33:58 +03:00
struct pcie_app_reg __iomem * app_reg = config - > va_app_base ;
ulong vector ;
u32 ven_msi ;
2013-06-04 08:15:16 +04:00
int ret ;
2011-03-23 02:33:58 +03:00
2013-06-04 08:15:16 +04:00
ret = kstrtoul ( buf , 0 , & vector ) ;
if ( ret )
return ret ;
2011-03-23 02:33:58 +03:00
if ( ! config - > configured_msi )
return - EINVAL ;
if ( vector > = config - > configured_msi )
return - EINVAL ;
ven_msi = readl ( & app_reg - > ven_msi_1 ) ;
ven_msi & = ~ VEN_MSI_FUN_NUM_MASK ;
ven_msi | = 0 < < VEN_MSI_FUN_NUM_ID ;
ven_msi & = ~ VEN_MSI_TC_MASK ;
ven_msi | = 0 < < VEN_MSI_TC_ID ;
ven_msi & = ~ VEN_MSI_VECTOR_MASK ;
ven_msi | = vector < < VEN_MSI_VECTOR_ID ;
/* generating interrupt for msi vector */
ven_msi | = VEN_MSI_REQ_EN ;
writel ( ven_msi , & app_reg - > ven_msi_1 ) ;
udelay ( 1 ) ;
ven_msi & = ~ VEN_MSI_REQ_EN ;
writel ( ven_msi , & app_reg - > ven_msi_1 ) ;
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_vendor_id_show ( struct config_item * item , char * buf )
2011-03-23 02:33:58 +03:00
{
u32 id ;
2015-10-03 16:32:54 +03:00
spear_dbi_read_reg ( to_target ( item ) , PCI_VENDOR_ID , 2 , & id ) ;
2011-03-23 02:33:58 +03:00
return sprintf ( buf , " %x " , id ) ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_vendor_id_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
ulong id ;
2013-06-04 08:15:16 +04:00
int ret ;
2011-03-23 02:33:58 +03:00
2013-06-04 08:15:16 +04:00
ret = kstrtoul ( buf , 0 , & id ) ;
if ( ret )
return ret ;
2011-03-23 02:33:58 +03:00
2015-10-03 16:32:54 +03:00
spear_dbi_write_reg ( to_target ( item ) , PCI_VENDOR_ID , 2 , id ) ;
2011-03-23 02:33:58 +03:00
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_device_id_show ( struct config_item * item , char * buf )
2011-03-23 02:33:58 +03:00
{
u32 id ;
2015-10-03 16:32:54 +03:00
spear_dbi_read_reg ( to_target ( item ) , PCI_DEVICE_ID , 2 , & id ) ;
2011-03-23 02:33:58 +03:00
return sprintf ( buf , " %x " , id ) ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_device_id_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
ulong id ;
2013-06-04 08:15:16 +04:00
int ret ;
2011-03-23 02:33:58 +03:00
2013-06-04 08:15:16 +04:00
ret = kstrtoul ( buf , 0 , & id ) ;
if ( ret )
return ret ;
2011-03-23 02:33:58 +03:00
2015-10-03 16:32:54 +03:00
spear_dbi_write_reg ( to_target ( item ) , PCI_DEVICE_ID , 2 , id ) ;
2011-03-23 02:33:58 +03:00
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_bar0_size_show ( struct config_item * item , char * buf )
2011-03-23 02:33:58 +03:00
{
2015-10-03 16:32:54 +03:00
return sprintf ( buf , " %lx " , to_target ( item ) - > bar0_size ) ;
2011-03-23 02:33:58 +03:00
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_bar0_size_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
2015-10-03 16:32:54 +03:00
struct spear_pcie_gadget_config * config = to_target ( item )
2011-03-23 02:33:58 +03:00
ulong size ;
u32 pos , pos1 ;
u32 no_of_bit = 0 ;
2013-06-04 08:15:16 +04:00
int ret ;
ret = kstrtoul ( buf , 0 , & size ) ;
if ( ret )
return ret ;
2011-03-23 02:33:58 +03:00
/* min bar size is 256 */
if ( size < = 0x100 )
size = 0x100 ;
/* max bar size is 1MB*/
else if ( size > = 0x100000 )
size = 0x100000 ;
else {
pos = 0 ;
pos1 = 0 ;
while ( pos < 21 ) {
pos = find_next_bit ( ( ulong * ) & size , 21 , pos ) ;
if ( pos ! = 21 )
pos1 = pos + 1 ;
pos + + ;
no_of_bit + + ;
}
if ( no_of_bit = = 2 )
pos1 - - ;
size = 1 < < pos1 ;
}
config - > bar0_size = size ;
spear_dbi_write_reg ( config , PCIE_BAR0_MASK_REG , 4 , size - 1 ) ;
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_bar0_address_show ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
char * buf )
{
2015-10-03 16:32:54 +03:00
struct pcie_app_reg __iomem * app_reg = to_target ( item ) - > va_app_base ;
2011-03-23 02:33:58 +03:00
u32 address = readl ( & app_reg - > pim0_mem_addr_start ) ;
return sprintf ( buf , " %x " , address ) ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_bar0_address_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
2015-10-03 16:32:54 +03:00
struct spear_pcie_gadget_config * config = to_target ( item )
2011-03-23 02:33:58 +03:00
struct pcie_app_reg __iomem * app_reg = config - > va_app_base ;
ulong address ;
2013-06-04 08:15:16 +04:00
int ret ;
2011-03-23 02:33:58 +03:00
2013-06-04 08:15:16 +04:00
ret = kstrtoul ( buf , 0 , & address ) ;
if ( ret )
return ret ;
2011-03-23 02:33:58 +03:00
address & = ~ ( config - > bar0_size - 1 ) ;
if ( config - > va_bar0_address )
iounmap ( config - > va_bar0_address ) ;
config - > va_bar0_address = ioremap ( address , config - > bar0_size ) ;
if ( ! config - > va_bar0_address )
return - ENOMEM ;
writel ( address , & app_reg - > pim0_mem_addr_start ) ;
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_bar0_rw_offset_show ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
char * buf )
{
2015-10-03 16:32:54 +03:00
return sprintf ( buf , " %lx " , to_target ( item ) - > bar0_rw_offset ) ;
2011-03-23 02:33:58 +03:00
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_bar0_rw_offset_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
ulong offset ;
2013-06-04 08:15:16 +04:00
int ret ;
2011-03-23 02:33:58 +03:00
2013-06-04 08:15:16 +04:00
ret = kstrtoul ( buf , 0 , & offset ) ;
if ( ret )
return ret ;
2011-03-23 02:33:58 +03:00
if ( offset % 4 )
return - EINVAL ;
2015-10-03 16:32:54 +03:00
to_target ( item ) - > bar0_rw_offset = offset ;
2011-03-23 02:33:58 +03:00
return count ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_bar0_data_show ( struct config_item * item , char * buf )
2011-03-23 02:33:58 +03:00
{
2015-10-03 16:32:54 +03:00
struct spear_pcie_gadget_config * config = to_target ( item )
2011-03-23 02:33:58 +03:00
ulong data ;
if ( ! config - > va_bar0_address )
return - ENOMEM ;
data = readl ( ( ulong ) config - > va_bar0_address + config - > bar0_rw_offset ) ;
return sprintf ( buf , " %lx " , data ) ;
}
2015-10-03 16:32:54 +03:00
static ssize_t pcie_gadget_bar0_data_store ( struct config_item * item ,
2011-03-23 02:33:58 +03:00
const char * buf , size_t count )
{
2015-10-03 16:32:54 +03:00
struct spear_pcie_gadget_config * config = to_target ( item )
2011-03-23 02:33:58 +03:00
ulong data ;
2013-06-04 08:15:16 +04:00
int ret ;
2011-03-23 02:33:58 +03:00
2013-06-04 08:15:16 +04:00
ret = kstrtoul ( buf , 0 , & data ) ;
if ( ret )
return ret ;
2011-03-23 02:33:58 +03:00
if ( ! config - > va_bar0_address )
return - ENOMEM ;
writel ( data , ( ulong ) config - > va_bar0_address + config - > bar0_rw_offset ) ;
return count ;
}
2015-10-03 16:32:54 +03:00
CONFIGFS_ATTR ( pcie_gadget_ , link ) ;
CONFIGFS_ATTR ( pcie_gadget_ , int_type ) ;
CONFIGFS_ATTR ( pcie_gadget_ , no_of_msi ) ;
CONFIGFS_ATTR_WO ( pcie_gadget_ , inta ) ;
CONFIGFS_ATTR_WO ( pcie_gadget_ , send_msi ) ;
CONFIGFS_ATTR ( pcie_gadget_ , vendor_id ) ;
CONFIGFS_ATTR ( pcie_gadget_ , device_id ) ;
CONFIGFS_ATTR ( pcie_gadget_ , bar0_size ) ;
CONFIGFS_ATTR ( pcie_gadget_ , bar0_address ) ;
CONFIGFS_ATTR ( pcie_gadget_ , bar0_rw_offset ) ;
CONFIGFS_ATTR ( pcie_gadget_ , bar0_data ) ;
2011-03-23 02:33:58 +03:00
static struct configfs_attribute * pcie_gadget_target_attrs [ ] = {
2015-10-03 16:32:54 +03:00
& pcie_gadget_attr_link ,
& pcie_gadget_attr_int_type ,
& pcie_gadget_attr_no_of_msi ,
& pcie_gadget_attr_inta ,
& pcie_gadget_attr_send_msi ,
& pcie_gadget_attr_vendor_id ,
& pcie_gadget_attr_device_id ,
& pcie_gadget_attr_bar0_size ,
& pcie_gadget_attr_bar0_address ,
& pcie_gadget_attr_bar0_rw_offset ,
& pcie_gadget_attr_bar0_data ,
2011-03-23 02:33:58 +03:00
NULL ,
} ;
static struct config_item_type pcie_gadget_target_type = {
. ct_attrs = pcie_gadget_target_attrs ,
. ct_owner = THIS_MODULE ,
} ;
static void spear13xx_pcie_device_init ( struct spear_pcie_gadget_config * config )
{
struct pcie_app_reg __iomem * app_reg = config - > va_app_base ;
/*setup registers for outbound translation */
writel ( config - > base , & app_reg - > in0_mem_addr_start ) ;
writel ( app_reg - > in0_mem_addr_start + IN0_MEM_SIZE ,
& app_reg - > in0_mem_addr_limit ) ;
writel ( app_reg - > in0_mem_addr_limit + 1 , & app_reg - > in1_mem_addr_start ) ;
writel ( app_reg - > in1_mem_addr_start + IN1_MEM_SIZE ,
& app_reg - > in1_mem_addr_limit ) ;
writel ( app_reg - > in1_mem_addr_limit + 1 , & app_reg - > in_io_addr_start ) ;
writel ( app_reg - > in_io_addr_start + IN_IO_SIZE ,
& app_reg - > in_io_addr_limit ) ;
writel ( app_reg - > in_io_addr_limit + 1 , & app_reg - > in_cfg0_addr_start ) ;
writel ( app_reg - > in_cfg0_addr_start + IN_CFG0_SIZE ,
& app_reg - > in_cfg0_addr_limit ) ;
writel ( app_reg - > in_cfg0_addr_limit + 1 , & app_reg - > in_cfg1_addr_start ) ;
writel ( app_reg - > in_cfg1_addr_start + IN_CFG1_SIZE ,
& app_reg - > in_cfg1_addr_limit ) ;
writel ( app_reg - > in_cfg1_addr_limit + 1 , & app_reg - > in_msg_addr_start ) ;
writel ( app_reg - > in_msg_addr_start + IN_MSG_SIZE ,
& app_reg - > in_msg_addr_limit ) ;
writel ( app_reg - > in0_mem_addr_start , & app_reg - > pom0_mem_addr_start ) ;
writel ( app_reg - > in1_mem_addr_start , & app_reg - > pom1_mem_addr_start ) ;
writel ( app_reg - > in_io_addr_start , & app_reg - > pom_io_addr_start ) ;
/*setup registers for inbound translation */
/* Keep AORAM mapped at BAR0 as default */
config - > bar0_size = INBOUND_ADDR_MASK + 1 ;
spear_dbi_write_reg ( config , PCIE_BAR0_MASK_REG , 4 , INBOUND_ADDR_MASK ) ;
spear_dbi_write_reg ( config , PCI_BASE_ADDRESS_0 , 4 , 0xC ) ;
config - > va_bar0_address = ioremap ( SPEAR13XX_SYSRAM1_BASE ,
config - > bar0_size ) ;
writel ( SPEAR13XX_SYSRAM1_BASE , & app_reg - > pim0_mem_addr_start ) ;
writel ( 0 , & app_reg - > pim1_mem_addr_start ) ;
writel ( INBOUND_ADDR_MASK + 1 , & app_reg - > mem0_addr_offset_limit ) ;
writel ( 0x0 , & app_reg - > pim_io_addr_start ) ;
writel ( 0x0 , & app_reg - > pim_io_addr_start ) ;
writel ( 0x0 , & app_reg - > pim_rom_addr_start ) ;
writel ( DEVICE_TYPE_EP | ( 1 < < MISCTRL_EN_ID )
| ( ( u32 ) 1 < < REG_TRANSLATION_ENABLE ) ,
& app_reg - > app_ctrl_0 ) ;
/* disable all rx interrupts */
writel ( 0 , & app_reg - > int_mask ) ;
/* Select INTA as default*/
spear_dbi_write_reg ( config , PCI_INTERRUPT_LINE , 1 , 1 ) ;
}
2012-11-19 22:23:05 +04:00
static int spear_pcie_gadget_probe ( struct platform_device * pdev )
2011-03-23 02:33:58 +03:00
{
struct resource * res0 , * res1 ;
unsigned int status = 0 ;
int irq ;
struct clk * clk ;
static struct pcie_gadget_target * target ;
struct spear_pcie_gadget_config * config ;
struct config_item * cg_item ;
struct configfs_subsystem * subsys ;
2014-08-07 16:13:28 +04:00
target = devm_kzalloc ( & pdev - > dev , sizeof ( * target ) , GFP_KERNEL ) ;
2011-03-23 02:33:58 +03:00
if ( ! target ) {
dev_err ( & pdev - > dev , " out of memory \n " ) ;
2014-08-07 16:13:28 +04:00
return - ENOMEM ;
2011-03-23 02:33:58 +03:00
}
cg_item = & target - > subsys . su_group . cg_item ;
sprintf ( cg_item - > ci_namebuf , " pcie_gadget.%d " , pdev - > id ) ;
cg_item - > ci_type = & pcie_gadget_target_type ;
config = & target - > config ;
2014-08-07 16:13:28 +04:00
/* get resource for application registers*/
res0 = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
config - > va_app_base = devm_ioremap_resource ( & pdev - > dev , res0 ) ;
if ( IS_ERR ( config - > va_app_base ) ) {
2011-03-23 02:33:58 +03:00
dev_err ( & pdev - > dev , " ioremap fail \n " ) ;
2014-08-07 16:13:28 +04:00
return PTR_ERR ( config - > va_app_base ) ;
2011-03-23 02:33:58 +03:00
}
2014-08-07 16:13:28 +04:00
/* get resource for dbi registers*/
res1 = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
2011-03-23 02:33:58 +03:00
config - > base = ( void __iomem * ) res1 - > start ;
2014-08-07 16:13:28 +04:00
config - > va_dbi_base = devm_ioremap_resource ( & pdev - > dev , res1 ) ;
if ( IS_ERR ( config - > va_dbi_base ) ) {
2011-03-23 02:33:58 +03:00
dev_err ( & pdev - > dev , " ioremap fail \n " ) ;
2014-08-07 16:13:28 +04:00
return PTR_ERR ( config - > va_dbi_base ) ;
2011-03-23 02:33:58 +03:00
}
2013-05-23 14:35:23 +04:00
platform_set_drvdata ( pdev , target ) ;
2011-03-23 02:33:58 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
dev_err ( & pdev - > dev , " no update irq? \n " ) ;
2014-08-07 16:13:28 +04:00
return irq ;
2011-03-23 02:33:58 +03:00
}
2014-08-07 16:13:28 +04:00
status = devm_request_irq ( & pdev - > dev , irq , spear_pcie_gadget_irq ,
0 , pdev - > name , NULL ) ;
2011-03-23 02:33:58 +03:00
if ( status ) {
2011-04-24 07:38:19 +04:00
dev_err ( & pdev - > dev ,
" pcie gadget interrupt IRQ%d already claimed \n " , irq ) ;
2014-08-07 16:13:28 +04:00
return status ;
2011-03-23 02:33:58 +03:00
}
/* Register configfs hooks */
subsys = & target - > subsys ;
config_group_init ( & subsys - > su_group ) ;
mutex_init ( & subsys - > su_mutex ) ;
status = configfs_register_subsystem ( subsys ) ;
if ( status )
2014-08-07 16:13:28 +04:00
return status ;
2011-03-23 02:33:58 +03:00
/*
* init basic pcie application registers
* do not enable clock if it is PCIE0 . Ideally , all controller should
* have been independent from others with respect to clock . But PCIE1
* and 2 depends on PCIE0 . So PCIE0 clk is provided during board init .
*/
if ( pdev - > id = = 1 ) {
/*
* Ideally CFG Clock should have been also enabled here . But
* it is done currently during board init routne
*/
clk = clk_get_sys ( " pcie1 " , NULL ) ;
if ( IS_ERR ( clk ) ) {
pr_err ( " %s:couldn't get clk for pcie1 \n " , __func__ ) ;
2014-08-07 16:13:28 +04:00
return PTR_ERR ( clk ) ;
2011-03-23 02:33:58 +03:00
}
2013-05-31 16:01:30 +04:00
status = clk_enable ( clk ) ;
if ( status ) {
2011-03-23 02:33:58 +03:00
pr_err ( " %s:couldn't enable clk for pcie1 \n " , __func__ ) ;
2014-08-07 16:13:28 +04:00
return status ;
2011-03-23 02:33:58 +03:00
}
} else if ( pdev - > id = = 2 ) {
/*
* Ideally CFG Clock should have been also enabled here . But
* it is done currently during board init routne
*/
clk = clk_get_sys ( " pcie2 " , NULL ) ;
if ( IS_ERR ( clk ) ) {
pr_err ( " %s:couldn't get clk for pcie2 \n " , __func__ ) ;
2014-08-07 16:13:28 +04:00
return PTR_ERR ( clk ) ;
2011-03-23 02:33:58 +03:00
}
2013-05-31 16:01:30 +04:00
status = clk_enable ( clk ) ;
if ( status ) {
2011-03-23 02:33:58 +03:00
pr_err ( " %s:couldn't enable clk for pcie2 \n " , __func__ ) ;
2014-08-07 16:13:28 +04:00
return status ;
2011-03-23 02:33:58 +03:00
}
}
spear13xx_pcie_device_init ( config ) ;
return 0 ;
}
2012-11-19 22:26:02 +04:00
static int spear_pcie_gadget_remove ( struct platform_device * pdev )
2011-03-23 02:33:58 +03:00
{
static struct pcie_gadget_target * target ;
2013-05-23 14:35:23 +04:00
target = platform_get_drvdata ( pdev ) ;
2011-03-23 02:33:58 +03:00
configfs_unregister_subsystem ( & target - > subsys ) ;
return 0 ;
}
static void spear_pcie_gadget_shutdown ( struct platform_device * pdev )
{
}
static struct platform_driver spear_pcie_gadget_driver = {
. probe = spear_pcie_gadget_probe ,
. remove = spear_pcie_gadget_remove ,
. shutdown = spear_pcie_gadget_shutdown ,
. driver = {
. name = " pcie-gadget-spear " ,
. bus = & platform_bus_type
} ,
} ;
2012-01-22 11:33:49 +04:00
module_platform_driver ( spear_pcie_gadget_driver ) ;
2011-03-23 02:33:58 +03:00
2011-10-31 06:20:28 +04:00
MODULE_ALIAS ( " platform:pcie-gadget-spear " ) ;
2011-03-23 02:33:58 +03:00
MODULE_AUTHOR ( " Pratyush Anand " ) ;
MODULE_LICENSE ( " GPL " ) ;