From 73597f6e6071735ae6e9d45ade0b7af9a14ef938 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 20 Aug 2019 00:48:07 -0700 Subject: [PATCH 1/9] phy: qcom-ufs: remove failure when rx/tx_iface_clk are absent Since in future UFS Phy's the tx_iface_clk and rx_iface_clk are no longer exist, we should not fail when their initialization fail, but rather just report with debug message. Change-Id: I87e4deca632d4d4ee9e35a03f2fc9c22987255b3 Signed-off-by: Yaniv Gardi [cang@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Can Guo --- drivers/phy/qualcomm/phy-qcom-ufs.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index 9194cf470509..af18fa467555 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, Linux Foundation. All rights reserved. */ #include "phy-qcom-ufs-i.h" @@ -184,16 +184,24 @@ int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common) if (of_device_is_compatible(phy_common->dev->of_node, "qcom,msm8996-ufs-phy-qmp-14nm")) goto skip_txrx_clk; - + /* + * tx_iface_clk does not exist in newer version of ufs-phy HW, + * so don't return error if it is not found + */ err = ufs_qcom_phy_clk_get(phy_common->dev, "tx_iface_clk", &phy_common->tx_iface_clk); if (err) - goto out; - + dev_dbg(phy_common->dev, "%s: failed to get tx_iface_clk\n", + __func__); + /* + * rx_iface_clk does not exist in newer version of ufs-phy HW, + * so don't return error if it is not found + */ err = ufs_qcom_phy_clk_get(phy_common->dev, "rx_iface_clk", &phy_common->rx_iface_clk); if (err) - goto out; + dev_dbg(phy_common->dev, "%s: failed to get rx_iface_clk\n", + __func__); skip_txrx_clk: err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk_src", @@ -445,6 +453,9 @@ static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy) if (phy->is_iface_clk_enabled) goto out; + if (!phy->tx_iface_clk) + goto out; + ret = clk_prepare_enable(phy->tx_iface_clk); if (ret) { dev_err(phy->dev, "%s: tx_iface_clk enable failed %d\n", @@ -467,6 +478,9 @@ out: /* Turn OFF M-PHY RMMI interface clocks */ static void ufs_qcom_phy_disable_iface_clk(struct ufs_qcom_phy *phy) { + if (!phy->tx_iface_clk) + return; + if (phy->is_iface_clk_enabled) { clk_disable_unprepare(phy->tx_iface_clk); clk_disable_unprepare(phy->rx_iface_clk); From 9e33a5d6ae5839f6799d2b2b5dd6035f413301b9 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 20 Aug 2019 00:52:05 -0700 Subject: [PATCH 2/9] phy: qcom-ufs: don't probe for "dev_ref_clk_ctrl_mem" This is handled in the ufs platform init. Drop the upstream change that was missed in the ufs driver port to 4.4 kernel. Change-Id: Ia3305f2b4f6c6eeafe3866833f2c98e186ad6632 Signed-off-by: Venkat Gopalakrishnan [cang@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Can Guo --- drivers/phy/qualcomm/phy-qcom-ufs.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index af18fa467555..29806f20f6f1 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -89,13 +89,6 @@ int ufs_qcom_phy_base_init(struct platform_device *pdev, return err; } - /* "dev_ref_clk_ctrl_mem" is optional resource */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "dev_ref_clk_ctrl_mem"); - phy_common->dev_ref_clk_ctrl_mmio = devm_ioremap_resource(dev, res); - if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio)) - phy_common->dev_ref_clk_ctrl_mmio = NULL; - return 0; } From ce32edf88ce4c1408c498f883e4d7fbfdfe58553 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 20 Aug 2019 00:53:01 -0700 Subject: [PATCH 3/9] phy: qcom-ufs: add optional ref aux clk Newer platforms need an additional ref aux clk to be enabled, add support for the new ref aux clk and make it optional as its not needed by other phy versions. Change-Id: I5e04980eb451b193e9c024bfe35383d10d17feff Signed-off-by: Venkat Gopalakrishnan [cang@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Can Guo --- drivers/phy/qualcomm/phy-qcom-ufs-i.h | 1 + drivers/phy/qualcomm/phy-qcom-ufs.c | 32 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h b/drivers/phy/qualcomm/phy-qcom-ufs-i.h index 282afa4b5561..5e0c9fc7282c 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h @@ -66,6 +66,7 @@ struct ufs_qcom_phy { struct clk *ref_clk_src; struct clk *ref_clk_parent; struct clk *ref_clk; + struct clk *ref_aux_clk; bool is_ref_clk_enabled; bool is_dev_ref_clk_enabled; struct ufs_qcom_phy_vreg vdda_pll; diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index 29806f20f6f1..5baa68ba2401 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -211,7 +211,15 @@ skip_txrx_clk: err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk", &phy_common->ref_clk); + if (err) + goto out; + /* + * "ref_aux_clk" is optional and only supported by certain + * phy versions, don't abort init if it's not found. + */ + __ufs_qcom_phy_clk_get(phy_common->dev, "ref_aux_clk", + &phy_common->ref_aux_clk, false); out: return err; } @@ -389,9 +397,26 @@ static int ufs_qcom_phy_enable_ref_clk(struct ufs_qcom_phy *phy) goto out_disable_parent; } + /* + * "ref_aux_clk" is optional clock and only supported by certain + * phy versions, hence make sure that clk reference is available + * before trying to enable the clock. + */ + if (phy->ref_aux_clk) { + ret = clk_prepare_enable(phy->ref_aux_clk); + if (ret) { + dev_err(phy->dev, "%s: ref_aux_clk enable failed %d\n", + __func__, ret); + goto out_disable_ref; + } + } + phy->is_ref_clk_enabled = true; goto out; +out_disable_ref: + if (phy->ref_clk) + clk_disable_unprepare(phy->ref_clk); out_disable_parent: if (phy->ref_clk_parent) clk_disable_unprepare(phy->ref_clk_parent); @@ -426,6 +451,13 @@ out: static void ufs_qcom_phy_disable_ref_clk(struct ufs_qcom_phy *phy) { if (phy->is_ref_clk_enabled) { + /* + * "ref_aux_clk" is optional clock and only supported by + * certain phy versions, hence make sure that clk reference + * is available before trying to disable the clock. + */ + if (phy->ref_aux_clk) + clk_disable_unprepare(phy->ref_aux_clk); clk_disable_unprepare(phy->ref_clk); /* * "ref_clk_parent" is optional clock hence make sure that clk From 9542a206ae8ed6bb0064ae531b763d7b0bb8ec2f Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 20 Aug 2019 00:55:21 -0700 Subject: [PATCH 4/9] phy: qcom-ufs: remove warnings for optional clocks tx_iface_clk and rx_iface_clk does not exist in newer version of ufs-phy HW, hence remove the missing clk warnings for them. Change-Id: Ic8dd3e9521159ce8da064da38cfa12e75f07209f Signed-off-by: Venkat Gopalakrishnan [cang@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Can Guo --- drivers/phy/qualcomm/phy-qcom-ufs.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index 5baa68ba2401..d6789c5161c7 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -181,20 +181,15 @@ int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common) * tx_iface_clk does not exist in newer version of ufs-phy HW, * so don't return error if it is not found */ - err = ufs_qcom_phy_clk_get(phy_common->dev, "tx_iface_clk", - &phy_common->tx_iface_clk); - if (err) - dev_dbg(phy_common->dev, "%s: failed to get tx_iface_clk\n", - __func__); + __ufs_qcom_phy_clk_get(phy_common->dev, "tx_iface_clk", + &phy_common->tx_iface_clk, false); + /* * rx_iface_clk does not exist in newer version of ufs-phy HW, * so don't return error if it is not found */ - err = ufs_qcom_phy_clk_get(phy_common->dev, "rx_iface_clk", - &phy_common->rx_iface_clk); - if (err) - dev_dbg(phy_common->dev, "%s: failed to get rx_iface_clk\n", - __func__); + __ufs_qcom_phy_clk_get(phy_common->dev, "rx_iface_clk", + &phy_common->rx_iface_clk, false); skip_txrx_clk: err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk_src", From d44fa17860ecc59d4180bf6b1ce4fdad7cd4d089 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 20 Aug 2019 00:56:46 -0700 Subject: [PATCH 5/9] phy: qcom-ufs: parse ref-clk details prior to resource request Do not request a resource if the ref clk regulator details are not defined in ufs phy node. Change-Id: I10eb426d4407388681340cb71fe9e761794dc298 Signed-off-by: Asutosh Das [cang@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Can Guo --- drivers/phy/qualcomm/phy-qcom-ufs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index d6789c5161c7..a83d5eee5392 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -228,6 +228,14 @@ static int ufs_qcom_phy_init_vreg(struct device *dev, char prop_name[MAX_PROP_NAME]; + if (dev->of_node) { + snprintf(prop_name, MAX_PROP_NAME, "%s-supply", name); + if (!of_parse_phandle(dev->of_node, prop_name, 0)) { + dev_dbg(dev, "No vreg data found for %s\n", prop_name); + return -ENODATA; + } + } + vreg->name = name; vreg->reg = devm_regulator_get(dev, name); if (IS_ERR(vreg->reg)) { From fee035811dffba38478632388f52fe9ccc0cf724 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 20 Aug 2019 00:57:28 -0700 Subject: [PATCH 6/9] phy: qcom-ufs: set no runtime PM callbacks flag UFS PHY power management is managed by its parent (UFS host controller) hence set the no runtime PM callbacks flag on UFS PHY device to avoid any accidental attempt to call the PM callbacks for PHY device. Change-Id: I06e6b140a98233e30d406754f0cdcdd27c834357 Signed-off-by: Subhash Jadavani Signed-off-by: Can Guo --- drivers/phy/qualcomm/phy-qcom-ufs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index a83d5eee5392..e1dde9740069 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -123,6 +123,14 @@ struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, goto out; } + /* + * UFS PHY power management is managed by its parent (UFS host + * controller) hence set the no runtime PM callbacks flag + * on UFS PHY device to avoid any accidental attempt to call the + * PM callbacks for PHY device. + */ + pm_runtime_no_callbacks(&generic_phy->dev); + common_cfg->phy_spec_ops = phy_spec_ops; common_cfg->dev = dev; From 427b10e68e236ec9ed0b01c29e14e01f2ffe4906 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 20 Aug 2019 00:58:46 -0700 Subject: [PATCH 7/9] phy: qcom-ufs: separate out 2 lanes configuration Some platforms have 2 UFS PHY instances, one instance supports 2-lane while other instance supports only 1-lane. This change separates out the 2nd lane configuration from 1-lane configuration so that we can apply the 2nd lane configuration only if needed. Change-Id: Idcf8aaa8ed7a9662c0f4186e5a28d2405f8fd5fc Signed-off-by: Subhash Jadavani [cang@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Can Guo --- drivers/phy/qualcomm/phy-qcom-ufs-i.h | 4 ++++ drivers/phy/qualcomm/phy-qcom-ufs.c | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h b/drivers/phy/qualcomm/phy-qcom-ufs-i.h index 5e0c9fc7282c..84e3aa525a4a 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h @@ -72,6 +72,10 @@ struct ufs_qcom_phy { struct ufs_qcom_phy_vreg vdda_pll; struct ufs_qcom_phy_vreg vdda_phy; struct ufs_qcom_phy_vreg vddp_ref_clk; + + /* Number of lanes available (1 or 2) for Rx/Tx */ + u32 lanes_per_direction; + unsigned int quirks; /* diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index e1dde9740069..6c7f17ef6ece 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -13,6 +13,8 @@ #define VDDP_REF_CLK_MIN_UV 1200000 #define VDDP_REF_CLK_MAX_UV 1200000 +#define UFS_PHY_DEFAULT_LANES_PER_DIRECTION 1 + int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A, @@ -123,6 +125,11 @@ struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, goto out; } + if (of_property_read_u32(dev->of_node, "lanes-per-direction", + &common_cfg->lanes_per_direction)) + common_cfg->lanes_per_direction = + UFS_PHY_DEFAULT_LANES_PER_DIRECTION; + /* * UFS PHY power management is managed by its parent (UFS host * controller) hence set the no runtime PM callbacks flag From a686b527a303fbcaa561168ee72ac0c89b2ba887 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 20 Aug 2019 01:01:54 -0700 Subject: [PATCH 8/9] phy: qcom-ufs: make ref_clk as optional Per newer UFS PHY design, some platforms may not have the ON/OFF control for reference clock, hence this clock may be optional. Change-Id: I26edd35970e88a8d17edded399b63c5d3cc7f5d9 Signed-off-by: Can Guo --- drivers/phy/qualcomm/phy-qcom-ufs.c | 35 ++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index 6c7f17ef6ece..326a52146b48 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -219,10 +219,12 @@ skip_txrx_clk: __ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk_parent", &phy_common->ref_clk_parent, false); - err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk", - &phy_common->ref_clk); - if (err) - goto out; + /* + * Some platforms may not have the ON/OFF control for reference clock, + * hence this clock may be optional. + */ + __ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk", + &phy_common->ref_clk, false); /* * "ref_aux_clk" is optional and only supported by certain @@ -408,11 +410,17 @@ static int ufs_qcom_phy_enable_ref_clk(struct ufs_qcom_phy *phy) } } - ret = clk_prepare_enable(phy->ref_clk); - if (ret) { - dev_err(phy->dev, "%s: ref_clk enable failed %d\n", - __func__, ret); - goto out_disable_parent; + /* + * "ref_clk" is optional clock hence make sure that clk reference + * is available before trying to enable the clock. + */ + if (phy->ref_clk) { + ret = clk_prepare_enable(phy->ref_clk); + if (ret) { + dev_err(phy->dev, "%s: ref_clk enable failed %d\n", + __func__, ret); + goto out_disable_parent; + } } /* @@ -476,7 +484,14 @@ static void ufs_qcom_phy_disable_ref_clk(struct ufs_qcom_phy *phy) */ if (phy->ref_aux_clk) clk_disable_unprepare(phy->ref_aux_clk); - clk_disable_unprepare(phy->ref_clk); + + /* + * "ref_clk" is optional clock hence make sure that clk + * reference is available before trying to disable the clock. + */ + if (phy->ref_clk) + clk_disable_unprepare(phy->ref_clk); + /* * "ref_clk_parent" is optional clock hence make sure that clk * reference is available before trying to disable the clock. From 5935b509daec38e82c8cd6437c432ff92c812bbb Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 20 Aug 2019 01:03:29 -0700 Subject: [PATCH 9/9] phy: qcom-ufs: don't error out if vddp-ref-clk-supply is absent vddp-ref-clk-supply is controlled by UFS host, so it can be absent in UFS PHY's DT and shouldn't be considered as error. Change-Id: I7f8af258c59851ccd8adceb73f9a6da62472e915 Signed-off-by: Can Guo --- drivers/phy/qualcomm/phy-qcom-ufs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index 326a52146b48..fbf9a2d81b7c 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -309,7 +309,7 @@ int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common) if (err) goto out; - err = ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk, + ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk, "vddp-ref-clk"); out: