Commit cf137b3e authored by Stanley Chu's avatar Stanley Chu Committed by Martin K. Petersen

scsi: ufs-mediatek: Support VA09 regulator operations

Some MediaTek UFS platforms need to control VA09 power
specifically. Provide such control according to the device tree binding.

Link: https://lore.kernel.org/r/20201029115750.24391-3-stanley.chu@mediatek.comSigned-off-by: default avatarStanley Chu <stanley.chu@mediatek.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent a004147a
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
arm_smccc_smc(MTK_SIP_UFS_CONTROL, \ arm_smccc_smc(MTK_SIP_UFS_CONTROL, \
cmd, val, 0, 0, 0, 0, 0, &(res)) cmd, val, 0, 0, 0, 0, 0, &(res))
#define ufs_mtk_va09_pwr_ctrl(res, on) \
ufs_mtk_smc(UFS_MTK_SIP_VA09_PWR_CTRL, on, res)
#define ufs_mtk_crypto_ctrl(res, enable) \ #define ufs_mtk_crypto_ctrl(res, enable) \
ufs_mtk_smc(UFS_MTK_SIP_CRYPTO_CTRL, enable, res) ufs_mtk_smc(UFS_MTK_SIP_CRYPTO_CTRL, enable, res)
...@@ -45,6 +48,10 @@ static struct ufs_dev_fix ufs_mtk_dev_fixups[] = { ...@@ -45,6 +48,10 @@ static struct ufs_dev_fix ufs_mtk_dev_fixups[] = {
END_FIX END_FIX
}; };
static const struct ufs_mtk_host_cfg ufs_mtk_mt8183_cfg = {
.caps = UFS_MTK_CAP_VA09_PWR_CTRL,
};
static const struct ufs_mtk_host_cfg ufs_mtk_mt8192_cfg = { static const struct ufs_mtk_host_cfg ufs_mtk_mt8192_cfg = {
.caps = UFS_MTK_CAP_BOOST_CRYPT_ENGINE, .caps = UFS_MTK_CAP_BOOST_CRYPT_ENGINE,
}; };
...@@ -52,6 +59,7 @@ static const struct ufs_mtk_host_cfg ufs_mtk_mt8192_cfg = { ...@@ -52,6 +59,7 @@ static const struct ufs_mtk_host_cfg ufs_mtk_mt8192_cfg = {
static const struct of_device_id ufs_mtk_of_match[] = { static const struct of_device_id ufs_mtk_of_match[] = {
{ {
.compatible = "mediatek,mt8183-ufshci", .compatible = "mediatek,mt8183-ufshci",
.data = &ufs_mtk_mt8183_cfg
}, },
{ {
.compatible = "mediatek,mt8192-ufshci", .compatible = "mediatek,mt8192-ufshci",
...@@ -67,6 +75,13 @@ static bool ufs_mtk_is_boost_crypt_enabled(struct ufs_hba *hba) ...@@ -67,6 +75,13 @@ static bool ufs_mtk_is_boost_crypt_enabled(struct ufs_hba *hba)
return (host->caps & UFS_MTK_CAP_BOOST_CRYPT_ENGINE); return (host->caps & UFS_MTK_CAP_BOOST_CRYPT_ENGINE);
} }
static bool ufs_mtk_is_va09_supported(struct ufs_hba *hba)
{
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
return (host->caps & UFS_MTK_CAP_VA09_PWR_CTRL);
}
static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable) static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)
{ {
u32 tmp; u32 tmp;
...@@ -300,21 +315,46 @@ static int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state, ...@@ -300,21 +315,46 @@ static int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static void ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on) static int ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on)
{ {
struct ufs_mtk_host *host = ufshcd_get_variant(hba); struct ufs_mtk_host *host = ufshcd_get_variant(hba);
struct phy *mphy = host->mphy; struct phy *mphy = host->mphy;
struct arm_smccc_res res;
int ret = 0;
if (!mphy) if (!mphy || !(on ^ host->mphy_powered_on))
return; return 0;
if (on && !host->mphy_powered_on) if (on) {
if (host->reg_va09) {
ret = regulator_enable(host->reg_va09);
if (ret < 0)
goto out;
/* wait 200 us to stablize VA09 */
usleep_range(200, 210);
ufs_mtk_va09_pwr_ctrl(res, 1);
}
phy_power_on(mphy); phy_power_on(mphy);
else if (!on && host->mphy_powered_on) } else {
phy_power_off(mphy); phy_power_off(mphy);
else if (host->reg_va09) {
return; ufs_mtk_va09_pwr_ctrl(res, 0);
host->mphy_powered_on = on; ret = regulator_disable(host->reg_va09);
if (ret < 0)
goto out;
}
}
out:
if (ret) {
dev_info(hba->dev,
"failed to %s va09: %d\n",
on ? "enable" : "disable",
ret);
} else {
host->mphy_powered_on = on;
}
return ret;
} }
static int ufs_mtk_get_host_clk(struct device *dev, const char *name, static int ufs_mtk_get_host_clk(struct device *dev, const char *name,
...@@ -402,7 +442,7 @@ static int ufs_mtk_init_host_clk(struct ufs_hba *hba, const char *name, ...@@ -402,7 +442,7 @@ static int ufs_mtk_init_host_clk(struct ufs_hba *hba, const char *name,
return ret; return ret;
} }
static void ufs_mtk_init_host_caps(struct ufs_hba *hba) static void ufs_mtk_init_boost_crypt(struct ufs_hba *hba)
{ {
struct ufs_mtk_host *host = ufshcd_get_variant(hba); struct ufs_mtk_host *host = ufshcd_get_variant(hba);
struct ufs_mtk_crypt_cfg *cfg; struct ufs_mtk_crypt_cfg *cfg;
...@@ -410,11 +450,6 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba) ...@@ -410,11 +450,6 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba)
struct regulator *reg; struct regulator *reg;
u32 volt; u32 volt;
host->caps = host->cfg->caps;
if (!ufs_mtk_is_boost_crypt_enabled(hba))
return;
host->crypt = devm_kzalloc(dev, sizeof(*(host->crypt)), host->crypt = devm_kzalloc(dev, sizeof(*(host->crypt)),
GFP_KERNEL); GFP_KERNEL);
if (!host->crypt) if (!host->crypt)
...@@ -448,13 +483,38 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba) ...@@ -448,13 +483,38 @@ static void ufs_mtk_init_host_caps(struct ufs_hba *hba)
cfg->reg_vcore = reg; cfg->reg_vcore = reg;
cfg->vcore_volt = volt; cfg->vcore_volt = volt;
dev_info(dev, "caps: boost-crypt");
return; return;
disable_caps: disable_caps:
host->caps &= ~UFS_MTK_CAP_BOOST_CRYPT_ENGINE; host->caps &= ~UFS_MTK_CAP_BOOST_CRYPT_ENGINE;
} }
static void ufs_mtk_init_va09_pwr_ctrl(struct ufs_hba *hba)
{
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
host->reg_va09 = regulator_get(hba->dev, "va09");
if (!host->reg_va09) {
dev_info(hba->dev, "failed to get va09");
host->caps &= ~UFS_MTK_CAP_VA09_PWR_CTRL;
}
}
static void ufs_mtk_init_host_caps(struct ufs_hba *hba)
{
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
host->caps = host->cfg->caps;
if (ufs_mtk_is_boost_crypt_enabled(hba))
ufs_mtk_init_boost_crypt(hba);
if (ufs_mtk_is_va09_supported(hba))
ufs_mtk_init_va09_pwr_ctrl(hba);
dev_info(hba->dev, "caps: 0x%x", host->caps);
}
/** /**
* ufs_mtk_setup_clocks - enables/disable clocks * ufs_mtk_setup_clocks - enables/disable clocks
* @hba: host controller instance * @hba: host controller instance
...@@ -467,8 +527,8 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, ...@@ -467,8 +527,8 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
enum ufs_notify_change_status status) enum ufs_notify_change_status status)
{ {
struct ufs_mtk_host *host = ufshcd_get_variant(hba); struct ufs_mtk_host *host = ufshcd_get_variant(hba);
int ret = 0;
bool clk_pwr_off = false; bool clk_pwr_off = false;
int ret = 0;
/* /*
* In case ufs_mtk_init() is not yet done, simply ignore. * In case ufs_mtk_init() is not yet done, simply ignore.
...@@ -499,10 +559,10 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, ...@@ -499,10 +559,10 @@ static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
if (clk_pwr_off) { if (clk_pwr_off) {
ufs_mtk_boost_crypt(hba, on); ufs_mtk_boost_crypt(hba, on);
ufs_mtk_setup_ref_clk(hba, on); ufs_mtk_setup_ref_clk(hba, on);
ufs_mtk_mphy_power_on(hba, on); phy_power_off(host->mphy);
} }
} else if (on && status == POST_CHANGE) { } else if (on && status == POST_CHANGE) {
ufs_mtk_mphy_power_on(hba, on); phy_power_on(host->mphy);
ufs_mtk_setup_ref_clk(hba, on); ufs_mtk_setup_ref_clk(hba, on);
ufs_mtk_boost_crypt(hba, on); ufs_mtk_boost_crypt(hba, on);
} }
...@@ -575,6 +635,7 @@ static int ufs_mtk_init(struct ufs_hba *hba) ...@@ -575,6 +635,7 @@ static int ufs_mtk_init(struct ufs_hba *hba)
* *
* Enable phy clocks specifically here. * Enable phy clocks specifically here.
*/ */
ufs_mtk_mphy_power_on(hba, true);
ufs_mtk_setup_clocks(hba, true, POST_CHANGE); ufs_mtk_setup_clocks(hba, true, POST_CHANGE);
goto out; goto out;
...@@ -826,40 +887,52 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) ...@@ -826,40 +887,52 @@ static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
if (ufshcd_is_link_hibern8(hba)) { if (ufshcd_is_link_hibern8(hba)) {
err = ufs_mtk_link_set_lpm(hba); err = ufs_mtk_link_set_lpm(hba);
if (err) { if (err)
/* goto fail;
* Set link as off state enforcedly to trigger }
* ufshcd_host_reset_and_restore() in ufshcd_suspend()
* for completed host reset. if (!ufshcd_is_link_active(hba)) {
*/
ufshcd_set_link_off(hba);
return -EAGAIN;
}
/* /*
* Make sure no error will be returned to prevent * Make sure no error will be returned to prevent
* ufshcd_suspend() re-enabling regulators while vreg is still * ufshcd_suspend() re-enabling regulators while vreg is still
* in low-power mode. * in low-power mode.
*/ */
ufs_mtk_vreg_set_lpm(hba, true); ufs_mtk_vreg_set_lpm(hba, true);
err = ufs_mtk_mphy_power_on(hba, false);
if (err)
goto fail;
} }
return 0; return 0;
fail:
/*
* Set link as off state enforcedly to trigger
* ufshcd_host_reset_and_restore() in ufshcd_suspend()
* for completed host reset.
*/
ufshcd_set_link_off(hba);
return -EAGAIN;
} }
static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{ {
int err; int err;
err = ufs_mtk_mphy_power_on(hba, true);
if (err)
goto fail;
ufs_mtk_vreg_set_lpm(hba, false);
if (ufshcd_is_link_hibern8(hba)) { if (ufshcd_is_link_hibern8(hba)) {
ufs_mtk_vreg_set_lpm(hba, false);
err = ufs_mtk_link_set_hpm(hba); err = ufs_mtk_link_set_hpm(hba);
if (err) { if (err)
err = ufshcd_link_recovery(hba); goto fail;
return err;
}
} }
return 0; return 0;
fail:
return ufshcd_link_recovery(hba);
} }
static void ufs_mtk_dbg_register_dump(struct ufs_hba *hba) static void ufs_mtk_dbg_register_dump(struct ufs_hba *hba)
......
...@@ -69,6 +69,7 @@ enum { ...@@ -69,6 +69,7 @@ enum {
* SiP commands * SiP commands
*/ */
#define MTK_SIP_UFS_CONTROL MTK_SIP_SMC_CMD(0x276) #define MTK_SIP_UFS_CONTROL MTK_SIP_SMC_CMD(0x276)
#define UFS_MTK_SIP_VA09_PWR_CTRL BIT(0)
#define UFS_MTK_SIP_DEVICE_RESET BIT(1) #define UFS_MTK_SIP_DEVICE_RESET BIT(1)
#define UFS_MTK_SIP_CRYPTO_CTRL BIT(2) #define UFS_MTK_SIP_CRYPTO_CTRL BIT(2)
#define UFS_MTK_SIP_REF_CLK_NOTIFICATION BIT(3) #define UFS_MTK_SIP_REF_CLK_NOTIFICATION BIT(3)
...@@ -94,6 +95,7 @@ enum { ...@@ -94,6 +95,7 @@ enum {
*/ */
enum ufs_mtk_host_caps { enum ufs_mtk_host_caps {
UFS_MTK_CAP_BOOST_CRYPT_ENGINE = 1 << 0, UFS_MTK_CAP_BOOST_CRYPT_ENGINE = 1 << 0,
UFS_MTK_CAP_VA09_PWR_CTRL = 1 << 1,
}; };
struct ufs_mtk_crypt_cfg { struct ufs_mtk_crypt_cfg {
...@@ -113,6 +115,7 @@ struct ufs_mtk_host { ...@@ -113,6 +115,7 @@ struct ufs_mtk_host {
struct phy *mphy; struct phy *mphy;
struct ufs_mtk_host_cfg *cfg; struct ufs_mtk_host_cfg *cfg;
struct ufs_mtk_crypt_cfg *crypt; struct ufs_mtk_crypt_cfg *crypt;
struct regulator *reg_va09;
enum ufs_mtk_host_caps caps; enum ufs_mtk_host_caps caps;
struct reset_control *hci_reset; struct reset_control *hci_reset;
struct reset_control *unipro_reset; struct reset_control *unipro_reset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment