From patchwork Mon Jul 17 07:36:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Lin X-Patchwork-Id: 9844107 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 4382460212 for ; Mon, 17 Jul 2017 07:38:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 34D1727F7F for ; Mon, 17 Jul 2017 07:38:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 299AD27FB6; Mon, 17 Jul 2017 07:38:04 +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=-1.4 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_SORBS_SPAM autolearn=no version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9011C27F7F for ; Mon, 17 Jul 2017 07:38:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=GU+MqgFlHb8RWBxABlamaEvTPl2kNBIpwt7TfocBYlw=; b=mSEYOHQWPFYPObwPBh8qm0N/Xd 4mF6IZSGF5mcOtTk7s6rgcZsLhXkWQhwIjt0WBHvMz+U3jR0zGXvWl0IYZexcKCjIwttCOzhLgNy3 f7xPBTo9ip5L+zqTV0WDpwfo11lpL2aeb2ejL9TpQlk4aVwgEiga9mnKsFeNvjE2O96FdZwQiBv58 KnzKWMVfe2DB/MMqOClM4VhkoAUyOHznlawpufeQDJZRWQE02TeOT80/ba/PB4XhmZ3yuW8rsXgOi WZPXTVzCAp1hGOAn1LZBEUfrU2AU5twtZ5311fRc09sMvwRQhkLpvgHUou++F9pOPjktHC2n/087m A7XY26zQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dX0bT-0007fH-5P; Mon, 17 Jul 2017 07:38:03 +0000 Received: from lucky1.263xmail.com ([211.157.147.133]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dX0bM-0007OT-3j for linux-rockchip@lists.infradead.org; Mon, 17 Jul 2017 07:38:02 +0000 Received: from shawn.lin?rock-chips.com (unknown [192.168.167.204]) by lucky1.263xmail.com (Postfix) with ESMTP id 17F348F7CD; Mon, 17 Jul 2017 15:37:30 +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 EE19E3C7; Mon, 17 Jul 2017 15:37:28 +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 27314FMR65B; Mon, 17 Jul 2017 15:37:30 +0800 (CST) From: Shawn Lin To: Bjorn Helgaas , Rob Herring , Kishon Vijay Abraham I Subject: [PATCH 2/7] PCI: rockchip: introduce per-lanes PHYs support Date: Mon, 17 Jul 2017 15:36:17 +0800 Message-Id: <1500276982-208439-3-git-send-email-shawn.lin@rock-chips.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1500276982-208439-1-git-send-email-shawn.lin@rock-chips.com> References: <1500276982-208439-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-20170717_003756_782305_D8979579 X-CRM114-Status: GOOD ( 15.02 ) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, Brian Norris , Heiko Stuebner , linux-pci@vger.kernel.org, Shawn Lin , Jeffy Chen , linux-rockchip@lists.infradead.org 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 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 | 144 ++++++++++++++++++++++++++++++++------- 1 file changed, 118 insertions(+), 26 deletions(-) diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 6632a51..f755df5 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 *phy_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,104 @@ 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_get(dev, "pcie-phy"); + if (IS_ERR(rockchip->phy)) { + if (PTR_ERR(rockchip->phy) == -EPROBE_DEFER) + return PTR_ERR(rockchip->phy); + dev_dbg(dev, "missing legacy phy, and search for per-lane PHY\n"); + } else { + rockchip->legacy_phy = true; + dev_warn(dev, "legacy phy model is deprecated!\n"); + 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)) { + if (PTR_ERR(phy) != -EPROBE_DEFER) + dev_err(dev, "missing phy for lane %d: %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: + if (phy->init_count > phy_num) + continue; + err = phy_init(phy); + break; + case PHY_PWR_ON: + if (phy->power_count > phy_num) + continue; + err = phy_power_on(phy); + break; + case PHY_PWR_OFF: + if (!phy->power_count) + continue; + err = phy_power_off(phy); + break; + case PHY_EXIT: + if (!phy->init_count) + continue; + 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", + phy_ops_name[type], err); + else + dev_err(dev, "fail to %s per-lane PHY#%u, err %d\n", + phy_ops_name[type], i, err); + return err; + } + } + + return 0; +} + /** * rockchip_pcie_init_port - Initialize hardware * @rockchip: PCIe port information @@ -537,11 +647,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 +710,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 +959,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 +1387,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 +1630,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);