From faca7230ba711f7f966cd51bf46f83c5848a8623 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 11 Jun 2020 09:57:03 +0100
Subject: [PATCH] PCI: brcmstb: Add DT property to control L1SS

The BRCM PCIe block has controls to enable control of the CLKREQ#
signal by the L1SS, and to gate the refclk with the CLKREQ# input.
These controls are mutually exclusive - the upstream code sets the
latter, but some use cases require the former.

Add a Device Tree property - brcm,enable-l1ss - to switch to the
L1SS configuration.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
 drivers/pci/controller/pcie-brcmstb.c | 30 ++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -102,8 +102,9 @@
 		PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8)
 
 #define PCIE_MISC_HARD_PCIE_HARD_DEBUG					0x4204
-#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK	0x2
-#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK		0x08000000
+#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK	BIT(1)
+#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK		BIT(21)
+#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK		BIT(27)
 
 #define PCIE_MSI_INTR2_STATUS				0x4500
 #define PCIE_MSI_INTR2_CLR				0x4508
@@ -170,6 +171,7 @@ struct brcm_pcie {
 	struct pci_bus		*root_bus;
 	struct device_node	*np;
 	bool			ssc;
+	bool			l1ss;
 	int			gen;
 	u64			msi_target_addr;
 	struct brcm_msi		*msi;
@@ -834,12 +836,25 @@ static int brcm_pcie_setup(struct brcm_p
 		PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK);
 	writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1);
 
-	/*
-	 * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
-	 * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1.
-	 */
 	tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
-	tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
+	if (pcie->l1ss) {
+		/*
+		 * Enable CLKREQ# signalling include L1 Substate control of
+		 * the CLKREQ# signal and the external reference clock buffer.
+		 * meet requirement for Endpoints that require CLKREQ#
+		 * assertion to clock active within 400ns.
+		 */
+		tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
+		tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK;
+	} else {
+		/*
+		 * Refclk from RC should be gated with CLKREQ# input when
+		 * ASPM L0s,L1 is enabled => setting the CLKREQ_DEBUG_ENABLE
+		 * field to 1.
+		 */
+		tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_L1SS_ENABLE_MASK;
+		tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
+	}
 	writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
 
 	return 0;
@@ -944,6 +959,7 @@ static int brcm_pcie_probe(struct platfo
 	pcie->gen = (ret < 0) ? 0 : ret;
 
 	pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc");
+	pcie->l1ss = of_property_read_bool(np, "brcm,enable-l1ss");
 
 	ret = pci_parse_request_of_pci_ranges(pcie->dev, &bridge->windows,
 					      &bridge->dma_ranges, NULL);
