ufs-hisi.c (17159B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * HiSilicon Hixxxx UFS Driver 4 * 5 * Copyright (c) 2016-2017 Linaro Ltd. 6 * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd. 7 */ 8 9#include <linux/time.h> 10#include <linux/delay.h> 11#include <linux/module.h> 12#include <linux/of.h> 13#include <linux/of_address.h> 14#include <linux/dma-mapping.h> 15#include <linux/platform_device.h> 16#include <linux/reset.h> 17 18#include <ufs/ufshcd.h> 19#include "ufshcd-pltfrm.h" 20#include <ufs/unipro.h> 21#include "ufs-hisi.h" 22#include <ufs/ufshci.h> 23#include <ufs/ufs_quirks.h> 24 25static int ufs_hisi_check_hibern8(struct ufs_hba *hba) 26{ 27 int err = 0; 28 u32 tx_fsm_val_0 = 0; 29 u32 tx_fsm_val_1 = 0; 30 unsigned long timeout = jiffies + msecs_to_jiffies(HBRN8_POLL_TOUT_MS); 31 32 do { 33 err = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, 0), 34 &tx_fsm_val_0); 35 err |= ufshcd_dme_get(hba, 36 UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, 1), &tx_fsm_val_1); 37 if (err || (tx_fsm_val_0 == TX_FSM_HIBERN8 && 38 tx_fsm_val_1 == TX_FSM_HIBERN8)) 39 break; 40 41 /* sleep for max. 200us */ 42 usleep_range(100, 200); 43 } while (time_before(jiffies, timeout)); 44 45 /* 46 * we might have scheduled out for long during polling so 47 * check the state again. 48 */ 49 if (time_after(jiffies, timeout)) { 50 err = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, 0), 51 &tx_fsm_val_0); 52 err |= ufshcd_dme_get(hba, 53 UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, 1), &tx_fsm_val_1); 54 } 55 56 if (err) { 57 dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n", 58 __func__, err); 59 } else if (tx_fsm_val_0 != TX_FSM_HIBERN8 || 60 tx_fsm_val_1 != TX_FSM_HIBERN8) { 61 err = -1; 62 dev_err(hba->dev, "%s: invalid TX_FSM_STATE, lane0 = %d, lane1 = %d\n", 63 __func__, tx_fsm_val_0, tx_fsm_val_1); 64 } 65 66 return err; 67} 68 69static void ufs_hisi_clk_init(struct ufs_hba *hba) 70{ 71 struct ufs_hisi_host *host = ufshcd_get_variant(hba); 72 73 ufs_sys_ctrl_clr_bits(host, BIT_SYSCTRL_REF_CLOCK_EN, PHY_CLK_CTRL); 74 if (ufs_sys_ctrl_readl(host, PHY_CLK_CTRL) & BIT_SYSCTRL_REF_CLOCK_EN) 75 mdelay(1); 76 /* use abb clk */ 77 ufs_sys_ctrl_clr_bits(host, BIT_UFS_REFCLK_SRC_SEl, UFS_SYSCTRL); 78 ufs_sys_ctrl_clr_bits(host, BIT_UFS_REFCLK_ISO_EN, PHY_ISO_EN); 79 /* open mphy ref clk */ 80 ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_REF_CLOCK_EN, PHY_CLK_CTRL); 81} 82 83static void ufs_hisi_soc_init(struct ufs_hba *hba) 84{ 85 struct ufs_hisi_host *host = ufshcd_get_variant(hba); 86 u32 reg; 87 88 if (!IS_ERR(host->rst)) 89 reset_control_assert(host->rst); 90 91 /* HC_PSW powerup */ 92 ufs_sys_ctrl_set_bits(host, BIT_UFS_PSW_MTCMOS_EN, PSW_POWER_CTRL); 93 udelay(10); 94 /* notify PWR ready */ 95 ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_PWR_READY, HC_LP_CTRL); 96 ufs_sys_ctrl_writel(host, MASK_UFS_DEVICE_RESET | 0, 97 UFS_DEVICE_RESET_CTRL); 98 99 reg = ufs_sys_ctrl_readl(host, PHY_CLK_CTRL); 100 reg = (reg & ~MASK_SYSCTRL_CFG_CLOCK_FREQ) | UFS_FREQ_CFG_CLK; 101 /* set cfg clk freq */ 102 ufs_sys_ctrl_writel(host, reg, PHY_CLK_CTRL); 103 /* set ref clk freq */ 104 ufs_sys_ctrl_clr_bits(host, MASK_SYSCTRL_REF_CLOCK_SEL, PHY_CLK_CTRL); 105 /* bypass ufs clk gate */ 106 ufs_sys_ctrl_set_bits(host, MASK_UFS_CLK_GATE_BYPASS, 107 CLOCK_GATE_BYPASS); 108 ufs_sys_ctrl_set_bits(host, MASK_UFS_SYSCRTL_BYPASS, UFS_SYSCTRL); 109 110 /* open psw clk */ 111 ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_PSW_CLK_EN, PSW_CLK_CTRL); 112 /* disable ufshc iso */ 113 ufs_sys_ctrl_clr_bits(host, BIT_UFS_PSW_ISO_CTRL, PSW_POWER_CTRL); 114 /* disable phy iso */ 115 ufs_sys_ctrl_clr_bits(host, BIT_UFS_PHY_ISO_CTRL, PHY_ISO_EN); 116 /* notice iso disable */ 117 ufs_sys_ctrl_clr_bits(host, BIT_SYSCTRL_LP_ISOL_EN, HC_LP_CTRL); 118 119 /* disable lp_reset_n */ 120 ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_LP_RESET_N, RESET_CTRL_EN); 121 mdelay(1); 122 123 ufs_sys_ctrl_writel(host, MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET, 124 UFS_DEVICE_RESET_CTRL); 125 126 msleep(20); 127 128 /* 129 * enable the fix of linereset recovery, 130 * and enable rx_reset/tx_rest beat 131 * enable ref_clk_en override(bit5) & 132 * override value = 1(bit4), with mask 133 */ 134 ufs_sys_ctrl_writel(host, 0x03300330, UFS_DEVICE_RESET_CTRL); 135 136 if (!IS_ERR(host->rst)) 137 reset_control_deassert(host->rst); 138} 139 140static int ufs_hisi_link_startup_pre_change(struct ufs_hba *hba) 141{ 142 struct ufs_hisi_host *host = ufshcd_get_variant(hba); 143 int err; 144 uint32_t value; 145 uint32_t reg; 146 147 /* Unipro VS_mphy_disable */ 148 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD0C1, 0x0), 0x1); 149 /* PA_HSSeries */ 150 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x156A, 0x0), 0x2); 151 /* MPHY CBRATESEL */ 152 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8114, 0x0), 0x1); 153 /* MPHY CBOVRCTRL2 */ 154 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8121, 0x0), 0x2D); 155 /* MPHY CBOVRCTRL3 */ 156 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8122, 0x0), 0x1); 157 158 if (host->caps & UFS_HISI_CAP_PHY10nm) { 159 /* MPHY CBOVRCTRL4 */ 160 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8127, 0x0), 0x98); 161 /* MPHY CBOVRCTRL5 */ 162 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8128, 0x0), 0x1); 163 } 164 165 /* Unipro VS_MphyCfgUpdt */ 166 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD085, 0x0), 0x1); 167 /* MPHY RXOVRCTRL4 rx0 */ 168 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x800D, 0x4), 0x58); 169 /* MPHY RXOVRCTRL4 rx1 */ 170 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x800D, 0x5), 0x58); 171 /* MPHY RXOVRCTRL5 rx0 */ 172 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x800E, 0x4), 0xB); 173 /* MPHY RXOVRCTRL5 rx1 */ 174 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x800E, 0x5), 0xB); 175 /* MPHY RXSQCONTROL rx0 */ 176 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8009, 0x4), 0x1); 177 /* MPHY RXSQCONTROL rx1 */ 178 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8009, 0x5), 0x1); 179 /* Unipro VS_MphyCfgUpdt */ 180 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD085, 0x0), 0x1); 181 182 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8113, 0x0), 0x1); 183 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD085, 0x0), 0x1); 184 185 if (host->caps & UFS_HISI_CAP_PHY10nm) { 186 /* RX_Hibern8Time_Capability*/ 187 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0092, 0x4), 0xA); 188 /* RX_Hibern8Time_Capability*/ 189 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0092, 0x5), 0xA); 190 /* RX_Min_ActivateTime */ 191 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008f, 0x4), 0xA); 192 /* RX_Min_ActivateTime*/ 193 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008f, 0x5), 0xA); 194 } else { 195 /* Tactive RX */ 196 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008F, 0x4), 0x7); 197 /* Tactive RX */ 198 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008F, 0x5), 0x7); 199 } 200 201 /* Gear3 Synclength */ 202 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0095, 0x4), 0x4F); 203 /* Gear3 Synclength */ 204 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0095, 0x5), 0x4F); 205 /* Gear2 Synclength */ 206 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0094, 0x4), 0x4F); 207 /* Gear2 Synclength */ 208 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0094, 0x5), 0x4F); 209 /* Gear1 Synclength */ 210 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008B, 0x4), 0x4F); 211 /* Gear1 Synclength */ 212 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008B, 0x5), 0x4F); 213 /* Thibernate Tx */ 214 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x000F, 0x0), 0x5); 215 /* Thibernate Tx */ 216 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x000F, 0x1), 0x5); 217 218 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD085, 0x0), 0x1); 219 /* Unipro VS_mphy_disable */ 220 ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(0xD0C1, 0x0), &value); 221 if (value != 0x1) 222 dev_info(hba->dev, 223 "Warring!!! Unipro VS_mphy_disable is 0x%x\n", value); 224 225 /* Unipro VS_mphy_disable */ 226 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD0C1, 0x0), 0x0); 227 err = ufs_hisi_check_hibern8(hba); 228 if (err) 229 dev_err(hba->dev, "ufs_hisi_check_hibern8 error\n"); 230 231 if (!(host->caps & UFS_HISI_CAP_PHY10nm)) 232 ufshcd_writel(hba, UFS_HCLKDIV_NORMAL_VALUE, UFS_REG_HCLKDIV); 233 234 /* disable auto H8 */ 235 reg = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER); 236 reg = reg & (~UFS_AHIT_AH8ITV_MASK); 237 ufshcd_writel(hba, reg, REG_AUTO_HIBERNATE_IDLE_TIMER); 238 239 /* Unipro PA_Local_TX_LCC_Enable */ 240 ufshcd_disable_host_tx_lcc(hba); 241 /* close Unipro VS_Mk2ExtnSupport */ 242 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD0AB, 0x0), 0x0); 243 ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(0xD0AB, 0x0), &value); 244 if (value != 0) { 245 /* Ensure close success */ 246 dev_info(hba->dev, "WARN: close VS_Mk2ExtnSupport failed\n"); 247 } 248 249 return err; 250} 251 252static int ufs_hisi_link_startup_post_change(struct ufs_hba *hba) 253{ 254 struct ufs_hisi_host *host = ufshcd_get_variant(hba); 255 256 /* Unipro DL_AFC0CreditThreshold */ 257 ufshcd_dme_set(hba, UIC_ARG_MIB(0x2044), 0x0); 258 /* Unipro DL_TC0OutAckThreshold */ 259 ufshcd_dme_set(hba, UIC_ARG_MIB(0x2045), 0x0); 260 /* Unipro DL_TC0TXFCThreshold */ 261 ufshcd_dme_set(hba, UIC_ARG_MIB(0x2040), 0x9); 262 263 /* not bypass ufs clk gate */ 264 ufs_sys_ctrl_clr_bits(host, MASK_UFS_CLK_GATE_BYPASS, 265 CLOCK_GATE_BYPASS); 266 ufs_sys_ctrl_clr_bits(host, MASK_UFS_SYSCRTL_BYPASS, 267 UFS_SYSCTRL); 268 269 /* select received symbol cnt */ 270 ufshcd_dme_set(hba, UIC_ARG_MIB(0xd09a), 0x80000000); 271 /* reset counter0 and enable */ 272 ufshcd_dme_set(hba, UIC_ARG_MIB(0xd09c), 0x00000005); 273 274 return 0; 275} 276 277static int ufs_hisi_link_startup_notify(struct ufs_hba *hba, 278 enum ufs_notify_change_status status) 279{ 280 int err = 0; 281 282 switch (status) { 283 case PRE_CHANGE: 284 err = ufs_hisi_link_startup_pre_change(hba); 285 break; 286 case POST_CHANGE: 287 err = ufs_hisi_link_startup_post_change(hba); 288 break; 289 default: 290 break; 291 } 292 293 return err; 294} 295 296static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param) 297{ 298 ufshcd_init_pwr_dev_param(hisi_param); 299} 300 301static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba) 302{ 303 struct ufs_hisi_host *host = ufshcd_get_variant(hba); 304 305 if (host->caps & UFS_HISI_CAP_PHY10nm) { 306 /* 307 * Boston platform need to set SaveConfigTime to 0x13, 308 * and change sync length to maximum value 309 */ 310 /* VS_DebugSaveConfigTime */ 311 ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0xD0A0), 0x13); 312 /* g1 sync length */ 313 ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x1552), 0x4f); 314 /* g2 sync length */ 315 ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x1554), 0x4f); 316 /* g3 sync length */ 317 ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x1556), 0x4f); 318 /* PA_Hibern8Time */ 319 ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x15a7), 0xA); 320 /* PA_Tactivate */ 321 ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x15a8), 0xA); 322 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xd085, 0x0), 0x01); 323 } 324 325 if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_VS_DEBUGSAVECONFIGTIME) { 326 pr_info("ufs flash device must set VS_DebugSaveConfigTime 0x10\n"); 327 /* VS_DebugSaveConfigTime */ 328 ufshcd_dme_set(hba, UIC_ARG_MIB(0xD0A0), 0x10); 329 /* sync length */ 330 ufshcd_dme_set(hba, UIC_ARG_MIB(0x1556), 0x48); 331 } 332 333 /* update */ 334 ufshcd_dme_set(hba, UIC_ARG_MIB(0x15A8), 0x1); 335 /* PA_TxSkip */ 336 ufshcd_dme_set(hba, UIC_ARG_MIB(0x155c), 0x0); 337 /*PA_PWRModeUserData0 = 8191, default is 0*/ 338 ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b0), 8191); 339 /*PA_PWRModeUserData1 = 65535, default is 0*/ 340 ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b1), 65535); 341 /*PA_PWRModeUserData2 = 32767, default is 0*/ 342 ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b2), 32767); 343 /*DME_FC0ProtectionTimeOutVal = 8191, default is 0*/ 344 ufshcd_dme_set(hba, UIC_ARG_MIB(0xd041), 8191); 345 /*DME_TC0ReplayTimeOutVal = 65535, default is 0*/ 346 ufshcd_dme_set(hba, UIC_ARG_MIB(0xd042), 65535); 347 /*DME_AFC0ReqTimeOutVal = 32767, default is 0*/ 348 ufshcd_dme_set(hba, UIC_ARG_MIB(0xd043), 32767); 349 /*PA_PWRModeUserData3 = 8191, default is 0*/ 350 ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b3), 8191); 351 /*PA_PWRModeUserData4 = 65535, default is 0*/ 352 ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b4), 65535); 353 /*PA_PWRModeUserData5 = 32767, default is 0*/ 354 ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b5), 32767); 355 /*DME_FC1ProtectionTimeOutVal = 8191, default is 0*/ 356 ufshcd_dme_set(hba, UIC_ARG_MIB(0xd044), 8191); 357 /*DME_TC1ReplayTimeOutVal = 65535, default is 0*/ 358 ufshcd_dme_set(hba, UIC_ARG_MIB(0xd045), 65535); 359 /*DME_AFC1ReqTimeOutVal = 32767, default is 0*/ 360 ufshcd_dme_set(hba, UIC_ARG_MIB(0xd046), 32767); 361} 362 363static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, 364 enum ufs_notify_change_status status, 365 struct ufs_pa_layer_attr *dev_max_params, 366 struct ufs_pa_layer_attr *dev_req_params) 367{ 368 struct ufs_dev_params ufs_hisi_cap; 369 int ret = 0; 370 371 if (!dev_req_params) { 372 dev_err(hba->dev, 373 "%s: incoming dev_req_params is NULL\n", __func__); 374 ret = -EINVAL; 375 goto out; 376 } 377 378 switch (status) { 379 case PRE_CHANGE: 380 ufs_hisi_set_dev_cap(&ufs_hisi_cap); 381 ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap, 382 dev_max_params, dev_req_params); 383 if (ret) { 384 dev_err(hba->dev, 385 "%s: failed to determine capabilities\n", __func__); 386 goto out; 387 } 388 389 ufs_hisi_pwr_change_pre_change(hba); 390 break; 391 case POST_CHANGE: 392 break; 393 default: 394 ret = -EINVAL; 395 break; 396 } 397out: 398 return ret; 399} 400 401static int ufs_hisi_suspend_prepare(struct device *dev) 402{ 403 /* RPM and SPM are different. Refer ufs_hisi_suspend() */ 404 return __ufshcd_suspend_prepare(dev, false); 405} 406 407static int ufs_hisi_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op, 408 enum ufs_notify_change_status status) 409{ 410 struct ufs_hisi_host *host = ufshcd_get_variant(hba); 411 412 if (status == PRE_CHANGE) 413 return 0; 414 415 if (pm_op == UFS_RUNTIME_PM) 416 return 0; 417 418 if (host->in_suspend) { 419 WARN_ON(1); 420 return 0; 421 } 422 423 ufs_sys_ctrl_clr_bits(host, BIT_SYSCTRL_REF_CLOCK_EN, PHY_CLK_CTRL); 424 udelay(10); 425 /* set ref_dig_clk override of PHY PCS to 0 */ 426 ufs_sys_ctrl_writel(host, 0x00100000, UFS_DEVICE_RESET_CTRL); 427 428 host->in_suspend = true; 429 430 return 0; 431} 432 433static int ufs_hisi_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) 434{ 435 struct ufs_hisi_host *host = ufshcd_get_variant(hba); 436 437 if (!host->in_suspend) 438 return 0; 439 440 /* set ref_dig_clk override of PHY PCS to 1 */ 441 ufs_sys_ctrl_writel(host, 0x00100010, UFS_DEVICE_RESET_CTRL); 442 udelay(10); 443 ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_REF_CLOCK_EN, PHY_CLK_CTRL); 444 445 host->in_suspend = false; 446 return 0; 447} 448 449static int ufs_hisi_get_resource(struct ufs_hisi_host *host) 450{ 451 struct device *dev = host->hba->dev; 452 struct platform_device *pdev = to_platform_device(dev); 453 454 /* get resource of ufs sys ctrl */ 455 host->ufs_sys_ctrl = devm_platform_ioremap_resource(pdev, 1); 456 return PTR_ERR_OR_ZERO(host->ufs_sys_ctrl); 457} 458 459static void ufs_hisi_set_pm_lvl(struct ufs_hba *hba) 460{ 461 hba->rpm_lvl = UFS_PM_LVL_1; 462 hba->spm_lvl = UFS_PM_LVL_3; 463} 464 465/** 466 * ufs_hisi_init_common 467 * @hba: host controller instance 468 */ 469static int ufs_hisi_init_common(struct ufs_hba *hba) 470{ 471 int err = 0; 472 struct device *dev = hba->dev; 473 struct ufs_hisi_host *host; 474 475 host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); 476 if (!host) 477 return -ENOMEM; 478 479 host->hba = hba; 480 ufshcd_set_variant(hba, host); 481 482 host->rst = devm_reset_control_get(dev, "rst"); 483 if (IS_ERR(host->rst)) { 484 dev_err(dev, "%s: failed to get reset control\n", __func__); 485 err = PTR_ERR(host->rst); 486 goto error; 487 } 488 489 ufs_hisi_set_pm_lvl(hba); 490 491 err = ufs_hisi_get_resource(host); 492 if (err) 493 goto error; 494 495 return 0; 496 497error: 498 ufshcd_set_variant(hba, NULL); 499 return err; 500} 501 502static int ufs_hi3660_init(struct ufs_hba *hba) 503{ 504 int ret = 0; 505 struct device *dev = hba->dev; 506 507 ret = ufs_hisi_init_common(hba); 508 if (ret) { 509 dev_err(dev, "%s: ufs common init fail\n", __func__); 510 return ret; 511 } 512 513 ufs_hisi_clk_init(hba); 514 515 ufs_hisi_soc_init(hba); 516 517 return 0; 518} 519 520static int ufs_hi3670_init(struct ufs_hba *hba) 521{ 522 int ret = 0; 523 struct device *dev = hba->dev; 524 struct ufs_hisi_host *host; 525 526 ret = ufs_hisi_init_common(hba); 527 if (ret) { 528 dev_err(dev, "%s: ufs common init fail\n", __func__); 529 return ret; 530 } 531 532 ufs_hisi_clk_init(hba); 533 534 ufs_hisi_soc_init(hba); 535 536 /* Add cap for 10nm PHY variant on HI3670 SoC */ 537 host = ufshcd_get_variant(hba); 538 host->caps |= UFS_HISI_CAP_PHY10nm; 539 540 return 0; 541} 542 543static const struct ufs_hba_variant_ops ufs_hba_hi3660_vops = { 544 .name = "hi3660", 545 .init = ufs_hi3660_init, 546 .link_startup_notify = ufs_hisi_link_startup_notify, 547 .pwr_change_notify = ufs_hisi_pwr_change_notify, 548 .suspend = ufs_hisi_suspend, 549 .resume = ufs_hisi_resume, 550}; 551 552static const struct ufs_hba_variant_ops ufs_hba_hi3670_vops = { 553 .name = "hi3670", 554 .init = ufs_hi3670_init, 555 .link_startup_notify = ufs_hisi_link_startup_notify, 556 .pwr_change_notify = ufs_hisi_pwr_change_notify, 557 .suspend = ufs_hisi_suspend, 558 .resume = ufs_hisi_resume, 559}; 560 561static const struct of_device_id ufs_hisi_of_match[] = { 562 { .compatible = "hisilicon,hi3660-ufs", .data = &ufs_hba_hi3660_vops }, 563 { .compatible = "hisilicon,hi3670-ufs", .data = &ufs_hba_hi3670_vops }, 564 {}, 565}; 566 567MODULE_DEVICE_TABLE(of, ufs_hisi_of_match); 568 569static int ufs_hisi_probe(struct platform_device *pdev) 570{ 571 const struct of_device_id *of_id; 572 573 of_id = of_match_node(ufs_hisi_of_match, pdev->dev.of_node); 574 575 return ufshcd_pltfrm_init(pdev, of_id->data); 576} 577 578static int ufs_hisi_remove(struct platform_device *pdev) 579{ 580 struct ufs_hba *hba = platform_get_drvdata(pdev); 581 582 ufshcd_remove(hba); 583 return 0; 584} 585 586static const struct dev_pm_ops ufs_hisi_pm_ops = { 587 SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume) 588 SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL) 589 .prepare = ufs_hisi_suspend_prepare, 590 .complete = ufshcd_resume_complete, 591}; 592 593static struct platform_driver ufs_hisi_pltform = { 594 .probe = ufs_hisi_probe, 595 .remove = ufs_hisi_remove, 596 .shutdown = ufshcd_pltfrm_shutdown, 597 .driver = { 598 .name = "ufshcd-hisi", 599 .pm = &ufs_hisi_pm_ops, 600 .of_match_table = of_match_ptr(ufs_hisi_of_match), 601 }, 602}; 603module_platform_driver(ufs_hisi_pltform); 604 605MODULE_LICENSE("GPL"); 606MODULE_ALIAS("platform:ufshcd-hisi"); 607MODULE_DESCRIPTION("HiSilicon Hixxxx UFS Driver");