@ -13,22 +13,35 @@
# define pr_fmt(fmt) "tegra-pcie: " fmt
# include <common.h>
# include <clk.h>
# include <dm.h>
# include <errno.h>
# include <fdtdec.h>
# include <malloc.h>
# include <pci.h>
# include <power-domain.h>
# include <reset.h>
# include <asm/io.h>
# include <asm/gpio.h>
# include <linux/list.h>
# ifndef CONFIG_TEGRA186
# include <asm/arch/clock.h>
# include <asm/arch/powergate.h>
# include <asm/arch-tegra/xusb-padctl.h>
# include <linux/list.h>
# include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
# endif
/*
* FIXME : TODO : This driver contains a number of ifdef CONFIG_TEGRA186 that
* should not be present . These are needed because newer Tegra SoCs support
* only the standard clock / reset APIs , whereas older Tegra SoCs support only
* a custom Tegra - specific API . ASAP the older Tegra SoCs ' code should be
* fixed to implement the standard APIs , and all drivers converted to solely
* use the new standard APIs , with no ifdefs .
*/
DECLARE_GLOBAL_DATA_PTR ;
@ -103,6 +116,9 @@ DECLARE_GLOBAL_DATA_PTR;
# define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20)
# define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20)
# define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20)
# define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20)
# define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20)
# define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20)
# define AFI_FUSE 0x104
# define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2)
@ -110,6 +126,7 @@ DECLARE_GLOBAL_DATA_PTR;
# define AFI_PEX0_CTRL 0x110
# define AFI_PEX1_CTRL 0x118
# define AFI_PEX2_CTRL 0x128
# define AFI_PEX2_CTRL_T186 0x19c
# define AFI_PEX_CTRL_RST (1 << 0)
# define AFI_PEX_CTRL_CLKREQ_EN (1 << 1)
# define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
@ -173,6 +190,7 @@ enum tegra_pci_id {
TEGRA30_PCIE ,
TEGRA124_PCIE ,
TEGRA210_PCIE ,
TEGRA186_PCIE ,
} ;
struct tegra_pcie_port {
@ -189,6 +207,7 @@ struct tegra_pcie_soc {
unsigned int num_ports ;
unsigned long pads_pll_ctl ;
unsigned long tx_ref_sel ;
unsigned long afi_pex2_ctrl ;
u32 pads_refclk_cfg0 ;
u32 pads_refclk_cfg1 ;
bool has_pex_clkreq_en ;
@ -209,7 +228,17 @@ struct tegra_pcie {
unsigned long xbar ;
const struct tegra_pcie_soc * soc ;
# ifdef CONFIG_TEGRA186
struct clk clk_afi ;
struct clk clk_pex ;
struct reset_ctl reset_afi ;
struct reset_ctl reset_pex ;
struct reset_ctl reset_pcie_x ;
struct power_domain pwrdom ;
# else
struct tegra_xusb_phy * phy ;
# endif
} ;
static void afi_writel ( struct tegra_pcie * pcie , unsigned long value ,
@ -229,10 +258,12 @@ static void pads_writel(struct tegra_pcie *pcie, unsigned long value,
writel ( value , pcie - > pads . start + offset ) ;
}
# ifndef CONFIG_TEGRA186
static unsigned long pads_readl ( struct tegra_pcie * pcie , unsigned long offset )
{
return readl ( pcie - > pads . start + offset ) ;
}
# endif
static unsigned long rp_readl ( struct tegra_pcie_port * port ,
unsigned long offset )
@ -400,6 +431,24 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
return 0 ;
}
break ;
case TEGRA186_PCIE :
switch ( lanes ) {
case 0x0010004 :
debug ( " x4 x1 configuration \n " ) ;
* xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 ;
return 0 ;
case 0x0010102 :
debug ( " x2 x1 x1 configuration \n " ) ;
* xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 ;
return 0 ;
case 0x0010101 :
debug ( " x1 x1 x1 configuration \n " ) ;
* xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 ;
return 0 ;
}
break ;
default :
break ;
}
@ -471,6 +520,7 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
return err ;
}
# ifndef CONFIG_TEGRA186
pcie - > phy = tegra_xusb_phy_get ( TEGRA_XUSB_PADCTL_PCIE ) ;
if ( pcie - > phy ) {
err = tegra_xusb_phy_prepare ( pcie - > phy ) ;
@ -479,6 +529,7 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
return err ;
}
}
# endif
fdt_for_each_subnode ( fdt , subnode , node ) {
unsigned int index = 0 , num_lanes = 0 ;
@ -523,6 +574,44 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id,
return 0 ;
}
# ifdef CONFIG_TEGRA186
static int tegra_pcie_power_on ( struct tegra_pcie * pcie )
{
int ret ;
ret = power_domain_on ( & pcie - > pwrdom ) ;
if ( ret ) {
error ( " power_domain_on() failed: %d \n " , ret ) ;
return ret ;
}
ret = clk_enable ( & pcie - > clk_afi ) ;
if ( ret ) {
error ( " clk_enable(afi) failed: %d \n " , ret ) ;
return ret ;
}
ret = clk_enable ( & pcie - > clk_pex ) ;
if ( ret ) {
error ( " clk_enable(pex) failed: %d \n " , ret ) ;
return ret ;
}
ret = reset_deassert ( & pcie - > reset_afi ) ;
if ( ret ) {
error ( " reset_deassert(afi) failed: %d \n " , ret ) ;
return ret ;
}
ret = reset_deassert ( & pcie - > reset_pex ) ;
if ( ret ) {
error ( " reset_deassert(pex) failed: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
# else
static int tegra_pcie_power_on ( struct tegra_pcie * pcie )
{
const struct tegra_pcie_soc * soc = pcie - > soc ;
@ -639,6 +728,7 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
return 0 ;
}
# endif
static int tegra_pcie_enable_controller ( struct tegra_pcie * pcie )
{
@ -647,7 +737,11 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
u32 value ;
int err ;
# ifdef CONFIG_TEGRA186
{
# else
if ( pcie - > phy ) {
# endif
value = afi_readl ( pcie , AFI_PLLE_CONTROL ) ;
value & = ~ AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL ;
value | = AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN ;
@ -675,6 +769,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
afi_writel ( pcie , value , AFI_FUSE ) ;
# ifndef CONFIG_TEGRA186
if ( pcie - > phy )
err = tegra_xusb_phy_enable ( pcie - > phy ) ;
else
@ -684,9 +779,18 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
error ( " failed to power on PHY: %d \n " , err ) ;
return err ;
}
# endif
/* take the PCIEXCLK logic out of reset */
# ifdef CONFIG_TEGRA186
err = reset_deassert ( & pcie - > reset_pcie_x ) ;
if ( err ) {
error ( " reset_deassert(pcie_x) failed: %d \n " , err ) ;
return err ;
}
# else
reset_set_enable ( PERIPH_ID_PCIEXCLK , 0 ) ;
# endif
/* finally enable PCIe */
value = afi_readl ( pcie , AFI_CONFIGURATION ) ;
@ -787,7 +891,7 @@ static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
break ;
case 2 :
ret = AFI_PEX2_CTRL ;
ret = port - > pcie - > soc - > afi_pex2_ctrl ;
break ;
}
@ -945,6 +1049,7 @@ static const struct tegra_pcie_soc pci_tegra_soc[] = {
. num_ports = 3 ,
. pads_pll_ctl = PADS_PLL_CTL_TEGRA30 ,
. tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN ,
. afi_pex2_ctrl = AFI_PEX2_CTRL ,
. pads_refclk_cfg0 = 0xfa5cfa5c ,
. pads_refclk_cfg1 = 0xfa5cfa5c ,
. has_pex_clkreq_en = true ,
@ -972,7 +1077,16 @@ static const struct tegra_pcie_soc pci_tegra_soc[] = {
. has_cml_clk = true ,
. has_gen2 = true ,
. force_pca_enable = true ,
}
} ,
[ TEGRA186_PCIE ] = {
. num_ports = 3 ,
. afi_pex2_ctrl = AFI_PEX2_CTRL_T186 ,
. pads_refclk_cfg0 = 0x80b880b8 ,
. pads_refclk_cfg1 = 0x000480b8 ,
. has_pex_clkreq_en = true ,
. has_pex_bias_ctrl = true ,
. has_gen2 = true ,
} ,
} ;
static int pci_tegra_ofdata_to_platdata ( struct udevice * dev )
@ -996,6 +1110,44 @@ static int pci_tegra_probe(struct udevice *dev)
struct tegra_pcie * pcie = dev_get_priv ( dev ) ;
int err ;
# ifdef CONFIG_TEGRA186
err = clk_get_by_name ( dev , " afi " , & pcie - > clk_afi ) ;
if ( err ) {
debug ( " clk_get_by_name(afi) failed: %d \n " , err ) ;
return err ;
}
err = clk_get_by_name ( dev , " pex " , & pcie - > clk_pex ) ;
if ( err ) {
debug ( " clk_get_by_name(pex) failed: %d \n " , err ) ;
return err ;
}
err = reset_get_by_name ( dev , " afi " , & pcie - > reset_afi ) ;
if ( err ) {
debug ( " reset_get_by_name(afi) failed: %d \n " , err ) ;
return err ;
}
err = reset_get_by_name ( dev , " pex " , & pcie - > reset_pex ) ;
if ( err ) {
debug ( " reset_get_by_name(pex) failed: %d \n " , err ) ;
return err ;
}
err = reset_get_by_name ( dev , " pcie_x " , & pcie - > reset_pcie_x ) ;
if ( err ) {
debug ( " reset_get_by_name(pcie_x) failed: %d \n " , err ) ;
return err ;
}
err = power_domain_get ( dev , & pcie - > pwrdom ) ;
if ( err ) {
debug ( " power_domain_get() failed: %d \n " , err ) ;
return err ;
}
# endif
err = tegra_pcie_power_on ( pcie ) ;
if ( err < 0 ) {
error ( " failed to power on " ) ;
@ -1033,6 +1185,7 @@ static const struct udevice_id pci_tegra_ids[] = {
{ . compatible = " nvidia,tegra30-pcie " , . data = TEGRA30_PCIE } ,
{ . compatible = " nvidia,tegra124-pcie " , . data = TEGRA124_PCIE } ,
{ . compatible = " nvidia,tegra210-pcie " , . data = TEGRA210_PCIE } ,
{ . compatible = " nvidia,tegra186-pcie " , . data = TEGRA186_PCIE } ,
{ }
} ;