From patchwork Tue Sep 23 04:11:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Zhu X-Patchwork-Id: 4952891 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id EB1BD9F348 for ; Tue, 23 Sep 2014 04:39:50 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C69A52020F for ; Tue, 23 Sep 2014 04:39:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7C7BB201D3 for ; Tue, 23 Sep 2014 04:39:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751270AbaIWEjp (ORCPT ); Tue, 23 Sep 2014 00:39:45 -0400 Received: from mail-bn1on0145.outbound.protection.outlook.com ([157.56.110.145]:23296 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751414AbaIWEjk (ORCPT ); Tue, 23 Sep 2014 00:39:40 -0400 Received: from DM2PR03MB351.namprd03.prod.outlook.com (10.141.54.22) by DM2PR03MB398.namprd03.prod.outlook.com (10.141.84.140) with Microsoft SMTP Server (TLS) id 15.0.1034.13; Tue, 23 Sep 2014 04:39:38 +0000 Received: from BY2PR03CA076.namprd03.prod.outlook.com (10.141.249.49) by DM2PR03MB351.namprd03.prod.outlook.com (10.141.54.22) with Microsoft SMTP Server (TLS) id 15.0.1034.8; Tue, 23 Sep 2014 04:39:36 +0000 Received: from BY2FFO11FD024.protection.gbl (2a01:111:f400:7c0c::169) by BY2PR03CA076.outlook.office365.com (2a01:111:e400:2c5d::49) with Microsoft SMTP Server (TLS) id 15.0.1034.13 via Frontend Transport; Tue, 23 Sep 2014 04:39:36 +0000 Received: from az84smr01.freescale.net (192.88.158.2) by BY2FFO11FD024.mail.protection.outlook.com (10.1.15.213) with Microsoft SMTP Server (TLS) id 15.0.1029.15 via Frontend Transport; Tue, 23 Sep 2014 04:39:35 +0000 Received: from shlinux1.ap.freescale.net (shlinux1.ap.freescale.net [10.192.225.216]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id s8N4dYkx020509; Mon, 22 Sep 2014 21:39:34 -0700 Received: by shlinux1.ap.freescale.net (Postfix, from userid 1003) id D35231AE202; Tue, 23 Sep 2014 12:11:39 +0800 (CST) From: Richard Zhu To: CC: , , , , , Richard Zhu Subject: [PATCH v2 5/5] PCI: imx6: add imx6sx pcie support Date: Tue, 23 Sep 2014 12:11:38 +0800 Message-ID: <1411445498-20250-6-git-send-email-r65037@freescale.com> X-Mailer: git-send-email 1.7.8 In-Reply-To: <1411445498-20250-1-git-send-email-r65037@freescale.com> References: <1411445498-20250-1-git-send-email-r65037@freescale.com> X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:192.88.158.2; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(428002)(189002)(199003)(99396002)(229853001)(103686003)(31966008)(105586002)(92566001)(76176999)(107046002)(106466001)(50986999)(81156004)(2351001)(76482002)(47776003)(120916001)(77096002)(95666004)(10300001)(97736003)(92726001)(64706001)(69596002)(36756003)(104166001)(16796002)(101416001)(45336002)(83072002)(52956003)(46386002)(20776003)(74502003)(88136002)(85852003)(77156001)(110136001)(42186005)(33646002)(6806004)(19580405001)(93916002)(46102003)(44976005)(83322001)(89996001)(19580395003)(87286001)(50466002)(4396001)(21056001)(68736004)(84676001)(62966002)(79102003)(85306004)(80022003)(102836001)(74662003)(90102001)(50226001)(48376002)(77982003)(81542003)(81342003)(87936001)(32563001)(90966001); DIR:OUT; SFP:1102; SCL:1; SRVR:DM2PR03MB351; H:az84smr01.freescale.net; FPR:; MLV:sfv; PTR:InfoDomainNonexistent; MX:1; A:0; LANG:en; MIME-Version: 1.0 X-Microsoft-Antispam: UriScan:;UriScan:; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:;SRVR:DM2PR03MB351; X-Forefront-PRVS: 0343AC1D30 Received-SPF: None (protection.outlook.com: shlinux1.ap.freescale.net does not designate permitted sender hosts) Authentication-Results: spf=none (sender IP is 192.88.158.2) smtp.mailfrom=r65037@shlinux1.ap.freescale.net; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:;SRVR:DM2PR03MB398; X-OriginatorOrg: freescale.com Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Spam-Status: No, score=-7.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP - imx6sx pcie has its own standalone pcie power supply. In order to turn on the imx6sx pcie power during initialization. Add the pcie regulator and the gpc regmap into the imx6sx pcie structure. - imx6sx pcie has the new added reset mechanism, add the reset operations into the initialization. - Register one PM call-back, enter/exit L2 state of the ASPM during system suspend/resume. Signed-off-by: Richard Zhu --- drivers/pci/host/pci-imx6.c | 164 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 146 insertions(+), 18 deletions(-) diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index bc4222b..99ecb5d 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -18,12 +18,16 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include +#include #include #include @@ -31,15 +35,30 @@ #define to_imx6_pcie(x) container_of(x, struct imx6_pcie, pp) +/* The pcie who have standalone power domain */ +#define PCIE_PHY_HAS_PWR_DOMAIN BIT(0) + +struct imx_pcie_data { + unsigned int flags; +}; + +static const struct imx_pcie_data imx6sx_pcie_data = { + .flags = PCIE_PHY_HAS_PWR_DOMAIN, +}; + struct imx6_pcie { int reset_gpio; + const struct imx_pcie_data *data; struct clk *pcie_bus; struct clk *pcie_phy; struct clk *pcie; struct pcie_port pp; struct regmap *iomuxc_gpr; + struct regmap *gpc_ips_reg; + struct regulator *pcie_regulator; void __iomem *mem_base; }; +static struct imx6_pcie *imx6_pcie; /* PCIe Root Complex registers (memory-mapped) */ #define PCIE_RC_LCR 0x7c @@ -77,6 +96,11 @@ struct imx6_pcie { #define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5) #define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3) +static inline bool is_imx6sx_pcie(struct imx6_pcie *imx6_pcie) +{ + return imx6_pcie->data == &imx6sx_pcie_data; +} + static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val) { u32 val; @@ -275,11 +299,17 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) goto err_pcie; } - /* power up core phy and enable ref clock */ - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, - IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18); - regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, - IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); + if (is_imx6sx_pcie(imx6_pcie)) { + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6SX_GPR12_PCIE_TEST_PD, + IMX6SX_GPR12_PCIE_TEST_PD_CLR); + } else { + /* power up core phy and enable ref clock */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, + IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, + IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16); + } /* allow the clocks to stabilize */ usleep_range(200, 500); @@ -290,6 +320,18 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp) msleep(100); gpio_set_value(imx6_pcie->reset_gpio, 1); } + + /* + * iMX6SX PCIe has the stand-alone power domain. + * refer to the initialization for iMX6SX PCIe, + * release the PCIe PHY reset here, + * before LTSSM enable is set. + */ + if (is_imx6sx_pcie(imx6_pcie)) + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5, + IMX6SX_GPR5_PCIE_BTNRST, + IMX6SX_GPR5_PCIE_BTNRST_CLR); + return 0; err_pcie: @@ -304,15 +346,38 @@ err_pcie_phy: static void imx6_pcie_init_phy(struct pcie_port *pp) { struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); + int ret; + + /* + * iMX6SX PCIe has the stand-alone power domain + * add the initialization here for iMX6SX PCIe. + */ + if (is_imx6sx_pcie(imx6_pcie)) { + /* Force PCIe PHY reset */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5, + IMX6SX_GPR5_PCIE_BTNRST, + IMX6SX_GPR5_PCIE_BTNRST); + + regmap_update_bits(imx6_pcie->gpc_ips_reg, 0, 1 << 7, 1 << 7); + /* Power up PCIe PHY, ANATOP_REG_CORE offset 0x140, bit13-9 */ + regulator_set_voltage(imx6_pcie->pcie_regulator, + 1100000, 1100000); + ret = regulator_enable(imx6_pcie->pcie_regulator); + if (ret) + dev_info(pp->dev, "failed to enable pcie regulator.\n"); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + IMX6SX_GPR12_RX_EQ_MASK, IMX6SX_GPR12_RX_EQ_2); + } regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 0 << 10); + IMX6Q_GPR12_PCIE_CTL_2, + IMX6Q_GPR12_PCIE_CTL_2_CLR); /* configure constant input signal to the pcie ctrl and phy */ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12); regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_LOS_LEVEL, 9 << 4); + IMX6Q_GPR12_LOS_LEVEL, IMX6Q_GPR12_LOS_LEVEL_9); regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8, IMX6Q_GPR8_TX_DEEMPH_GEN1, 0 << 0); @@ -370,7 +435,8 @@ static int imx6_pcie_start_link(struct pcie_port *pp) /* Start LTSSM. */ regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, - IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); + IMX6Q_GPR12_PCIE_CTL_2, + IMX6Q_GPR12_PCIE_CTL_2); ret = imx6_pcie_wait_for_link(pp); if (ret) @@ -546,10 +612,64 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp, return 0; } +static const struct of_device_id imx6_pcie_of_match[] = { + { .compatible = "fsl,imx6q-pcie", }, + { .compatible = "fsl,imx6sx-pcie", .data = &imx6sx_pcie_data}, + {}, +}; +MODULE_DEVICE_TABLE(of, imx6_pcie_of_match); + +#ifdef CONFIG_PM_SLEEP +static int pci_imx_suspend(void) +{ + if (is_imx6sx_pcie(imx6_pcie)) { + /* PM_TURN_OFF */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + BIT(16), 1 << 16); + udelay(10); + regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, + BIT(16), 0 << 16); + } + + return 0; +} + +static void pci_imx_resume(void) +{ + struct pcie_port *pp = &imx6_pcie->pp; + + if (is_imx6sx_pcie(imx6_pcie)) { + /* reset iMX6SX PCIe */ + regmap_update_bits(imx6_pcie->iomuxc_gpr, + IOMUXC_GPR5, BIT(18), 1 << 18); + + regmap_update_bits(imx6_pcie->iomuxc_gpr, + IOMUXC_GPR5, BIT(18), 0 << 18); + + /* + * controller maybe turn off, re-configure again + * Set the CLASS_REV of RC CFG header to + * PCI_CLASS_BRIDGE_PCI + */ + writel(readl(pp->dbi_base + PCI_CLASS_REVISION) + | (PCI_CLASS_BRIDGE_PCI << 16), + pp->dbi_base + PCI_CLASS_REVISION); + + dw_pcie_setup_rc(pp); + } +} + +static struct syscore_ops pci_imx_syscore_ops = { + .suspend = pci_imx_suspend, + .resume = pci_imx_resume, +}; +#endif + static int __init imx6_pcie_probe(struct platform_device *pdev) { - struct imx6_pcie *imx6_pcie; struct pcie_port *pp; + const struct of_device_id *of_id = + of_match_device(imx6_pcie_of_match, &pdev->dev); struct device_node *np = pdev->dev.of_node; struct resource *dbi_base; int ret; @@ -560,6 +680,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) pp = &imx6_pcie->pp; pp->dev = &pdev->dev; + imx6_pcie->data = of_id->data; /* Added for PCI abort handling */ hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0, @@ -603,9 +724,19 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) return PTR_ERR(imx6_pcie->pcie); } - /* Grab GPR config register range */ - imx6_pcie->iomuxc_gpr = - syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (is_imx6sx_pcie(imx6_pcie)) { + imx6_pcie->pcie_regulator = devm_regulator_get(pp->dev, "pcie"); + + imx6_pcie->iomuxc_gpr = + syscon_regmap_lookup_by_compatible + ("fsl,imx6sx-iomuxc-gpr"); + imx6_pcie->gpc_ips_reg = + syscon_regmap_lookup_by_compatible("fsl,imx6sx-gpc"); + } else { + imx6_pcie->iomuxc_gpr = + syscon_regmap_lookup_by_compatible + ("fsl,imx6q-iomuxc-gpr"); + } if (IS_ERR(imx6_pcie->iomuxc_gpr)) { dev_err(&pdev->dev, "unable to find iomuxc registers\n"); return PTR_ERR(imx6_pcie->iomuxc_gpr); @@ -616,6 +747,9 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) return ret; platform_set_drvdata(pdev, imx6_pcie); +#ifdef CONFIG_PM_SLEEP + register_syscore_ops(&pci_imx_syscore_ops); +#endif return 0; } @@ -627,12 +761,6 @@ static void imx6_pcie_shutdown(struct platform_device *pdev) imx6_pcie_assert_core_reset(&imx6_pcie->pp); } -static const struct of_device_id imx6_pcie_of_match[] = { - { .compatible = "fsl,imx6q-pcie", }, - {}, -}; -MODULE_DEVICE_TABLE(of, imx6_pcie_of_match); - static struct platform_driver imx6_pcie_driver = { .driver = { .name = "imx6q-pcie",