diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h b/drivers/phy/qualcomm/phy-qcom-ufs-i.h index 84e3aa525a4a..99447cbf8c97 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, 2019, Linux Foundation. All rights reserved. */ #ifndef UFS_QCOM_PHY_I_H_ @@ -97,6 +97,7 @@ struct ufs_qcom_phy { struct ufs_qcom_phy_specific_ops *phy_spec_ops; enum phy_mode mode; + int submode; struct reset_control *ufs_reset; }; @@ -114,7 +115,8 @@ struct ufs_qcom_phy { * Rx line config */ struct ufs_qcom_phy_specific_ops { - int (*calibrate)(struct ufs_qcom_phy *ufs_qcom_phy, bool is_rate_B); + int (*calibrate)(struct ufs_qcom_phy *ufs_qcom_phy, bool is_rate_B, + bool is_g4); void (*start_serdes)(struct ufs_qcom_phy *phy); int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy); void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val); diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c index 54b355bfc24c..7f5b03cfdaff 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, 2019, Linux Foundation. All rights reserved. */ #include "phy-qcom-ufs-qmp-14nm.h" @@ -10,7 +10,7 @@ static int ufs_qcom_phy_qmp_14nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, - bool is_rate_B) + bool is_rate_B, bool is_g4) { int tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A); int tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); @@ -44,6 +44,8 @@ int ufs_qcom_phy_qmp_14nm_set_mode(struct phy *generic_phy, if (mode > 0) phy_common->mode = mode; + phy_common->submode = submode; + return 0; } diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c index 3e9d8b71e995..5113a6e70fbd 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2015, 2019, Linux Foundation. All rights reserved. */ #include "phy-qcom-ufs-qmp-20nm.h" @@ -9,7 +9,7 @@ static int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, - bool is_rate_B) + bool is_rate_B, bool is_g4) { struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; int tbl_size_A, tbl_size_B; @@ -63,6 +63,8 @@ int ufs_qcom_phy_qmp_20nm_set_mode(struct phy *generic_phy, if (mode > 0) phy_common->mode = mode; + phy_common->submode = submode; + return 0; } diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qrbtc-sdm845.c b/drivers/phy/qualcomm/phy-qcom-ufs-qrbtc-sdm845.c index f6c211426489..8b53a81ec7db 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qrbtc-sdm845.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qrbtc-sdm845.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016, Linux Foundation. All rights reserved. + * Copyright (c) 2016, 2019, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,7 +19,7 @@ static int ufs_qcom_phy_qrbtc_sdm845_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, - bool is_rate_B) + bool is_rate_B, bool is_g4) { int err; int tbl_size_A, tbl_size_B; diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index fbf9a2d81b7c..a692465d8f68 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -599,37 +599,9 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy) struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); struct device *dev = phy_common->dev; bool is_rate_B = false; + bool is_gear4 = false; int err; - err = ufs_qcom_phy_get_reset(phy_common); - if (err) - return err; - - err = reset_control_assert(phy_common->ufs_reset); - if (err) - return err; - - if (phy_common->mode == PHY_MODE_UFS_HS_B) - is_rate_B = true; - - err = phy_common->phy_spec_ops->calibrate(phy_common, is_rate_B); - if (err) - return err; - - err = reset_control_deassert(phy_common->ufs_reset); - if (err) { - dev_err(dev, "Failed to assert UFS PHY reset"); - return err; - } - - err = ufs_qcom_phy_start_serdes(phy_common); - if (err) - return err; - - err = ufs_qcom_phy_is_pcs_ready(phy_common); - if (err) - return err; - err = ufs_qcom_phy_enable_vreg(dev, &phy_common->vdda_phy); if (err) { dev_err(dev, "%s enable vdda_phy failed, err=%d\n", @@ -672,6 +644,40 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy) } } + err = ufs_qcom_phy_get_reset(phy_common); + if (err) + goto out_disable_ref_clk; + + err = reset_control_assert(phy_common->ufs_reset); + if (err) { + dev_err(dev, "Failed to assert UFS PHY reset\n"); + goto out_disable_ref_clk; + } + + if (phy_common->mode == PHY_MODE_UFS_HS_B) + is_rate_B = true; + + is_gear4 = !!phy_common->submode; + + err = phy_common->phy_spec_ops->calibrate(phy_common, is_rate_B, + is_gear4); + if (err) + goto out_disable_ref_clk; + + err = reset_control_deassert(phy_common->ufs_reset); + if (err) { + dev_err(dev, "Failed to deassert UFS PHY reset\n"); + goto out_disable_ref_clk; + } + + err = ufs_qcom_phy_start_serdes(phy_common); + if (err) + goto out_disable_ref_clk; + + err = ufs_qcom_phy_is_pcs_ready(phy_common); + if (err) + goto out_disable_ref_clk; + goto out; out_disable_ref_clk: