aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>2019-03-19 10:33:10 +0530
committerManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>2019-03-19 21:18:31 +0530
commit4917380ad023c62960aa0f876bd4f23cefc8729e (patch)
tree917e8d8ff59cf169cb74636cec72534e21946a89
parent38e59f0f58eb53c4a5797b8400b95f6300e4f18c (diff)
pci: Add HI3670 PCI-E controller supporthikey970_pcie
Add HiSilicon HI3670 SoC PCI-E controller support based on Designware PCI-E controller IP. Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
-rw-r--r--drivers/pci/controller/dwc/pcie-kirin.c720
1 files changed, 702 insertions, 18 deletions
diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
index 9b599296205d..324e674fedef 100644
--- a/drivers/pci/controller/dwc/pcie-kirin.c
+++ b/drivers/pci/controller/dwc/pcie-kirin.c
@@ -29,6 +29,7 @@
#define to_kirin_pcie(x) dev_get_drvdata((x)->dev)
#define REF_CLK_FREQ 100000000
+#define AXI_CLK_FREQ 207500000
/* PCIe ELBI registers */
#define SOC_PCIECTRL_CTRL0_ADDR 0x000
@@ -60,6 +61,65 @@
#define PCIE_DEBOUNCE_PARAM 0xF0F400
#define PCIE_OE_BYPASS (0x3 << 28)
+/* PCIe CTRL registers */
+#define SOC_PCIECTRL_CTRL0_ADDR 0x000
+#define SOC_PCIECTRL_CTRL1_ADDR 0x004
+#define SOC_PCIECTRL_CTRL7_ADDR 0x01c
+#define SOC_PCIECTRL_CTRL12_ADDR 0x030
+#define SOC_PCIECTRL_CTRL20_ADDR 0x050
+#define SOC_PCIECTRL_CTRL21_ADDR 0x054
+#define SOC_PCIECTRL_STATE0_ADDR 0x400
+
+/* PCIe PHY registers */
+#define SOC_PCIEPHY_CTRL0_ADDR 0x000
+#define SOC_PCIEPHY_CTRL1_ADDR 0x004
+#define SOC_PCIEPHY_CTRL2_ADDR 0x008
+#define SOC_PCIEPHY_CTRL3_ADDR 0x00c
+#define SOC_PCIEPHY_CTRL38_ADDR 0x0098
+#define SOC_PCIEPHY_STATE0_ADDR 0x400
+
+#define PCIE_LINKUP_ENABLE (0x8020)
+#define PCIE_ELBI_SLV_DBI_ENABLE (0x1 << 21)
+#define PCIE_LTSSM_ENABLE_BIT (0x1 << 11)
+#define PCIEPHY_RESET_BIT (0x1 << 17)
+#define PCIEPHY_PIPE_LINE0_RESET_BIT (0x1 << 19)
+
+#define PORT_MSI_CTRL_ADDR 0x820
+#define PORT_MSI_CTRL_UPPER_ADDR 0x824
+#define PORT_MSI_CTRL_INT0_ENABLE 0x828
+
+#define EYEPARAM_NOCFG 0xFFFFFFFF
+#define RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1 0x3001
+#define SUP_DIG_LVL_OVRD_IN 0xf
+#define LANEN_DIG_ASIC_TX_OVRD_IN_1 0x1002
+#define LANEN_DIG_ASIC_TX_OVRD_IN_2 0x1003
+
+/* kirin970 pciephy register */
+#define SOC_PCIEPHY_MMC1PLL_CTRL1 0xc04
+#define SOC_PCIEPHY_MMC1PLL_CTRL16 0xC40
+#define SOC_PCIEPHY_MMC1PLL_CTRL17 0xC44
+#define SOC_PCIEPHY_MMC1PLL_CTRL20 0xC50
+#define SOC_PCIEPHY_MMC1PLL_CTRL21 0xC54
+#define SOC_PCIEPHY_MMC1PLL_STAT0 0xE00
+
+#define CRGPERIPH_PEREN12 0x470
+#define CRGPERIPH_PERDIS12 0x474
+#define CRGPERIPH_PCIECTRL0 0x800
+
+/* define ie,oe cfg */
+#define IO_IE_EN_HARD_BYPASS (0x1 << 27)
+#define IO_OE_EN_HARD_BYPASS (0x1 << 11)
+#define IO_HARD_CTRL_DEBOUNCE_BYPASS (0x1 << 10)
+#define IO_OE_GT_MODE (0x2 << 7)
+#define DEBOUNCE_WAITCFG_IN (0xf << 20)
+#define DEBOUNCE_WAITCFG_OUT (0xf << 13)
+
+/* noc power domain */
+#define NOC_POWER_IDLEREQ_1 0x38c
+#define NOC_POWER_IDLE_1 0x394
+#define NOC_PW_MASK 0x10000
+#define NOC_PW_SET_BIT 0x1
+
/* peri_crg ctrl */
#define CRGCTRL_PCIE_ASSERT_OFFSET 0x88
#define CRGCTRL_PCIE_ASSERT_BIT 0x8c000000
@@ -84,12 +144,21 @@ struct kirin_pcie {
void __iomem *phy_base;
struct regmap *crgctrl;
struct regmap *sysctrl;
+ struct regmap *pmctrl;
struct clk *apb_sys_clk;
struct clk *apb_phy_clk;
struct clk *phy_ref_clk;
struct clk *pcie_aclk;
struct clk *pcie_aux_clk;
- int gpio_id_reset;
+ int gpio_id_reset[4];
+ int gpio_id_clkreq[3];
+ u32 eye_param[5];
+};
+
+struct kirin_pcie_ops {
+ long (*get_resource)(struct kirin_pcie *kirin_pcie,
+ struct platform_device *pdev);
+ int (*power_on)(struct kirin_pcie *kirin_pcie);
};
/* Registers in PCIeCTRL */
@@ -116,6 +185,28 @@ static inline u32 kirin_apb_phy_readl(struct kirin_pcie *kirin_pcie, u32 reg)
return readl(kirin_pcie->phy_base + reg);
}
+static inline void kirin970_apb_phy_writel(struct kirin_pcie *kirin_pcie,
+ u32 val, u32 reg)
+{
+ writel(val, kirin_pcie->phy_base + 0x40000 + reg);
+}
+
+static inline u32 kirin970_apb_phy_readl(struct kirin_pcie *kirin_pcie, u32 reg)
+{
+ return readl(kirin_pcie->phy_base + 0x40000 + reg);
+}
+
+static inline void kirin_apb_natural_phy_writel(struct kirin_pcie *kirin_pcie,
+ u32 val, u32 reg)
+{
+ writel(val, kirin_pcie->phy_base + reg * 4);
+}
+
+static inline u32 kirin_apb_natural_phy_readl(struct kirin_pcie *kirin_pcie, u32 reg)
+{
+ return readl(kirin_pcie->phy_base + reg * 4);
+}
+
static long kirin_pcie_get_clk(struct kirin_pcie *kirin_pcie,
struct platform_device *pdev)
{
@@ -144,8 +235,65 @@ static long kirin_pcie_get_clk(struct kirin_pcie *kirin_pcie,
return 0;
}
-static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
- struct platform_device *pdev)
+void kirin970_pcie_get_eyeparam(struct kirin_pcie *pcie)
+{
+ struct device *dev = pcie->pci->dev;
+ int i;
+ struct device_node *np;
+
+ np = dev->of_node;
+
+ if (of_property_read_u32_array(np, "eye_param", pcie->eye_param, 5)) {
+ for (i = 0; i < 5; i++)
+ pcie->eye_param[i] = EYEPARAM_NOCFG;
+ }
+
+ dev_dbg(dev, "eye_param_vboost = [0x%x]\n", pcie->eye_param[0]);
+ dev_dbg(dev, "eye_param_iboost = [0x%x]\n", pcie->eye_param[1]);
+ dev_dbg(dev, "eye_param_pre = [0x%x]\n", pcie->eye_param[2]);
+ dev_dbg(dev, "eye_param_post = [0x%x]\n", pcie->eye_param[3]);
+ dev_dbg(dev, "eye_param_main = [0x%x]\n", pcie->eye_param[4]);
+}
+
+static void kirin970_pcie_set_eyeparam(struct kirin_pcie *kirin_pcie)
+{
+ u32 val;
+
+ val = kirin_apb_natural_phy_readl(kirin_pcie, RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1);
+
+ if (kirin_pcie->eye_param[1] != EYEPARAM_NOCFG) {
+ val &= (~0xf00);
+ val |= (kirin_pcie->eye_param[1] << 8) | (0x1 << 12);
+ }
+ kirin_apb_natural_phy_writel(kirin_pcie, val, RAWLANEN_DIG_PCS_XF_TX_OVRD_IN_1);
+
+ val = kirin_apb_natural_phy_readl(kirin_pcie, LANEN_DIG_ASIC_TX_OVRD_IN_2);
+ val &= (~0x1FBF);
+ if (kirin_pcie->eye_param[2] != EYEPARAM_NOCFG)
+ val |= (kirin_pcie->eye_param[2]<< 0) | (0x1 << 6);
+
+ if (kirin_pcie->eye_param[3] != EYEPARAM_NOCFG)
+ val |= (kirin_pcie->eye_param[3] << 7) | (0x1 << 13);
+
+ kirin_apb_natural_phy_writel(kirin_pcie, val, LANEN_DIG_ASIC_TX_OVRD_IN_2);
+
+ val = kirin_apb_natural_phy_readl(kirin_pcie, SUP_DIG_LVL_OVRD_IN);
+ if (kirin_pcie->eye_param[0] != EYEPARAM_NOCFG) {
+ val &= (~0x1C0);
+ val |= (kirin_pcie->eye_param[0] << 6) | (0x1 << 9);
+ }
+ kirin_apb_natural_phy_writel(kirin_pcie, val, SUP_DIG_LVL_OVRD_IN);
+
+ val = kirin_apb_natural_phy_readl(kirin_pcie, LANEN_DIG_ASIC_TX_OVRD_IN_1);
+ if (kirin_pcie->eye_param[4] != EYEPARAM_NOCFG) {
+ val &= (~0x7E00);
+ val |= (kirin_pcie->eye_param[4] << 9) | (0x1 << 15);
+ }
+ kirin_apb_natural_phy_writel(kirin_pcie, val, LANEN_DIG_ASIC_TX_OVRD_IN_1);
+}
+
+static long kirin960_pcie_get_resource(struct kirin_pcie *kirin_pcie,
+ struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *apb;
@@ -177,6 +325,122 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
if (IS_ERR(kirin_pcie->sysctrl))
return PTR_ERR(kirin_pcie->sysctrl);
+ kirin_pcie->gpio_id_reset[0] = of_get_named_gpio(dev->of_node,
+ "reset-gpios", 0);
+ if (kirin_pcie->gpio_id_reset[0] < 0)
+ return -ENODEV;
+
+ return 0;
+}
+
+static long kirin970_pcie_get_resource(struct kirin_pcie *kirin_pcie,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *apb;
+ struct resource *phy;
+ struct resource *dbi;
+ int ret;
+
+ apb = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apb");
+ kirin_pcie->apb_base = devm_ioremap_resource(dev, apb);
+ if (IS_ERR(kirin_pcie->apb_base))
+ return PTR_ERR(kirin_pcie->apb_base);
+
+ phy = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
+ kirin_pcie->phy_base = devm_ioremap_resource(dev, phy);
+ if (IS_ERR(kirin_pcie->phy_base))
+ return PTR_ERR(kirin_pcie->phy_base);
+
+ dbi = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+ kirin_pcie->pci->dbi_base = devm_ioremap_resource(dev, dbi);
+ if (IS_ERR(kirin_pcie->pci->dbi_base))
+ return PTR_ERR(kirin_pcie->pci->dbi_base);
+
+ kirin970_pcie_get_eyeparam(kirin_pcie);
+
+ kirin_pcie->gpio_id_reset[0] = of_get_named_gpio(dev->of_node,
+ "switch,reset-gpios", 0);
+ if (kirin_pcie->gpio_id_reset[0] < 0)
+ return -ENODEV;
+
+ kirin_pcie->gpio_id_reset[1] = of_get_named_gpio(dev->of_node,
+ "eth,reset-gpios", 0);
+ if (kirin_pcie->gpio_id_reset[1] < 0)
+ return -ENODEV;
+
+ kirin_pcie->gpio_id_reset[2] = of_get_named_gpio(dev->of_node,
+ "m_2,reset-gpios", 0);
+ if (kirin_pcie->gpio_id_reset[2] < 0)
+ return -ENODEV;
+
+ kirin_pcie->gpio_id_reset[3] = of_get_named_gpio(dev->of_node,
+ "mini1,reset-gpios", 0);
+ if (kirin_pcie->gpio_id_reset[3] < 0)
+ return -ENODEV;
+
+ ret = devm_gpio_request(dev, kirin_pcie->gpio_id_reset[0],
+ "pcie_switch_reset");
+ if (ret)
+ return ret;
+ ret = devm_gpio_request(dev, kirin_pcie->gpio_id_reset[1],
+ "pcie_eth_reset");
+ if (ret)
+ return ret;
+ ret = devm_gpio_request(dev, kirin_pcie->gpio_id_reset[2],
+ "pcie_m_2_reset");
+ if (ret)
+ return ret;
+ ret = devm_gpio_request(dev, kirin_pcie->gpio_id_reset[3],
+ "pcie_mini1_reset");
+ if (ret)
+ return ret;
+
+ kirin_pcie->gpio_id_clkreq[0] = of_get_named_gpio(dev->of_node,
+ "eth,clkreq-gpios", 0);
+ if (kirin_pcie->gpio_id_clkreq[0] < 0)
+ return -ENODEV;
+
+ kirin_pcie->gpio_id_clkreq[1] = of_get_named_gpio(dev->of_node,
+ "m_2,clkreq-gpios", 0);
+ if (kirin_pcie->gpio_id_clkreq[1] < 0)
+ return -ENODEV;
+
+ kirin_pcie->gpio_id_clkreq[2] = of_get_named_gpio(dev->of_node,
+ "mini1,clkreq-gpios", 0);
+ if (kirin_pcie->gpio_id_clkreq[2] < 0)
+ return -ENODEV;
+
+ ret = devm_gpio_request(dev, kirin_pcie->gpio_id_clkreq[0],
+ "pcie_eth_clkreq");
+ if (ret)
+ return ret;
+
+ ret = devm_gpio_request(dev, kirin_pcie->gpio_id_clkreq[1],
+ "pcie_m_2_clkreq");
+ if (ret)
+ return ret;
+
+ ret = devm_gpio_request(dev, kirin_pcie->gpio_id_clkreq[2],
+ "pcie_mini1_clkreq");
+ if (ret)
+ return ret;
+
+ kirin_pcie->crgctrl =
+ syscon_regmap_lookup_by_compatible("hisilicon,hi3670-crgctrl");
+ if (IS_ERR(kirin_pcie->crgctrl))
+ return PTR_ERR(kirin_pcie->crgctrl);
+
+ kirin_pcie->sysctrl =
+ syscon_regmap_lookup_by_compatible("hisilicon,hi3670-sctrl");
+ if (IS_ERR(kirin_pcie->sysctrl))
+ return PTR_ERR(kirin_pcie->sysctrl);
+
+ kirin_pcie->pmctrl =
+ syscon_regmap_lookup_by_compatible("hisilicon,hi3670-pmctrl");
+ if (IS_ERR(kirin_pcie->sysctrl))
+ return PTR_ERR(kirin_pcie->sysctrl);
+
return 0;
}
@@ -218,6 +482,21 @@ static void kirin_pcie_oe_enable(struct kirin_pcie *kirin_pcie)
regmap_write(kirin_pcie->sysctrl, SCTRL_PCIE_OE_OFFSET, val);
}
+static int kirin970_pcie_clk_ctrl(struct clk *clk, int clk_on)
+{
+ int ret = 0;
+
+ if (clk_on) {
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
+ } else {
+ clk_disable_unprepare(clk);
+ }
+
+ return ret;
+}
+
static int kirin_pcie_clk_ctrl(struct kirin_pcie *kirin_pcie, bool enable)
{
int ret = 0;
@@ -265,7 +544,401 @@ apb_sys_fail:
return ret;
}
-static int kirin_pcie_power_on(struct kirin_pcie *kirin_pcie)
+static void kirin970_pcie_natural_cfg(struct kirin_pcie *kirin_pcie)
+{
+ u32 val;
+
+ /* change 2p mem_ctrl */
+ kirin_apb_ctrl_writel(kirin_pcie, 0x02605550, SOC_PCIECTRL_CTRL20_ADDR);
+
+ /* pull up sys_aux_pwr_det */
+ val = kirin_apb_ctrl_readl(kirin_pcie, SOC_PCIECTRL_CTRL7_ADDR);
+ val |= (0x1 << 10);
+ kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL7_ADDR);
+
+ /* output, pull down */
+ val = kirin_apb_ctrl_readl(kirin_pcie, SOC_PCIECTRL_CTRL12_ADDR);
+ val &= ~(0x3 << 2);
+ val |= (0x1 << 1);
+ val &= ~(0x1 << 0);
+ kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL12_ADDR);
+
+ /* Handle phy_reset and lane0_reset to HW */
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_CTRL1_ADDR);
+ val |= PCIEPHY_RESET_BIT;
+ val &= ~PCIEPHY_PIPE_LINE0_RESET_BIT;
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_CTRL1_ADDR);
+
+ /* fix chip bug: TxDetectRx fail */
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_CTRL38_ADDR);
+ val |= (0x1 << 2);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_CTRL38_ADDR);
+}
+
+static void kirin970_pcie_pll_init(struct kirin_pcie *kirin_pcie)
+{
+ u32 val;
+
+ /* choose FNPLL */
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL1);
+ val |= (0x1 << 27);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL1);
+
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL16);
+ val &= 0xF000FFFF;
+ /* fnpll fbdiv = 0xD0 */
+ val |= (0xd0 << 16);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL16);
+
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL17);
+ val &= 0xFF000000;
+ /* fnpll fracdiv = 0x555555 */
+ val |= (0x555555 << 0);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL17);
+
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL20);
+ val &= 0xF5FF88FF;
+ /* fnpll dll_en = 0x1 */
+ val |= (0x1 << 27);
+ /* fnpll postdiv1 = 0x5 */
+ val |= (0x5 << 8);
+ /* fnpll postdiv2 = 0x4 */
+ val |= (0x4 << 12);
+ /* fnpll pll_mode = 0x0 */
+ val &= ~(0x1 << 25);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL20);
+
+ kirin970_apb_phy_writel(kirin_pcie, 0x20, SOC_PCIEPHY_MMC1PLL_CTRL21);
+}
+
+static int kirin970_pcie_pll_ctrl(struct kirin_pcie *kirin_pcie, bool enable)
+{
+ struct device *dev = kirin_pcie->pci->dev;
+ u32 val;
+ int time = 200;
+
+ if (enable) {
+ /* pd = 0 */
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL16);
+ val &= ~(0x1 << 0);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL16);
+
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_STAT0);
+
+ /* choose FNPLL */
+ while (!(val & 0x10)) {
+ if (!time) {
+ dev_err(dev, "wait for pll_lock timeout\n");
+ return -1;
+ }
+ time --;
+ udelay(1);
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_STAT0);
+ }
+
+ /* pciepll_bp = 0 */
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL20);
+ val &= ~(0x1 << 16);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL20);
+
+ } else {
+ /* pd = 1 */
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL16);
+ val |= (0x1 << 0);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL16);
+
+ /* pciepll_bp = 1 */
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_MMC1PLL_CTRL20);
+ val |= (0x1 << 16);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_MMC1PLL_CTRL20);
+ }
+
+ return 0;
+}
+
+static void kirin970_pcie_hp_debounce_gt(struct kirin_pcie *kirin_pcie, bool open)
+{
+ if (open)
+ /* gt_clk_pcie_hp/gt_clk_pcie_debounce open */
+ regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PEREN12, 0x9000);
+ else
+ /* gt_clk_pcie_hp/gt_clk_pcie_debounce close */
+ regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PERDIS12, 0x9000);
+}
+
+static void kirin970_pcie_phyref_gt(struct kirin_pcie *kirin_pcie, bool open)
+{
+ unsigned int val;
+
+ regmap_read(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, &val);
+
+ if (open)
+ val &= ~(0x1 << 1); //enable hard gt mode
+ else
+ val |= (0x1 << 1); //disable hard gt mode
+
+ regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, val);
+
+ /* disable soft gt mode */
+ regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PERDIS12, 0x4000);
+}
+
+static void kirin970_pcie_oe_ctrl(struct kirin_pcie *kirin_pcie, bool en_flag)
+{
+ unsigned int val;
+
+ regmap_read(kirin_pcie->crgctrl , CRGPERIPH_PCIECTRL0, &val);
+
+ /* set ie cfg */
+ val |= IO_IE_EN_HARD_BYPASS;
+
+ /* set oe cfg */
+ val &= ~IO_HARD_CTRL_DEBOUNCE_BYPASS;
+
+ /* set phy_debounce in&out time */
+ val |= (DEBOUNCE_WAITCFG_IN | DEBOUNCE_WAITCFG_OUT);
+
+ /* select oe_gt_mode */
+ val |= IO_OE_GT_MODE;
+
+ if (en_flag)
+ val &= ~IO_OE_EN_HARD_BYPASS;
+ else
+ val |= IO_OE_EN_HARD_BYPASS;
+
+ regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, val);
+}
+
+static void kirin970_pcie_ioref_gt(struct kirin_pcie *kirin_pcie, bool open)
+{
+ unsigned int val;
+
+ if (open) {
+ kirin_apb_ctrl_writel(kirin_pcie, 0x20000070, SOC_PCIECTRL_CTRL21_ADDR);
+
+ kirin970_pcie_oe_ctrl(kirin_pcie, true);
+
+ /* en hard gt mode */
+ regmap_read(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, &val);
+ val &= ~(0x1 << 0);
+ regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, val);
+
+ /* disable soft gt mode */
+ regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PERDIS12, 0x2000);
+
+ } else {
+ /* disable hard gt mode */
+ regmap_read(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, &val);
+ val |= (0x1 << 0);
+ regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PCIECTRL0, val);
+
+ /* disable soft gt mode */
+ regmap_write(kirin_pcie->crgctrl, CRGPERIPH_PERDIS12, 0x2000);
+
+ kirin970_pcie_oe_ctrl(kirin_pcie, false);
+ }
+}
+
+static int kirin970_pcie_allclk_ctrl(struct kirin_pcie *kirin_pcie, bool clk_on)
+{
+ struct device *dev = kirin_pcie->pci->dev;
+ u32 val;
+ int ret = 0;
+
+ if (!clk_on)
+ goto ALL_CLOSE;
+
+ /* choose 100MHz clk src: Bit[8]==1 pad, Bit[8]==0 pll */
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_CTRL1_ADDR);
+ val &= ~(0x1 << 8);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_CTRL1_ADDR);
+
+ kirin970_pcie_pll_init(kirin_pcie);
+
+ ret = kirin970_pcie_pll_ctrl(kirin_pcie, true);
+ if (ret) {
+ dev_err(dev, "Failed to enable pll\n");
+ return -1;
+ }
+ kirin970_pcie_hp_debounce_gt(kirin_pcie, true);
+ kirin970_pcie_phyref_gt(kirin_pcie, true);
+ kirin970_pcie_ioref_gt(kirin_pcie, true);
+
+ ret = clk_set_rate(kirin_pcie->pcie_aclk, AXI_CLK_FREQ);
+ if (ret) {
+ dev_err(dev, "Failed to set rate\n");
+ goto GT_CLOSE;
+ }
+
+ ret = kirin970_pcie_clk_ctrl(kirin_pcie->pcie_aclk, true);
+ if (ret) {
+ dev_err(dev, "Failed to enable pcie_aclk\n");
+ goto GT_CLOSE;
+ }
+
+ ret = kirin970_pcie_clk_ctrl(kirin_pcie->pcie_aux_clk, true);
+ if (ret) {
+ dev_err(dev, "Failed to enable pcie_aux_clk\n");
+ goto AUX_CLK_FAIL;
+ }
+
+ return 0;
+
+ALL_CLOSE:
+ kirin970_pcie_clk_ctrl(kirin_pcie->pcie_aux_clk, false);
+AUX_CLK_FAIL:
+ kirin970_pcie_clk_ctrl(kirin_pcie->pcie_aclk, false);
+GT_CLOSE:
+ kirin970_pcie_ioref_gt(kirin_pcie, false);
+ kirin970_pcie_phyref_gt(kirin_pcie, false);
+ kirin970_pcie_hp_debounce_gt(kirin_pcie, false);
+
+ kirin970_pcie_pll_ctrl(kirin_pcie, false);
+
+ return ret;
+}
+
+static bool is_pipe_clk_stable(struct kirin_pcie *kirin_pcie)
+{
+ struct device *dev = kirin_pcie->pci->dev;
+ u32 val;
+ u32 time = 100;
+ u32 pipe_clk_stable = 0x1 << 19;
+
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_STATE0_ADDR);
+ while (val & pipe_clk_stable) {
+ mdelay(1);
+ if (time == 0) {
+ dev_err(dev, "PIPE clk is not stable\n");
+ return false;
+ }
+ time--;
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_STATE0_ADDR);
+ }
+
+ return true;
+}
+
+static int kirin970_pcie_noc_power(struct kirin_pcie *kirin_pcie, bool enable)
+{
+ struct device *dev = kirin_pcie->pci->dev;
+ u32 time = 100;
+ unsigned int val = NOC_PW_MASK;
+ int rst;
+
+ if (enable)
+ val = NOC_PW_MASK | NOC_PW_SET_BIT;
+ else
+ val = NOC_PW_MASK;
+ rst = enable ? 1 : 0;
+
+ regmap_write(kirin_pcie->pmctrl, NOC_POWER_IDLEREQ_1, val);
+
+ time = 100;
+ regmap_read(kirin_pcie->pmctrl, NOC_POWER_IDLE_1, &val);
+ while((val & NOC_PW_SET_BIT) != rst) {
+ udelay(10);
+ if (!time) {
+ dev_err(dev, "Failed to reverse noc power-status\n");
+ return -1;
+ }
+ time--;
+ regmap_read(kirin_pcie->pmctrl, NOC_POWER_IDLE_1, &val);
+ }
+
+ return 0;
+}
+
+static int kirin970_pcie_power_on(struct kirin_pcie *kirin_pcie)
+{
+ struct device *dev = kirin_pcie->pci->dev;
+ int ret;
+ u32 val;
+
+ /* Power supply for Host */
+ regmap_write(kirin_pcie->sysctrl,
+ SCTRL_PCIE_CMOS_OFFSET, SCTRL_PCIE_CMOS_BIT);
+ usleep_range(TIME_CMOS_MIN, TIME_CMOS_MAX);
+ kirin_pcie_oe_enable(kirin_pcie);
+
+ ret = gpio_direction_output(kirin_pcie->gpio_id_clkreq[0], 0);
+ if (ret)
+ dev_err(dev, "Failed to pulse eth clkreq signal\n");
+
+ ret = gpio_direction_output(kirin_pcie->gpio_id_clkreq[1], 0);
+ if (ret)
+ dev_err(dev, "Failed to pulse m.2 clkreq signal\n");
+
+ ret = gpio_direction_output(kirin_pcie->gpio_id_clkreq[2], 0);
+ if (ret)
+ dev_err(dev, "Failed to pulse mini1 clkreq signal\n");
+
+ ret = kirin_pcie_clk_ctrl(kirin_pcie, true);
+ if (ret)
+ return ret;
+
+ /* ISO disable, PCIeCtrl, PHY assert and clk gate clear */
+ regmap_write(kirin_pcie->sysctrl,
+ SCTRL_PCIE_ISO_OFFSET, SCTRL_PCIE_ISO_BIT);
+ regmap_write(kirin_pcie->crgctrl,
+ CRGCTRL_PCIE_ASSERT_OFFSET, CRGCTRL_PCIE_ASSERT_BIT);
+ regmap_write(kirin_pcie->sysctrl,
+ SCTRL_PCIE_HPCLK_OFFSET, SCTRL_PCIE_HPCLK_BIT);
+
+ kirin970_pcie_natural_cfg(kirin_pcie);
+
+ ret = kirin970_pcie_allclk_ctrl(kirin_pcie, true);
+ if (ret)
+ goto close_clk;
+
+ /* pull down phy_test_powerdown signal */
+ val = kirin970_apb_phy_readl(kirin_pcie, SOC_PCIEPHY_CTRL0_ADDR);
+ val &= ~(0x1 << 22);
+ kirin970_apb_phy_writel(kirin_pcie, val, SOC_PCIEPHY_CTRL0_ADDR);
+
+ /* deassert controller perst_n */
+ val = kirin_apb_ctrl_readl(kirin_pcie, SOC_PCIECTRL_CTRL12_ADDR);
+ val |= (0x1 << 2);
+ kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL12_ADDR);
+ udelay(10);
+
+ /* perst assert Endpoints */
+ usleep_range(21000, 23000);
+ ret = gpio_direction_output(kirin_pcie->gpio_id_reset[0], 1);
+ if (ret)
+ goto close_clk;
+
+ ret = gpio_direction_output(kirin_pcie->gpio_id_reset[1], 1);
+ if (ret)
+ goto close_clk;
+
+ ret = gpio_direction_output(kirin_pcie->gpio_id_reset[2], 1);
+ if (ret)
+ goto close_clk;
+
+ ret = gpio_direction_output(kirin_pcie->gpio_id_reset[3], 1);
+ if (ret)
+ goto close_clk;
+
+ usleep_range(10000, 11000);
+
+ ret = is_pipe_clk_stable(kirin_pcie);
+ if (!ret)
+ goto close_clk;
+
+ kirin970_pcie_set_eyeparam(kirin_pcie);
+
+ ret = kirin970_pcie_noc_power(kirin_pcie, false);
+ if (ret)
+ goto close_clk;
+
+ return 0;
+close_clk:
+ kirin_pcie_clk_ctrl(kirin_pcie, false);
+ return ret;
+}
+
+static int kirin960_pcie_power_on(struct kirin_pcie *kirin_pcie)
{
int ret;
@@ -292,9 +965,9 @@ static int kirin_pcie_power_on(struct kirin_pcie *kirin_pcie)
goto close_clk;
/* perst assert Endpoint */
- if (!gpio_request(kirin_pcie->gpio_id_reset, "pcie_perst")) {
+ if (!gpio_request(kirin_pcie->gpio_id_reset[0], "pcie_perst")) {
usleep_range(REF_2_PERST_MIN, REF_2_PERST_MAX);
- ret = gpio_direction_output(kirin_pcie->gpio_id_reset, 1);
+ ret = gpio_direction_output(kirin_pcie->gpio_id_reset[0], 1);
if (ret)
goto close_clk;
usleep_range(PERST_2_ACCESS_MIN, PERST_2_ACCESS_MAX);
@@ -481,11 +1154,29 @@ static int kirin_add_pcie_port(struct dw_pcie *pci,
return dw_pcie_host_init(&pci->pp);
}
+struct kirin_pcie_ops kirin960_pcie_ops = {
+ .get_resource = kirin960_pcie_get_resource,
+ .power_on = kirin960_pcie_power_on,
+};
+
+struct kirin_pcie_ops kirin970_pcie_ops = {
+ .get_resource = kirin970_pcie_get_resource,
+ .power_on = kirin970_pcie_power_on,
+};
+
+static const struct of_device_id kirin_pcie_match[] = {
+ { .compatible = "hisilicon,kirin960-pcie", .data = &kirin960_pcie_ops },
+ { .compatible = "hisilicon,kirin970-pcie", .data = &kirin970_pcie_ops },
+ {},
+};
+
static int kirin_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct kirin_pcie *kirin_pcie;
struct dw_pcie *pci;
+ const struct of_device_id *of_id;
+ struct kirin_pcie_ops *ops;
int ret;
if (!dev->of_node) {
@@ -493,6 +1184,9 @@ static int kirin_pcie_probe(struct platform_device *pdev)
return -EINVAL;
}
+ of_id = of_match_node(kirin_pcie_match, dev->of_node);
+ ops = (struct kirin_pcie_ops *)of_id->data;
+
kirin_pcie = devm_kzalloc(dev, sizeof(struct kirin_pcie), GFP_KERNEL);
if (!kirin_pcie)
return -ENOMEM;
@@ -509,16 +1203,11 @@ static int kirin_pcie_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = kirin_pcie_get_resource(kirin_pcie, pdev);
+ ret = ops->get_resource(kirin_pcie, pdev);
if (ret)
return ret;
- kirin_pcie->gpio_id_reset = of_get_named_gpio(dev->of_node,
- "reset-gpios", 0);
- if (kirin_pcie->gpio_id_reset < 0)
- return -ENODEV;
-
- ret = kirin_pcie_power_on(kirin_pcie);
+ ret = ops->power_on(kirin_pcie);
if (ret)
return ret;
@@ -527,11 +1216,6 @@ static int kirin_pcie_probe(struct platform_device *pdev)
return kirin_add_pcie_port(pci, pdev);
}
-static const struct of_device_id kirin_pcie_match[] = {
- { .compatible = "hisilicon,kirin960-pcie" },
- {},
-};
-
static struct platform_driver kirin_pcie_driver = {
.probe = kirin_pcie_probe,
.driver = {