diff mbox

[1/3] ARM: tegra: pcie: Add tegra3 support

Message ID 1365435688-4179-1-git-send-email-jagarwal@nvidia.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Jay Agarwal April 8, 2013, 3:41 p.m. UTC
Signed-off-by: Jay Agarwal <jagarwal@nvidia.com>

- Enable pcie root port 2 for cardhu
- Make private data structure for each SOC
- Add required tegra3 clocks and regulators
- Add tegra3 specific code in enable controller
- Modify clock tree to get clocks based on device
- Based on git://gitorious.org/thierryreding/linux.git

 drivers/clk/tegra/clk-tegra30.c |   12 ++--
 drivers/pci/host/pci-tegra.c    |  146 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 133 insertions(+), 25 deletions(-)

Comments

Stephen Warren April 8, 2013, 6:11 p.m. UTC | #1
On 04/08/2013 09:41 AM, Jay Agarwal wrote:
> Signed-off-by: Jay Agarwal <jagarwal@nvidia.com>
> 
> - Enable pcie root port 2 for cardhu
> - Make private data structure for each SOC
> - Add required tegra3 clocks and regulators
> - Add tegra3 specific code in enable controller
> - Modify clock tree to get clocks based on device
> - Based on git://gitorious.org/thierryreding/linux.git

There are quite a few capitalization errors above. The correct versions
are: PCIe, Cardhu, SoC, Tegra.

Upstream uses engineering names not marketing names, so Tegra30 not Tegra3.

>  drivers/clk/tegra/clk-tegra30.c |   12 ++--
>  drivers/pci/host/pci-tegra.c    |  146 ++++++++++++++++++++++++++++++++++-----

This patch touches two unrelated drivers. There is no dependency between
the changes, since PCIe doesn't work yet on Tegra30, so there's no need
for those unrelated changes to be part of the same patch. Please split
them into separate patches. The clk patch can likely be applied very
soon, without waiting for any of the other PCIe patches.

> - Modify clock tree to get clocks based on device

That description doesn't seem to describe the change made to
clk-tegra30.c. Can you please include more details re: what the patch is
doing and why.

> diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c

> +/* used to differente tegra chips code */

differentiate

> +struct tegra_pcie_soc_data {
...
> +	bool need_avdd_supply;
> +	bool need_cml0_clk;

s/need/has/ would be better.

> @@ -749,6 +778,11 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
>  	struct tegra_pcie_port *port;
>  	unsigned int timeout;
>  	unsigned long value;
> +	struct tegra_pcie_soc_data *soc = pcie->soc_data;
> +
> +	/* power down to PCIe slot clock bias pad */
> +	if (soc->pex_bias_ctrl)
> +		afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);

Power down when /enabling/ a controller?

>  	err = regulator_disable(pcie->pex_clk_supply);
>  	if (err < 0)
> -		dev_err(pcie->dev, "failed to disable pex-clk regulator: %d\n",
> +		dev_warn(pcie->dev, "failed to disable pex-clk regulator: %d\n",
>  			err);
>  
>  	err = regulator_disable(pcie->vdd_supply);
>  	if (err < 0)
> -		dev_err(pcie->dev, "failed to disable VDD regulator: %d\n",
> +		dev_warn(pcie->dev, "failed to disable VDD regulator: %d\n",
>  			err);

Please explain why that change is correct. If the regulators only exist
on Tegra20, please represent that fact in the SoC data. Regulators must
always exist, so enable/disable should never fail due to missing
regulators. Actual run-time failures seem like something that really is
an error.

> @@ -1489,6 +1597,11 @@ static int tegra_pcie_probe(struct platform_device *pdev)
>  	INIT_LIST_HEAD(&pcie->busses);
>  	INIT_LIST_HEAD(&pcie->ports);
>  	pcie->dev = &pdev->dev;
> +	match = of_match_device(tegra_pcie_of_match, &pdev->dev);
> +	if (match)
> +		pcie->soc_data = (struct tegra_pcie_soc_data *)match->data;
> +	else
> +		return -ENODEV;

that would be more idiomatic as:

if (!match)
	return -ENODEV;
pcie->soc_data = ...;

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Warren April 8, 2013, 6:21 p.m. UTC | #2
On 04/08/2013 09:41 AM, Jay Agarwal wrote:
> Signed-off-by: Jay Agarwal <jagarwal@nvidia.com>
> 
> - Enable pcie root port 2 for cardhu
> - Make private data structure for each SOC
> - Add required tegra3 clocks and regulators
> - Add tegra3 specific code in enable controller
> - Modify clock tree to get clocks based on device
> - Based on git://gitorious.org/thierryreding/linux.git

A couple more points on this patch:

* You didn't mention that this series is based on Thierry's
work-in-progress tree, and not something immediately destined for
upstream. As such, only Thierry is expected to actually apply any of
these patches.

* Your changes to the Tegra PCIe driver require that device tree include
extra clocks and regulators. You need to update
Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt to
describe these new requirements.
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Warren April 10, 2013, 5:23 p.m. UTC | #3
On 04/08/2013 09:41 AM, Jay Agarwal wrote:
> Signed-off-by: Jay Agarwal <jagarwal@nvidia.com>
> 
> - Enable pcie root port 2 for cardhu
> - Make private data structure for each SOC
> - Add required tegra3 clocks and regulators
> - Add tegra3 specific code in enable controller
> - Modify clock tree to get clocks based on device
> - Based on git://gitorious.org/thierryreding/linux.git

Did you test these patches? They don't work for me on my Cardhu A04.

First off, I had to change the num-lanes properties to match Cardhu's
actual configuration:

> diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi
> index d64d12c..6426226 100644
> --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi
> +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi
> @@ -143,8 +143,17 @@
>                 vdd-supply = <&ldo1_reg>;
>                 avdd-supply = <&ldo2_reg>;
>  
> +               pci@1,0 {
> +                       nvidia,num-lanes = <4>;
> +               };
> +
> +               pci@2,0 {
> +                       nvidia,num-lanes = <1>;
> +               };
> +
>                 pci@3,0 {
>                         status = "okay";
> +                       nvidia,num-lanes = <1>;
>                 };
>         };
>  

However, even after doing that, the driver doesn't detect anything
attached to port@3,0, even though I have the board plugged into the
docking station, and hence the PCI Ethernet should be detected:

> [    3.103860] tegra-pcie 3000.pcie-controller: 4x1, 1x2 configuration
> [    3.113755] tegra-pcie 3000.pcie-controller: probing port 2, using 1 lanes
> [    3.324364] tegra-pcie 3000.pcie-controller: link 2 down, retrying
> [    3.534249] tegra-pcie 3000.pcie-controller: link 2 down, retrying
> [    3.744160] tegra-pcie 3000.pcie-controller: link 2 down, retrying
> [    3.751359] tegra-pcie 3000.pcie-controller: link 2 down, ignoring

(I see the same messages even without fixing the lane configuration,
exception for the first configuration message obviously prints something
different).

Are you testing with U-Boot, or using our binary bootloader? Upstream
code must be tested with U-Boot, to make sure it doesn't rely on any HW
programming performed by the bootloader.
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jay Agarwal April 12, 2013, 2:58 p.m. UTC | #4
> >  	err = regulator_disable(pcie->pex_clk_supply);
> >  	if (err < 0)
> > -		dev_err(pcie->dev, "failed to disable pex-clk regulator:
> %d\n",
> > +		dev_warn(pcie->dev, "failed to disable pex-clk regulator:
> %d\n",
> >  			err);
> >
> >  	err = regulator_disable(pcie->vdd_supply);
> >  	if (err < 0)
> > -		dev_err(pcie->dev, "failed to disable VDD regulator: %d\n",
> > +		dev_warn(pcie->dev, "failed to disable VDD regulator:
> %d\n",
> >  			err);
> 
> Please explain why that change is correct. If the regulators only exist on
> Tegra20, please represent that fact in the SoC data. Regulators must always
> exist, so enable/disable should never fail due to missing regulators. Actual
> run-time failures seem like something that really is an error.
> 
[>] These regulators are needed for both tegra20 & tegra30. Since we are not returning error here, so changed to dev_warn.

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Warren April 12, 2013, 3:34 p.m. UTC | #5
On 04/12/2013 08:58 AM, Jay Agarwal wrote:
>>>  	err = regulator_disable(pcie->pex_clk_supply);
>>>  	if (err < 0)
>>> -		dev_err(pcie->dev, "failed to disable pex-clk regulator:
>> %d\n",
>>> +		dev_warn(pcie->dev, "failed to disable pex-clk regulator:
>> %d\n",
>>>  			err);
>>>
>>>  	err = regulator_disable(pcie->vdd_supply);
>>>  	if (err < 0)
>>> -		dev_err(pcie->dev, "failed to disable VDD regulator: %d\n",
>>> +		dev_warn(pcie->dev, "failed to disable VDD regulator:
>> %d\n",
>>>  			err);
>>
>> Please explain why that change is correct. If the regulators only exist on
>> Tegra20, please represent that fact in the SoC data. Regulators must always
>> exist, so enable/disable should never fail due to missing regulators. Actual
>> run-time failures seem like something that really is an error.
>>
> [>] These regulators are needed for both tegra20 & tegra30. Since we are not returning error here, so changed to dev_warn.

If the regulators are required, then any failure to operate them should
be an error, hence dev_err() seems correct.

As to why the code doesn't actually return an error? I'm not sure.
Perhaps that should be fixed with a separate patch, although I don't
recall exactly where in the code the above excerpt is; if it's in
remove(), then continuing on without returning an error would be
appropriate.
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jay Agarwal April 12, 2013, 4:43 p.m. UTC | #6
> On 04/08/2013 09:41 AM, Jay Agarwal wrote:
> > Signed-off-by: Jay Agarwal <jagarwal@nvidia.com>
> >
> > - Enable pcie root port 2 for cardhu
> > - Make private data structure for each SOC
> > - Add required tegra3 clocks and regulators
> > - Add tegra3 specific code in enable controller
> > - Modify clock tree to get clocks based on device
> > - Based on git://gitorious.org/thierryreding/linux.git
> 	
> A couple more points on this patch:
> 
> * You didn't mention that this series is based on Thierry's work-in-progress
> tree, and not something immediately destined for upstream. As such, only
> Thierry is expected to actually apply any of these patches.
> 
[>] Stephen, I have mentioned it in comment description as Based on git://gitorious.org/thierryreding/linux.git, is this not enough?

> * Your changes to the Tegra PCIe driver require that device tree include
> extra clocks and regulators. You need to update
> Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt to describe
> these new requirements.
[>] Should I create tegra30-pcie.txt? or made changes in tegra20-pcie.txt itself?
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Warren April 12, 2013, 5:01 p.m. UTC | #7
On 04/12/2013 10:43 AM, Jay Agarwal wrote:
>> On 04/08/2013 09:41 AM, Jay Agarwal wrote:
>>> Signed-off-by: Jay Agarwal <jagarwal@nvidia.com>
>>>
>>> - Enable pcie root port 2 for cardhu
>>> - Make private data structure for each SOC
>>> - Add required tegra3 clocks and regulators
>>> - Add tegra3 specific code in enable controller
>>> - Modify clock tree to get clocks based on device
>>> - Based on git://gitorious.org/thierryreding/linux.git
>> 	
>> A couple more points on this patch:
>>
>> * You didn't mention that this series is based on Thierry's work-in-progress
>> tree, and not something immediately destined for upstream. As such, only
>> Thierry is expected to actually apply any of these patches.
>>
> [>] Stephen, I have mentioned it in comment description as Based on git://gitorious.org/thierryreding/linux.git, is this not enough?

Well, first off, there are many branches there, and secondly the branch
that a series is based on doesn't necessarily imply much about what you
expect people to do with it.

> 
>> * Your changes to the Tegra PCIe driver require that device tree include
>> extra clocks and regulators. You need to update
>> Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt to describe
>> these new requirements.
>
> [>] Should I create tegra30-pcie.txt? or made changes in tegra20-pcie.txt itself?

(What is "[>]"?)

It'd probably be simplest to edit tegra20-pcie.txt, and just mention the
extra requirements for Tegra30.
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jay Agarwal April 12, 2013, 5:06 p.m. UTC | #8
> On 04/12/2013 10:43 AM, Jay Agarwal wrote:
> >> On 04/08/2013 09:41 AM, Jay Agarwal wrote:
> >>> Signed-off-by: Jay Agarwal <jagarwal@nvidia.com>
> >>>
> >>> - Enable pcie root port 2 for cardhu
> >>> - Make private data structure for each SOC
> >>> - Add required tegra3 clocks and regulators
> >>> - Add tegra3 specific code in enable controller
> >>> - Modify clock tree to get clocks based on device
> >>> - Based on git://gitorious.org/thierryreding/linux.git
> >>
> >> A couple more points on this patch:
> >>
> >> * You didn't mention that this series is based on Thierry's
> >> work-in-progress tree, and not something immediately destined for
> >> upstream. As such, only Thierry is expected to actually apply any of these
> patches.
> >>
> > [>] Stephen, I have mentioned it in comment description as Based on
> git://gitorious.org/thierryreding/linux.git, is this not enough?
> 
> Well, first off, there are many branches there, and secondly the branch that
> a series is based on doesn't necessarily imply much about what you expect
> people to do with it.
> 
I am not clear, What should I mention then?

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Warren April 12, 2013, 6:29 p.m. UTC | #9
On 04/12/2013 11:06 AM, Jay Agarwal wrote:
>> On 04/12/2013 10:43 AM, Jay Agarwal wrote:
>>>> On 04/08/2013 09:41 AM, Jay Agarwal wrote:
>>>>> Signed-off-by: Jay Agarwal <jagarwal@nvidia.com>
>>>>>
>>>>> - Enable pcie root port 2 for cardhu
>>>>> - Make private data structure for each SOC
>>>>> - Add required tegra3 clocks and regulators
>>>>> - Add tegra3 specific code in enable controller
>>>>> - Modify clock tree to get clocks based on device
>>>>> - Based on git://gitorious.org/thierryreding/linux.git
>>>>
>>>> A couple more points on this patch:
>>>>
>>>> * You didn't mention that this series is based on Thierry's
>>>> work-in-progress tree, and not something immediately destined for
>>>> upstream. As such, only Thierry is expected to actually apply any of these
>> patches.
>>>>
>>> [>] Stephen, I have mentioned it in comment description as Based on
>> git://gitorious.org/thierryreding/linux.git, is this not enough?
>>
>> Well, first off, there are many branches there, and secondly the branch that
>> a series is based on doesn't necessarily imply much about what you expect
>> people to do with it.
>>
> I am not clear, What should I mention then?

The branch name. Thierry's branch has the following:

  remotes/gitorious_thierryreding_linux/drm/hdmi-for-3.9
  remotes/gitorious_thierryreding_linux/drm/tegra-for-3.9
  remotes/gitorious_thierryreding_linux/tegra/drm/for-3.8
  remotes/gitorious_thierryreding_linux/tegra/drm/next
  remotes/gitorious_thierryreding_linux/tegra/next
  remotes/gitorious_thierryreding_linux/tegra/next-20130122

which of those was it based on?

Also, you simply said it was based on that repo. If you intend Thierry
to apply the patches to his repo/branch, rather than the usual
maintainers of the files you're editing, who you also CC'd, you should
specify that.
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thierry Reding April 13, 2013, 10:23 a.m. UTC | #10
On Fri, Apr 12, 2013 at 09:34:13AM -0600, Stephen Warren wrote:
> On 04/12/2013 08:58 AM, Jay Agarwal wrote:
> >>>  	err = regulator_disable(pcie->pex_clk_supply);
> >>>  	if (err < 0)
> >>> -		dev_err(pcie->dev, "failed to disable pex-clk regulator:
> >> %d\n",
> >>> +		dev_warn(pcie->dev, "failed to disable pex-clk regulator:
> >> %d\n",
> >>>  			err);
> >>>
> >>>  	err = regulator_disable(pcie->vdd_supply);
> >>>  	if (err < 0)
> >>> -		dev_err(pcie->dev, "failed to disable VDD regulator: %d\n",
> >>> +		dev_warn(pcie->dev, "failed to disable VDD regulator:
> >> %d\n",
> >>>  			err);
> >>
> >> Please explain why that change is correct. If the regulators only exist on
> >> Tegra20, please represent that fact in the SoC data. Regulators must always
> >> exist, so enable/disable should never fail due to missing regulators. Actual
> >> run-time failures seem like something that really is an error.
> >>
> > [>] These regulators are needed for both tegra20 & tegra30. Since we are not returning error here, so changed to dev_warn.
> 
> If the regulators are required, then any failure to operate them should
> be an error, hence dev_err() seems correct.
> 
> As to why the code doesn't actually return an error? I'm not sure.
> Perhaps that should be fixed with a separate patch, although I don't
> recall exactly where in the code the above excerpt is; if it's in
> remove(), then continuing on without returning an error would be
> appropriate.

That code is from tegra_pcie_power_off(), which is called only during
error cleanup or from tegra_pcie_put_resources() which in turn is also
only called in cleanup paths or during module/device removal. Disabling
as many regulators as possible is still what we want in that case, so
returning an error prematurely might leave more regulators turned on
than necessary.

Thierry
Stephen Warren May 6, 2013, 7:49 p.m. UTC | #11
On 04/08/2013 09:41 AM, Jay Agarwal wrote:
> Signed-off-by: Jay Agarwal <jagarwal@nvidia.com>
> 
> - Enable pcie root port 2 for cardhu
> - Make private data structure for each SOC
> - Add required tegra3 clocks and regulators
> - Add tegra3 specific code in enable controller
> - Modify clock tree to get clocks based on device
> - Based on git://gitorious.org/thierryreding/linux.git

Jay, I made quite a few comments on this series, and pointed out that it
didn't actually work for me. Are you planning on fixes these issues and
reposting?
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index ba6f51b..6a80b40 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -1592,6 +1592,12 @@  static void __init tegra30_periph_clk_init(void)
 	clk_register_clkdev(clk, "afi", "tegra-pcie");
 	clks[afi] = clk;
 
+	/* pciex */
+	clk = tegra_clk_register_periph_gate("pciex", "pll_e", 0, clk_base, 0,
+				    74, &periph_u_regs, periph_clk_enb_refcnt);
+	clk_register_clkdev(clk, "pciex", NULL);
+	clks[pciex] = clk;
+
 	/* kfuse */
 	clk = tegra_clk_register_periph_gate("kfuse", "clk_m",
 				    TEGRA_PERIPH_ON_APB,
@@ -1710,11 +1716,6 @@  static void __init tegra30_fixed_clk_init(void)
 				1, 0, &cml_lock);
 	clk_register_clkdev(clk, "cml1", NULL);
 	clks[cml1] = clk;
-
-	/* pciex */
-	clk = clk_register_fixed_rate(NULL, "pciex", "pll_e", 0, 100000000);
-	clk_register_clkdev(clk, "pciex", NULL);
-	clks[pciex] = clk;
 }
 
 static void __init tegra30_osc_clk_init(void)
@@ -1930,7 +1931,6 @@  static struct tegra_clk_duplicate tegra_clk_duplicates[] = {
 	TEGRA_CLK_DUPLICATE(bsea, "nvavp", "bsea"),
 	TEGRA_CLK_DUPLICATE(cml1, "tegra_sata_cml", NULL),
 	TEGRA_CLK_DUPLICATE(cml0, "tegra_pcie", "cml"),
-	TEGRA_CLK_DUPLICATE(pciex, "tegra_pcie", "pciex"),
 	TEGRA_CLK_DUPLICATE(vcp, "nvavp", "vcp"),
 	TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* MUST be the last entry */
 };
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 24085ed..79c0996 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -51,7 +51,6 @@ 
 #include <mach/powergate.h>
 
 #define INT_PCI_MSI_NR (8 * 32)
-#define TEGRA_MAX_PORTS 2
 
 /* register definitions */
 
@@ -143,14 +142,15 @@ 
 #define  AFI_INTR_EN_DFPCI_DECERR	(1 << 5)
 #define  AFI_INTR_EN_AXI_DECERR		(1 << 6)
 #define  AFI_INTR_EN_FPCI_TIMEOUT	(1 << 7)
+#define AFI_INTR_EN_PRSNT_SENSE		(1 << 8)
 
 #define AFI_PCIE_CONFIG					0x0f8
 #define  AFI_PCIE_CONFIG_PCIE_DISABLE(x)		(1 << ((x) + 1))
 #define  AFI_PCIE_CONFIG_PCIE_DISABLE_ALL		0xe
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK	(0xf << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE	(0x0 << 20)
-#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420	(0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL	(0x1 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420	(0x0 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222	(0x1 << 20)
 #define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411	(0x2 << 20)
 
@@ -161,8 +161,11 @@ 
 #define AFI_PEX1_CTRL			0x118
 #define AFI_PEX2_CTRL			0x128
 #define  AFI_PEX_CTRL_RST		(1 << 0)
+#define  AFI_PEX_CTRL_CLKREQ_EN		(1 << 1)
 #define  AFI_PEX_CTRL_REFCLK_EN		(1 << 3)
 
+#define  AFI_PEXBIAS_CTRL_0		0x168
+
 #define RP_VEND_XP	0x00000F00
 #define  RP_VEND_XP_DL_UP	(1 << 30)
 
@@ -176,7 +179,8 @@ 
 #define  PADS_CTL_TX_DATA_EN_1L	(1 << 6)
 #define  PADS_CTL_RX_DATA_EN_1L	(1 << 10)
 
-#define PADS_PLL_CTL				0x000000B8
+#define  PADS_PLL_CTL_T20			0x000000B8
+#define  PADS_PLL_CTL_T30			0x000000B4
 #define  PADS_PLL_CTL_RST_B4SM			(1 << 1)
 #define  PADS_PLL_CTL_LOCKDET			(1 << 8)
 #define  PADS_PLL_CTL_REFCLK_MASK		(0x3 << 16)
@@ -184,8 +188,11 @@ 
 #define  PADS_PLL_CTL_REFCLK_INTERNAL_CMOS	(1 << 16)
 #define  PADS_PLL_CTL_REFCLK_EXTERNAL		(2 << 16)
 #define  PADS_PLL_CTL_TXCLKREF_MASK		(0x1 << 20)
+#define  PADS_PLL_CTL_TXCLKREF_BUF_EN		(1 << 22)
 #define  PADS_PLL_CTL_TXCLKREF_DIV10		(0 << 20)
 #define  PADS_PLL_CTL_TXCLKREF_DIV5		(1 << 20)
+#define  PADS_REFCLK_CFG0			0x000000C8
+#define  PADS_REFCLK_CFG1			0x000000CC
 
 struct tegra_msi {
 	DECLARE_BITMAP(used, INT_PCI_MSI_NR);
@@ -196,6 +203,19 @@  struct tegra_msi {
 	int irq;
 };
 
+/* used to differente tegra chips code */
+struct tegra_pcie_soc_data {
+	unsigned int num_max_ports;
+	unsigned int pads_pll_ctl;
+	unsigned int tx_ref_sel;
+	unsigned int msi_base_shift;
+	bool pex_clkreq_en;
+	bool pex_bias_ctrl;
+	bool intr_prsnt_sense;
+	bool need_avdd_supply;
+	bool need_cml0_clk;
+};
+
 static inline struct tegra_msi *to_tegra_msi(struct msi_chip *chip)
 {
 	return container_of(chip, struct tegra_msi, chip);
@@ -220,6 +240,7 @@  struct tegra_pcie {
 	struct clk *afi_clk;
 	struct clk *pcie_xclk;
 	struct clk *pll_e;
+	struct clk *cml0_clk;
 
 	struct tegra_msi msi;
 
@@ -229,6 +250,9 @@  struct tegra_pcie {
 
 	struct regulator *pex_clk_supply;
 	struct regulator *vdd_supply;
+	struct regulator *avdd_supply;
+
+	struct tegra_pcie_soc_data *soc_data;
 };
 
 struct tegra_pcie_port {
@@ -511,12 +535,15 @@  static void tegra_pcie_port_reset(struct tegra_pcie_port *port)
 
 static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
 {
+	struct tegra_pcie_soc_data *soc = port->pcie->soc_data;
 	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
 	unsigned long value;
 
 	/* enable reference clock */
 	value = afi_readl(port->pcie, ctrl);
 	value |= AFI_PEX_CTRL_REFCLK_EN;
+	if (soc->pex_clkreq_en)
+		value |= AFI_PEX_CTRL_CLKREQ_EN;
 	afi_writel(port->pcie, value, ctrl);
 
 	tegra_pcie_port_reset(port);
@@ -569,6 +596,8 @@  static void tegra_pcie_fixup_class(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class);
 
 /* Tegra PCIE requires relaxed ordering */
 static void tegra_pcie_relax_enable(struct pci_dev *dev)
@@ -749,6 +778,11 @@  static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 	struct tegra_pcie_port *port;
 	unsigned int timeout;
 	unsigned long value;
+	struct tegra_pcie_soc_data *soc = pcie->soc_data;
+
+	/* power down to PCIe slot clock bias pad */
+	if (soc->pex_bias_ctrl)
+		afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
 
 	/* configure mode and disable all ports */
 	value = afi_readl(pcie, AFI_PCIE_CONFIG);
@@ -776,26 +810,26 @@  static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 	 * Set up PHY PLL inputs select PLLE output as refclock,
 	 * set TX ref sel to div10 (not div5).
 	 */
-	value = pads_readl(pcie, PADS_PLL_CTL);
+	value = pads_readl(pcie, soc->pads_pll_ctl);
 	value &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
-	value |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML | PADS_PLL_CTL_TXCLKREF_DIV10);
-	pads_writel(pcie, value, PADS_PLL_CTL);
+	value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel;
+	pads_writel(pcie, value, soc->pads_pll_ctl);
 
 	/* take PLL out of reset  */
-	value = pads_readl(pcie, PADS_PLL_CTL);
+	value = pads_readl(pcie, soc->pads_pll_ctl);
 	value |= PADS_PLL_CTL_RST_B4SM;
-	pads_writel(pcie, value, PADS_PLL_CTL);
+	pads_writel(pcie, value, soc->pads_pll_ctl);
 
 	/*
 	 * Hack, set the clock voltage to the DEFAULT provided by hw folks.
 	 * This doesn't exist in the documentation.
 	 */
-	pads_writel(pcie, 0xfa5cfa5c, 0xc8);
+	pads_writel(pcie, 0xfa5cfa5c, PADS_REFCLK_CFG0);
 
 	/* wait for the PLL to lock */
 	timeout = 300;
 	do {
-		value = pads_readl(pcie, PADS_PLL_CTL);
+		value = pads_readl(pcie, soc->pads_pll_ctl);
 		usleep_range(1000, 1000);
 		if (--timeout == 0) {
 			pr_err("Tegra PCIe error: timeout waiting for PLL\n");
@@ -824,6 +858,8 @@  static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 	value = AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
 		AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR |
 		AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR;
+	if (soc->intr_prsnt_sense)
+		value |= AFI_INTR_EN_PRSNT_SENSE;
 	afi_writel(pcie, value, AFI_AFI_INTR_ENABLE);
 	afi_writel(pcie, 0xffffffff, AFI_SM_INTR_ENABLE);
 
@@ -838,6 +874,7 @@  static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
 
 static void tegra_pcie_power_off(struct tegra_pcie *pcie)
 {
+	struct tegra_pcie_soc_data *soc = pcie->soc_data;
 	int err;
 
 	/* TODO: disable and unprepare clocks? */
@@ -849,19 +886,26 @@  static void tegra_pcie_power_off(struct tegra_pcie *pcie)
 	tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
 	tegra_pmc_pcie_xclk_clamp(true);
 
+	if (soc->need_avdd_supply) {
+		err = regulator_disable(pcie->avdd_supply);
+		if (err < 0)
+			dev_warn(pcie->dev, "failed to disable AVDD regulator: %d\n",
+			err);
+	}
 	err = regulator_disable(pcie->pex_clk_supply);
 	if (err < 0)
-		dev_err(pcie->dev, "failed to disable pex-clk regulator: %d\n",
+		dev_warn(pcie->dev, "failed to disable pex-clk regulator: %d\n",
 			err);
 
 	err = regulator_disable(pcie->vdd_supply);
 	if (err < 0)
-		dev_err(pcie->dev, "failed to disable VDD regulator: %d\n",
+		dev_warn(pcie->dev, "failed to disable VDD regulator: %d\n",
 			err);
 }
 
 static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 {
+	struct tegra_pcie_soc_data *soc = pcie->soc_data;
 	int err;
 
 	tegra_periph_reset_assert(pcie->pcie_xclk);
@@ -885,6 +929,15 @@  static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 		return err;
 	}
 
+	if (soc->need_avdd_supply) {
+		err = regulator_enable(pcie->avdd_supply);
+		if (err < 0) {
+			dev_err(pcie->dev, "failed to enable AVDD regulator: %d\n",
+				err);
+			return err;
+		}
+	}
+
 	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
 						pcie->pex_clk);
 	if (err) {
@@ -902,6 +955,15 @@  static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 		return err;
 	}
 
+	if (soc->need_cml0_clk) {
+		err = clk_prepare_enable(pcie->cml0_clk);
+		if (err < 0) {
+			dev_err(pcie->dev, "failed to enable cml0 clock: %d\n",
+				err);
+			return err;
+		}
+	}
+
 	err = clk_prepare_enable(pcie->pll_e);
 	if (err < 0) {
 		dev_err(pcie->dev, "failed to enable PLLE clock: %d\n", err);
@@ -913,6 +975,8 @@  static int tegra_pcie_power_on(struct tegra_pcie *pcie)
 
 static int tegra_pcie_clocks_get(struct tegra_pcie *pcie)
 {
+	struct tegra_pcie_soc_data *soc = pcie->soc_data;
+
 	pcie->pex_clk = devm_clk_get(pcie->dev, "pex");
 	if (IS_ERR(pcie->pex_clk))
 		return PTR_ERR(pcie->pex_clk);
@@ -929,6 +993,11 @@  static int tegra_pcie_clocks_get(struct tegra_pcie *pcie)
 	if (IS_ERR(pcie->pll_e))
 		return PTR_ERR(pcie->pll_e);
 
+	if (soc->need_cml0_clk) {
+		pcie->cml0_clk = devm_clk_get(pcie->dev, "cml0");
+		if (IS_ERR(pcie->cml0_clk))
+			return PTR_ERR(pcie->cml0_clk);
+	}
 	return 0;
 }
 
@@ -1151,6 +1220,7 @@  static int tegra_pcie_enable_msi(struct tegra_pcie *pcie)
 {
 	struct platform_device *pdev = to_platform_device(pcie->dev);
 	struct tegra_msi *msi = &pcie->msi;
+	struct tegra_pcie_soc_data *soc = pcie->soc_data;
 	unsigned long base;
 	int err;
 	u32 reg;
@@ -1187,7 +1257,7 @@  static int tegra_pcie_enable_msi(struct tegra_pcie *pcie)
 	msi->pages = __get_free_pages(GFP_KERNEL, 3);
 	base = virt_to_phys((void *)msi->pages);
 
-	afi_writel(pcie, base, AFI_MSI_FPCI_BAR_ST);
+	afi_writel(pcie, base >> soc->msi_base_shift, AFI_MSI_FPCI_BAR_ST);
 	afi_writel(pcie, base, AFI_MSI_AXI_BAR_ST);
 	/* this register is in 4K increments */
 	afi_writel(pcie, 1, AFI_MSI_BAR_SZ);
@@ -1284,6 +1354,7 @@  static u32 tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes)
 static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
 {
 	struct device_node *np = pcie->dev->of_node, *port;
+	struct tegra_pcie_soc_data *soc = pcie->soc_data;
 	const __be32 *range = NULL;
 	struct resource res;
 	u32 lanes = 0;
@@ -1297,6 +1368,12 @@  static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
 	if (IS_ERR(pcie->pex_clk_supply))
 		return PTR_ERR(pcie->pex_clk_supply);
 
+	if (soc->need_avdd_supply) {
+		pcie->avdd_supply = devm_regulator_get(pcie->dev, "avdd");
+		if (IS_ERR(pcie->avdd_supply))
+			return PTR_ERR(pcie->avdd_supply);
+	}
+
 	while ((range = of_pci_process_ranges(np, &res, range)) != NULL) {
 		switch (res.flags & IORESOURCE_TYPE_BITS) {
 		case IORESOURCE_IO:
@@ -1341,7 +1418,7 @@  static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
 
 		index = PCI_SLOT(err);
 
-		if (index < 1 || index > TEGRA_MAX_PORTS) {
+		if (index < 1 || index > pcie->soc_data->num_max_ports) {
 			dev_err(pcie->dev, "invalid port number: %d\n", index);
 			return -EINVAL;
 		}
@@ -1477,8 +1554,39 @@  static int tegra_pcie_enable(struct tegra_pcie *pcie)
 	return 0;
 }
 
+static const struct tegra_pcie_soc_data tegra20_pcie_data = {
+	.num_max_ports = 2,
+	.pads_pll_ctl = PADS_PLL_CTL_T20,
+	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
+	.msi_base_shift = 0,
+	.pex_clkreq_en = false,
+	.pex_bias_ctrl = false,
+	.intr_prsnt_sense = false,
+	.need_avdd_supply = false,
+	.need_cml0_clk = false,
+};
+
+static const struct tegra_pcie_soc_data tegra30_pcie_data = {
+	.num_max_ports = 3,
+	.pads_pll_ctl = PADS_PLL_CTL_T30,
+	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+	.msi_base_shift = 8,
+	.pex_clkreq_en = true,
+	.pex_bias_ctrl = true,
+	.intr_prsnt_sense = true,
+	.need_avdd_supply = true,
+	.need_cml0_clk = true,
+};
+
+static const struct of_device_id tegra_pcie_of_match[] = {
+	{ .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie_data},
+	{ .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie_data},
+	{ },
+};
+
 static int tegra_pcie_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *match;
 	struct tegra_pcie *pcie;
 	int err;
 
@@ -1489,6 +1597,11 @@  static int tegra_pcie_probe(struct platform_device *pdev)
 	INIT_LIST_HEAD(&pcie->busses);
 	INIT_LIST_HEAD(&pcie->ports);
 	pcie->dev = &pdev->dev;
+	match = of_match_device(tegra_pcie_of_match, &pdev->dev);
+	if (match)
+		pcie->soc_data = (struct tegra_pcie_soc_data *)match->data;
+	else
+		return -ENODEV;
 
 	err = tegra_pcie_parse_dt(pcie);
 	if (err < 0)
@@ -1560,11 +1673,6 @@  static int tegra_pcie_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id tegra_pcie_of_match[] = {
-	{ .compatible = "nvidia,tegra20-pcie", },
-	{ },
-};
-
 static struct platform_driver tegra_pcie_driver = {
 	.driver = {
 		.name = "tegra-pcie",