Loading arch/arm/boot/dts/qti/apq8084.dtsi +2 −4 Original line number Diff line number Diff line Loading @@ -2013,10 +2013,8 @@ vccq2-max-microamp = <145000>; clock-names = "core_clk_src", "core_clk", "bus_clk", "iface_clk", "ref_clk", "rx_lane0_sync_clk", "tx_lane0_sync_clk", "rx_lane1_sync_clk", "tx_lane1_sync_clk"; max-clock-frequency-hz = <200000000>, <0>, <0>, <0>, <0>, <0>, <0>, <0>, <0>; "ref_clk"; max-clock-frequency-hz = <200000000>, <0>, <0>, <0>, <0>; qcom,msm-bus,name = "ufs1"; qcom,msm-bus,num-cases = <22>; Loading drivers/scsi/ufs/ufs-msm.c +138 −6 Original line number Diff line number Diff line Loading @@ -851,6 +851,116 @@ static void msm_ufs_phy_calibrate(struct msm_ufs_phy *phy) mb(); } static int msm_ufs_host_clk_get(struct device *dev, const char *name, struct clk **clk_out) { struct clk *clk; int err = 0; clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { err = PTR_ERR(clk); dev_err(dev, "%s: failed to get %s err %d", __func__, name, err); } else { *clk_out = clk; } return err; } static int msm_ufs_host_clk_enable(struct device *dev, const char *name, struct clk *clk) { int err = 0; err = clk_prepare_enable(clk); if (err) dev_err(dev, "%s: %s enable failed %d\n", __func__, name, err); return err; } static void msm_ufs_disable_lane_clks(struct msm_ufs_host *host) { if (!host->is_lane_clks_enabled) return; clk_disable_unprepare(host->tx_l1_sync_clk); clk_disable_unprepare(host->tx_l0_sync_clk); clk_disable_unprepare(host->rx_l1_sync_clk); clk_disable_unprepare(host->rx_l0_sync_clk); host->is_lane_clks_enabled = false; } static int msm_ufs_enable_lane_clks(struct msm_ufs_host *host) { int err = 0; struct device *dev = host->hba->dev; if (host->is_lane_clks_enabled) return 0; err = msm_ufs_host_clk_enable(dev, "rx_lane0_sync_clk", host->rx_l0_sync_clk); if (err) goto out; err = msm_ufs_host_clk_enable(dev, "rx_lane1_sync_clk", host->rx_l1_sync_clk); if (err) goto disable_rx_l0; err = msm_ufs_host_clk_enable(dev, "tx_lane0_sync_clk", host->tx_l0_sync_clk); if (err) goto disable_rx_l1; err = msm_ufs_host_clk_enable(dev, "tx_lane1_sync_clk", host->tx_l1_sync_clk); if (err) goto disable_tx_l0; host->is_lane_clks_enabled = true; goto out; disable_tx_l0: clk_disable_unprepare(host->tx_l0_sync_clk); disable_rx_l1: clk_disable_unprepare(host->rx_l1_sync_clk); disable_rx_l0: clk_disable_unprepare(host->rx_l0_sync_clk); out: return err; } static int msm_ufs_init_lane_clks(struct msm_ufs_host *host) { int err = 0; struct device *dev = host->hba->dev; err = msm_ufs_host_clk_get(dev, "rx_lane0_sync_clk", &host->rx_l0_sync_clk); if (err) goto out; err = msm_ufs_host_clk_get(dev, "rx_lane1_sync_clk", &host->rx_l1_sync_clk); if (err) goto out; err = msm_ufs_host_clk_get(dev, "tx_lane0_sync_clk", &host->tx_l0_sync_clk); if (err) goto out; err = msm_ufs_host_clk_get(dev, "tx_lane1_sync_clk", &host->tx_l1_sync_clk); out: return err; } static int msm_ufs_enable_tx_lanes(struct ufs_hba *hba) { int err; Loading Loading @@ -1013,10 +1123,17 @@ static int msm_ufs_hce_enable_notify(struct ufs_hba *hba, bool status) /* poll for PCS_READY for max. 1sec */ err = readl_poll_timeout(phy->mmio + UFS_PHY_PCS_READY_STATUS, val, (val & MASK_PCS_READY), 10, 1000000); if (err) if (err) { dev_err(phy->dev, "%s: phy init failed, %d\n", __func__, err); break; } /* * The PHY PLL output is the source of tx/rx lane symbol clocks. * Hence, enable the lane clocks only after PHY is initialized. */ err = msm_ufs_enable_lane_clks(host); break; case POST_CHANGE: /* check if UFS PHY moved from DISABLED to HIBERN8 */ err = msm_ufs_check_hibern8(hba); Loading Loading @@ -1060,6 +1177,12 @@ static int msm_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) return 0; if (ufshcd_is_link_off(hba)) { /* * Disable the tx/rx lane symbol clocks before PHY is * powered down as the PLL source should be disabled * after downstream clocks are disabled. */ msm_ufs_disable_lane_clks(host); msm_ufs_phy_power_off(phy); goto out; } Loading Loading @@ -1698,7 +1821,11 @@ static int msm_ufs_init(struct ufs_hba *hba) err = msm_ufs_phy_power_on(phy); if (err) goto out_host_free; goto out_unregister_bus; err = msm_ufs_init_lane_clks(host); if (err) goto out_disable_phy; msm_ufs_advertise_quirks(hba); if (hba->quirks & UFSHCD_QUIRK_BROKEN_SUSPEND) { Loading Loading @@ -1727,11 +1854,15 @@ static int msm_ufs_init(struct ufs_hba *hba) hba->spm_lvl = UFS_PM_LVL_3; } goto out; out_disable_phy: msm_ufs_phy_power_off(phy); out_unregister_bus: msm_bus_scale_unregister_client(host->bus_vote.client_handle); out_host_free: if (err) { devm_kfree(dev, host); hba->priv = NULL; } out: return err; } Loading @@ -1742,6 +1873,7 @@ static void msm_ufs_exit(struct ufs_hba *hba) struct msm_ufs_phy *phy = host->phy; msm_bus_scale_unregister_client(host->bus_vote.client_handle); msm_ufs_disable_lane_clks(host); msm_ufs_phy_power_off(phy); } Loading drivers/scsi/ufs/ufs-msm.h +5 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,11 @@ struct msm_ufs_host { struct ufs_hba *hba; struct msm_ufs_bus_vote bus_vote; struct ufs_pa_layer_attr dev_req_params; struct clk *rx_l0_sync_clk; struct clk *tx_l0_sync_clk; struct clk *rx_l1_sync_clk; struct clk *tx_l1_sync_clk; bool is_lane_clks_enabled; }; static unsigned long Loading Loading
arch/arm/boot/dts/qti/apq8084.dtsi +2 −4 Original line number Diff line number Diff line Loading @@ -2013,10 +2013,8 @@ vccq2-max-microamp = <145000>; clock-names = "core_clk_src", "core_clk", "bus_clk", "iface_clk", "ref_clk", "rx_lane0_sync_clk", "tx_lane0_sync_clk", "rx_lane1_sync_clk", "tx_lane1_sync_clk"; max-clock-frequency-hz = <200000000>, <0>, <0>, <0>, <0>, <0>, <0>, <0>, <0>; "ref_clk"; max-clock-frequency-hz = <200000000>, <0>, <0>, <0>, <0>; qcom,msm-bus,name = "ufs1"; qcom,msm-bus,num-cases = <22>; Loading
drivers/scsi/ufs/ufs-msm.c +138 −6 Original line number Diff line number Diff line Loading @@ -851,6 +851,116 @@ static void msm_ufs_phy_calibrate(struct msm_ufs_phy *phy) mb(); } static int msm_ufs_host_clk_get(struct device *dev, const char *name, struct clk **clk_out) { struct clk *clk; int err = 0; clk = devm_clk_get(dev, name); if (IS_ERR(clk)) { err = PTR_ERR(clk); dev_err(dev, "%s: failed to get %s err %d", __func__, name, err); } else { *clk_out = clk; } return err; } static int msm_ufs_host_clk_enable(struct device *dev, const char *name, struct clk *clk) { int err = 0; err = clk_prepare_enable(clk); if (err) dev_err(dev, "%s: %s enable failed %d\n", __func__, name, err); return err; } static void msm_ufs_disable_lane_clks(struct msm_ufs_host *host) { if (!host->is_lane_clks_enabled) return; clk_disable_unprepare(host->tx_l1_sync_clk); clk_disable_unprepare(host->tx_l0_sync_clk); clk_disable_unprepare(host->rx_l1_sync_clk); clk_disable_unprepare(host->rx_l0_sync_clk); host->is_lane_clks_enabled = false; } static int msm_ufs_enable_lane_clks(struct msm_ufs_host *host) { int err = 0; struct device *dev = host->hba->dev; if (host->is_lane_clks_enabled) return 0; err = msm_ufs_host_clk_enable(dev, "rx_lane0_sync_clk", host->rx_l0_sync_clk); if (err) goto out; err = msm_ufs_host_clk_enable(dev, "rx_lane1_sync_clk", host->rx_l1_sync_clk); if (err) goto disable_rx_l0; err = msm_ufs_host_clk_enable(dev, "tx_lane0_sync_clk", host->tx_l0_sync_clk); if (err) goto disable_rx_l1; err = msm_ufs_host_clk_enable(dev, "tx_lane1_sync_clk", host->tx_l1_sync_clk); if (err) goto disable_tx_l0; host->is_lane_clks_enabled = true; goto out; disable_tx_l0: clk_disable_unprepare(host->tx_l0_sync_clk); disable_rx_l1: clk_disable_unprepare(host->rx_l1_sync_clk); disable_rx_l0: clk_disable_unprepare(host->rx_l0_sync_clk); out: return err; } static int msm_ufs_init_lane_clks(struct msm_ufs_host *host) { int err = 0; struct device *dev = host->hba->dev; err = msm_ufs_host_clk_get(dev, "rx_lane0_sync_clk", &host->rx_l0_sync_clk); if (err) goto out; err = msm_ufs_host_clk_get(dev, "rx_lane1_sync_clk", &host->rx_l1_sync_clk); if (err) goto out; err = msm_ufs_host_clk_get(dev, "tx_lane0_sync_clk", &host->tx_l0_sync_clk); if (err) goto out; err = msm_ufs_host_clk_get(dev, "tx_lane1_sync_clk", &host->tx_l1_sync_clk); out: return err; } static int msm_ufs_enable_tx_lanes(struct ufs_hba *hba) { int err; Loading Loading @@ -1013,10 +1123,17 @@ static int msm_ufs_hce_enable_notify(struct ufs_hba *hba, bool status) /* poll for PCS_READY for max. 1sec */ err = readl_poll_timeout(phy->mmio + UFS_PHY_PCS_READY_STATUS, val, (val & MASK_PCS_READY), 10, 1000000); if (err) if (err) { dev_err(phy->dev, "%s: phy init failed, %d\n", __func__, err); break; } /* * The PHY PLL output is the source of tx/rx lane symbol clocks. * Hence, enable the lane clocks only after PHY is initialized. */ err = msm_ufs_enable_lane_clks(host); break; case POST_CHANGE: /* check if UFS PHY moved from DISABLED to HIBERN8 */ err = msm_ufs_check_hibern8(hba); Loading Loading @@ -1060,6 +1177,12 @@ static int msm_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) return 0; if (ufshcd_is_link_off(hba)) { /* * Disable the tx/rx lane symbol clocks before PHY is * powered down as the PLL source should be disabled * after downstream clocks are disabled. */ msm_ufs_disable_lane_clks(host); msm_ufs_phy_power_off(phy); goto out; } Loading Loading @@ -1698,7 +1821,11 @@ static int msm_ufs_init(struct ufs_hba *hba) err = msm_ufs_phy_power_on(phy); if (err) goto out_host_free; goto out_unregister_bus; err = msm_ufs_init_lane_clks(host); if (err) goto out_disable_phy; msm_ufs_advertise_quirks(hba); if (hba->quirks & UFSHCD_QUIRK_BROKEN_SUSPEND) { Loading Loading @@ -1727,11 +1854,15 @@ static int msm_ufs_init(struct ufs_hba *hba) hba->spm_lvl = UFS_PM_LVL_3; } goto out; out_disable_phy: msm_ufs_phy_power_off(phy); out_unregister_bus: msm_bus_scale_unregister_client(host->bus_vote.client_handle); out_host_free: if (err) { devm_kfree(dev, host); hba->priv = NULL; } out: return err; } Loading @@ -1742,6 +1873,7 @@ static void msm_ufs_exit(struct ufs_hba *hba) struct msm_ufs_phy *phy = host->phy; msm_bus_scale_unregister_client(host->bus_vote.client_handle); msm_ufs_disable_lane_clks(host); msm_ufs_phy_power_off(phy); } Loading
drivers/scsi/ufs/ufs-msm.h +5 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,11 @@ struct msm_ufs_host { struct ufs_hba *hba; struct msm_ufs_bus_vote bus_vote; struct ufs_pa_layer_attr dev_req_params; struct clk *rx_l0_sync_clk; struct clk *tx_l0_sync_clk; struct clk *rx_l1_sync_clk; struct clk *tx_l1_sync_clk; bool is_lane_clks_enabled; }; static unsigned long Loading