[PATCH] PCI: cadence: LTSSM Detect Quiet state minimum delay setting.

2021-04-08 Thread Nadeem Athani
Adding a quirk flag "quirk_detect_quiet_flag" to program the minimum time
that LTSSM waits on entering Detect.Quiet state.
Setting this to 2ms for TI j721e SOC as a workaround to resolve a bug in
IP.
In future revisions this setting will not be required.

As per PCIe specification, all Receivers must meet the Z-RX-DC
specification for 2.5 GT/s within 1ms of entering Detect.Quiet LTSSM
substate. The LTSSM must stay in this substate until the ZRXDC
specification for 2.5 GT/s is met.

00 : 0us minimum wait time in Detect.Quiet state.
01 : 100us minimum wait time in Detect.Quiet state.
10 : 1ms minimum wait time in Detect.Quiet state.
11 : 2ms minimum wait time in Detect.Quiet state.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pci-j721e.c |  6 ++
 drivers/pci/controller/cadence/pcie-cadence-ep.c   | 21 +
 drivers/pci/controller/cadence/pcie-cadence-host.c | 21 +
 drivers/pci/controller/cadence/pcie-cadence.h  | 12 
 4 files changed, 60 insertions(+)

diff --git a/drivers/pci/controller/cadence/pci-j721e.c 
b/drivers/pci/controller/cadence/pci-j721e.c
index 35e61048e133..40ebe698e179 100644
--- a/drivers/pci/controller/cadence/pci-j721e.c
+++ b/drivers/pci/controller/cadence/pci-j721e.c
@@ -67,6 +67,7 @@ enum j721e_pcie_mode {
 struct j721e_pcie_data {
enum j721e_pcie_modemode;
bool quirk_retrain_flag;
+   bool quirk_detect_quiet_flag;
 };
 
 static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
@@ -284,10 +285,12 @@ static struct pci_ops cdns_ti_pcie_host_ops = {
 static const struct j721e_pcie_data j721e_pcie_rc_data = {
.mode = PCI_MODE_RC,
.quirk_retrain_flag = true,
+   .quirk_detect_quiet_flag = true,
 };
 
 static const struct j721e_pcie_data j721e_pcie_ep_data = {
.mode = PCI_MODE_EP,
+   .quirk_detect_quiet_flag = true,
 };
 
 static const struct of_device_id of_j721e_pcie_match[] = {
@@ -394,6 +397,7 @@ static int j721e_pcie_probe(struct platform_device *pdev)
bridge->ops = &cdns_ti_pcie_host_ops;
rc = pci_host_bridge_priv(bridge);
rc->quirk_retrain_flag = data->quirk_retrain_flag;
+   rc->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
 
cdns_pcie = &rc->pcie;
cdns_pcie->dev = dev;
@@ -460,6 +464,8 @@ static int j721e_pcie_probe(struct platform_device *pdev)
goto err_get_sync;
}
 
+   ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
+
cdns_pcie = &ep->pcie;
cdns_pcie->dev = dev;
cdns_pcie->ops = &j721e_pcie_ops;
diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c 
b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 897cdde02bd8..245771f03c21 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -552,6 +552,23 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = {
.get_features   = cdns_pcie_ep_get_features,
 };
 
+static void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie_ep *ep)
+{
+   struct cdns_pcie *pcie = &ep->pcie;
+   u32 delay = 0x3;
+   u32 ltssm_control_cap;
+
+   /*
+* Set the LTSSM Detect Quiet state min. delay to 2ms.
+*/
+
+   ltssm_control_cap = cdns_pcie_readl(pcie, CDNS_PCIE_LTSSM_CONTROL_CAP);
+   ltssm_control_cap = ((ltssm_control_cap &
+   ~CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK) |
+   CDNS_PCIE_DETECT_QUIET_MIN_DELAY(delay));
+
+   cdns_pcie_writel(pcie, CDNS_PCIE_LTSSM_CONTROL_CAP, ltssm_control_cap);
+}
 
 int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
 {
@@ -623,6 +640,10 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
/* Reserve region 0 for IRQs */
set_bit(0, &ep->ob_region_map);
+
+   if (ep->quirk_detect_quiet_flag)
+   cdns_pcie_detect_quiet_min_delay_set(ep);
+
spin_lock_init(&ep->lock);
 
return 0;
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 73dcf8cf98fb..0ed2bfac4855 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -461,6 +461,24 @@ static int cdns_pcie_host_init(struct device *dev,
return cdns_pcie_host_init_address_translation(rc);
 }
 
+static void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie_rc *rc)
+{
+   struct cdns_pcie *pcie = &rc->pcie;
+   u32 delay = 0x3;
+   u32 ltssm_control_cap;
+
+   /*
+* Set the LTSSM Detect Quiet state min. delay to 2ms.
+*/
+
+   ltssm_control_cap =

[PATCH 1/2] dt-bindings:pci: Set LTSSM Detect.Quiet state delay.

2021-03-08 Thread Nadeem Athani
The parameter detect-quiet-min-delay can be used to program the minimum
time that LTSSM waits on entering Detect.Quiet state.
00 : 0us minimum wait time in Detect.Quiet state.
01 : 100us minimum wait time in Detect.Quiet state.
10 : 1000us minimum wait time in Detect.Quiet state.
11 : 2000us minimum wait time in Detect.Quiet state.

Signed-off-by: Nadeem Athani 
---
 .../devicetree/bindings/pci/cdns,cdns-pcie-host.yaml| 13 +
 1 file changed, 13 insertions(+)

diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml 
b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
index 293b8ec318bc..a1d56e0be419 100644
--- a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
+++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
@@ -27,6 +27,18 @@ properties:
 
   msi-parent: true
 
+  detect-quiet-min-delay:
+description:
+  LTSSM Detect.Quiet state minimum delay.
+  00 : 0us minimum wait time
+  01 : 100us minimum wait time
+  10 : 1000us minimum wait time
+  11 : 2000us minimum wait time
+$ref: /schemas/types.yaml#/definitions/uint32
+minimum: 0
+maximum: 3
+default: 0
+
 required:
   - reg
   - reg-names
@@ -48,6 +60,7 @@ examples:
 linux,pci-domain = <0>;
 vendor-id = <0x17cd>;
 device-id = <0x0200>;
+detect-quiet-min-delay = <0>;
 
 reg = <0x0 0xfb00  0x0 0x0100>,
   <0x0 0x4100  0x0 0x1000>;
-- 
2.15.0



[PATCH 2/2] PCI: cadence: Set LTSSM Detect.Quiet state delay.

2021-03-08 Thread Nadeem Athani
The parameter detect_quiet_min_delay can be used to program the minimum
time that LTSSM waits on entering Detect.Quiet state.
00 : 0us minimum wait time in Detect.Quiet state.
01 : 100us minimum wait time in Detect.Quiet state.
10 : 1000us minimum wait time in Detect.Quiet state.
11 : 2000us minimum wait time in Detect.Quiet state.

As per PCIe specification, all Receivers must meet the Z-RX-DC
specification for 2.5 GT/s within 1000us of entering Detect.Quiet LTSSM
substate. The LTSSM must stay in this substate until the ZRXDC
specification for 2.5 GT/s is met.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 22 ++
 drivers/pci/controller/cadence/pcie-cadence.h  | 10 ++
 2 files changed, 32 insertions(+)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 73dcf8cf98fb..056161b3fe65 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -461,6 +461,20 @@ static int cdns_pcie_host_init(struct device *dev,
return cdns_pcie_host_init_address_translation(rc);
 }
 
+static void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie_rc *rc)
+{
+   struct cdns_pcie *pcie = &rc->pcie;
+   u32 delay = rc->detect_quiet_min_delay;
+   u32 ltssm_control_cap;
+
+   ltssm_control_cap = cdns_pcie_readl(pcie, CDNS_PCIE_LTSSM_CONTROL_CAP);
+   ltssm_control_cap = ((ltssm_control_cap &
+~CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK) |
+   CDNS_PCIE_DETECT_QUIET_MIN_DELAY(delay));
+
+   cdns_pcie_writel(pcie, CDNS_PCIE_LTSSM_CONTROL_CAP, ltssm_control_cap);
+}
+
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
struct device *dev = rc->pcie.dev;
@@ -485,6 +499,10 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
rc->device_id = 0x;
of_property_read_u32(np, "device-id", &rc->device_id);
 
+   rc->detect_quiet_min_delay = 0;
+   of_property_read_u32(np, "detect-quiet-min-delay",
+&rc->detect_quiet_min_delay);
+
pcie->reg_base = devm_platform_ioremap_resource_byname(pdev, "reg");
if (IS_ERR(pcie->reg_base)) {
dev_err(dev, "missing \"reg\"\n");
@@ -497,6 +515,10 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
return PTR_ERR(rc->cfg_base);
rc->cfg_res = res;
 
+   /* Default Detect.Quiet state delay is 0 */
+   if (rc->detect_quiet_min_delay)
+   cdns_pcie_detect_quiet_min_delay_set(rc);
+
ret = cdns_pcie_start_link(pcie);
if (ret) {
dev_err(dev, "Failed to start link\n");
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h 
b/drivers/pci/controller/cadence/pcie-cadence.h
index 254d2570f8c9..f2d3cca2c707 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -189,6 +189,14 @@
 /* AXI link down register */
 #define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824)
 
+/* LTSSM Capabilities register */
+#define CDNS_PCIE_LTSSM_CONTROL_CAP (CDNS_PCIE_LM_BASE + 0x0054)
+#define  CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK  GENMASK(2, 1)
+#define  CDNS_PCIE_DETECT_QUIET_MIN_DELAY_SHIFT 1
+#define  CDNS_PCIE_DETECT_QUIET_MIN_DELAY(delay) \
+ (((delay) << CDNS_PCIE_DETECT_QUIET_MIN_DELAY_SHIFT) & \
+ CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK)
+
 enum cdns_pcie_rp_bar {
RP_BAR_UNDEFINED = -1,
RP_BAR0,
@@ -289,6 +297,7 @@ struct cdns_pcie {
  *single function at a time
  * @vendor_id: PCI vendor ID
  * @device_id: PCI device ID
+ * @detect_quiet_min_delay: LTSSM Detect Quite state min. delay
  * @avail_ib_bar: Satus of RP_BAR0, RP_BAR1 andRP_NO_BAR if it's free 
or
  *available
  * @quirk_retrain_flag: Retrain link as quirk for PCIe Gen2
@@ -299,6 +308,7 @@ struct cdns_pcie_rc {
void __iomem*cfg_base;
u32 vendor_id;
u32 device_id;
+   u32 detect_quiet_min_delay;
boolavail_ib_bar[CDNS_PCIE_RP_MAX_IB];
boolquirk_retrain_flag;
 };
-- 
2.15.0



[PATCH 0/2] PCI: cadence: Set LTSSM Detect.Quiet state delay.

2021-03-08 Thread Nadeem Athani
This patch includes a set of two patches.
First patch for adding a new property detect-quiet-min-delay in yaml file.
Second patch programs the delay value in host pcie driver.

The parameter detect-quiet-min-delay can be used to program the minimum
time that LTSSM waits on entering Detect.Quiet state.
00 : 0us minimum wait time in Detect.Quiet state.
01 : 100us minimum wait time in Detect.Quiet state.
10 : 1000us minimum wait time in Detect.Quiet state.
11 : 2000us minimum wait time in Detect.Quiet state.

Nadeem Athani (2):
  dt-bindings:pci: Set LTSSM Detect.Quiet state delay.
  PCI: cadence: Set LTSSM Detect.Quiet state delay.

 .../bindings/pci/cdns,cdns-pcie-host.yaml  | 13 +
 drivers/pci/controller/cadence/pcie-cadence-host.c | 22 ++
 drivers/pci/controller/cadence/pcie-cadence.h  | 10 ++
 3 files changed, 45 insertions(+)

-- 
2.15.0



[PATCH v8 2/2] PCI: cadence: Retrain Link to work around Gen2 training defect.

2021-02-09 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped
as Gen2. The Retrain Link bit is set as quirk to enable this speed change.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pci-j721e.c |  3 ++
 drivers/pci/controller/cadence/pcie-cadence-host.c | 48 +-
 drivers/pci/controller/cadence/pcie-cadence.h  | 11 -
 3 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/cadence/pci-j721e.c 
b/drivers/pci/controller/cadence/pci-j721e.c
index dac1ac8a7615..849f1e416ea5 100644
--- a/drivers/pci/controller/cadence/pci-j721e.c
+++ b/drivers/pci/controller/cadence/pci-j721e.c
@@ -64,6 +64,7 @@ enum j721e_pcie_mode {
 
 struct j721e_pcie_data {
enum j721e_pcie_modemode;
+   bool quirk_retrain_flag;
 };
 
 static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
@@ -280,6 +281,7 @@ static struct pci_ops cdns_ti_pcie_host_ops = {
 
 static const struct j721e_pcie_data j721e_pcie_rc_data = {
.mode = PCI_MODE_RC,
+   .quirk_retrain_flag = true,
 };
 
 static const struct j721e_pcie_data j721e_pcie_ep_data = {
@@ -388,6 +390,7 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
bridge->ops = &cdns_ti_pcie_host_ops;
rc = pci_host_bridge_priv(bridge);
+   rc->quirk_retrain_flag = data->quirk_retrain_flag;
 
cdns_pcie = &rc->pcie;
cdns_pcie->dev = dev;
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 9f7aa718c8d4..6f591d382578 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -94,6 +94,52 @@ static int cdns_pcie_host_wait_for_link(struct cdns_pcie 
*pcie)
return -ETIMEDOUT;
 }
 
+static int cdns_pcie_retrain(struct cdns_pcie *pcie)
+{
+   u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
+   u16 lnk_stat, lnk_ctl;
+   int ret = 0;
+
+   /*
+* Set retrain bit if current speed is 2.5 GB/s,
+* but the PCIe root port support is > 2.5 GB/s.
+*/
+
+   lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
+PCI_EXP_LNKCAP));
+   if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+   return ret;
+
+   lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
+   if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+   lnk_ctl = cdns_pcie_rp_readw(pcie,
+pcie_cap_off + PCI_EXP_LNKCTL);
+   lnk_ctl |= PCI_EXP_LNKCTL_RL;
+   cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
+   lnk_ctl);
+
+   ret = cdns_pcie_host_wait_for_link(pcie);
+   }
+   return ret;
+}
+
+static int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc)
+{
+   struct cdns_pcie *pcie = &rc->pcie;
+   int ret;
+
+   ret = cdns_pcie_host_wait_for_link(pcie);
+
+   /*
+* Retrain link for Gen2 training defect
+* if quirk flag is set.
+*/
+   if (!ret && rc->quirk_retrain_flag)
+   ret = cdns_pcie_retrain(pcie);
+
+   return ret;
+}
+
 static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
struct cdns_pcie *pcie = &rc->pcie;
@@ -456,7 +502,7 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
return ret;
}
 
-   ret = cdns_pcie_host_wait_for_link(pcie);
+   ret = cdns_pcie_host_start_link(rc);
if (ret)
dev_dbg(dev, "PCIe link never came up\n");
 
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h 
b/drivers/pci/controller/cadence/pcie-cadence.h
index 30eba6cafe2c..254d2570f8c9 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -119,7 +119,7 @@
  * Root Port Registers (PCI configuration space for the root port function)
  */
 #define CDNS_PCIE_RP_BASE  0x0020
-
+#define CDNS_PCIE_RP_CAP_OFFSET 0xc0
 
 /*
  * Address Translation Registers
@@ -291,6 +291,7 @@ struct cdns_pcie {
  * @device_id: PCI device ID
  * @avail_ib_bar: Satus of RP_BAR0, RP_BAR1 andRP_NO_BAR if it's free 
or
  *available
+ * @quirk_retrain_flag: Retrain link as quirk for PCIe Gen2
  */
 struct cdns_pcie_rc {
struct cdns_pciepcie;
@@ -299,6 +300,7 @@ struct cdns_pcie_rc {
u32 vendor_id;
u32 device_id;
boolavail_ib_bar[CDNS_PCIE_RP_MAX_IB];
+   boolquirk_retrain_flag;
 };
 
 /**
@@ -414,6 +416,13 @@ static inline void cdns_pcie_rp_writew(struct cdns_pcie 

[PATCH v8 1/2] PCI: cadence: Shifting of a function to support new code.

2021-02-09 Thread Nadeem Athani
Moving the function cdns_pcie_host_wait_for_link() further up in the file,
as it's going to be used by upcoming additional code in the driver.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 33 +++---
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 811c1cb2e8de..9f7aa718c8d4 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -77,6 +77,22 @@ static struct pci_ops cdns_pcie_host_ops = {
.write  = pci_generic_config_write,
 };
 
+static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
+{
+   struct device *dev = pcie->dev;
+   int retries;
+
+   /* Check if the link is up or not */
+   for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+   if (cdns_pcie_link_up(pcie)) {
+   dev_info(dev, "Link up\n");
+   return 0;
+   }
+   usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+   }
+
+   return -ETIMEDOUT;
+}
 
 static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
@@ -398,23 +414,6 @@ static int cdns_pcie_host_init(struct device *dev,
return cdns_pcie_host_init_address_translation(rc);
 }
 
-static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
-{
-   struct device *dev = pcie->dev;
-   int retries;
-
-   /* Check if the link is up or not */
-   for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-   if (cdns_pcie_link_up(pcie)) {
-   dev_info(dev, "Link up\n");
-   return 0;
-   }
-   usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
-   }
-
-   return -ETIMEDOUT;
-}
-
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
struct device *dev = rc->pcie.dev;
-- 
2.15.0



[PATCH v8 0/2] PCI: cadence: Retrain Link to work around Gen2

2021-02-09 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped
as Gen2. The Retrain Link bit is set as quirk to enable this speed change.
Adding a quirk flag for defective IP. In future IP revisions this will not
be applicable.

Version history:
Changes in v8:
- Adding a new function cdns_pcie_host_start_link().
Changes in v7:
- Changing the commit title of patch 1 in this series.
- Added a return value for function cdns_pcie_retrain().
Changes in v6:
- Move the position of function cdns_pcie_host_wait_for_link to remove
  compilation error. No changes in code. Separate patch for this.
Changes in v5:
- Remove the compatible string based setting of quirk flag.
- Removed additional Link Up Check
- Removed quirk from pcie-cadence-plat.c and added in pci-j721e.c
Changes in v4:
- Added a quirk flag based on a new compatible string.
- Change of api for link up: cdns_pcie_host_wait_for_link().
Changes in v3:
- To set retrain link bit,checking device capability & link status.
- 32bit read in place of 8bit.
- Minor correction in patch comment.
- Change in variable & macro name.
Changes in v2:
- 16bit read in place of 8bit.

Nadeem Athani (2):
  PCI: cadence: Shifting of a function to support new code.
  PCI: cadence: Retrain Link to work around Gen2 training defect.

 drivers/pci/controller/cadence/pci-j721e.c |  3 +
 drivers/pci/controller/cadence/pcie-cadence-host.c | 81 +-
 drivers/pci/controller/cadence/pcie-cadence.h  | 11 ++-
 3 files changed, 76 insertions(+), 19 deletions(-)

-- 
2.15.0



[PATCH v7 0/2] PCI: cadence: Retrain Link to work around Gen2

2020-12-30 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped
as Gen2. The Retrain Link bit is set as quirk to enable this speed change.
Adding a quirk flag for defective IP. In future IP revisions this will not
be applicable.

Version history:
Changes in v7:
- Changing the commit title of patch 1 in this series.
- Added a return value for function cdns_pcie_retrain().
Changes in v6:
- Move the position of function cdns_pcie_host_wait_for_link to remove
  compilation error. No changes in code. Separate patch for this.
Changes in v5:
- Remove the compatible string based setting of quirk flag.
- Removed additional Link Up Check
- Removed quirk from pcie-cadence-plat.c and added in pci-j721e.c
Changes in v4:
- Added a quirk flag based on a new compatible string.
- Change of api for link up: cdns_pcie_host_wait_for_link().
Changes in v3:
- To set retrain link bit,checking device capability & link status.
- 32bit read in place of 8bit.
- Minor correction in patch comment.
- Change in variable & macro name.
Changes in v2:
- 16bit read in place of 8bit.

Nadeem Athani (2):
  PCI: cadence: Shifting of a function to support new code.
  PCI: cadence: Retrain Link to work around Gen2 training defect.

 drivers/pci/controller/cadence/pci-j721e.c |  3 +
 drivers/pci/controller/cadence/pcie-cadence-host.c | 70 --
 drivers/pci/controller/cadence/pcie-cadence.h  | 11 +++-
 3 files changed, 65 insertions(+), 19 deletions(-)

-- 
2.15.0



[PATCH v7 2/2] PCI: cadence: Retrain Link to work around Gen2 training defect.

2020-12-30 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped
as Gen2. The Retrain Link bit is set as quirk to enable this speed change.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pci-j721e.c |  3 ++
 drivers/pci/controller/cadence/pcie-cadence-host.c | 37 +-
 drivers/pci/controller/cadence/pcie-cadence.h  | 11 ++-
 3 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/cadence/pci-j721e.c 
b/drivers/pci/controller/cadence/pci-j721e.c
index dac1ac8a7615..849f1e416ea5 100644
--- a/drivers/pci/controller/cadence/pci-j721e.c
+++ b/drivers/pci/controller/cadence/pci-j721e.c
@@ -64,6 +64,7 @@ enum j721e_pcie_mode {
 
 struct j721e_pcie_data {
enum j721e_pcie_modemode;
+   bool quirk_retrain_flag;
 };
 
 static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
@@ -280,6 +281,7 @@ static struct pci_ops cdns_ti_pcie_host_ops = {
 
 static const struct j721e_pcie_data j721e_pcie_rc_data = {
.mode = PCI_MODE_RC,
+   .quirk_retrain_flag = true,
 };
 
 static const struct j721e_pcie_data j721e_pcie_ep_data = {
@@ -388,6 +390,7 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
bridge->ops = &cdns_ti_pcie_host_ops;
rc = pci_host_bridge_priv(bridge);
+   rc->quirk_retrain_flag = data->quirk_retrain_flag;
 
cdns_pcie = &rc->pcie;
cdns_pcie->dev = dev;
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 9f7aa718c8d4..f3496588862d 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -94,6 +94,35 @@ static int cdns_pcie_host_wait_for_link(struct cdns_pcie 
*pcie)
return -ETIMEDOUT;
 }
 
+static int cdns_pcie_retrain(struct cdns_pcie *pcie)
+{
+   u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
+   u16 lnk_stat, lnk_ctl;
+   int ret = 0;
+
+   /*
+* Set retrain bit if current speed is 2.5 GB/s,
+* but the PCIe root port support is > 2.5 GB/s.
+*/
+
+   lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
+PCI_EXP_LNKCAP));
+   if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+   return ret;
+
+   lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
+   if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+   lnk_ctl = cdns_pcie_rp_readw(pcie,
+pcie_cap_off + PCI_EXP_LNKCTL);
+   lnk_ctl |= PCI_EXP_LNKCTL_RL;
+   cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
+   lnk_ctl);
+
+   ret = cdns_pcie_host_wait_for_link(pcie);
+   }
+   return ret;
+}
+
 static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
struct cdns_pcie *pcie = &rc->pcie;
@@ -457,8 +486,14 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
}
 
ret = cdns_pcie_host_wait_for_link(pcie);
-   if (ret)
+   if (ret) {
dev_dbg(dev, "PCIe link never came up\n");
+   } else {
+   if (rc->quirk_retrain_flag) {
+   if (cdns_pcie_retrain(pcie))
+   dev_dbg(dev, "PCIe link never came up\n");
+   }
+   }
 
for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
rc->avail_ib_bar[bar] = true;
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h 
b/drivers/pci/controller/cadence/pcie-cadence.h
index 30eba6cafe2c..0f29128a5d0a 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -119,7 +119,7 @@
  * Root Port Registers (PCI configuration space for the root port function)
  */
 #define CDNS_PCIE_RP_BASE  0x0020
-
+#define CDNS_PCIE_RP_CAP_OFFSET 0xc0
 
 /*
  * Address Translation Registers
@@ -291,6 +291,7 @@ struct cdns_pcie {
  * @device_id: PCI device ID
  * @avail_ib_bar: Satus of RP_BAR0, RP_BAR1 andRP_NO_BAR if it's free 
or
  *available
+ * @quirk_retrain_flag: Retrain link as quirk for PCIe Gen2
  */
 struct cdns_pcie_rc {
struct cdns_pciepcie;
@@ -299,6 +300,7 @@ struct cdns_pcie_rc {
u32 vendor_id;
u32 device_id;
boolavail_ib_bar[CDNS_PCIE_RP_MAX_IB];
+   boolquirk_retrain_flag;
 };
 
 /**
@@ -414,6 +416,13 @@ static inline void cdns_pcie_rp_writew(struct cdns_pcie 
*pcie,
cdns_pcie_write_sz(addr, 0x2, value);
 }
 
+static inline u16 cdns_pcie_rp_readw(struct cdns_pcie *pcie, u32 reg)
+{
+   v

[PATCH v7 1/2] PCI: cadence: Shifting of a function to support new code.

2020-12-30 Thread Nadeem Athani
Move the function cdns_pcie_host_wait_for_link() further up in the file,
as it's going to be used by upcoming additional code in the driver.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 33 +++---
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 811c1cb2e8de..9f7aa718c8d4 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -77,6 +77,22 @@ static struct pci_ops cdns_pcie_host_ops = {
.write  = pci_generic_config_write,
 };
 
+static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
+{
+   struct device *dev = pcie->dev;
+   int retries;
+
+   /* Check if the link is up or not */
+   for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+   if (cdns_pcie_link_up(pcie)) {
+   dev_info(dev, "Link up\n");
+   return 0;
+   }
+   usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+   }
+
+   return -ETIMEDOUT;
+}
 
 static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
@@ -398,23 +414,6 @@ static int cdns_pcie_host_init(struct device *dev,
return cdns_pcie_host_init_address_translation(rc);
 }
 
-static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
-{
-   struct device *dev = pcie->dev;
-   int retries;
-
-   /* Check if the link is up or not */
-   for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-   if (cdns_pcie_link_up(pcie)) {
-   dev_info(dev, "Link up\n");
-   return 0;
-   }
-   usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
-   }
-
-   return -ETIMEDOUT;
-}
-
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
struct device *dev = rc->pcie.dev;
-- 
2.15.0



[PATCH v6 1/2] PCI: cadence: Retrain Link to work around Gen2 training defect.

2020-12-28 Thread Nadeem Athani
Moving the function above to remove compilation error.
No changes in function.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 33 +++---
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 811c1cb2e8de..9f7aa718c8d4 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -77,6 +77,22 @@ static struct pci_ops cdns_pcie_host_ops = {
.write  = pci_generic_config_write,
 };
 
+static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
+{
+   struct device *dev = pcie->dev;
+   int retries;
+
+   /* Check if the link is up or not */
+   for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+   if (cdns_pcie_link_up(pcie)) {
+   dev_info(dev, "Link up\n");
+   return 0;
+   }
+   usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+   }
+
+   return -ETIMEDOUT;
+}
 
 static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
@@ -398,23 +414,6 @@ static int cdns_pcie_host_init(struct device *dev,
return cdns_pcie_host_init_address_translation(rc);
 }
 
-static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
-{
-   struct device *dev = pcie->dev;
-   int retries;
-
-   /* Check if the link is up or not */
-   for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-   if (cdns_pcie_link_up(pcie)) {
-   dev_info(dev, "Link up\n");
-   return 0;
-   }
-   usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
-   }
-
-   return -ETIMEDOUT;
-}
-
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
struct device *dev = rc->pcie.dev;
-- 
2.15.0



[PATCH v6 2/2] PCI: cadence: Retrain Link to work around Gen2 training defect.

2020-12-28 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped
as Gen2. The Retrain Link bit is set as quirk to enable this speed change.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pci-j721e.c |  3 ++
 drivers/pci/controller/cadence/pcie-cadence-host.c | 32 ++
 drivers/pci/controller/cadence/pcie-cadence.h  | 11 +++-
 3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/cadence/pci-j721e.c 
b/drivers/pci/controller/cadence/pci-j721e.c
index dac1ac8a7615..23a30be207a5 100644
--- a/drivers/pci/controller/cadence/pci-j721e.c
+++ b/drivers/pci/controller/cadence/pci-j721e.c
@@ -64,6 +64,7 @@ enum j721e_pcie_mode {
 
 struct j721e_pcie_data {
enum j721e_pcie_modemode;
+   boolquirk_retrain_flag;
 };
 
 static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
@@ -280,6 +281,7 @@ static struct pci_ops cdns_ti_pcie_host_ops = {
 
 static const struct j721e_pcie_data j721e_pcie_rc_data = {
.mode = PCI_MODE_RC,
+   .quirk_retrain_flag = true,
 };
 
 static const struct j721e_pcie_data j721e_pcie_ep_data = {
@@ -388,6 +390,7 @@ static int j721e_pcie_probe(struct platform_device *pdev)
 
bridge->ops = &cdns_ti_pcie_host_ops;
rc = pci_host_bridge_priv(bridge);
+   rc->quirk_retrain_flag = data->quirk_retrain_flag;
 
cdns_pcie = &rc->pcie;
cdns_pcie->dev = dev;
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 9f7aa718c8d4..9d730c10083b 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -94,6 +94,34 @@ static int cdns_pcie_host_wait_for_link(struct cdns_pcie 
*pcie)
return -ETIMEDOUT;
 }
 
+static void cdns_pcie_retrain(struct cdns_pcie *pcie)
+{
+   u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
+   u16 lnk_stat, lnk_ctl;
+
+   /*
+* Set retrain bit if current speed is 2.5 GB/s,
+* but the PCIe root port support is > 2.5 GB/s.
+*/
+
+   lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
+PCI_EXP_LNKCAP));
+   if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+   return;
+
+   lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
+   if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+   lnk_ctl = cdns_pcie_rp_readw(pcie,
+pcie_cap_off + PCI_EXP_LNKCTL);
+   lnk_ctl |= PCI_EXP_LNKCTL_RL;
+   cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
+   lnk_ctl);
+
+   if (cdns_pcie_host_wait_for_link(pcie))
+   return;
+   }
+}
+
 static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
struct cdns_pcie *pcie = &rc->pcie;
@@ -459,6 +487,10 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
ret = cdns_pcie_host_wait_for_link(pcie);
if (ret)
dev_dbg(dev, "PCIe link never came up\n");
+   else {
+   if (rc->quirk_retrain_flag)
+   cdns_pcie_retrain(pcie);
+   }
 
for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++)
rc->avail_ib_bar[bar] = true;
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h 
b/drivers/pci/controller/cadence/pcie-cadence.h
index 30eba6cafe2c..0f29128a5d0a 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -119,7 +119,7 @@
  * Root Port Registers (PCI configuration space for the root port function)
  */
 #define CDNS_PCIE_RP_BASE  0x0020
-
+#define CDNS_PCIE_RP_CAP_OFFSET 0xc0
 
 /*
  * Address Translation Registers
@@ -291,6 +291,7 @@ struct cdns_pcie {
  * @device_id: PCI device ID
  * @avail_ib_bar: Satus of RP_BAR0, RP_BAR1 andRP_NO_BAR if it's free 
or
  *available
+ * @quirk_retrain_flag: Retrain link as quirk for PCIe Gen2
  */
 struct cdns_pcie_rc {
struct cdns_pciepcie;
@@ -299,6 +300,7 @@ struct cdns_pcie_rc {
u32 vendor_id;
u32 device_id;
boolavail_ib_bar[CDNS_PCIE_RP_MAX_IB];
+   boolquirk_retrain_flag;
 };
 
 /**
@@ -414,6 +416,13 @@ static inline void cdns_pcie_rp_writew(struct cdns_pcie 
*pcie,
cdns_pcie_write_sz(addr, 0x2, value);
 }
 
+static inline u16 cdns_pcie_rp_readw(struct cdns_pcie *pcie, u32 reg)
+{
+   void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+   return cdns_pcie_read_sz(addr, 0x2);
+}
+
 /* Endpoint Function register access */
 

[PATCH v6 0/2] PCI: cadence: Retrain Link to work around Gen2

2020-12-28 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped 
as Gen2. The Retrain Link bit is set as quirk to enable this speed change.
Adding a quirk flag for defective IP. In future IP revisions this will not
be applicable.

Version history:
Changes in v6:
- Move the position of function cdns_pcie_host_wait_for_link to remove
  compilation error. No changes in code. Separate patch for this.
Changes in v5:
- Remove the compatible string based setting of quirk flag.
- Removed additional Link Up Check
- Removed quirk from pcie-cadence-plat.c and added in pci-j721e.c
Changes in v4:
- Added a quirk flag based on a new compatible string.
- Change of api for link up: cdns_pcie_host_wait_for_link().
Changes in v3:
- To set retrain link bit,checking device capability & link status.
- 32bit read in place of 8bit.
- Minor correction in patch comment.
- Change in variable & macro name.
Changes in v2:
- 16bit read in place of 8bit.

Nadeem Athani (2):
  PCI: cadence: Retrain Link to work around Gen2 training defect.
  PCI: cadence: Retrain Link to work around Gen2 training defect.

 drivers/pci/controller/cadence/pci-j721e.c |  3 +
 drivers/pci/controller/cadence/pcie-cadence-host.c | 65 --
 drivers/pci/controller/cadence/pcie-cadence.h  | 11 +++-
 3 files changed, 61 insertions(+), 18 deletions(-)

-- 
2.15.0



[PATCH v4 0/2] PCI: cadence: Retrain Link to work around Gen2

2020-12-11 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped as
Gen2. The Retrain Link bit is set as quirk to enable this speed change.
Adding a quirk flag based on a new compatible string. In future IP 
revisions this will not be applicable.

Version history:
Changes in v4:
- Added a quirk flag based on a new compatible string.
- Change of api for link up: cdns_pcie_host_wait_for_link().
Changes in v3:
- To set retrain link bit,checking device capability & link status.
- 32bit read in place of 8bit.
- Minor correction in patch comment.
- Change in variable & macro name.
Changes in v2:
- 16bit read in place of 8bit.

Nadeem Athani (2):
  dt-bindings: pci: Retrain Link to work around Gen2 training defect.
  PCI: cadence: Retrain Link to work around Gen2 training defect.

 .../bindings/pci/cdns,cdns-pcie-host.yaml  |  4 +-
 drivers/pci/controller/cadence/pcie-cadence-host.c | 67 --
 drivers/pci/controller/cadence/pcie-cadence-plat.c | 13 +
 drivers/pci/controller/cadence/pcie-cadence.h  | 11 +++-
 4 files changed, 76 insertions(+), 19 deletions(-)

-- 
2.15.0



[PATCH v4 2/2] PCI: cadence: Retrain Link to work around Gen2 training defect.

2020-12-11 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped as
Gen2. The Retrain Link bit is set as quirk to enable this speed change.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 67 --
 drivers/pci/controller/cadence/pcie-cadence-plat.c | 13 +
 drivers/pci/controller/cadence/pcie-cadence.h  | 11 +++-
 3 files changed, 73 insertions(+), 18 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 811c1cb2e8de..36dccf7241fe 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -77,6 +77,53 @@ static struct pci_ops cdns_pcie_host_ops = {
.write  = pci_generic_config_write,
 };
 
+static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
+{
+   struct device *dev = pcie->dev;
+   int retries;
+
+   /* Check if the link is up or not */
+   for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+   if (cdns_pcie_link_up(pcie)) {
+   dev_info(dev, "Link up\n");
+   return 0;
+   }
+   usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+   }
+
+   return -ETIMEDOUT;
+}
+
+static void cdns_pcie_retrain(struct cdns_pcie *pcie)
+{
+   u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
+   u16 lnk_stat, lnk_ctl;
+
+   if (cdns_pcie_host_wait_for_link(pcie))
+   return;
+
+   /*
+* Set retrain bit if current speed is 2.5 GB/s,
+* but the PCIe root port support is > 2.5 GB/s.
+*/
+
+   lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
+PCI_EXP_LNKCAP));
+   if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+   return;
+
+   lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
+   if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+   lnk_ctl = cdns_pcie_rp_readw(pcie,
+pcie_cap_off + PCI_EXP_LNKCTL);
+   lnk_ctl |= PCI_EXP_LNKCTL_RL;
+   cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
+   lnk_ctl);
+
+   if (cdns_pcie_host_wait_for_link(pcie))
+   return;
+   }
+}
 
 static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
@@ -115,6 +162,9 @@ static int cdns_pcie_host_init_root_port(struct 
cdns_pcie_rc *rc)
cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
 
+   if (rc->quirk_retrain_flag)
+   cdns_pcie_retrain(pcie);
+
return 0;
 }
 
@@ -398,23 +448,6 @@ static int cdns_pcie_host_init(struct device *dev,
return cdns_pcie_host_init_address_translation(rc);
 }
 
-static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
-{
-   struct device *dev = pcie->dev;
-   int retries;
-
-   /* Check if the link is up or not */
-   for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-   if (cdns_pcie_link_up(pcie)) {
-   dev_info(dev, "Link up\n");
-   return 0;
-   }
-   usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
-   }
-
-   return -ETIMEDOUT;
-}
-
 int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
 {
struct device *dev = rc->pcie.dev;
diff --git a/drivers/pci/controller/cadence/pcie-cadence-plat.c 
b/drivers/pci/controller/cadence/pcie-cadence-plat.c
index 5fee0f89ab59..97b4b4f98fa4 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-plat.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-plat.c
@@ -28,6 +28,7 @@ struct cdns_plat_pcie {
 
 struct cdns_plat_pcie_of_data {
bool is_rc;
+   bool quirk_retrain_flag;
 };
 
 static const struct of_device_id cdns_plat_pcie_of_match[];
@@ -78,6 +79,7 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
rc = pci_host_bridge_priv(bridge);
rc->pcie.dev = dev;
rc->pcie.ops = &cdns_plat_ops;
+   rc->quirk_retrain_flag = data->quirk_retrain_flag;
cdns_plat_pcie->pcie = &rc->pcie;
cdns_plat_pcie->is_rc = is_rc;
 
@@ -156,6 +158,13 @@ static void cdns_plat_pcie_shutdown(struct platform_device 
*pdev)
 
 static const struct cdns_plat_pcie_of_data cdns_plat_pcie_host_of_data = {
.is_rc = true,
+   .quirk_retrain_flag = false,
+};
+
+static const struct cdns_plat_pcie_of_data
+   cdns_plat_pcie_host_quirk_retrain_of_data = {
+   .is_rc = true,
+   .quirk_retrain_flag = true,
 };
 
 s

[PATCH v4 1/2] dt-bindings: pci: Retrain Link to work around Gen2 training defect.

2020-12-11 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped as
Gen2. The Retrain Link bit is set as quirk to enable this speed change.
Adding a quirk flag based on a new compatible string.

Signed-off-by: Nadeem Athani 
---
 Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml 
b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
index 293b8ec318bc..204d78f9efe3 100644
--- a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
+++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-host.yaml
@@ -15,7 +15,9 @@ allOf:
 
 properties:
   compatible:
-const: cdns,cdns-pcie-host
+enum:
+- cdns,cdns-pcie-host
+- cdns,cdns-pcie-host-quirk-retrain
 
   reg:
 maxItems: 2
-- 
2.15.0



[PATCH v3] PCI: cadence: Retrain Link to work around Gen2 training defect.

2020-09-30 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if strapped
as Gen2. The Retrain Link bit is set as quirk to enable this speed change.

Signed-off-by: Nadeem Athani 
---
Changes in v3:
- To set retrain link bit,checking device capability & link status.
- 32bit read in place of 8bit.
- Minor correction in patch comment.
- Change in variable & macro name.
Changes in v2:
- 16bit read in place of 8bit.
 drivers/pci/controller/cadence/pcie-cadence-host.c | 31 ++
 drivers/pci/controller/cadence/pcie-cadence.h  |  9 ++-
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 4550e0d469ca..2b2ae4e18032 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -77,6 +77,36 @@ static struct pci_ops cdns_pcie_host_ops = {
.write  = pci_generic_config_write,
 };
 
+static void cdns_pcie_retrain(struct cdns_pcie *pcie)
+{
+   u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
+   u16 lnk_stat, lnk_ctl;
+
+   if (!cdns_pcie_link_up(pcie))
+   return;
+
+   /*
+* Set retrain bit if current speed is 2.5 GB/s,
+* but the PCIe root port support is > 2.5 GB/s.
+*/
+
+   lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
+ PCI_EXP_LNKCAP));
+   if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+   return;
+
+   lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
+   if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+   lnk_ctl = cdns_pcie_rp_readw(pcie,
+pcie_cap_off + PCI_EXP_LNKCTL);
+   lnk_ctl |= PCI_EXP_LNKCTL_RL;
+   cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
+   lnk_ctl);
+
+   if (!cdns_pcie_link_up(pcie))
+   return;
+   }
+}
 
 static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
 {
@@ -115,6 +145,7 @@ static int cdns_pcie_host_init_root_port(struct 
cdns_pcie_rc *rc)
cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
 
+   cdns_pcie_retrain(pcie);
return 0;
 }
 
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h 
b/drivers/pci/controller/cadence/pcie-cadence.h
index feed1e3038f4..5f1cf032ae15 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -119,7 +119,7 @@
  * Root Port Registers (PCI configuration space for the root port function)
  */
 #define CDNS_PCIE_RP_BASE  0x0020
-
+#define CDNS_PCIE_RP_CAP_OFFSET 0xc0
 
 /*
  * Address Translation Registers
@@ -413,6 +413,13 @@ static inline void cdns_pcie_rp_writew(struct cdns_pcie 
*pcie,
cdns_pcie_write_sz(addr, 0x2, value);
 }
 
+static inline u16 cdns_pcie_rp_readw(struct cdns_pcie *pcie, u32 reg)
+{
+   void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+   return cdns_pcie_read_sz(addr, 0x2);
+}
+
 /* Endpoint Function register access */
 static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
  u32 reg, u8 value)
-- 
2.15.0



[PATCH v2] PCI: Cadence: Add quirk for Gen2 controller to do autonomous speed change.

2020-09-23 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if
strapped as Gen2. The Retrain bit is set as a quirk to trigger
this speed change.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pcie-cadence-host.c | 14 ++
 drivers/pci/controller/cadence/pcie-cadence.h  | 15 +++
 2 files changed, 29 insertions(+)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 4550e0d469ca..a2317614268d 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -83,6 +83,9 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc 
*rc)
struct cdns_pcie *pcie = &rc->pcie;
u32 value, ctrl;
u32 id;
+   u32 link_cap = CDNS_PCIE_LINK_CAP_OFFSET;
+   u8 sls;
+   u16 lnk_ctl;
 
/*
 * Set the root complex BAR configuration register:
@@ -111,6 +114,17 @@ static int cdns_pcie_host_init_root_port(struct 
cdns_pcie_rc *rc)
if (rc->device_id != 0x)
cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
 
+   /* Quirk to enable autonomous speed change for GEN2 controller */
+   /* Reading Supported Link Speed value */
+   sls = PCI_EXP_LNKCAP_SLS &
+   cdns_pcie_rp_readb(pcie, link_cap + PCI_EXP_LNKCAP);
+   if (sls == PCI_EXP_LNKCAP_SLS_5_0GB) {
+   /* Since this a Gen2 controller, set Retrain Link(RL) bit */
+   lnk_ctl = cdns_pcie_rp_readw(pcie, link_cap + PCI_EXP_LNKCTL);
+   lnk_ctl |= PCI_EXP_LNKCTL_RL;
+   cdns_pcie_rp_writew(pcie, link_cap + PCI_EXP_LNKCTL, lnk_ctl);
+   }
+
cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h 
b/drivers/pci/controller/cadence/pcie-cadence.h
index feed1e3038f4..fe560480c573 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -120,6 +120,7 @@
  */
 #define CDNS_PCIE_RP_BASE  0x0020
 
+#define CDNS_PCIE_LINK_CAP_OFFSET 0xC0
 
 /*
  * Address Translation Registers
@@ -413,6 +414,20 @@ static inline void cdns_pcie_rp_writew(struct cdns_pcie 
*pcie,
cdns_pcie_write_sz(addr, 0x2, value);
 }
 
+static inline u8 cdns_pcie_rp_readb(struct cdns_pcie *pcie, u32 reg)
+{
+   void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+   return cdns_pcie_read_sz(addr, 0x1);
+}
+
+static inline u16 cdns_pcie_rp_readw(struct cdns_pcie *pcie, u32 reg)
+{
+   void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg;
+
+   return cdns_pcie_read_sz(addr, 0x2);
+}
+
 /* Endpoint Function register access */
 static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
  u32 reg, u8 value)
-- 
2.15.0



[PATCH] PCI: Cadence: Add quirk for Gen2 controller to do autonomous speed change.

2020-09-18 Thread Nadeem Athani
Cadence controller will not initiate autonomous speed change if
strapped as Gen2. The Retrain bit is set as a quirk to trigger
this speed change.

Signed-off-by: Nadeem Athani 
---
 drivers/pci/controller/cadence/pcie-cadence-host.c |   13 +
 drivers/pci/controller/cadence/pcie-cadence.h  |6 ++
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c 
b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 4550e0d..4cb7f29 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -83,6 +83,8 @@ static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc 
*rc)
struct cdns_pcie *pcie = &rc->pcie;
u32 value, ctrl;
u32 id;
+   u32 link_cap = CDNS_PCIE_LINK_CAP_OFFSET;
+   u8 sls, lnk_ctl;
 
/*
 * Set the root complex BAR configuration register:
@@ -111,6 +113,17 @@ static int cdns_pcie_host_init_root_port(struct 
cdns_pcie_rc *rc)
if (rc->device_id != 0x)
cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
 
+   /* Quirk to enable autonomous speed change for GEN2 controller */
+   /* Reading Supported Link Speed value */
+   sls = PCI_EXP_LNKCAP_SLS &
+   cdns_pcie_rp_readb(pcie, link_cap + PCI_EXP_LNKCAP);
+   if (sls == PCI_EXP_LNKCAP_SLS_5_0GB) {
+   /* Since this a Gen2 controller, set Retrain Link(RL) bit */
+   lnk_ctl = cdns_pcie_rp_readb(pcie, link_cap + PCI_EXP_LNKCTL);
+   lnk_ctl |= PCI_EXP_LNKCTL_RL;
+   cdns_pcie_rp_writeb(pcie, link_cap + PCI_EXP_LNKCTL, lnk_ctl);
+   }
+
cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h 
b/drivers/pci/controller/cadence/pcie-cadence.h
index feed1e3..075c263 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -120,6 +120,7 @@
  */
 #define CDNS_PCIE_RP_BASE  0x0020
 
+#define CDNS_PCIE_LINK_CAP_OFFSET 0xC0
 
 /*
  * Address Translation Registers
@@ -413,6 +414,11 @@ static inline void cdns_pcie_rp_writew(struct cdns_pcie 
*pcie,
cdns_pcie_write_sz(addr, 0x2, value);
 }
 
+static inline u8 cdns_pcie_rp_readb(struct cdns_pcie *pcie, u32 reg)
+{
+   return readb(pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
+}
+
 /* Endpoint Function register access */
 static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
  u32 reg, u8 value)
-- 
1.7.1