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