From patchwork Fri Jul 14 03:52:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Lin X-Patchwork-Id: 9839849 X-Patchwork-Delegate: bhelgaas@google.com 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 7367C60212 for ; Fri, 14 Jul 2017 03:53:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6349128783 for ; Fri, 14 Jul 2017 03:53:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 581D228789; Fri, 14 Jul 2017 03:53:06 +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=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3871528783 for ; Fri, 14 Jul 2017 03:53:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753239AbdGNDxE (ORCPT ); Thu, 13 Jul 2017 23:53:04 -0400 Received: from lucky1.263xmail.com ([211.157.147.130]:50920 "EHLO lucky1.263xmail.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753182AbdGNDxD (ORCPT ); Thu, 13 Jul 2017 23:53:03 -0400 Received: from shawn.lin?rock-chips.com (unknown [192.168.167.205]) by lucky1.263xmail.com (Postfix) with ESMTP id 5C1591EF0AB; Fri, 14 Jul 2017 11:52:58 +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 ESMTPA id 57A6B38A; Fri, 14 Jul 2017 11:52:57 +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 localhost.localdomain (unknown [58.22.7.114]) by smtp.263.net (Postfix) whith ESMTP id 10780VTHXGJ; Fri, 14 Jul 2017 11:52:58 +0800 (CST) From: Shawn Lin To: Bjorn Helgaas , Rob Herring , Kishon Vijay Abraham I Cc: Heiko Stuebner , linux-pci@vger.kernel.org, linux-rockchip@lists.infradead.org, Brian Norris , Jeffy Chen , devicetree@vger.kernel.org, Shawn Lin Subject: [RFC PATCH 2/6] PCI: rockchip: introduce per-lanes PHYs support Date: Fri, 14 Jul 2017 11:52:42 +0800 Message-Id: <1500004366-241633-1-git-send-email-shawn.lin@rock-chips.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1500004101-240296-1-git-send-email-shawn.lin@rock-chips.com> References: <1500004101-240296-1-git-send-email-shawn.lin@rock-chips.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP We distinguish the legacy PHY with the newer per-lane PHYs by adding legacy_phy flag and consolidate all the phy operations into a single function to simply the code. Note that the legacy phy is still the first option to be searched in order not to break the backward compatibility of DT blob, althoug we use devm_phy_optional_get instead which seams to violate the original statement of pcie-rockchip's DT document. Signed-off-by: Shawn Lin --- drivers/pci/host/pcie-rockchip.c | 138 +++++++++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 26 deletions(-) diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 6632a51..a3dc7bd 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -47,6 +47,7 @@ #define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val) #define ENCODE_LANES(x) ((((x) >> 1) & 3) << 4) +#define MAX_LANE_NUM 4 #define PCIE_CLIENT_BASE 0x0 #define PCIE_CLIENT_CONFIG (PCIE_CLIENT_BASE + 0x00) @@ -210,7 +211,9 @@ struct rockchip_pcie { void __iomem *reg_base; /* DT axi-base */ void __iomem *apb_base; /* DT apb-base */ + bool legacy_phy; struct phy *phy; + struct phy **phys; struct reset_control *core_rst; struct reset_control *mgmt_rst; struct reset_control *mgmt_sticky_rst; @@ -242,6 +245,15 @@ struct rockchip_pcie { phys_addr_t mem_bus_addr; }; +enum phy_ops_type { + PHY_INIT, + PHY_PWR_ON, + PHY_PWR_OFF, + PHY_EXIT, +}; + +const char *ops_name[] = {"init", "power on", "power off", "exit"}; + static u32 rockchip_pcie_read(struct rockchip_pcie *rockchip, u32 reg) { return readl(rockchip->apb_base + reg); @@ -507,6 +519,98 @@ static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip) rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCR); } +static int rockchip_pcie_get_phys(struct rockchip_pcie *rockchip) +{ + struct device *dev = rockchip->dev; + struct phy *phy; + char *name; + u32 i; + + rockchip->phy = devm_phy_optional_get(dev, "pcie-phy"); + if (IS_ERR(rockchip->phy)) { + if (PTR_ERR(rockchip->phy) != -EPROBE_DEFER) + dev_err(dev, "missing phy\n"); + return PTR_ERR(rockchip->phy); + } else if (!rockchip->phy) { + rockchip->legacy_phy = false; + } else { + rockchip->legacy_phy = true; + return 0; + } + + /* per-lane PHYs */ + rockchip->phys = devm_kcalloc(dev, sizeof(phy), MAX_LANE_NUM, + GFP_KERNEL); + if (!rockchip->phys) + return -ENOMEM; + + for (i = 0; i < MAX_LANE_NUM; i++) { + name = kasprintf(GFP_KERNEL, "%s-%u", "pcie-phy", i); + if (!name) + return -ENOMEM; + + phy = devm_of_phy_get(rockchip->dev, + rockchip->dev->of_node, name); + kfree(name); + + if (IS_ERR(phy) && PTR_ERR(phy) == -ENODEV) { + phy = NULL; + } else if (IS_ERR(phy)) { + dev_err(dev, "failed to get per-lane PHY#%u: %ld\n", i, + PTR_ERR(phy)); + return PTR_ERR(phy); + } + + rockchip->phys[i] = phy; + } + + return 0; +} + +static int rockchip_pcie_manipulate_phys(struct rockchip_pcie *rockchip, + enum phy_ops_type type) +{ + int i, phy_num, err; + struct device *dev = rockchip->dev; + struct phy *phy; + + phy_num = rockchip->legacy_phy ? 1 : MAX_LANE_NUM; + + for (i = 0; i < phy_num; i++) { + phy = rockchip->legacy_phy ? rockchip->phy : + rockchip->phys[i]; + switch (type) { + case PHY_INIT: + err = phy_init(phy); + break; + case PHY_PWR_ON: + err = phy_power_on(phy); + break; + case PHY_PWR_OFF: + err = phy_power_off(phy); + break; + case PHY_EXIT: + err = phy_exit(phy); + break; + default: + dev_err(dev, "unsupported phy_ops_type\n"); + return -EOPNOTSUPP; + } + + if (err < 0) { + if (rockchip->legacy_phy) + dev_err(dev, "fail to %s legacy PHY, err %d\n", + ops_name[type], err); + else + dev_err(dev, "fail to %s per-lane PHY#%u, err %d\n", + ops_name[type], i, err); + return err; + } + } + + return 0; +} + /** * rockchip_pcie_init_port - Initialize hardware * @rockchip: PCIe port information @@ -537,11 +641,9 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) return err; } - err = phy_init(rockchip->phy); - if (err < 0) { - dev_err(dev, "fail to init phy, err %d\n", err); + err = rockchip_pcie_manipulate_phys(rockchip, PHY_INIT); + if (err < 0) return err; - } err = reset_control_assert(rockchip->core_rst); if (err) { @@ -602,11 +704,9 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) PCIE_CLIENT_MODE_RC, PCIE_CLIENT_CONFIG); - err = phy_power_on(rockchip->phy); - if (err) { - dev_err(dev, "fail to power on phy, err %d\n", err); + err = rockchip_pcie_manipulate_phys(rockchip, PHY_PWR_ON); + if (err) return err; - } /* * Please don't reorder the deassert sequence of the following @@ -853,20 +953,6 @@ static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int rockchip_pcie_get_phys(struct rockchip_pcie *rockchip) -{ - struct device *dev = rockchip->dev; - - rockchip->phy = devm_phy_get(dev, "pcie-phy"); - if (IS_ERR(rockchip->phy)) { - if (PTR_ERR(rockchip->phy) != -EPROBE_DEFER) - dev_err(dev, "missing phy\n"); - return PTR_ERR(rockchip->phy); - } - - return 0; -} - /** * rockchip_pcie_parse_dt - Parse Device Tree * @rockchip: PCIe port information @@ -1295,8 +1381,8 @@ static int __maybe_unused rockchip_pcie_suspend_noirq(struct device *dev) return ret; } - phy_power_off(rockchip->phy); - phy_exit(rockchip->phy); + rockchip_pcie_manipulate_phys(rockchip, PHY_PWR_OFF); + rockchip_pcie_manipulate_phys(rockchip, PHY_EXIT); clk_disable_unprepare(rockchip->clk_pcie_pm); clk_disable_unprepare(rockchip->hclk_pcie); @@ -1538,8 +1624,8 @@ static int rockchip_pcie_remove(struct platform_device *pdev) pci_unmap_iospace(rockchip->io); irq_domain_remove(rockchip->irq_domain); - phy_power_off(rockchip->phy); - phy_exit(rockchip->phy); + rockchip_pcie_manipulate_phys(rockchip, PHY_PWR_OFF); + rockchip_pcie_manipulate_phys(rockchip, PHY_EXIT); clk_disable_unprepare(rockchip->clk_pcie_pm); clk_disable_unprepare(rockchip->hclk_pcie);