From patchwork Thu Nov 24 01:54:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Lin X-Patchwork-Id: 9444701 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id D8C0F60235 for ; Thu, 24 Nov 2016 01:55:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CCA6027C7A for ; Thu, 24 Nov 2016 01:55:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C0EA127D45; Thu, 24 Nov 2016 01:55:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 37B4727C7A for ; Thu, 24 Nov 2016 01:55:44 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1c9jGJ-0003ae-Op; Thu, 24 Nov 2016 01:55:43 +0000 Received: from lucky1.263xmail.com ([211.157.147.135]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1c9jGD-0003Xo-VA for linux-rockchip@lists.infradead.org; Thu, 24 Nov 2016 01:55:42 +0000 Received: from shawn.lin?rock-chips.com (unknown [192.168.167.97]) by lucky1.263xmail.com (Postfix) with ESMTP id 49B1193E; Thu, 24 Nov 2016 09:55:13 +0800 (CST) X-263anti-spam: KSV:0; X-MAIL-GRAY: 1 X-MAIL-DELIVERY: 0 X-KSVirus-check: 0 X-ABS-CHECKED: 4 Received: from localhost.localdomain (localhost [127.0.0.1]) by smtp.263.net (Postfix) with ESMTP id BD2B1369; Thu, 24 Nov 2016 09:55:11 +0800 (CST) X-RL-SENDER: shawn.lin@rock-chips.com X-FST-TO: bhelgaas@google.com X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: shawn.lin@rock-chips.com X-UNIQUE-TAG: X-ATTACHMENT-NUM: 0 X-SENDER: lintao@rock-chips.com X-DNS-TYPE: 0 Received: from unknown (unknown [58.22.7.114]) by smtp.263.net (Postfix) whith SMTP id 29248VTM2WB; Thu, 24 Nov 2016 09:55:12 +0800 (CST) From: Shawn Lin To: Bjorn Helgaas Subject: [PATCH v3 3/3] PCI: rockchip: Add system PM support Date: Thu, 24 Nov 2016 09:54:22 +0800 Message-Id: <1479952462-194300-3-git-send-email-shawn.lin@rock-chips.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1479952462-194300-1-git-send-email-shawn.lin@rock-chips.com> References: <1479952462-194300-1-git-send-email-shawn.lin@rock-chips.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161123_175540_900197_1E2425E4 X-CRM114-Status: GOOD ( 15.77 ) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jeffy Chen , linux-pci@vger.kernel.org, Shawn Lin , Brian Norris , linux-rockchip@lists.infradead.org, Wenrui Li MIME-Version: 1.0 Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds system PM support for Rockchip's RC. For pre S3, the EP is configured into D3 state which guarantees the link state should be in L1. So we could send PME_Turn_Off message to the EP and wait for its ACK to make the link state into L2 or L3 without the aux-supply. This could help save more power which I think should be very important for mobile devices. As note that there is a 5s timeout for RC to wait for the PMA_ACK aftering send PME_Turn_Off. Technically it should depends on the hierarchy of devices but seems PCIe core framework doesn't handle the L2/3 for S3 at all. So that means we should presume to set a default value for PME_ACK. From the bug report[1], we could find a statment that Microsoft Windows versions typically wait for 5 seconds. So we are prone to take 5s for this timeout here. [1] https://lists.launchpad.net/kernel-packages/msg123315.html Signed-off-by: Shawn Lin Reviewed-by: Brian Norris --- Changes in v3: - check the return value of devm_ioremap - elaborate for commit msg - add tag from Brian Changes in v2: - Wrap the 'x' in parentheses - add msg regison mapped support - enable int for err case in suspend_noirq drivers/pci/host/pcie-rockchip.c | 107 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 457401d..2b36795 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,10 @@ #define PCIE_CLIENT_MODE_RC HIWORD_UPDATE_BIT(0x0040) #define PCIE_CLIENT_GEN_SEL_1 HIWORD_UPDATE(0x0080, 0) #define PCIE_CLIENT_GEN_SEL_2 HIWORD_UPDATE_BIT(0x0080) +#define PCIE_CLIENT_DEBUG_OUT_0 (PCIE_CLIENT_BASE + 0x3c) +#define PCIE_CLIENT_DEBUG_LTSSM_MASK GENMASK(5, 0) +#define PCIE_CLIENT_DEBUG_LTSSM_L1 0x18 +#define PCIE_CLIENT_DEBUG_LTSSM_L2 0x19 #define PCIE_CLIENT_BASIC_STATUS1 (PCIE_CLIENT_BASE + 0x48) #define PCIE_CLIENT_LINK_STATUS_UP 0x00300000 #define PCIE_CLIENT_LINK_STATUS_MASK 0x00300000 @@ -169,9 +174,11 @@ #define IB_ROOT_PORT_REG_SIZE_SHIFT 3 #define AXI_WRAPPER_IO_WRITE 0x6 #define AXI_WRAPPER_MEM_WRITE 0x2 +#define AXI_WRAPPER_NOR_MSG 0xc #define MAX_AXI_IB_ROOTPORT_REGION_NUM 3 #define MIN_AXI_ADDR_BITS_PASSED 8 +#define PCIE_RC_SEND_PME_OFF 0x11960 #define ROCKCHIP_VENDOR_ID 0x1d87 #define PCIE_ECAM_BUS(x) (((x) & 0xff) << 20) #define PCIE_ECAM_DEV(x) (((x) & 0x1f) << 15) @@ -180,6 +187,9 @@ #define PCIE_ECAM_ADDR(bus, dev, func, reg) \ (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \ PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg)) +#define PCIE_LINK_IS_L2(x) \ + (((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == \ + PCIE_CLIENT_DEBUG_LTSSM_L2) #define RC_REGION_0_ADDR_TRANS_H 0x00000000 #define RC_REGION_0_ADDR_TRANS_L 0x00000000 @@ -213,6 +223,7 @@ struct rockchip_pcie { u32 io_size; int offset; phys_addr_t io_bus_addr; + void __iomem *msg_region; u32 mem_size; phys_addr_t mem_bus_addr; }; @@ -1196,8 +1207,96 @@ static int rockchip_cfg_atu(struct rockchip_pcie *rockchip) } } + /* assign message regions */ + rockchip_pcie_prog_ob_atu(rockchip, reg_no + 1 + offset, + AXI_WRAPPER_NOR_MSG, + 20 - 1, 0, 0); + if (rockchip->msg_region) + goto out; + + rockchip->msg_region = devm_ioremap(rockchip->dev, + rockchip->mem_bus_addr + + ((reg_no + offset) << 20), + SZ_1M); + if (!rockchip->msg_region) + err = -ENOMEM; + +out: return err; } + +static int rockchip_pcie_wait_l2(struct rockchip_pcie *rockchip) +{ + u32 value; + int err; + + /* send PME_TURN_OFF message */ + writel(0x0, rockchip->msg_region + PCIE_RC_SEND_PME_OFF); + + /* read LTSSM and wait for falling into L2 link state */ + err = readl_poll_timeout(rockchip->apb_base + PCIE_CLIENT_DEBUG_OUT_0, + value, PCIE_LINK_IS_L2(value), 20, + jiffies_to_usecs(5 * HZ)); + if (err) { + dev_err(rockchip->dev, "PCIe link enter L2 timeout!\n"); + return err; + } + + return 0; +} + +static int rockchip_pcie_suspend_noirq(struct device *dev) +{ + struct rockchip_pcie *rockchip = dev_get_drvdata(dev); + int ret; + + /* disable core and cli int since we don't need to ack PME_ACK */ + rockchip_pcie_write(rockchip, (PCIE_CLIENT_INT_CLI << 16) | + PCIE_CLIENT_INT_CLI, PCIE_CLIENT_INT_MASK); + rockchip_pcie_write(rockchip, (u32)PCIE_CORE_INT, PCIE_CORE_INT_MASK); + + ret = rockchip_pcie_wait_l2(rockchip); + if (ret) { + rockchip_pcie_enable_interrupts(rockchip); + return ret; + } + + phy_power_off(rockchip->phy); + phy_exit(rockchip->phy); + + clk_disable_unprepare(rockchip->clk_pcie_pm); + clk_disable_unprepare(rockchip->hclk_pcie); + clk_disable_unprepare(rockchip->aclk_perf_pcie); + clk_disable_unprepare(rockchip->aclk_pcie); + + return ret; +} + +static int rockchip_pcie_resume_noirq(struct device *dev) +{ + struct rockchip_pcie *rockchip = dev_get_drvdata(dev); + int err; + + clk_prepare_enable(rockchip->clk_pcie_pm); + clk_prepare_enable(rockchip->hclk_pcie); + clk_prepare_enable(rockchip->aclk_perf_pcie); + clk_prepare_enable(rockchip->aclk_pcie); + + err = rockchip_pcie_init_port(rockchip); + if (err) + return err; + + err = rockchip_cfg_atu(rockchip); + if (err) + return err; + + /* Need this to enter L1 again */ + rockchip_pcie_update_txcredit_mui(rockchip); + rockchip_pcie_enable_interrupts(rockchip); + + return 0; +} + static int rockchip_pcie_probe(struct platform_device *pdev) { struct rockchip_pcie *rockchip; @@ -1218,6 +1317,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev) if (!rockchip) return -ENOMEM; + platform_set_drvdata(pdev, rockchip); + rockchip->dev = dev; err = rockchip_pcie_parse_dt(rockchip); @@ -1341,6 +1442,11 @@ static int rockchip_pcie_probe(struct platform_device *pdev) return err; } +static const struct dev_pm_ops rockchip_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_pcie_suspend_noirq, + rockchip_pcie_resume_noirq) +}; + static const struct of_device_id rockchip_pcie_of_match[] = { { .compatible = "rockchip,rk3399-pcie", }, {} @@ -1350,6 +1456,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) .driver = { .name = "rockchip-pcie", .of_match_table = rockchip_pcie_of_match, + .pm = &rockchip_pcie_pm_ops, }, .probe = rockchip_pcie_probe,