[PATCH v4 17/17] PCI: dwc: artpec6: Add support for the ARTPEC-7 SoC
Add support for the ARTPEC-7 SoC in the artpec6 driver. The ARTPEC-6 SoC and the ARTPEC-7 SoC are very similar. Unfortunately, some fields in the PCIECFG and PCIESTAT register have changed. Signed-off-by: Niklas Cassel--- drivers/pci/dwc/pcie-artpec6.c | 162 - 1 file changed, 159 insertions(+), 3 deletions(-) diff --git a/drivers/pci/dwc/pcie-artpec6.c b/drivers/pci/dwc/pcie-artpec6.c index e5030477099c..d27f1b42cee6 100644 --- a/drivers/pci/dwc/pcie-artpec6.c +++ b/drivers/pci/dwc/pcie-artpec6.c @@ -27,14 +27,21 @@ #define to_artpec6_pcie(x) dev_get_drvdata((x)->dev) +enum artpec_pcie_variants { + ARTPEC6, + ARTPEC7, +}; + struct artpec6_pcie { struct dw_pcie *pci; struct regmap *regmap;/* DT axis,syscon-pcie */ void __iomem*phy_base; /* DT phy */ + enum artpec_pcie_variants variant; enum dw_pcie_device_mode mode; }; struct artpec_pcie_of_data { + enum artpec_pcie_variants variant; enum dw_pcie_device_mode mode; }; @@ -45,6 +52,13 @@ static const struct of_device_id artpec6_pcie_of_match[]; #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) #define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c) +#define ACK_F_ASPM_CTRL_OFF(PL_OFFSET + 0xc) +#define ACK_N_FTS_MASK GENMASK(15, 8) +#define ACK_N_FTS(x) (((x) << 8) & ACK_N_FTS_MASK) + +#define FAST_TRAINING_SEQ_MASK GENMASK(7, 0) +#define FAST_TRAINING_SEQ(x) (((x) << 0) & FAST_TRAINING_SEQ_MASK) + /* ARTPEC-6 specific registers */ #define PCIECFG0x18 #define PCIECFG_DBG_OEN BIT(24) @@ -59,6 +73,13 @@ static const struct of_device_id artpec6_pcie_of_match[]; #define PCIECFG_MODE_TX_DRV_ENBIT(3) #define PCIECFG_CISRREN BIT(2) #define PCIECFG_MACRO_ENABLE BIT(0) +/* ARTPEC-7 specific fields */ +#define PCIECFG_REFCLKSEL BIT(23) +#define PCIECFG_NOC_RESET BIT(3) + +#define PCIESTAT 0x1c +/* ARTPEC-7 specific fields */ +#define PCIESTAT_EXTREFCLKBIT(3) #define NOCCFG 0x40 #define NOCCFG_ENABLE_CLK_PCIEBIT(4) @@ -69,6 +90,12 @@ static const struct of_device_id artpec6_pcie_of_match[]; #define PHY_STATUS 0x118 #define PHY_COSPLLLOCKBIT(0) +#define PHY_TX_ASIC_OUT0x1014 +#define PHY_TX_ASIC_OUT_TX_ACKBIT(0) + +#define PHY_RX_ASIC_OUT0x101b +#define PHY_RX_ASIC_OUT_ACK BIT(0) + static u32 artpec6_pcie_readl(struct artpec6_pcie *artpec6_pcie, u32 offset) { u32 val; @@ -127,7 +154,7 @@ static const struct dw_pcie_ops dw_pcie_ops = { .stop_link = artpec6_pcie_stop_link, }; -static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie) +static void artpec6_pcie_init_phy_a6(struct artpec6_pcie *artpec6_pcie) { u32 val; unsigned int retries; @@ -173,12 +200,109 @@ static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie) } while (retries && !(val & PHY_COSPLLLOCK)); } +static void artpec6_pcie_init_phy_a7(struct artpec6_pcie *artpec6_pcie) +{ + struct dw_pcie *pci = artpec6_pcie->pci; + u32 val; + u16 phy_status_tx, phy_status_rx; + unsigned int retries; + bool extrefclk; + + /* Check if external reference clock is connected */ + val = artpec6_pcie_readl(artpec6_pcie, PCIESTAT); + extrefclk = !!(val & PCIESTAT_EXTREFCLK); + dev_dbg(pci->dev, "Using reference clock: %s\n", + extrefclk ? "external" : "internal"); + + val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); + val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ + PCIECFG_PCLK_ENABLE; + if (extrefclk) + val |= PCIECFG_REFCLKSEL; + else + val &= ~PCIECFG_REFCLKSEL; + artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); + usleep_range(10, 20); + + val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); + val |= NOCCFG_ENABLE_CLK_PCIE; + artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); + usleep_range(20, 30); + + val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); + val &= ~NOCCFG_POWER_PCIE_IDLEREQ; + artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); + + retries = 50; + do { + usleep_range(1000, 2000); + val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); + retries--; + } while (retries && + (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); + + retries = 50; + do { + usleep_range(1000, 2000); + phy_status_tx = readw(artpec6_pcie->phy_base + PHY_TX_ASIC_OUT); +
[PATCH v4 17/17] PCI: dwc: artpec6: Add support for the ARTPEC-7 SoC
Add support for the ARTPEC-7 SoC in the artpec6 driver. The ARTPEC-6 SoC and the ARTPEC-7 SoC are very similar. Unfortunately, some fields in the PCIECFG and PCIESTAT register have changed. Signed-off-by: Niklas Cassel --- drivers/pci/dwc/pcie-artpec6.c | 162 - 1 file changed, 159 insertions(+), 3 deletions(-) diff --git a/drivers/pci/dwc/pcie-artpec6.c b/drivers/pci/dwc/pcie-artpec6.c index e5030477099c..d27f1b42cee6 100644 --- a/drivers/pci/dwc/pcie-artpec6.c +++ b/drivers/pci/dwc/pcie-artpec6.c @@ -27,14 +27,21 @@ #define to_artpec6_pcie(x) dev_get_drvdata((x)->dev) +enum artpec_pcie_variants { + ARTPEC6, + ARTPEC7, +}; + struct artpec6_pcie { struct dw_pcie *pci; struct regmap *regmap;/* DT axis,syscon-pcie */ void __iomem*phy_base; /* DT phy */ + enum artpec_pcie_variants variant; enum dw_pcie_device_mode mode; }; struct artpec_pcie_of_data { + enum artpec_pcie_variants variant; enum dw_pcie_device_mode mode; }; @@ -45,6 +52,13 @@ static const struct of_device_id artpec6_pcie_of_match[]; #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) #define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c) +#define ACK_F_ASPM_CTRL_OFF(PL_OFFSET + 0xc) +#define ACK_N_FTS_MASK GENMASK(15, 8) +#define ACK_N_FTS(x) (((x) << 8) & ACK_N_FTS_MASK) + +#define FAST_TRAINING_SEQ_MASK GENMASK(7, 0) +#define FAST_TRAINING_SEQ(x) (((x) << 0) & FAST_TRAINING_SEQ_MASK) + /* ARTPEC-6 specific registers */ #define PCIECFG0x18 #define PCIECFG_DBG_OEN BIT(24) @@ -59,6 +73,13 @@ static const struct of_device_id artpec6_pcie_of_match[]; #define PCIECFG_MODE_TX_DRV_ENBIT(3) #define PCIECFG_CISRREN BIT(2) #define PCIECFG_MACRO_ENABLE BIT(0) +/* ARTPEC-7 specific fields */ +#define PCIECFG_REFCLKSEL BIT(23) +#define PCIECFG_NOC_RESET BIT(3) + +#define PCIESTAT 0x1c +/* ARTPEC-7 specific fields */ +#define PCIESTAT_EXTREFCLKBIT(3) #define NOCCFG 0x40 #define NOCCFG_ENABLE_CLK_PCIEBIT(4) @@ -69,6 +90,12 @@ static const struct of_device_id artpec6_pcie_of_match[]; #define PHY_STATUS 0x118 #define PHY_COSPLLLOCKBIT(0) +#define PHY_TX_ASIC_OUT0x1014 +#define PHY_TX_ASIC_OUT_TX_ACKBIT(0) + +#define PHY_RX_ASIC_OUT0x101b +#define PHY_RX_ASIC_OUT_ACK BIT(0) + static u32 artpec6_pcie_readl(struct artpec6_pcie *artpec6_pcie, u32 offset) { u32 val; @@ -127,7 +154,7 @@ static const struct dw_pcie_ops dw_pcie_ops = { .stop_link = artpec6_pcie_stop_link, }; -static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie) +static void artpec6_pcie_init_phy_a6(struct artpec6_pcie *artpec6_pcie) { u32 val; unsigned int retries; @@ -173,12 +200,109 @@ static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie) } while (retries && !(val & PHY_COSPLLLOCK)); } +static void artpec6_pcie_init_phy_a7(struct artpec6_pcie *artpec6_pcie) +{ + struct dw_pcie *pci = artpec6_pcie->pci; + u32 val; + u16 phy_status_tx, phy_status_rx; + unsigned int retries; + bool extrefclk; + + /* Check if external reference clock is connected */ + val = artpec6_pcie_readl(artpec6_pcie, PCIESTAT); + extrefclk = !!(val & PCIESTAT_EXTREFCLK); + dev_dbg(pci->dev, "Using reference clock: %s\n", + extrefclk ? "external" : "internal"); + + val = artpec6_pcie_readl(artpec6_pcie, PCIECFG); + val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */ + PCIECFG_PCLK_ENABLE; + if (extrefclk) + val |= PCIECFG_REFCLKSEL; + else + val &= ~PCIECFG_REFCLKSEL; + artpec6_pcie_writel(artpec6_pcie, PCIECFG, val); + usleep_range(10, 20); + + val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); + val |= NOCCFG_ENABLE_CLK_PCIE; + artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); + usleep_range(20, 30); + + val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); + val &= ~NOCCFG_POWER_PCIE_IDLEREQ; + artpec6_pcie_writel(artpec6_pcie, NOCCFG, val); + + retries = 50; + do { + usleep_range(1000, 2000); + val = artpec6_pcie_readl(artpec6_pcie, NOCCFG); + retries--; + } while (retries && + (val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE))); + + retries = 50; + do { + usleep_range(1000, 2000); + phy_status_tx = readw(artpec6_pcie->phy_base + PHY_TX_ASIC_OUT); + phy_status_rx =