2014-02-11 11:39:26 +05:30
/*
* PCIe host controller driver for ST Microelectronics SPEAr13xx SoCs
*
* SPEAr13xx PCIe Glue Layer Source Code
*
* Copyright ( C ) 2010 - 2014 ST Microelectronics
2015-06-25 15:01:08 -07:00
* Pratyush Anand < pratyush . anand @ gmail . com >
2015-06-25 15:01:11 -07:00
* Mohit Kumar < mohit . kumar . dhaka @ gmail . com >
2014-02-11 11:39:26 +05:30
*
* 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 .
*/
# include <linux/clk.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
2016-08-22 17:59:45 -04:00
# include <linux/init.h>
2014-02-11 11:39:26 +05:30
# include <linux/of.h>
# include <linux/pci.h>
# include <linux/phy/phy.h>
# include <linux/platform_device.h>
# include <linux/resource.h>
# include "pcie-designware.h"
struct spear13xx_pcie {
2016-10-06 13:42:08 -05:00
struct pcie_port pp ; /* DT dbi is pp.dbi_base */
2014-02-11 11:39:26 +05:30
void __iomem * app_base ;
struct phy * phy ;
struct clk * clk ;
bool is_gen1 ;
} ;
struct pcie_app_reg {
u32 app_ctrl_0 ; /* cr0 */
u32 app_ctrl_1 ; /* cr1 */
u32 app_status_0 ; /* cr2 */
u32 app_status_1 ; /* cr3 */
u32 msg_status ; /* cr4 */
u32 msg_payload ; /* cr5 */
u32 int_sts ; /* cr6 */
u32 int_clr ; /* cr7 */
u32 int_mask ; /* cr8 */
u32 mst_bmisc ; /* cr9 */
u32 phy_ctrl ; /* cr10 */
u32 phy_status ; /* cr11 */
u32 cxpl_debug_info_0 ; /* cr12 */
u32 cxpl_debug_info_1 ; /* cr13 */
u32 ven_msg_ctrl_0 ; /* cr14 */
u32 ven_msg_ctrl_1 ; /* cr15 */
u32 ven_msg_data_0 ; /* cr16 */
u32 ven_msg_data_1 ; /* cr17 */
u32 ven_msi_0 ; /* cr18 */
u32 ven_msi_1 ; /* cr19 */
u32 mst_rmisc ; /* cr20 */
} ;
/* CR0 ID */
# define APP_LTSSM_ENABLE_ID 3
# define DEVICE_TYPE_RC (4 << 25)
# define MISCTRL_EN_ID 30
# define REG_TRANSLATION_ENABLE 31
/* CR3 ID */
# define XMLH_LINK_UP (1 << 6)
/* CR6 */
# define MSI_CTRL_INT (1 << 26)
# define EXP_CAP_ID_OFFSET 0x70
# define to_spear13xx_pcie(x) container_of(x, struct spear13xx_pcie, pp)
2016-10-06 13:42:08 -05:00
static int spear13xx_pcie_establish_link ( struct spear13xx_pcie * spear13xx_pcie )
2014-02-11 11:39:26 +05:30
{
2016-10-06 13:42:08 -05:00
struct pcie_port * pp = & spear13xx_pcie - > pp ;
2014-02-11 11:39:26 +05:30
struct pcie_app_reg * app_reg = spear13xx_pcie - > app_base ;
2016-10-06 13:42:08 -05:00
u32 val ;
2014-02-11 11:39:26 +05:30
u32 exp_cap_off = EXP_CAP_ID_OFFSET ;
if ( dw_pcie_link_up ( pp ) ) {
dev_err ( pp - > dev , " link already up \n " ) ;
return 0 ;
}
dw_pcie_setup_rc ( pp ) ;
/*
* this controller support only 128 bytes read size , however its
* default value in capability register is 512 bytes . So force
* it to 128 here .
*/
2015-10-08 14:27:48 -05:00
dw_pcie_cfg_read ( pp - > dbi_base + exp_cap_off + PCI_EXP_DEVCTL , 2 , & val ) ;
2014-02-11 11:39:26 +05:30
val & = ~ PCI_EXP_DEVCTL_READRQ ;
2015-10-08 14:27:48 -05:00
dw_pcie_cfg_write ( pp - > dbi_base + exp_cap_off + PCI_EXP_DEVCTL , 2 , val ) ;
2014-02-11 11:39:26 +05:30
2015-10-08 14:27:48 -05:00
dw_pcie_cfg_write ( pp - > dbi_base + PCI_VENDOR_ID , 2 , 0x104A ) ;
dw_pcie_cfg_write ( pp - > dbi_base + PCI_DEVICE_ID , 2 , 0xCD80 ) ;
2014-02-11 11:39:26 +05:30
/*
* if is_gen1 is set then handle it , so that some buggy card
* also works
*/
if ( spear13xx_pcie - > is_gen1 ) {
2015-10-08 14:27:38 -05:00
dw_pcie_cfg_read ( pp - > dbi_base + exp_cap_off + PCI_EXP_LNKCAP ,
2015-10-08 14:27:48 -05:00
4 , & val ) ;
2014-02-11 11:39:26 +05:30
if ( ( val & PCI_EXP_LNKCAP_SLS ) ! = PCI_EXP_LNKCAP_SLS_2_5GB ) {
val & = ~ ( ( u32 ) PCI_EXP_LNKCAP_SLS ) ;
val | = PCI_EXP_LNKCAP_SLS_2_5GB ;
2015-10-08 14:27:38 -05:00
dw_pcie_cfg_write ( pp - > dbi_base + exp_cap_off +
2015-10-08 14:27:48 -05:00
PCI_EXP_LNKCAP , 4 , val ) ;
2014-02-11 11:39:26 +05:30
}
2015-10-08 14:27:38 -05:00
dw_pcie_cfg_read ( pp - > dbi_base + exp_cap_off + PCI_EXP_LNKCTL2 ,
2015-10-08 14:27:48 -05:00
2 , & val ) ;
2014-02-11 11:39:26 +05:30
if ( ( val & PCI_EXP_LNKCAP_SLS ) ! = PCI_EXP_LNKCAP_SLS_2_5GB ) {
val & = ~ ( ( u32 ) PCI_EXP_LNKCAP_SLS ) ;
val | = PCI_EXP_LNKCAP_SLS_2_5GB ;
2015-10-08 14:27:38 -05:00
dw_pcie_cfg_write ( pp - > dbi_base + exp_cap_off +
2015-10-08 14:27:48 -05:00
PCI_EXP_LNKCTL2 , 2 , val ) ;
2014-02-11 11:39:26 +05:30
}
}
/* enable ltssm */
writel ( DEVICE_TYPE_RC | ( 1 < < MISCTRL_EN_ID )
| ( 1 < < APP_LTSSM_ENABLE_ID )
| ( ( u32 ) 1 < < REG_TRANSLATION_ENABLE ) ,
& app_reg - > app_ctrl_0 ) ;
PCI: designware: Add generic dw_pcie_wait_for_link()
Several DesignWare-based drivers (dra7xx, exynos, imx6, keystone, qcom, and
spear13xx) had similar loops waiting for the link to come up.
Add a generic dw_pcie_wait_for_link() for use by all these drivers so the
waiting is done consistently, e.g., always using usleep_range() rather than
mdelay() and using similar timeouts and retry counts.
Note that this changes the Keystone link training/wait for link strategy,
so we initiate link training, then wait longer for the link to come up
before re-initiating link training.
[bhelgaas: changelog, split into its own patch, update pci-keystone.c, pcie-qcom.c]
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Pratyush Anand <pratyush.anand@gmail.com>
2016-03-10 14:44:35 -06:00
return dw_pcie_wait_for_link ( pp ) ;
2014-02-11 11:39:26 +05:30
}
static irqreturn_t spear13xx_pcie_irq_handler ( int irq , void * arg )
{
2016-10-06 13:42:08 -05:00
struct spear13xx_pcie * spear13xx_pcie = arg ;
2014-02-11 11:39:26 +05:30
struct pcie_app_reg * app_reg = spear13xx_pcie - > app_base ;
2016-10-06 13:42:08 -05:00
struct pcie_port * pp = & spear13xx_pcie - > pp ;
2014-02-11 11:39:26 +05:30
unsigned int status ;
status = readl ( & app_reg - > int_sts ) ;
if ( status & MSI_CTRL_INT ) {
2015-08-20 01:31:24 -05:00
BUG_ON ( ! IS_ENABLED ( CONFIG_PCI_MSI ) ) ;
2014-02-11 11:39:26 +05:30
dw_handle_msi_irq ( pp ) ;
}
writel ( status , & app_reg - > int_clr ) ;
return IRQ_HANDLED ;
}
2016-10-06 13:42:08 -05:00
static void spear13xx_pcie_enable_interrupts ( struct spear13xx_pcie * spear13xx_pcie )
2014-02-11 11:39:26 +05:30
{
2016-10-06 13:42:08 -05:00
struct pcie_port * pp = & spear13xx_pcie - > pp ;
2014-02-11 11:39:26 +05:30
struct pcie_app_reg * app_reg = spear13xx_pcie - > app_base ;
/* Enable MSI interrupt */
if ( IS_ENABLED ( CONFIG_PCI_MSI ) ) {
dw_pcie_msi_init ( pp ) ;
writel ( readl ( & app_reg - > int_mask ) |
MSI_CTRL_INT , & app_reg - > int_mask ) ;
}
}
static int spear13xx_pcie_link_up ( struct pcie_port * pp )
{
struct spear13xx_pcie * spear13xx_pcie = to_spear13xx_pcie ( pp ) ;
struct pcie_app_reg * app_reg = spear13xx_pcie - > app_base ;
if ( readl ( & app_reg - > app_status_1 ) & XMLH_LINK_UP )
return 1 ;
return 0 ;
}
static void spear13xx_pcie_host_init ( struct pcie_port * pp )
{
2016-10-06 13:42:08 -05:00
struct spear13xx_pcie * spear13xx_pcie = to_spear13xx_pcie ( pp ) ;
spear13xx_pcie_establish_link ( spear13xx_pcie ) ;
spear13xx_pcie_enable_interrupts ( spear13xx_pcie ) ;
2014-02-11 11:39:26 +05:30
}
static struct pcie_host_ops spear13xx_pcie_host_ops = {
. link_up = spear13xx_pcie_link_up ,
. host_init = spear13xx_pcie_host_init ,
} ;
2016-10-06 13:42:08 -05:00
static int spear13xx_add_pcie_port ( struct spear13xx_pcie * spear13xx_pcie ,
struct platform_device * pdev )
2014-02-11 11:39:26 +05:30
{
2016-10-06 13:42:08 -05:00
struct pcie_port * pp = & spear13xx_pcie - > pp ;
2016-10-06 13:42:09 -05:00
struct device * dev = pp - > dev ;
2014-02-11 11:39:26 +05:30
int ret ;
pp - > irq = platform_get_irq ( pdev , 0 ) ;
if ( ! pp - > irq ) {
dev_err ( dev , " failed to get irq \n " ) ;
return - ENODEV ;
}
ret = devm_request_irq ( dev , pp - > irq , spear13xx_pcie_irq_handler ,
2015-12-10 21:18:20 +02:00
IRQF_SHARED | IRQF_NO_THREAD ,
2016-10-06 13:42:08 -05:00
" spear1340-pcie " , spear13xx_pcie ) ;
2014-02-11 11:39:26 +05:30
if ( ret ) {
dev_err ( dev , " failed to request irq %d \n " , pp - > irq ) ;
return ret ;
}
pp - > root_bus_nr = - 1 ;
pp - > ops = & spear13xx_pcie_host_ops ;
ret = dw_pcie_host_init ( pp ) ;
if ( ret ) {
dev_err ( dev , " failed to initialize host \n " ) ;
return ret ;
}
return 0 ;
}
2015-02-19 20:41:48 +03:00
static int spear13xx_pcie_probe ( struct platform_device * pdev )
2014-02-11 11:39:26 +05:30
{
2016-10-06 13:42:09 -05:00
struct device * dev = & pdev - > dev ;
2014-02-11 11:39:26 +05:30
struct spear13xx_pcie * spear13xx_pcie ;
struct pcie_port * pp ;
2016-10-06 13:42:09 -05:00
struct device_node * np = dev - > of_node ;
2014-02-11 11:39:26 +05:30
struct resource * dbi_base ;
int ret ;
spear13xx_pcie = devm_kzalloc ( dev , sizeof ( * spear13xx_pcie ) , GFP_KERNEL ) ;
2014-11-12 12:29:02 +09:00
if ( ! spear13xx_pcie )
2014-02-11 11:39:26 +05:30
return - ENOMEM ;
spear13xx_pcie - > phy = devm_phy_get ( dev , " pcie-phy " ) ;
if ( IS_ERR ( spear13xx_pcie - > phy ) ) {
ret = PTR_ERR ( spear13xx_pcie - > phy ) ;
if ( ret = = - EPROBE_DEFER )
dev_info ( dev , " probe deferred \n " ) ;
else
dev_err ( dev , " couldn't get pcie-phy \n " ) ;
return ret ;
}
phy_init ( spear13xx_pcie - > phy ) ;
spear13xx_pcie - > clk = devm_clk_get ( dev , NULL ) ;
if ( IS_ERR ( spear13xx_pcie - > clk ) ) {
dev_err ( dev , " couldn't get clk for pcie \n " ) ;
return PTR_ERR ( spear13xx_pcie - > clk ) ;
}
ret = clk_prepare_enable ( spear13xx_pcie - > clk ) ;
if ( ret ) {
dev_err ( dev , " couldn't enable clk for pcie \n " ) ;
return ret ;
}
pp = & spear13xx_pcie - > pp ;
pp - > dev = dev ;
2014-09-03 10:50:49 +05:30
dbi_base = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " dbi " ) ;
2014-02-11 11:39:26 +05:30
pp - > dbi_base = devm_ioremap_resource ( dev , dbi_base ) ;
if ( IS_ERR ( pp - > dbi_base ) ) {
dev_err ( dev , " couldn't remap dbi base %p \n " , dbi_base ) ;
ret = PTR_ERR ( pp - > dbi_base ) ;
goto fail_clk ;
}
spear13xx_pcie - > app_base = pp - > dbi_base + 0x2000 ;
if ( of_property_read_bool ( np , " st,pcie-is-gen1 " ) )
spear13xx_pcie - > is_gen1 = true ;
2016-10-06 13:42:08 -05:00
ret = spear13xx_add_pcie_port ( spear13xx_pcie , pdev ) ;
2014-02-11 11:39:26 +05:30
if ( ret < 0 )
goto fail_clk ;
platform_set_drvdata ( pdev , spear13xx_pcie ) ;
return 0 ;
fail_clk :
clk_disable_unprepare ( spear13xx_pcie - > clk ) ;
return ret ;
}
static const struct of_device_id spear13xx_pcie_of_match [ ] = {
{ . compatible = " st,spear1340-pcie " , } ,
{ } ,
} ;
2015-02-19 20:41:48 +03:00
static struct platform_driver spear13xx_pcie_driver = {
2014-02-11 11:39:26 +05:30
. probe = spear13xx_pcie_probe ,
. driver = {
. name = " spear-pcie " ,
. of_match_table = of_match_ptr ( spear13xx_pcie_of_match ) ,
} ,
} ;
2014-11-06 10:29:41 +09:00
static int __init spear13xx_pcie_init ( void )
2014-02-11 11:39:26 +05:30
{
return platform_driver_register ( & spear13xx_pcie_driver ) ;
}
2016-08-22 17:59:45 -04:00
device_initcall ( spear13xx_pcie_init ) ;