diff mbox

[U-Boot,1/5] pci: tegra: port to standard clock/reset/pwr domain APIs

Message ID 20160727214822.26697-1-swarren@wwwdotorg.org
State Superseded
Delegated to: Tom Warren
Headers show

Commit Message

Stephen Warren July 27, 2016, 9:48 p.m. UTC
From: Stephen Warren <swarren@nvidia.com>

Tegra186 supports the new standard clock, reset, and power domain APIs.
Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so
that it can operate with either set of APIs.

On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming.
Consequently, this logic is disabled too.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
This whole series builds on the other Tegra186 series that I just sent.

 drivers/pci/Kconfig     |   1 +
 drivers/pci/pci_tegra.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 150 insertions(+), 5 deletions(-)

Comments

Simon Glass Aug. 1, 2016, 1:02 a.m. UTC | #1
Hi Stephen,

On 27 July 2016 at 15:48, Stephen Warren <swarren@wwwdotorg.org> wrote:
> From: Stephen Warren <swarren@nvidia.com>
>
> Tegra186 supports the new standard clock, reset, and power domain APIs.
> Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so
> that it can operate with either set of APIs.
>
> On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming.
> Consequently, this logic is disabled too.
>
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> ---
> This whole series builds on the other Tegra186 series that I just sent.
>
>  drivers/pci/Kconfig     |   1 +
>  drivers/pci/pci_tegra.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 150 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index 26aa2b0930a0..669e37bb5dc5 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -31,6 +31,7 @@ config PCI_SANDBOX
>  config PCI_TEGRA
>         bool "Tegra PCI support"
>         depends on TEGRA
> +       depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186)
>         help
>           Enable support for the PCIe controller found on some generations of
>           Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has
> diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
> index 352cdef56ab4..a6785ad0bbee 100644
> --- a/drivers/pci/pci_tegra.c
> +++ b/drivers/pci/pci_tegra.c
> @@ -13,22 +13,26 @@
>  #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
>
>  DECLARE_GLOBAL_DATA_PTR;
>
> @@ -103,6 +107,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 +117,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 +181,7 @@ enum tegra_pci_id {
>         TEGRA30_PCIE,
>         TEGRA124_PCIE,
>         TEGRA210_PCIE,
> +       TEGRA186_PCIE,
>  };
>
>  struct tegra_pcie_port {
> @@ -189,6 +198,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 +219,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

Eek. This is a compile-time driver configuration. Can you use the
device tree compatible string to detect which to use?

[...]

Regards,
Simon
Simon Glass Aug. 4, 2016, 1:16 a.m. UTC | #2
Hi Stephen,

On 1 August 2016 at 09:22, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 07/31/2016 07:02 PM, Simon Glass wrote:
>>
>> Hi Stephen,
>>
>> On 27 July 2016 at 15:48, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>
>>> From: Stephen Warren <swarren@nvidia.com>
>>>
>>> Tegra186 supports the new standard clock, reset, and power domain APIs.
>>> Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so
>>> that it can operate with either set of APIs.
>>>
>>> On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming.
>>> Consequently, this logic is disabled too.
>>>
>>> Signed-off-by: Stephen Warren <swarren@nvidia.com>
>>> ---
>>> This whole series builds on the other Tegra186 series that I just sent.
>>>
>>>  drivers/pci/Kconfig     |   1 +
>>>  drivers/pci/pci_tegra.c | 154
>>> ++++++++++++++++++++++++++++++++++++++++++++++--
>>>  2 files changed, 150 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
>>> index 26aa2b0930a0..669e37bb5dc5 100644
>>> --- a/drivers/pci/Kconfig
>>> +++ b/drivers/pci/Kconfig
>>> @@ -31,6 +31,7 @@ config PCI_SANDBOX
>>>  config PCI_TEGRA
>>>         bool "Tegra PCI support"
>>>         depends on TEGRA
>>> +       depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186)
>>>         help
>>>           Enable support for the PCIe controller found on some
>>> generations of
>>>           Tegra. Tegra20 has 2 root ports with a total of 4 lanes,
>>> Tegra30 has
>>> diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
>>> index 352cdef56ab4..a6785ad0bbee 100644
>>> --- a/drivers/pci/pci_tegra.c
>>> +++ b/drivers/pci/pci_tegra.c
>>> @@ -13,22 +13,26 @@
>>>  #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
>>>
>>>  DECLARE_GLOBAL_DATA_PTR;
>>>
>>> @@ -103,6 +107,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 +117,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 +181,7 @@ enum tegra_pci_id {
>>>         TEGRA30_PCIE,
>>>         TEGRA124_PCIE,
>>>         TEGRA210_PCIE,
>>> +       TEGRA186_PCIE,
>>>  };
>>>
>>>  struct tegra_pcie_port {
>>> @@ -189,6 +198,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 +219,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
>>
>>
>> Eek. This is a compile-time driver configuration. Can you use the
>> device tree compatible string to detect which to use?
>
>
> No. The legacy APIs are simply not available (not compiled in) on the newer
> SoCs, so there must be a compile-time condition.
>
> It is theoretically possible to convert all the old SoCs to the new APIs so
> that this conditional goes away in the future, but we don't have that work
> scheduled at present.

What did you do with Linux?

Regards,
Simon
Stephen Warren Aug. 4, 2016, 6:52 p.m. UTC | #3
On 08/03/2016 07:16 PM, Simon Glass wrote:
> Hi Stephen,
>
> On 1 August 2016 at 09:22, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 07/31/2016 07:02 PM, Simon Glass wrote:
>>>
>>> Hi Stephen,
>>>
>>> On 27 July 2016 at 15:48, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>>
>>>> From: Stephen Warren <swarren@nvidia.com>
>>>>
>>>> Tegra186 supports the new standard clock, reset, and power domain APIs.
>>>> Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver so
>>>> that it can operate with either set of APIs.
>>>>
>>>> On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY) programming.
>>>> Consequently, this logic is disabled too.
>>>>
>>>> Signed-off-by: Stephen Warren <swarren@nvidia.com>
>>>> ---
>>>> This whole series builds on the other Tegra186 series that I just sent.
>>>>
>>>>  drivers/pci/Kconfig     |   1 +
>>>>  drivers/pci/pci_tegra.c | 154
>>>> ++++++++++++++++++++++++++++++++++++++++++++++--
>>>>  2 files changed, 150 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
>>>> index 26aa2b0930a0..669e37bb5dc5 100644
>>>> --- a/drivers/pci/Kconfig
>>>> +++ b/drivers/pci/Kconfig
>>>> @@ -31,6 +31,7 @@ config PCI_SANDBOX
>>>>  config PCI_TEGRA
>>>>         bool "Tegra PCI support"
>>>>         depends on TEGRA
>>>> +       depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186)
>>>>         help
>>>>           Enable support for the PCIe controller found on some
>>>> generations of
>>>>           Tegra. Tegra20 has 2 root ports with a total of 4 lanes,
>>>> Tegra30 has
>>>> diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
>>>> index 352cdef56ab4..a6785ad0bbee 100644
>>>> --- a/drivers/pci/pci_tegra.c
>>>> +++ b/drivers/pci/pci_tegra.c
>>>> @@ -13,22 +13,26 @@
>>>>  #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
>>>>
>>>>  DECLARE_GLOBAL_DATA_PTR;
>>>>
>>>> @@ -103,6 +107,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 +117,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 +181,7 @@ enum tegra_pci_id {
>>>>         TEGRA30_PCIE,
>>>>         TEGRA124_PCIE,
>>>>         TEGRA210_PCIE,
>>>> +       TEGRA186_PCIE,
>>>>  };
>>>>
>>>>  struct tegra_pcie_port {
>>>> @@ -189,6 +198,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 +219,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
>>>
>>>
>>> Eek. This is a compile-time driver configuration. Can you use the
>>> device tree compatible string to detect which to use?
>>
>>
>> No. The legacy APIs are simply not available (not compiled in) on the newer
>> SoCs, so there must be a compile-time condition.
>>
>> It is theoretically possible to convert all the old SoCs to the new APIs so
>> that this conditional goes away in the future, but we don't have that work
>> scheduled at present.
>
> What did you do with Linux?

We lucked out and life was a bit simpler:

When we started adding Tegra support, there was already a standard clock 
API header, albeit with an entirely separate implementation for each 
SoC. When the common clock framework/core appeared, it maintained this 
same API so drivers weren't affected, except for a change in a #include 
filename.

As far as converting the clock driver from a standalone/custom 
implementation to being based on the common clock framework/core, life 
was much easier. At that time, we only supported 2 Tegra SoC generations 
and many fewer boards and drivers, and so significantly less testing was 
required for the converted implementation. Many SoC generations, board, 
and drivers were only written once the new clock implementation was in 
place, so never needed conversion.

Tegra started out with a completely custom reset API and implementation. 
When Tegra converted from its custom standalone clock implementation to 
the common clock framework/core, that same API was re-implemented using 
the new clock code (as you know, clocks and resets on Tegra are very 
closely tied), and so there was no effect on drivers.

Later, we converted to the new reset API/framework/core. At this point, 
we did support 4 SoC generations and many more boards. However, IIRC 
during this time, there was a huge focus on converting to standard APIs, 
and a lull in new SoC and board support, so there was time to spend on 
large-scale conversions; they didn't take time away from other work 
required to support new SoCs/boards. This conversion implemented the new 
standard reset for all SoCs first, converted all drivers to use the new 
API roughly at once, and then removed the old API.

So we got away without ifdefs.

In U-Boot, we now support many more SoCs, boards, and perhaps even 
drivers, so a "convert everything at once" approach is quite a lot more 
work than it was in the kernel, especially on the clock/reset driver 
implementation side. Equally, to be honest, my primary focus is 
currently on adding Tegra186 support at the moment. Given we needed a 
completely new clock/reset/... implementation anyway due to the 
existence of the BPMP, it was a no-brainer to create and/or use the new 
standard clock/reset/... APIs for Tegra186, rather than basing the new 
implementation on the old custom APIs. However, converting all the other 
SoCs/boards first is just going to delay any forward progress on 
Tegra186 and lead to a mega series of code conversions that I'd rather 
avoid doing all at once. Adding these ifdefs, allows incremental forward 
progress to be made pretty easily. They should be removed when older SoC 
generations are converted to the new APIs, so everything is unified 
again. Granted, I have no definite timescale for that at present.
Simon Glass Aug. 5, 2016, 1:36 a.m. UTC | #4
Hi Stephen,

On 4 August 2016 at 12:52, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 08/03/2016 07:16 PM, Simon Glass wrote:
>>
>> Hi Stephen,
>>
>> On 1 August 2016 at 09:22, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>
>>> On 07/31/2016 07:02 PM, Simon Glass wrote:
>>>>
>>>>
>>>> Hi Stephen,
>>>>
>>>> On 27 July 2016 at 15:48, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>>>
>>>>>
>>>>> From: Stephen Warren <swarren@nvidia.com>
>>>>>
>>>>> Tegra186 supports the new standard clock, reset, and power domain APIs.
>>>>> Older Tegra SoCs still use custom APIs. Enhance the Tegra PCIe driver
>>>>> so
>>>>> that it can operate with either set of APIs.
>>>>>
>>>>> On Tegra186, the BPMP handles all aspects of PCIe PHY (UPHY)
>>>>> programming.
>>>>> Consequently, this logic is disabled too.
>>>>>
>>>>> Signed-off-by: Stephen Warren <swarren@nvidia.com>
>>>>> ---
>>>>> This whole series builds on the other Tegra186 series that I just sent.
>>>>>
>>>>>  drivers/pci/Kconfig     |   1 +
>>>>>  drivers/pci/pci_tegra.c | 154
>>>>> ++++++++++++++++++++++++++++++++++++++++++++++--
>>>>>  2 files changed, 150 insertions(+), 5 deletions(-)
>>>>>
>>>>> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
>>>>> index 26aa2b0930a0..669e37bb5dc5 100644
>>>>> --- a/drivers/pci/Kconfig
>>>>> +++ b/drivers/pci/Kconfig
>>>>> @@ -31,6 +31,7 @@ config PCI_SANDBOX
>>>>>  config PCI_TEGRA
>>>>>         bool "Tegra PCI support"
>>>>>         depends on TEGRA
>>>>> +       depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186)
>>>>>         help
>>>>>           Enable support for the PCIe controller found on some
>>>>> generations of
>>>>>           Tegra. Tegra20 has 2 root ports with a total of 4 lanes,
>>>>> Tegra30 has
>>>>> diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
>>>>> index 352cdef56ab4..a6785ad0bbee 100644
>>>>> --- a/drivers/pci/pci_tegra.c
>>>>> +++ b/drivers/pci/pci_tegra.c
>>>>> @@ -13,22 +13,26 @@
>>>>>  #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
>>>>>
>>>>>  DECLARE_GLOBAL_DATA_PTR;
>>>>>
>>>>> @@ -103,6 +107,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 +117,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 +181,7 @@ enum tegra_pci_id {
>>>>>         TEGRA30_PCIE,
>>>>>         TEGRA124_PCIE,
>>>>>         TEGRA210_PCIE,
>>>>> +       TEGRA186_PCIE,
>>>>>  };
>>>>>
>>>>>  struct tegra_pcie_port {
>>>>> @@ -189,6 +198,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 +219,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
>>>>
>>>>
>>>>
>>>> Eek. This is a compile-time driver configuration. Can you use the
>>>> device tree compatible string to detect which to use?
>>>
>>>
>>>
>>> No. The legacy APIs are simply not available (not compiled in) on the
>>> newer
>>> SoCs, so there must be a compile-time condition.
>>>
>>> It is theoretically possible to convert all the old SoCs to the new APIs
>>> so
>>> that this conditional goes away in the future, but we don't have that
>>> work
>>> scheduled at present.
>>
>>
>> What did you do with Linux?
>
>
> We lucked out and life was a bit simpler:
>
> When we started adding Tegra support, there was already a standard clock API
> header, albeit with an entirely separate implementation for each SoC. When
> the common clock framework/core appeared, it maintained this same API so
> drivers weren't affected, except for a change in a #include filename.
>
> As far as converting the clock driver from a standalone/custom
> implementation to being based on the common clock framework/core, life was
> much easier. At that time, we only supported 2 Tegra SoC generations and
> many fewer boards and drivers, and so significantly less testing was
> required for the converted implementation. Many SoC generations, board, and
> drivers were only written once the new clock implementation was in place, so
> never needed conversion.
>
> Tegra started out with a completely custom reset API and implementation.
> When Tegra converted from its custom standalone clock implementation to the
> common clock framework/core, that same API was re-implemented using the new
> clock code (as you know, clocks and resets on Tegra are very closely tied),
> and so there was no effect on drivers.
>
> Later, we converted to the new reset API/framework/core. At this point, we
> did support 4 SoC generations and many more boards. However, IIRC during
> this time, there was a huge focus on converting to standard APIs, and a lull
> in new SoC and board support, so there was time to spend on large-scale
> conversions; they didn't take time away from other work required to support
> new SoCs/boards. This conversion implemented the new standard reset for all
> SoCs first, converted all drivers to use the new API roughly at once, and
> then removed the old API.
>
> So we got away without ifdefs.
>
> In U-Boot, we now support many more SoCs, boards, and perhaps even drivers,
> so a "convert everything at once" approach is quite a lot more work than it
> was in the kernel, especially on the clock/reset driver implementation side.
> Equally, to be honest, my primary focus is currently on adding Tegra186
> support at the moment. Given we needed a completely new clock/reset/...
> implementation anyway due to the existence of the BPMP, it was a no-brainer
> to create and/or use the new standard clock/reset/... APIs for Tegra186,
> rather than basing the new implementation on the old custom APIs. However,
> converting all the other SoCs/boards first is just going to delay any
> forward progress on Tegra186 and lead to a mega series of code conversions
> that I'd rather avoid doing all at once. Adding these ifdefs, allows
> incremental forward progress to be made pretty easily. They should be
> removed when older SoC generations are converted to the new APIs, so
> everything is unified again. Granted, I have no definite timescale for that
> at present.

OK, well I'd like to see some TODOs in the code around these #ifdefs.
They are definitely not what we want, and should be marked as interim.
Please see if you can find someone to convert things over. I can
perhaps help too.

Regards,
Simon
diff mbox

Patch

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 26aa2b0930a0..669e37bb5dc5 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -31,6 +31,7 @@  config PCI_SANDBOX
 config PCI_TEGRA
 	bool "Tegra PCI support"
 	depends on TEGRA
+	depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186)
 	help
 	  Enable support for the PCIe controller found on some generations of
 	  Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
index 352cdef56ab4..a6785ad0bbee 100644
--- a/drivers/pci/pci_tegra.c
+++ b/drivers/pci/pci_tegra.c
@@ -13,22 +13,26 @@ 
 #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
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -103,6 +107,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 +117,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 +181,7 @@  enum tegra_pci_id {
 	TEGRA30_PCIE,
 	TEGRA124_PCIE,
 	TEGRA210_PCIE,
+	TEGRA186_PCIE,
 };
 
 struct tegra_pcie_port {
@@ -189,6 +198,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 +219,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 +249,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 +422,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 +511,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 +520,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 +565,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 +719,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 +728,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 +760,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 +770,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 +882,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 +1040,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 +1068,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 +1101,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 +1176,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 },
 	{ }
 };