162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * UNISOC UFS Host Controller driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2022 Unisoc, Inc. 662306a36Sopenharmony_ci * Author: Zhe Wang <zhe.wang1@unisoc.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/arm-smccc.h> 1062306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/regmap.h> 1462306a36Sopenharmony_ci#include <linux/reset.h> 1562306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <ufs/ufshcd.h> 1862306a36Sopenharmony_ci#include "ufshcd-pltfrm.h" 1962306a36Sopenharmony_ci#include "ufs-sprd.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic const struct of_device_id ufs_sprd_of_match[]; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic struct ufs_sprd_priv *ufs_sprd_get_priv_data(struct ufs_hba *hba) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct ufs_sprd_host *host = ufshcd_get_variant(hba); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci WARN_ON(!host->priv); 2862306a36Sopenharmony_ci return host->priv; 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void ufs_sprd_regmap_update(struct ufs_sprd_priv *priv, unsigned int index, 3262306a36Sopenharmony_ci unsigned int reg, unsigned int bits, unsigned int val) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci regmap_update_bits(priv->sysci[index].regmap, reg, bits, val); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void ufs_sprd_regmap_read(struct ufs_sprd_priv *priv, unsigned int index, 3862306a36Sopenharmony_ci unsigned int reg, unsigned int *val) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci regmap_read(priv->sysci[index].regmap, reg, val); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic void ufs_sprd_get_unipro_ver(struct ufs_hba *hba) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct ufs_sprd_host *host = ufshcd_get_variant(hba); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (ufshcd_dme_get(hba, UIC_ARG_MIB(PA_LOCALVERINFO), &host->unipro_ver)) 4862306a36Sopenharmony_ci host->unipro_ver = 0; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void ufs_sprd_ctrl_uic_compl(struct ufs_hba *hba, bool enable) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (enable == true) 5662306a36Sopenharmony_ci set |= UIC_COMMAND_COMPL; 5762306a36Sopenharmony_ci else 5862306a36Sopenharmony_ci set &= ~UIC_COMMAND_COMPL; 5962306a36Sopenharmony_ci ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic int ufs_sprd_get_reset_ctrl(struct device *dev, struct ufs_sprd_rst *rci) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci rci->rc = devm_reset_control_get(dev, rci->name); 6562306a36Sopenharmony_ci if (IS_ERR(rci->rc)) { 6662306a36Sopenharmony_ci dev_err(dev, "failed to get reset ctrl:%s\n", rci->name); 6762306a36Sopenharmony_ci return PTR_ERR(rci->rc); 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int ufs_sprd_get_syscon_reg(struct device *dev, struct ufs_sprd_syscon *sysci) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci sysci->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, sysci->name); 7662306a36Sopenharmony_ci if (IS_ERR(sysci->regmap)) { 7762306a36Sopenharmony_ci dev_err(dev, "failed to get ufs syscon:%s\n", sysci->name); 7862306a36Sopenharmony_ci return PTR_ERR(sysci->regmap); 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int ufs_sprd_get_vreg(struct device *dev, struct ufs_sprd_vreg *vregi) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci vregi->vreg = devm_regulator_get(dev, vregi->name); 8762306a36Sopenharmony_ci if (IS_ERR(vregi->vreg)) { 8862306a36Sopenharmony_ci dev_err(dev, "failed to get vreg:%s\n", vregi->name); 8962306a36Sopenharmony_ci return PTR_ERR(vregi->vreg); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int ufs_sprd_parse_dt(struct device *dev, struct ufs_hba *hba, struct ufs_sprd_host *host) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci u32 i; 9862306a36Sopenharmony_ci struct ufs_sprd_priv *priv = host->priv; 9962306a36Sopenharmony_ci int ret = 0; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* Parse UFS reset ctrl info */ 10262306a36Sopenharmony_ci for (i = 0; i < SPRD_UFS_RST_MAX; i++) { 10362306a36Sopenharmony_ci if (!priv->rci[i].name) 10462306a36Sopenharmony_ci continue; 10562306a36Sopenharmony_ci ret = ufs_sprd_get_reset_ctrl(dev, &priv->rci[i]); 10662306a36Sopenharmony_ci if (ret) 10762306a36Sopenharmony_ci goto out; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Parse UFS syscon reg info */ 11162306a36Sopenharmony_ci for (i = 0; i < SPRD_UFS_SYSCON_MAX; i++) { 11262306a36Sopenharmony_ci if (!priv->sysci[i].name) 11362306a36Sopenharmony_ci continue; 11462306a36Sopenharmony_ci ret = ufs_sprd_get_syscon_reg(dev, &priv->sysci[i]); 11562306a36Sopenharmony_ci if (ret) 11662306a36Sopenharmony_ci goto out; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* Parse UFS vreg info */ 12062306a36Sopenharmony_ci for (i = 0; i < SPRD_UFS_VREG_MAX; i++) { 12162306a36Sopenharmony_ci if (!priv->vregi[i].name) 12262306a36Sopenharmony_ci continue; 12362306a36Sopenharmony_ci ret = ufs_sprd_get_vreg(dev, &priv->vregi[i]); 12462306a36Sopenharmony_ci if (ret) 12562306a36Sopenharmony_ci goto out; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciout: 12962306a36Sopenharmony_ci return ret; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int ufs_sprd_common_init(struct ufs_hba *hba) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct device *dev = hba->dev; 13562306a36Sopenharmony_ci struct ufs_sprd_host *host; 13662306a36Sopenharmony_ci struct platform_device __maybe_unused *pdev = to_platform_device(dev); 13762306a36Sopenharmony_ci const struct of_device_id *of_id; 13862306a36Sopenharmony_ci int ret = 0; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); 14162306a36Sopenharmony_ci if (!host) 14262306a36Sopenharmony_ci return -ENOMEM; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci of_id = of_match_node(ufs_sprd_of_match, pdev->dev.of_node); 14562306a36Sopenharmony_ci if (of_id->data != NULL) 14662306a36Sopenharmony_ci host->priv = container_of(of_id->data, struct ufs_sprd_priv, 14762306a36Sopenharmony_ci ufs_hba_sprd_vops); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci host->hba = hba; 15062306a36Sopenharmony_ci ufshcd_set_variant(hba, host); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci hba->caps |= UFSHCD_CAP_CLK_GATING | 15362306a36Sopenharmony_ci UFSHCD_CAP_CRYPTO | 15462306a36Sopenharmony_ci UFSHCD_CAP_WB_EN; 15562306a36Sopenharmony_ci hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci ret = ufs_sprd_parse_dt(dev, hba, host); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return ret; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int sprd_ufs_pwr_change_notify(struct ufs_hba *hba, 16362306a36Sopenharmony_ci enum ufs_notify_change_status status, 16462306a36Sopenharmony_ci struct ufs_pa_layer_attr *dev_max_params, 16562306a36Sopenharmony_ci struct ufs_pa_layer_attr *dev_req_params) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct ufs_sprd_host *host = ufshcd_get_variant(hba); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (status == PRE_CHANGE) { 17062306a36Sopenharmony_ci memcpy(dev_req_params, dev_max_params, 17162306a36Sopenharmony_ci sizeof(struct ufs_pa_layer_attr)); 17262306a36Sopenharmony_ci if (host->unipro_ver >= UFS_UNIPRO_VER_1_8) 17362306a36Sopenharmony_ci ufshcd_dme_configure_adapt(hba, dev_req_params->gear_tx, 17462306a36Sopenharmony_ci PA_INITIAL_ADAPT); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int ufs_sprd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op, 18162306a36Sopenharmony_ci enum ufs_notify_change_status status) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci unsigned long flags; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (status == PRE_CHANGE) { 18662306a36Sopenharmony_ci if (ufshcd_is_auto_hibern8_supported(hba)) { 18762306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 18862306a36Sopenharmony_ci ufshcd_writel(hba, 0, REG_AUTO_HIBERNATE_IDLE_TIMER); 18962306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void ufs_sprd_n6_host_reset(struct ufs_hba *hba) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci dev_info(hba->dev, "ufs host reset!\n"); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci reset_control_assert(priv->rci[SPRD_UFSHCI_SOFT_RST].rc); 20362306a36Sopenharmony_ci usleep_range(1000, 1100); 20462306a36Sopenharmony_ci reset_control_deassert(priv->rci[SPRD_UFSHCI_SOFT_RST].rc); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int ufs_sprd_n6_device_reset(struct ufs_hba *hba) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci dev_info(hba->dev, "ufs device reset!\n"); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci reset_control_assert(priv->rci[SPRD_UFS_DEV_RST].rc); 21462306a36Sopenharmony_ci usleep_range(1000, 1100); 21562306a36Sopenharmony_ci reset_control_deassert(priv->rci[SPRD_UFS_DEV_RST].rc); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic void ufs_sprd_n6_key_acc_enable(struct ufs_hba *hba) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci u32 val; 22362306a36Sopenharmony_ci u32 retry = 10; 22462306a36Sopenharmony_ci struct arm_smccc_res res; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cicheck_hce: 22762306a36Sopenharmony_ci /* Key access only can be enabled under HCE enable */ 22862306a36Sopenharmony_ci val = ufshcd_readl(hba, REG_CONTROLLER_ENABLE); 22962306a36Sopenharmony_ci if (!(val & CONTROLLER_ENABLE)) { 23062306a36Sopenharmony_ci ufs_sprd_n6_host_reset(hba); 23162306a36Sopenharmony_ci val |= CONTROLLER_ENABLE; 23262306a36Sopenharmony_ci ufshcd_writel(hba, val, REG_CONTROLLER_ENABLE); 23362306a36Sopenharmony_ci usleep_range(1000, 1100); 23462306a36Sopenharmony_ci if (retry) { 23562306a36Sopenharmony_ci retry--; 23662306a36Sopenharmony_ci goto check_hce; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci goto disable_crypto; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci arm_smccc_smc(SPRD_SIP_SVC_STORAGE_UFS_CRYPTO_ENABLE, 24262306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, &res); 24362306a36Sopenharmony_ci if (!res.a0) 24462306a36Sopenharmony_ci return; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cidisable_crypto: 24762306a36Sopenharmony_ci dev_err(hba->dev, "key reg access enable fail, disable crypto\n"); 24862306a36Sopenharmony_ci hba->caps &= ~UFSHCD_CAP_CRYPTO; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int ufs_sprd_n6_init(struct ufs_hba *hba) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct ufs_sprd_priv *priv; 25462306a36Sopenharmony_ci int ret = 0; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci ret = ufs_sprd_common_init(hba); 25762306a36Sopenharmony_ci if (ret != 0) 25862306a36Sopenharmony_ci return ret; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci priv = ufs_sprd_get_priv_data(hba); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci ret = regulator_enable(priv->vregi[SPRD_UFS_VDD_MPHY].vreg); 26362306a36Sopenharmony_ci if (ret) 26462306a36Sopenharmony_ci return -ENODEV; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (hba->caps & UFSHCD_CAP_CRYPTO) 26762306a36Sopenharmony_ci ufs_sprd_n6_key_acc_enable(hba); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int ufs_sprd_n6_phy_init(struct ufs_hba *hba) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci int ret = 0; 27562306a36Sopenharmony_ci uint32_t val = 0; 27662306a36Sopenharmony_ci uint32_t retry = 10; 27762306a36Sopenharmony_ci uint32_t offset; 27862306a36Sopenharmony_ci struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(CBREFCLKCTRL2), 0x90); 28162306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(CBCRCTRL), 0x01); 28262306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RXSQCONTROL, 28362306a36Sopenharmony_ci UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x01); 28462306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RXSQCONTROL, 28562306a36Sopenharmony_ci UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x01); 28662306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01); 28762306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(CBRATESEL), 0x01); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci do { 29062306a36Sopenharmony_ci /* phy_sram_init_done */ 29162306a36Sopenharmony_ci ufs_sprd_regmap_read(priv, SPRD_UFS_ANLG, 0xc, &val); 29262306a36Sopenharmony_ci if ((val & 0x1) == 0x1) { 29362306a36Sopenharmony_ci for (offset = 0x40; offset < 0x42; offset++) { 29462306a36Sopenharmony_ci /* Lane afe calibration */ 29562306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGADDRLSB), 0x1c); 29662306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGADDRMSB), offset); 29762306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGWRLSB), 0x04); 29862306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGWRMSB), 0x00); 29962306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGRDWRSEL), 0x01); 30062306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci goto update_phy; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci udelay(1000); 30662306a36Sopenharmony_ci retry--; 30762306a36Sopenharmony_ci } while (retry > 0); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci ret = -ETIMEDOUT; 31062306a36Sopenharmony_ci goto out; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ciupdate_phy: 31362306a36Sopenharmony_ci /* phy_sram_ext_ld_done */ 31462306a36Sopenharmony_ci ufs_sprd_regmap_update(priv, SPRD_UFS_ANLG, 0xc, 0x2, 0); 31562306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01); 31662306a36Sopenharmony_ci ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYDISABLE), 0x0); 31762306a36Sopenharmony_ciout: 31862306a36Sopenharmony_ci return ret; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic int sprd_ufs_n6_hce_enable_notify(struct ufs_hba *hba, 32362306a36Sopenharmony_ci enum ufs_notify_change_status status) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci int err = 0; 32662306a36Sopenharmony_ci struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (status == PRE_CHANGE) { 32962306a36Sopenharmony_ci /* phy_sram_ext_ld_done */ 33062306a36Sopenharmony_ci ufs_sprd_regmap_update(priv, SPRD_UFS_ANLG, 0xc, 0x2, 0x2); 33162306a36Sopenharmony_ci /* phy_sram_bypass */ 33262306a36Sopenharmony_ci ufs_sprd_regmap_update(priv, SPRD_UFS_ANLG, 0xc, 0x4, 0x4); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ufs_sprd_n6_host_reset(hba); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (hba->caps & UFSHCD_CAP_CRYPTO) 33762306a36Sopenharmony_ci ufs_sprd_n6_key_acc_enable(hba); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (status == POST_CHANGE) { 34162306a36Sopenharmony_ci err = ufs_sprd_n6_phy_init(hba); 34262306a36Sopenharmony_ci if (err) { 34362306a36Sopenharmony_ci dev_err(hba->dev, "Phy setup failed (%d)\n", err); 34462306a36Sopenharmony_ci goto out; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci ufs_sprd_get_unipro_ver(hba); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ciout: 35062306a36Sopenharmony_ci return err; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic void sprd_ufs_n6_h8_notify(struct ufs_hba *hba, 35462306a36Sopenharmony_ci enum uic_cmd_dme cmd, 35562306a36Sopenharmony_ci enum ufs_notify_change_status status) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (status == PRE_CHANGE) { 36062306a36Sopenharmony_ci if (cmd == UIC_CMD_DME_HIBER_ENTER) 36162306a36Sopenharmony_ci /* 36262306a36Sopenharmony_ci * Disable UIC COMPL INTR to prevent access to UFSHCI after 36362306a36Sopenharmony_ci * checking HCS.UPMCRS 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_ci ufs_sprd_ctrl_uic_compl(hba, false); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (cmd == UIC_CMD_DME_HIBER_EXIT) { 36862306a36Sopenharmony_ci ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_UFSDEV_REG, 36962306a36Sopenharmony_ci APB_UFSDEV_REFCLK_EN, APB_UFSDEV_REFCLK_EN); 37062306a36Sopenharmony_ci ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_USB31PLL_CTRL, 37162306a36Sopenharmony_ci APB_USB31PLLV_REF2MPHY, APB_USB31PLLV_REF2MPHY); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (status == POST_CHANGE) { 37662306a36Sopenharmony_ci if (cmd == UIC_CMD_DME_HIBER_EXIT) 37762306a36Sopenharmony_ci ufs_sprd_ctrl_uic_compl(hba, true); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (cmd == UIC_CMD_DME_HIBER_ENTER) { 38062306a36Sopenharmony_ci ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_UFSDEV_REG, 38162306a36Sopenharmony_ci APB_UFSDEV_REFCLK_EN, 0); 38262306a36Sopenharmony_ci ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_USB31PLL_CTRL, 38362306a36Sopenharmony_ci APB_USB31PLLV_REF2MPHY, 0); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic struct ufs_sprd_priv n6_ufs = { 38962306a36Sopenharmony_ci .rci[SPRD_UFSHCI_SOFT_RST] = { .name = "controller", }, 39062306a36Sopenharmony_ci .rci[SPRD_UFS_DEV_RST] = { .name = "device", }, 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci .sysci[SPRD_UFS_ANLG] = { .name = "sprd,ufs-anlg-syscon", }, 39362306a36Sopenharmony_ci .sysci[SPRD_UFS_AON_APB] = { .name = "sprd,aon-apb-syscon", }, 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci .vregi[SPRD_UFS_VDD_MPHY] = { .name = "vdd-mphy", }, 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci .ufs_hba_sprd_vops = { 39862306a36Sopenharmony_ci .name = "sprd,ums9620-ufs", 39962306a36Sopenharmony_ci .init = ufs_sprd_n6_init, 40062306a36Sopenharmony_ci .hce_enable_notify = sprd_ufs_n6_hce_enable_notify, 40162306a36Sopenharmony_ci .pwr_change_notify = sprd_ufs_pwr_change_notify, 40262306a36Sopenharmony_ci .hibern8_notify = sprd_ufs_n6_h8_notify, 40362306a36Sopenharmony_ci .device_reset = ufs_sprd_n6_device_reset, 40462306a36Sopenharmony_ci .suspend = ufs_sprd_suspend, 40562306a36Sopenharmony_ci }, 40662306a36Sopenharmony_ci}; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic const struct of_device_id __maybe_unused ufs_sprd_of_match[] = { 40962306a36Sopenharmony_ci { .compatible = "sprd,ums9620-ufs", .data = &n6_ufs.ufs_hba_sprd_vops}, 41062306a36Sopenharmony_ci {}, 41162306a36Sopenharmony_ci}; 41262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ufs_sprd_of_match); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic int ufs_sprd_probe(struct platform_device *pdev) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci int err; 41762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 41862306a36Sopenharmony_ci const struct of_device_id *of_id; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci of_id = of_match_node(ufs_sprd_of_match, dev->of_node); 42162306a36Sopenharmony_ci err = ufshcd_pltfrm_init(pdev, of_id->data); 42262306a36Sopenharmony_ci if (err) 42362306a36Sopenharmony_ci dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return err; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int ufs_sprd_remove(struct platform_device *pdev) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct ufs_hba *hba = platform_get_drvdata(pdev); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci pm_runtime_get_sync(&(pdev)->dev); 43362306a36Sopenharmony_ci ufshcd_remove(hba); 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const struct dev_pm_ops ufs_sprd_pm_ops = { 43862306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume) 43962306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL) 44062306a36Sopenharmony_ci .prepare = ufshcd_suspend_prepare, 44162306a36Sopenharmony_ci .complete = ufshcd_resume_complete, 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic struct platform_driver ufs_sprd_pltform = { 44562306a36Sopenharmony_ci .probe = ufs_sprd_probe, 44662306a36Sopenharmony_ci .remove = ufs_sprd_remove, 44762306a36Sopenharmony_ci .driver = { 44862306a36Sopenharmony_ci .name = "ufshcd-sprd", 44962306a36Sopenharmony_ci .pm = &ufs_sprd_pm_ops, 45062306a36Sopenharmony_ci .of_match_table = of_match_ptr(ufs_sprd_of_match), 45162306a36Sopenharmony_ci }, 45262306a36Sopenharmony_ci}; 45362306a36Sopenharmony_cimodule_platform_driver(ufs_sprd_pltform); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ciMODULE_AUTHOR("Zhe Wang <zhe.wang1@unisoc.com>"); 45662306a36Sopenharmony_ciMODULE_DESCRIPTION("Unisoc UFS Host Driver"); 45762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 458