[PATCH 2/2] PCI: brcmstb: Use "num-lanes" DT property if present

Jim Quinlan posted 2 patches 6 months, 2 weeks ago
[PATCH 2/2] PCI: brcmstb: Use "num-lanes" DT property if present
Posted by Jim Quinlan 6 months, 2 weeks ago
By default, we use automatic HW negotiation to ascertain the number of
lanes of the PCIe connection.  If the "num-lanes" DT property is present,
assume that the chip's built-in capability information is incorrect or
undesired, and use the specified value instead.

Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>
---
 drivers/pci/controller/pcie-brcmstb.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
index e19628e13898..79fc6d00b7bc 100644
--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -46,6 +46,7 @@
 #define  PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK	0xffffff
 
 #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY			0x04dc
+#define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK	0x1f0
 #define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK	0xc00
 
 #define PCIE_RC_CFG_PRIV1_ROOT_CAP			0x4f8
@@ -55,6 +56,9 @@
 #define PCIE_RC_DL_MDIO_WR_DATA				0x1104
 #define PCIE_RC_DL_MDIO_RD_DATA				0x1108
 
+#define PCIE_RC_PL_REG_PHY_CTL_1			0x1804
+#define  PCIE_RC_PL_REG_PHY_CTL_1_REG_P2_POWERDOWN_ENA_NOSYNC_MASK	0x8
+
 #define PCIE_RC_PL_PHY_CTL_15				0x184c
 #define  PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK		0x400000
 #define  PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK	0xff
@@ -1072,7 +1076,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
 	void __iomem *base = pcie->base;
 	struct pci_host_bridge *bridge;
 	struct resource_entry *entry;
-	u32 tmp, burst, aspm_support;
+	u32 tmp, burst, aspm_support, num_lanes, num_lanes_cap;
 	u8 num_out_wins = 0;
 	int num_inbound_wins = 0;
 	int memc, ret;
@@ -1180,6 +1184,26 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
 		PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK);
 	writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
 
+	/* 'tmp' still holds the contents of PRIV1_LINK_CAPABILITY */
+	num_lanes_cap = u32_get_bits(tmp, PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK);
+	num_lanes = 0;
+	/*
+	 * Use automatic num-lanes HW negotiation by default.  If the
+	 * "num-lanes" DT property is present, assume that the chip's
+	 * built-in link width capability information is
+	 * incorrect/undesired and use the specified value instead.
+	 */
+	if (!of_property_read_u32(pcie->np, "num-lanes", &num_lanes) &&
+	    num_lanes && num_lanes <= 4 && num_lanes_cap != num_lanes) {
+		u32p_replace_bits(&tmp, num_lanes,
+			PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK);
+		writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
+		tmp = readl(base + PCIE_RC_PL_REG_PHY_CTL_1);
+		u32p_replace_bits(&tmp, 1,
+			PCIE_RC_PL_REG_PHY_CTL_1_REG_P2_POWERDOWN_ENA_NOSYNC_MASK);
+		writel(tmp, base + PCIE_RC_PL_REG_PHY_CTL_1);
+	}
+
 	/*
 	 * For config space accesses on the RC, show the right class for
 	 * a PCIe-PCIe bridge (the default setting is to be EP mode).
-- 
2.43.0
Re: [PATCH 2/2] PCI: brcmstb: Use "num-lanes" DT property if present
Posted by Bjorn Helgaas 5 months, 3 weeks ago
On Fri, May 30, 2025 at 06:40:33PM -0400, Jim Quinlan wrote:
> By default, we use automatic HW negotiation to ascertain the number of
> lanes of the PCIe connection.  If the "num-lanes" DT property is present,
> assume that the chip's built-in capability information is incorrect or
> undesired, and use the specified value instead.
> 
> Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>
> ---
>  drivers/pci/controller/pcie-brcmstb.c | 26 +++++++++++++++++++++++++-
>  1 file changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
> index e19628e13898..79fc6d00b7bc 100644
> --- a/drivers/pci/controller/pcie-brcmstb.c
> +++ b/drivers/pci/controller/pcie-brcmstb.c
> @@ -46,6 +46,7 @@
>  #define  PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK	0xffffff
>  
>  #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY			0x04dc
> +#define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK	0x1f0
>  #define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK	0xc00
>  
>  #define PCIE_RC_CFG_PRIV1_ROOT_CAP			0x4f8
   #define  PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK      0xf8

If you squint, PCIE_RC_CFG_PRIV1_LINK_CAPABILITY looks a little like
these standard PCIe things:

  #define PCI_EXP_LNKCAP          0x0c    /* Link Capabilities */
  #define  PCI_EXP_LNKCAP_MLW     0x000003f0 /* Maximum Link Width */
  #define  PCI_EXP_LNKCAP_ASPMS   0x00000c00 /* ASPM Support */

  #define PCI_EXP_DEVCTL2         0x28    /* Device Control 2 */

So I was hoping we had an opportunity to use PCI_EXP_LNKCAP_MLW and
PCI_EXP_LNKCAP_ASPMS instead of
PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK and
PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK.

But I guess PCIE_RC_CFG_PRIV1_LINK_CAPABILITY is probably not actually
PCI_EXP_LNKCAP, because PCI_EXP_LNKCAP being 0x0c into a PCIe
Capability would mean the cap started at 0x04d0, and
PCIE_RC_CFG_PRIV1_ROOT_CAP would be at offset 0x28
(0x04d0 + 0x28 == 0x04f8).

But offset 0x28 in a PCIe Capability would be PCI_EXP_DEVCTL2, not 
PCIE_RC_CFG_PRIV1_ROOT_CAP, and I can't squint hard enough to see
anything related to L1SS anywhere in the PCIe Capability.

So never mind ;)

Bjorn
Re: [PATCH 2/2] PCI: brcmstb: Use "num-lanes" DT property if present
Posted by Jim Quinlan 5 months, 3 weeks ago
On Tue, Jun 24, 2025 at 6:01 PM Bjorn Helgaas <helgaas@kernel.org> wrote:
>
> On Fri, May 30, 2025 at 06:40:33PM -0400, Jim Quinlan wrote:
> > By default, we use automatic HW negotiation to ascertain the number of
> > lanes of the PCIe connection.  If the "num-lanes" DT property is present,
> > assume that the chip's built-in capability information is incorrect or
> > undesired, and use the specified value instead.
> >
> > Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>
> > ---
> >  drivers/pci/controller/pcie-brcmstb.c | 26 +++++++++++++++++++++++++-
> >  1 file changed, 25 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
> > index e19628e13898..79fc6d00b7bc 100644
> > --- a/drivers/pci/controller/pcie-brcmstb.c
> > +++ b/drivers/pci/controller/pcie-brcmstb.c
> > @@ -46,6 +46,7 @@
> >  #define  PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK   0xffffff
> >
> >  #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY                    0x04dc
> > +#define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK       0x1f0
> >  #define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00
> >
> >  #define PCIE_RC_CFG_PRIV1_ROOT_CAP                   0x4f8
>    #define  PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK      0xf8
>
> If you squint, PCIE_RC_CFG_PRIV1_LINK_CAPABILITY looks a little like
> these standard PCIe things:
>
>   #define PCI_EXP_LNKCAP          0x0c    /* Link Capabilities */
>   #define  PCI_EXP_LNKCAP_MLW     0x000003f0 /* Maximum Link Width */
>   #define  PCI_EXP_LNKCAP_ASPMS   0x00000c00 /* ASPM Support */
>
>   #define PCI_EXP_DEVCTL2         0x28    /* Device Control 2 */
>
> So I was hoping we had an opportunity to use PCI_EXP_LNKCAP_MLW and
> PCI_EXP_LNKCAP_ASPMS instead of
> PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK and
> PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK.
>
> But I guess PCIE_RC_CFG_PRIV1_LINK_CAPABILITY is probably not actually
> PCI_EXP_LNKCAP, because PCI_EXP_LNKCAP being 0x0c into a PCIe
> Capability would mean the cap started at 0x04d0, and
> PCIE_RC_CFG_PRIV1_ROOT_CAP would be at offset 0x28
> (0x04d0 + 0x28 == 0x04f8).
>
> But offset 0x28 in a PCIe Capability would be PCI_EXP_DEVCTL2, not
> PCIE_RC_CFG_PRIV1_ROOT_CAP, and I can't squint hard enough to see
> anything related to L1SS anywhere in the PCIe Capability.
>
> So never mind ;)
Hi Bjorn,

Not only are the "priv" register offsets slightly different, the
values of the masks may be different as well.  For example,
PCI_EXP_LNKCAP_MLW  is 0x3f0 while our "priv" version is 0x1f0, as
something unrelated occupies the missing "priv" bit.

Cheers,
Jim Quinlan
Broadcom STB/CM


>
> Bjorn
Re: [PATCH 2/2] PCI: brcmstb: Use "num-lanes" DT property if present
Posted by Manivannan Sadhasivam 6 months, 2 weeks ago
On Fri, May 30, 2025 at 06:40:33PM -0400, Jim Quinlan wrote:
> By default, we use automatic HW negotiation to ascertain the number of
> lanes of the PCIe connection.  If the "num-lanes" DT property is present,
> assume that the chip's built-in capability information is incorrect or
> undesired, and use the specified value instead.
> 
> Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>
> ---
>  drivers/pci/controller/pcie-brcmstb.c | 26 +++++++++++++++++++++++++-
>  1 file changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
> index e19628e13898..79fc6d00b7bc 100644
> --- a/drivers/pci/controller/pcie-brcmstb.c
> +++ b/drivers/pci/controller/pcie-brcmstb.c
> @@ -46,6 +46,7 @@
>  #define  PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK	0xffffff
>  
>  #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY			0x04dc
> +#define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK	0x1f0
>  #define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK	0xc00
>  
>  #define PCIE_RC_CFG_PRIV1_ROOT_CAP			0x4f8
> @@ -55,6 +56,9 @@
>  #define PCIE_RC_DL_MDIO_WR_DATA				0x1104
>  #define PCIE_RC_DL_MDIO_RD_DATA				0x1108
>  
> +#define PCIE_RC_PL_REG_PHY_CTL_1			0x1804
> +#define  PCIE_RC_PL_REG_PHY_CTL_1_REG_P2_POWERDOWN_ENA_NOSYNC_MASK	0x8
> +
>  #define PCIE_RC_PL_PHY_CTL_15				0x184c
>  #define  PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK		0x400000
>  #define  PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK	0xff
> @@ -1072,7 +1076,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
>  	void __iomem *base = pcie->base;
>  	struct pci_host_bridge *bridge;
>  	struct resource_entry *entry;
> -	u32 tmp, burst, aspm_support;
> +	u32 tmp, burst, aspm_support, num_lanes, num_lanes_cap;
>  	u8 num_out_wins = 0;
>  	int num_inbound_wins = 0;
>  	int memc, ret;
> @@ -1180,6 +1184,26 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
>  		PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK);
>  	writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
>  
> +	/* 'tmp' still holds the contents of PRIV1_LINK_CAPABILITY */
> +	num_lanes_cap = u32_get_bits(tmp, PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK);
> +	num_lanes = 0;
> +	/*
> +	 * Use automatic num-lanes HW negotiation by default.  If the

"Use hardware negotiated Max Link Width value by default."

> +	 * "num-lanes" DT property is present, assume that the chip's
> +	 * built-in link width capability information is
> +	 * incorrect/undesired and use the specified value instead.
> +	 */
> +	if (!of_property_read_u32(pcie->np, "num-lanes", &num_lanes) &&
> +	    num_lanes && num_lanes <= 4 && num_lanes_cap != num_lanes) {

I think you should drop the 'num_lanes && num_lanes <= 4' check since the DT
binding should take care of that. Otherwise, once link width gets increased, you
need to update both binding and the driver, which is redundant.

- Mani

-- 
மணிவண்ணன் சதாசிவம்
Re: [PATCH 2/2] PCI: brcmstb: Use "num-lanes" DT property if present
Posted by Jim Quinlan 6 months, 2 weeks ago
On Sat, May 31, 2025 at 2:34 AM Manivannan Sadhasivam
<manivannan.sadhasivam@linaro.org> wrote:
>
> On Fri, May 30, 2025 at 06:40:33PM -0400, Jim Quinlan wrote:
> > By default, we use automatic HW negotiation to ascertain the number of
> > lanes of the PCIe connection.  If the "num-lanes" DT property is present,
> > assume that the chip's built-in capability information is incorrect or
> > undesired, and use the specified value instead.
> >
> > Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>
> > ---
> >  drivers/pci/controller/pcie-brcmstb.c | 26 +++++++++++++++++++++++++-
> >  1 file changed, 25 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
> > index e19628e13898..79fc6d00b7bc 100644
> > --- a/drivers/pci/controller/pcie-brcmstb.c
> > +++ b/drivers/pci/controller/pcie-brcmstb.c
> > @@ -46,6 +46,7 @@
> >  #define  PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK   0xffffff
> >
> >  #define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY                    0x04dc
> > +#define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK       0x1f0
> >  #define  PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00
> >
> >  #define PCIE_RC_CFG_PRIV1_ROOT_CAP                   0x4f8
> > @@ -55,6 +56,9 @@
> >  #define PCIE_RC_DL_MDIO_WR_DATA                              0x1104
> >  #define PCIE_RC_DL_MDIO_RD_DATA                              0x1108
> >
> > +#define PCIE_RC_PL_REG_PHY_CTL_1                     0x1804
> > +#define  PCIE_RC_PL_REG_PHY_CTL_1_REG_P2_POWERDOWN_ENA_NOSYNC_MASK   0x8
> > +
> >  #define PCIE_RC_PL_PHY_CTL_15                                0x184c
> >  #define  PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK               0x400000
> >  #define  PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK    0xff
> > @@ -1072,7 +1076,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
> >       void __iomem *base = pcie->base;
> >       struct pci_host_bridge *bridge;
> >       struct resource_entry *entry;
> > -     u32 tmp, burst, aspm_support;
> > +     u32 tmp, burst, aspm_support, num_lanes, num_lanes_cap;
> >       u8 num_out_wins = 0;
> >       int num_inbound_wins = 0;
> >       int memc, ret;
> > @@ -1180,6 +1184,26 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
> >               PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK);
> >       writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
> >
> > +     /* 'tmp' still holds the contents of PRIV1_LINK_CAPABILITY */
> > +     num_lanes_cap = u32_get_bits(tmp, PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_MAX_LINK_WIDTH_MASK);
> > +     num_lanes = 0;
> > +     /*
> > +      * Use automatic num-lanes HW negotiation by default.  If the
>
> "Use hardware negotiated Max Link Width value by default."
>
> > +      * "num-lanes" DT property is present, assume that the chip's
> > +      * built-in link width capability information is
> > +      * incorrect/undesired and use the specified value instead.
> > +      */
> > +     if (!of_property_read_u32(pcie->np, "num-lanes", &num_lanes) &&
> > +         num_lanes && num_lanes <= 4 && num_lanes_cap != num_lanes) {
>
> I think you should drop the 'num_lanes && num_lanes <= 4' check since the DT
> binding should take care of that. Otherwise, once link width gets increased, you
> need to update both binding and the driver, which is redundant.
Not all Linux release configuration systems run a comprehensive DT
validator  before execution.  Our bootloader modifies the DT blob on
the fly and also permits -- with restrictions -- customers to modify
the DT at the bootloader command line.  Yes, we can do partial a
priori DT validation, but there is still value to checking the params
in the driver code, at least for us.

>
> - Mani
>
> --
> மணிவண்ணன் சதாசிவம்
Re: [PATCH 2/2] PCI: brcmstb: Use "num-lanes" DT property if present
Posted by Florian Fainelli 6 months, 2 weeks ago
On 5/30/25 15:40, Jim Quinlan wrote:
> By default, we use automatic HW negotiation to ascertain the number of
> lanes of the PCIe connection.  If the "num-lanes" DT property is present,
> assume that the chip's built-in capability information is incorrect or
> undesired, and use the specified value instead.
> 
> Signed-off-by: Jim Quinlan <james.quinlan@broadcom.com>

Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
-- 
Florian