Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: samsung: gs101-ufs: Add .notify_phystate() & hibern8 enter/exit values

Implement the .notify_phystate() callback and provide the gs101 specific
phy values that need to be programmed when entering and exiting the hibern8
state.

Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patch.msgid.link/20251112-phy-notify-pmstate-v5-2-39df622d8fcb@linaro.org
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Peter Griffin and committed by
Vinod Koul
a1af5d2b 4edf654b

+75
+28
drivers/phy/samsung/phy-gs101-ufs.c
··· 108 108 END_UFS_PHY_CFG, 109 109 }; 110 110 111 + static const struct samsung_ufs_phy_cfg tensor_gs101_post_h8_enter[] = { 112 + PHY_TRSV_REG_CFG_GS101(0x262, 0x08, PWR_MODE_ANY), 113 + PHY_TRSV_REG_CFG_GS101(0x265, 0x0A, PWR_MODE_ANY), 114 + PHY_COMN_REG_CFG(0x1, 0x8, PWR_MODE_ANY), 115 + PHY_COMN_REG_CFG(0x0, 0x86, PWR_MODE_ANY), 116 + PHY_COMN_REG_CFG(0x8, 0x60, PWR_MODE_HS_ANY), 117 + PHY_TRSV_REG_CFG_GS101(0x222, 0x08, PWR_MODE_HS_ANY), 118 + PHY_TRSV_REG_CFG_GS101(0x246, 0x01, PWR_MODE_HS_ANY), 119 + END_UFS_PHY_CFG, 120 + }; 121 + 122 + static const struct samsung_ufs_phy_cfg tensor_gs101_pre_h8_exit[] = { 123 + PHY_COMN_REG_CFG(0x0, 0xC6, PWR_MODE_ANY), 124 + PHY_COMN_REG_CFG(0x1, 0x0C, PWR_MODE_ANY), 125 + PHY_TRSV_REG_CFG_GS101(0x262, 0x00, PWR_MODE_ANY), 126 + PHY_TRSV_REG_CFG_GS101(0x265, 0x00, PWR_MODE_ANY), 127 + PHY_COMN_REG_CFG(0x8, 0xE0, PWR_MODE_HS_ANY), 128 + PHY_TRSV_REG_CFG_GS101(0x246, 0x03, PWR_MODE_HS_ANY), 129 + PHY_TRSV_REG_CFG_GS101(0x222, 0x18, PWR_MODE_HS_ANY), 130 + END_UFS_PHY_CFG, 131 + }; 132 + 111 133 static const struct samsung_ufs_phy_cfg *tensor_gs101_ufs_phy_cfgs[CFG_TAG_MAX] = { 112 134 [CFG_PRE_INIT] = tensor_gs101_pre_init_cfg, 113 135 [CFG_PRE_PWR_HS] = tensor_gs101_pre_pwr_hs_config, 114 136 [CFG_POST_PWR_HS] = tensor_gs101_post_pwr_hs_config, 137 + }; 138 + 139 + static const struct samsung_ufs_phy_cfg *tensor_gs101_hibern8_cfgs[] = { 140 + [CFG_POST_HIBERN8_ENTER] = tensor_gs101_post_h8_enter, 141 + [CFG_PRE_HIBERN8_EXIT] = tensor_gs101_pre_h8_exit, 115 142 }; 116 143 117 144 static const char * const tensor_gs101_ufs_phy_clks[] = { ··· 197 170 198 171 const struct samsung_ufs_phy_drvdata tensor_gs101_ufs_phy = { 199 172 .cfgs = tensor_gs101_ufs_phy_cfgs, 173 + .cfgs_hibern8 = tensor_gs101_hibern8_cfgs, 200 174 .isol = { 201 175 .offset = TENSOR_GS101_PHY_CTRL, 202 176 .mask = TENSOR_GS101_PHY_CTRL_MASK,
+40
drivers/phy/samsung/phy-samsung-ufs.c
··· 217 217 return 0; 218 218 } 219 219 220 + static int samsung_ufs_phy_notify_state(struct phy *phy, 221 + union phy_notify state) 222 + { 223 + struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy); 224 + const struct samsung_ufs_phy_cfg *cfg; 225 + int i, err = -EINVAL; 226 + 227 + if (!ufs_phy->cfgs_hibern8) 228 + return 0; 229 + 230 + if (state.ufs_state == PHY_UFS_HIBERN8_ENTER) 231 + cfg = ufs_phy->cfgs_hibern8[CFG_POST_HIBERN8_ENTER]; 232 + else if (state.ufs_state == PHY_UFS_HIBERN8_EXIT) 233 + cfg = ufs_phy->cfgs_hibern8[CFG_PRE_HIBERN8_EXIT]; 234 + else 235 + goto err_out; 236 + 237 + for_each_phy_cfg(cfg) { 238 + for_each_phy_lane(ufs_phy, i) { 239 + samsung_ufs_phy_config(ufs_phy, cfg, i); 240 + } 241 + } 242 + 243 + if (state.ufs_state == PHY_UFS_HIBERN8_EXIT) { 244 + for_each_phy_lane(ufs_phy, i) { 245 + if (ufs_phy->drvdata->wait_for_cdr) { 246 + err = ufs_phy->drvdata->wait_for_cdr(phy, i); 247 + if (err) 248 + goto err_out; 249 + } 250 + } 251 + } 252 + 253 + return 0; 254 + err_out: 255 + return err; 256 + } 257 + 220 258 static int samsung_ufs_phy_exit(struct phy *phy) 221 259 { 222 260 struct samsung_ufs_phy *ss_phy = get_samsung_ufs_phy(phy); ··· 271 233 .power_off = samsung_ufs_phy_power_off, 272 234 .calibrate = samsung_ufs_phy_calibrate, 273 235 .set_mode = samsung_ufs_phy_set_mode, 236 + .notify_phystate = samsung_ufs_phy_notify_state, 274 237 .owner = THIS_MODULE, 275 238 }; 276 239 ··· 326 287 phy->dev = dev; 327 288 phy->drvdata = drvdata; 328 289 phy->cfgs = drvdata->cfgs; 290 + phy->cfgs_hibern8 = drvdata->cfgs_hibern8; 329 291 memcpy(&phy->isol, &drvdata->isol, sizeof(phy->isol)); 330 292 331 293 if (!of_property_read_u32_index(dev->of_node, "samsung,pmu-syscon", 1,
+7
drivers/phy/samsung/phy-samsung-ufs.h
··· 92 92 CFG_TAG_MAX, 93 93 }; 94 94 95 + enum { 96 + CFG_POST_HIBERN8_ENTER, 97 + CFG_PRE_HIBERN8_EXIT, 98 + }; 99 + 95 100 struct samsung_ufs_phy_cfg { 96 101 u32 off_0; 97 102 u32 off_1; ··· 113 108 114 109 struct samsung_ufs_phy_drvdata { 115 110 const struct samsung_ufs_phy_cfg **cfgs; 111 + const struct samsung_ufs_phy_cfg **cfgs_hibern8; 116 112 struct samsung_ufs_phy_pmu_isol isol; 117 113 const char * const *clk_list; 118 114 int num_clks; ··· 130 124 struct clk_bulk_data *clks; 131 125 const struct samsung_ufs_phy_drvdata *drvdata; 132 126 const struct samsung_ufs_phy_cfg * const *cfgs; 127 + const struct samsung_ufs_phy_cfg * const *cfgs_hibern8; 133 128 struct samsung_ufs_phy_pmu_isol isol; 134 129 u8 lane_cnt; 135 130 int ufs_phy_state;