From patchwork Wed Feb 3 07:01:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 12063525 X-Patchwork-Delegate: lorenzo.pieralisi@arm.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.0 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E41DFC433E6 for ; Wed, 3 Feb 2021 07:05:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AC08F64F69 for ; Wed, 3 Feb 2021 07:05:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232012AbhBCHF2 (ORCPT ); Wed, 3 Feb 2021 02:05:28 -0500 Received: from mail.kernel.org ([198.145.29.99]:35514 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232019AbhBCHD0 (ORCPT ); Wed, 3 Feb 2021 02:03:26 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 658ED64F61; Wed, 3 Feb 2021 07:02:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1612335720; bh=PXM78pfcnqkFSSmah6qG8tteTKKf8qMP7BnbaaAulOc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OQ9RipH8U1aCSI+/7P6qUWbkfEkXtMYSlA2Y3a/pXNml9JVSR+tvDk4vS6TQm5EnG QzLNlWplzCeYDdcqsE0T9E1blxzYqT5TBnU20w/LZr+QmrlZX9J5VYSkI8wtyZFVGP a8D7d4KkOJwe9X+3Tyc+SJMZHLeBHUdvirbHjH+0KFFDExXmRR2y42nv1LC/R/ydc9 kO8urBVfqU21H4B7T5sXj46nuuSCZ8Rp8209aIcGwx6bZnLDNqLN4vAba0701fpEfA l7UxUDvbuyN/qhMhx1VUHTJg9Nq9Rz7QxQTl0n/B+G66R8gaiXHN0S6C2+70Wl6aTd sClTWLyIoYHiQ== Received: by mail.kernel.org with local (Exim 4.94) (envelope-from ) id 1l7CAo-001CAW-43; Wed, 03 Feb 2021 08:01:58 +0100 From: Mauro Carvalho Chehab Cc: Manivannan Sadhasivam , Binghui Wang , Bjorn Helgaas , Lorenzo Pieralisi , Rob Herring , Xiaowei Song , linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, Mauro Carvalho Chehab Subject: [PATCH v2 04/11] PCI: dwc: pcie-kirin: add support for Kirin 970 PCIe controller Date: Wed, 3 Feb 2021 08:01:48 +0100 Message-Id: <4c9d6581478aa966698758c0420933f5defab4dd.1612335031.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: Manivannan Sadhasivam Add support for HiSilicon Kirin 970 (hi3670) SoC PCIe controller, based on Synopsys DesignWare PCIe controller IP. [mchehab+huawei@kernel.org: fix merge conflicts] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Mauro Carvalho Chehab Reported-by: kernel test robot --- drivers/pci/controller/dwc/pcie-kirin.c | 723 +++++++++++++++++++++++- 1 file changed, 707 insertions(+), 16 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index 026fd1e42a55..5925d2b345a8 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,9 +235,68 @@ 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; + kirin_pcie->apb_base = devm_platform_ioremap_resource_byname(pdev, "apb"); if (IS_ERR(kirin_pcie->apb_base)) @@ -167,6 +317,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; } @@ -208,6 +474,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; @@ -255,7 +536,401 @@ static int kirin_pcie_clk_ctrl(struct kirin_pcie *kirin_pcie, bool enable) 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; @@ -282,9 +957,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); @@ -419,11 +1094,29 @@ static const struct dw_pcie_host_ops kirin_pcie_host_ops = { .host_init = kirin_pcie_host_init, }; +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) { @@ -431,6 +1124,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; @@ -448,20 +1144,20 @@ 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, + kirin_pcie->gpio_id_reset[0] = of_get_named_gpio(dev->of_node, "reset-gpios", 0); - if (kirin_pcie->gpio_id_reset == -EPROBE_DEFER) { + if (kirin_pcie->gpio_id_reset[0] == -EPROBE_DEFER) { return -EPROBE_DEFER; - } else if (!gpio_is_valid(kirin_pcie->gpio_id_reset)) { + } else if (!gpio_is_valid(kirin_pcie->gpio_id_reset[0])) { dev_err(dev, "unable to get a valid gpio pin\n"); return -ENODEV; } - ret = kirin_pcie_power_on(kirin_pcie); + ret = ops->power_on(kirin_pcie); if (ret) return ret; @@ -470,11 +1166,6 @@ static int kirin_pcie_probe(struct platform_device *pdev) return dw_pcie_host_init(&pci->pp); } -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 = {