scsi: ufs-qcom: change device reference clock control
As of HW major version 2, bit 'UFS_DEV_REF_CLK_EN' which is used to gate/ungate the ref_clk to external UFS device, was moved into the UFS register space to UFS_CFG1 register. This change adds support to appropriately control the device reference clock and it also adds the missing documentation for the device reference clock control register address space. Change-Id: I66a6a75dc5a1cf130b1cee90ae20f9f950edfb3a Signed-off-by: Gilad Broner <gbroner@codeaurora.org> [subhashj@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
parent
7ae3423485
commit
4ad04d8bc5
3 changed files with 35 additions and 30 deletions
|
@ -11,6 +11,8 @@ Required properties:
|
||||||
"qcom,ufshc"
|
"qcom,ufshc"
|
||||||
- interrupts : <interrupt mapping for UFS host controller IRQ>
|
- interrupts : <interrupt mapping for UFS host controller IRQ>
|
||||||
- reg : <registers mapping>
|
- reg : <registers mapping>
|
||||||
|
first entry should contain UFS host controller register address space (mandatory),
|
||||||
|
second entry is the device ref. clock control register map (optional).
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- phys : phandle to UFS PHY node
|
- phys : phandle to UFS PHY node
|
||||||
|
@ -57,7 +59,7 @@ regulators or clocks are always on.
|
||||||
Example:
|
Example:
|
||||||
ufshc@0xfc598000 {
|
ufshc@0xfc598000 {
|
||||||
compatible = "jedec,ufs-1.1";
|
compatible = "jedec,ufs-1.1";
|
||||||
reg = <0xfc598000 0x800>;
|
reg = <0xfc598000 0x800>, <0xfd512074 0x4>;
|
||||||
interrupts = <0 28 0>;
|
interrupts = <0 28 0>;
|
||||||
|
|
||||||
ufs-qcom-crypto = <&ufs_ice>;
|
ufs-qcom-crypto = <&ufs_ice>;
|
||||||
|
|
|
@ -801,17 +801,16 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define UFS_REF_CLK_EN (1 << 5)
|
static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable)
|
||||||
static void ufs_qcom_enable_dev_ref_clk(struct ufs_qcom_host *host, bool enable)
|
|
||||||
{
|
{
|
||||||
if (host->dev_ref_clk_ctrl_mmio &&
|
if (host->dev_ref_clk_ctrl_mmio &&
|
||||||
(enable ^ host->is_dev_ref_clk_enabled)) {
|
(enable ^ host->is_dev_ref_clk_enabled)) {
|
||||||
u32 temp = readl_relaxed(host->dev_ref_clk_ctrl_mmio);
|
u32 temp = readl_relaxed(host->dev_ref_clk_ctrl_mmio);
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
temp |= UFS_REF_CLK_EN;
|
temp |= host->dev_ref_clk_en_mask;
|
||||||
else
|
else
|
||||||
temp &= ~UFS_REF_CLK_EN;
|
temp &= ~host->dev_ref_clk_en_mask;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are here to disable this clock it might be immediately
|
* If we are here to disable this clock it might be immediately
|
||||||
|
@ -885,7 +884,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
|
||||||
/* enable the device ref clock before changing to HS mode */
|
/* enable the device ref clock before changing to HS mode */
|
||||||
if (!ufshcd_is_hs_mode(&hba->pwr_info) &&
|
if (!ufshcd_is_hs_mode(&hba->pwr_info) &&
|
||||||
ufshcd_is_hs_mode(dev_req_params))
|
ufshcd_is_hs_mode(dev_req_params))
|
||||||
ufs_qcom_enable_dev_ref_clk(host, true);
|
ufs_qcom_dev_ref_clk_ctrl(host, true);
|
||||||
break;
|
break;
|
||||||
case POST_CHANGE:
|
case POST_CHANGE:
|
||||||
if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
|
if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
|
||||||
|
@ -917,7 +916,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
|
||||||
/* disable the device ref clock if entered PWM mode */
|
/* disable the device ref clock if entered PWM mode */
|
||||||
if (ufshcd_is_hs_mode(&hba->pwr_info) &&
|
if (ufshcd_is_hs_mode(&hba->pwr_info) &&
|
||||||
!ufshcd_is_hs_mode(dev_req_params))
|
!ufshcd_is_hs_mode(dev_req_params))
|
||||||
ufs_qcom_enable_dev_ref_clk(host, false);
|
ufs_qcom_dev_ref_clk_ctrl(host, false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
@ -1075,7 +1074,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
|
||||||
}
|
}
|
||||||
/* enable the device ref clock for HS mode*/
|
/* enable the device ref clock for HS mode*/
|
||||||
if (ufshcd_is_hs_mode(&hba->pwr_info))
|
if (ufshcd_is_hs_mode(&hba->pwr_info))
|
||||||
ufs_qcom_enable_dev_ref_clk(host, true);
|
ufs_qcom_dev_ref_clk_ctrl(host, true);
|
||||||
vote = host->bus_vote.saved_vote;
|
vote = host->bus_vote.saved_vote;
|
||||||
if (vote == host->bus_vote.min_bw_vote)
|
if (vote == host->bus_vote.min_bw_vote)
|
||||||
ufs_qcom_update_bus_bw_vote(host);
|
ufs_qcom_update_bus_bw_vote(host);
|
||||||
|
@ -1086,7 +1085,7 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
|
||||||
/* turn off UFS local PHY ref_clk */
|
/* turn off UFS local PHY ref_clk */
|
||||||
ufs_qcom_phy_disable_ref_clk(host->generic_phy);
|
ufs_qcom_phy_disable_ref_clk(host->generic_phy);
|
||||||
/* disable device ref_clk */
|
/* disable device ref_clk */
|
||||||
ufs_qcom_enable_dev_ref_clk(host, false);
|
ufs_qcom_dev_ref_clk_ctrl(host, false);
|
||||||
}
|
}
|
||||||
vote = host->bus_vote.min_bw_vote;
|
vote = host->bus_vote.min_bw_vote;
|
||||||
}
|
}
|
||||||
|
@ -1196,8 +1195,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
||||||
struct device *dev = hba->dev;
|
struct device *dev = hba->dev;
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
struct ufs_qcom_host *host;
|
struct ufs_qcom_host *host;
|
||||||
u8 major;
|
|
||||||
u16 minor, step;
|
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
|
||||||
if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev)))
|
if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev)))
|
||||||
|
@ -1252,10 +1249,32 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
||||||
if (err)
|
if (err)
|
||||||
goto out_host_free;
|
goto out_host_free;
|
||||||
|
|
||||||
ufs_qcom_get_controller_revision(hba, &major, &minor, &step);
|
ufs_qcom_get_controller_revision(hba, &host->hw_ver.major,
|
||||||
|
&host->hw_ver.minor, &host->hw_ver.step);
|
||||||
|
|
||||||
|
/* "dev_ref_clk_ctrl_mem" is optional resource */
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||||
|
if (!res) {
|
||||||
|
dev_info(dev, "%s: dev_ref_clk_ctrl_mem resource not found\n",
|
||||||
|
__func__);
|
||||||
|
} else {
|
||||||
|
host->dev_ref_clk_ctrl_mmio = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(host->dev_ref_clk_ctrl_mmio)) {
|
||||||
|
dev_warn(dev,
|
||||||
|
"%s: could not map dev_ref_clk_ctrl_mmio, err %ld\n",
|
||||||
|
__func__, PTR_ERR(host->dev_ref_clk_ctrl_mmio));
|
||||||
|
host->dev_ref_clk_ctrl_mmio = NULL;
|
||||||
|
}
|
||||||
|
/* Set the correct mask for the device ref. clock enable bit */
|
||||||
|
if (host->hw_ver.major >= 0x02)
|
||||||
|
host->dev_ref_clk_en_mask = BIT(26);
|
||||||
|
else
|
||||||
|
host->dev_ref_clk_en_mask = BIT(5);
|
||||||
|
}
|
||||||
|
|
||||||
/* update phy revision information before calling phy_init() */
|
/* update phy revision information before calling phy_init() */
|
||||||
ufs_qcom_phy_save_controller_version(host->generic_phy,
|
ufs_qcom_phy_save_controller_version(host->generic_phy,
|
||||||
major, minor, step);
|
host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
|
||||||
|
|
||||||
phy_init(host->generic_phy);
|
phy_init(host->generic_phy);
|
||||||
err = phy_power_on(host->generic_phy);
|
err = phy_power_on(host->generic_phy);
|
||||||
|
@ -1267,8 +1286,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
||||||
goto out_disable_phy;
|
goto out_disable_phy;
|
||||||
|
|
||||||
ufs_qcom_set_caps(hba);
|
ufs_qcom_set_caps(hba);
|
||||||
ufs_qcom_get_controller_revision(hba, &host->hw_ver.major,
|
|
||||||
&host->hw_ver.minor, &host->hw_ver.step);
|
|
||||||
ufs_qcom_advertise_quirks(hba);
|
ufs_qcom_advertise_quirks(hba);
|
||||||
|
|
||||||
hba->caps |= UFSHCD_CAP_CLK_GATING |
|
hba->caps |= UFSHCD_CAP_CLK_GATING |
|
||||||
|
@ -1277,21 +1294,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
||||||
hba->caps |= UFSHCD_CAP_HIBERN8_ENTER_ON_IDLE;
|
hba->caps |= UFSHCD_CAP_HIBERN8_ENTER_ON_IDLE;
|
||||||
ufs_qcom_setup_clocks(hba, true);
|
ufs_qcom_setup_clocks(hba, true);
|
||||||
|
|
||||||
/* "dev_ref_clk_ctrl_mem" is optional resource */
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
|
||||||
if (!res) {
|
|
||||||
dev_dbg(dev, "%s: dev_ref_clk_ctrl_mem resource not found\n",
|
|
||||||
__func__);
|
|
||||||
} else {
|
|
||||||
host->dev_ref_clk_ctrl_mmio = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(host->dev_ref_clk_ctrl_mmio)) {
|
|
||||||
dev_warn(dev,
|
|
||||||
"%s: could not map dev_ref_clk_ctrl_mmio, err %ld\n",
|
|
||||||
__func__, PTR_ERR(host->dev_ref_clk_ctrl_mmio));
|
|
||||||
host->dev_ref_clk_ctrl_mmio = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
|
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
|
||||||
ufs_qcom_hosts[hba->dev->id] = host;
|
ufs_qcom_hosts[hba->dev->id] = host;
|
||||||
|
|
||||||
|
|
|
@ -251,6 +251,7 @@ struct ufs_qcom_host {
|
||||||
void __iomem *dev_ref_clk_ctrl_mmio;
|
void __iomem *dev_ref_clk_ctrl_mmio;
|
||||||
bool is_dev_ref_clk_enabled;
|
bool is_dev_ref_clk_enabled;
|
||||||
struct ufs_hw_version hw_ver;
|
struct ufs_hw_version hw_ver;
|
||||||
|
u32 dev_ref_clk_en_mask;
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
struct qcom_debugfs_files debugfs_files;
|
struct qcom_debugfs_files debugfs_files;
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue