162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * HiSilicon Hixxxx UFS Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2016-2017 Linaro Ltd.
662306a36Sopenharmony_ci * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/time.h>
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/of.h>
1362306a36Sopenharmony_ci#include <linux/of_address.h>
1462306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/reset.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <ufs/ufshcd.h>
1962306a36Sopenharmony_ci#include "ufshcd-pltfrm.h"
2062306a36Sopenharmony_ci#include <ufs/unipro.h>
2162306a36Sopenharmony_ci#include "ufs-hisi.h"
2262306a36Sopenharmony_ci#include <ufs/ufshci.h>
2362306a36Sopenharmony_ci#include <ufs/ufs_quirks.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic int ufs_hisi_check_hibern8(struct ufs_hba *hba)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	int err = 0;
2862306a36Sopenharmony_ci	u32 tx_fsm_val_0 = 0;
2962306a36Sopenharmony_ci	u32 tx_fsm_val_1 = 0;
3062306a36Sopenharmony_ci	unsigned long timeout = jiffies + msecs_to_jiffies(HBRN8_POLL_TOUT_MS);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	do {
3362306a36Sopenharmony_ci		err = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, 0),
3462306a36Sopenharmony_ci				      &tx_fsm_val_0);
3562306a36Sopenharmony_ci		err |= ufshcd_dme_get(hba,
3662306a36Sopenharmony_ci		    UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, 1), &tx_fsm_val_1);
3762306a36Sopenharmony_ci		if (err || (tx_fsm_val_0 == TX_FSM_HIBERN8 &&
3862306a36Sopenharmony_ci			tx_fsm_val_1 == TX_FSM_HIBERN8))
3962306a36Sopenharmony_ci			break;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci		/* sleep for max. 200us */
4262306a36Sopenharmony_ci		usleep_range(100, 200);
4362306a36Sopenharmony_ci	} while (time_before(jiffies, timeout));
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/*
4662306a36Sopenharmony_ci	 * we might have scheduled out for long during polling so
4762306a36Sopenharmony_ci	 * check the state again.
4862306a36Sopenharmony_ci	 */
4962306a36Sopenharmony_ci	if (time_after(jiffies, timeout)) {
5062306a36Sopenharmony_ci		err = ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, 0),
5162306a36Sopenharmony_ci				     &tx_fsm_val_0);
5262306a36Sopenharmony_ci		err |= ufshcd_dme_get(hba,
5362306a36Sopenharmony_ci		 UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, 1), &tx_fsm_val_1);
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (err) {
5762306a36Sopenharmony_ci		dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n",
5862306a36Sopenharmony_ci			__func__, err);
5962306a36Sopenharmony_ci	} else if (tx_fsm_val_0 != TX_FSM_HIBERN8 ||
6062306a36Sopenharmony_ci			 tx_fsm_val_1 != TX_FSM_HIBERN8) {
6162306a36Sopenharmony_ci		err = -1;
6262306a36Sopenharmony_ci		dev_err(hba->dev, "%s: invalid TX_FSM_STATE, lane0 = %d, lane1 = %d\n",
6362306a36Sopenharmony_ci			__func__, tx_fsm_val_0, tx_fsm_val_1);
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return err;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic void ufs_hisi_clk_init(struct ufs_hba *hba)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct ufs_hisi_host *host = ufshcd_get_variant(hba);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, BIT_SYSCTRL_REF_CLOCK_EN, PHY_CLK_CTRL);
7462306a36Sopenharmony_ci	if (ufs_sys_ctrl_readl(host, PHY_CLK_CTRL) & BIT_SYSCTRL_REF_CLOCK_EN)
7562306a36Sopenharmony_ci		mdelay(1);
7662306a36Sopenharmony_ci	/* use abb clk */
7762306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, BIT_UFS_REFCLK_SRC_SEl, UFS_SYSCTRL);
7862306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, BIT_UFS_REFCLK_ISO_EN, PHY_ISO_EN);
7962306a36Sopenharmony_ci	/* open mphy ref clk */
8062306a36Sopenharmony_ci	ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_REF_CLOCK_EN, PHY_CLK_CTRL);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic void ufs_hisi_soc_init(struct ufs_hba *hba)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct ufs_hisi_host *host = ufshcd_get_variant(hba);
8662306a36Sopenharmony_ci	u32 reg;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (!IS_ERR(host->rst))
8962306a36Sopenharmony_ci		reset_control_assert(host->rst);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* HC_PSW powerup */
9262306a36Sopenharmony_ci	ufs_sys_ctrl_set_bits(host, BIT_UFS_PSW_MTCMOS_EN, PSW_POWER_CTRL);
9362306a36Sopenharmony_ci	udelay(10);
9462306a36Sopenharmony_ci	/* notify PWR ready */
9562306a36Sopenharmony_ci	ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_PWR_READY, HC_LP_CTRL);
9662306a36Sopenharmony_ci	ufs_sys_ctrl_writel(host, MASK_UFS_DEVICE_RESET | 0,
9762306a36Sopenharmony_ci		UFS_DEVICE_RESET_CTRL);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	reg = ufs_sys_ctrl_readl(host, PHY_CLK_CTRL);
10062306a36Sopenharmony_ci	reg = (reg & ~MASK_SYSCTRL_CFG_CLOCK_FREQ) | UFS_FREQ_CFG_CLK;
10162306a36Sopenharmony_ci	/* set cfg clk freq */
10262306a36Sopenharmony_ci	ufs_sys_ctrl_writel(host, reg, PHY_CLK_CTRL);
10362306a36Sopenharmony_ci	/* set ref clk freq */
10462306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, MASK_SYSCTRL_REF_CLOCK_SEL, PHY_CLK_CTRL);
10562306a36Sopenharmony_ci	/* bypass ufs clk gate */
10662306a36Sopenharmony_ci	ufs_sys_ctrl_set_bits(host, MASK_UFS_CLK_GATE_BYPASS,
10762306a36Sopenharmony_ci						 CLOCK_GATE_BYPASS);
10862306a36Sopenharmony_ci	ufs_sys_ctrl_set_bits(host, MASK_UFS_SYSCRTL_BYPASS, UFS_SYSCTRL);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* open psw clk */
11162306a36Sopenharmony_ci	ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_PSW_CLK_EN, PSW_CLK_CTRL);
11262306a36Sopenharmony_ci	/* disable ufshc iso */
11362306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, BIT_UFS_PSW_ISO_CTRL, PSW_POWER_CTRL);
11462306a36Sopenharmony_ci	/* disable phy iso */
11562306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, BIT_UFS_PHY_ISO_CTRL, PHY_ISO_EN);
11662306a36Sopenharmony_ci	/* notice iso disable */
11762306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, BIT_SYSCTRL_LP_ISOL_EN, HC_LP_CTRL);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* disable lp_reset_n */
12062306a36Sopenharmony_ci	ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_LP_RESET_N, RESET_CTRL_EN);
12162306a36Sopenharmony_ci	mdelay(1);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	ufs_sys_ctrl_writel(host, MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET,
12462306a36Sopenharmony_ci		UFS_DEVICE_RESET_CTRL);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	msleep(20);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/*
12962306a36Sopenharmony_ci	 * enable the fix of linereset recovery,
13062306a36Sopenharmony_ci	 * and enable rx_reset/tx_rest beat
13162306a36Sopenharmony_ci	 * enable ref_clk_en override(bit5) &
13262306a36Sopenharmony_ci	 * override value = 1(bit4), with mask
13362306a36Sopenharmony_ci	 */
13462306a36Sopenharmony_ci	ufs_sys_ctrl_writel(host, 0x03300330, UFS_DEVICE_RESET_CTRL);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (!IS_ERR(host->rst))
13762306a36Sopenharmony_ci		reset_control_deassert(host->rst);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int ufs_hisi_link_startup_pre_change(struct ufs_hba *hba)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct ufs_hisi_host *host = ufshcd_get_variant(hba);
14362306a36Sopenharmony_ci	int err;
14462306a36Sopenharmony_ci	uint32_t value;
14562306a36Sopenharmony_ci	uint32_t reg;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	/* Unipro VS_mphy_disable */
14862306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD0C1, 0x0), 0x1);
14962306a36Sopenharmony_ci	/* PA_HSSeries */
15062306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x156A, 0x0), 0x2);
15162306a36Sopenharmony_ci	/* MPHY CBRATESEL */
15262306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8114, 0x0), 0x1);
15362306a36Sopenharmony_ci	/* MPHY CBOVRCTRL2 */
15462306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8121, 0x0), 0x2D);
15562306a36Sopenharmony_ci	/* MPHY CBOVRCTRL3 */
15662306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8122, 0x0), 0x1);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (host->caps & UFS_HISI_CAP_PHY10nm) {
15962306a36Sopenharmony_ci		/* MPHY CBOVRCTRL4 */
16062306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8127, 0x0), 0x98);
16162306a36Sopenharmony_ci		/* MPHY CBOVRCTRL5 */
16262306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8128, 0x0), 0x1);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* Unipro VS_MphyCfgUpdt */
16662306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD085, 0x0), 0x1);
16762306a36Sopenharmony_ci	/* MPHY RXOVRCTRL4 rx0 */
16862306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x800D, 0x4), 0x58);
16962306a36Sopenharmony_ci	/* MPHY RXOVRCTRL4 rx1 */
17062306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x800D, 0x5), 0x58);
17162306a36Sopenharmony_ci	/* MPHY RXOVRCTRL5 rx0 */
17262306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x800E, 0x4), 0xB);
17362306a36Sopenharmony_ci	/* MPHY RXOVRCTRL5 rx1 */
17462306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x800E, 0x5), 0xB);
17562306a36Sopenharmony_ci	/* MPHY RXSQCONTROL rx0 */
17662306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8009, 0x4), 0x1);
17762306a36Sopenharmony_ci	/* MPHY RXSQCONTROL rx1 */
17862306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8009, 0x5), 0x1);
17962306a36Sopenharmony_ci	/* Unipro VS_MphyCfgUpdt */
18062306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD085, 0x0), 0x1);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8113, 0x0), 0x1);
18362306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD085, 0x0), 0x1);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (host->caps & UFS_HISI_CAP_PHY10nm) {
18662306a36Sopenharmony_ci		/* RX_Hibern8Time_Capability*/
18762306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0092, 0x4), 0xA);
18862306a36Sopenharmony_ci		/* RX_Hibern8Time_Capability*/
18962306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0092, 0x5), 0xA);
19062306a36Sopenharmony_ci		/* RX_Min_ActivateTime */
19162306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008f, 0x4), 0xA);
19262306a36Sopenharmony_ci		/* RX_Min_ActivateTime*/
19362306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008f, 0x5), 0xA);
19462306a36Sopenharmony_ci	} else {
19562306a36Sopenharmony_ci		/* Tactive RX */
19662306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008F, 0x4), 0x7);
19762306a36Sopenharmony_ci		/* Tactive RX */
19862306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008F, 0x5), 0x7);
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Gear3 Synclength */
20262306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0095, 0x4), 0x4F);
20362306a36Sopenharmony_ci	/* Gear3 Synclength */
20462306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0095, 0x5), 0x4F);
20562306a36Sopenharmony_ci	/* Gear2 Synclength */
20662306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0094, 0x4), 0x4F);
20762306a36Sopenharmony_ci	/* Gear2 Synclength */
20862306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0094, 0x5), 0x4F);
20962306a36Sopenharmony_ci	/* Gear1 Synclength */
21062306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008B, 0x4), 0x4F);
21162306a36Sopenharmony_ci	/* Gear1 Synclength */
21262306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x008B, 0x5), 0x4F);
21362306a36Sopenharmony_ci	/* Thibernate Tx */
21462306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x000F, 0x0), 0x5);
21562306a36Sopenharmony_ci	/* Thibernate Tx */
21662306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x000F, 0x1), 0x5);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD085, 0x0), 0x1);
21962306a36Sopenharmony_ci	/* Unipro VS_mphy_disable */
22062306a36Sopenharmony_ci	ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(0xD0C1, 0x0), &value);
22162306a36Sopenharmony_ci	if (value != 0x1)
22262306a36Sopenharmony_ci		dev_info(hba->dev,
22362306a36Sopenharmony_ci		    "Warring!!! Unipro VS_mphy_disable is 0x%x\n", value);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* Unipro VS_mphy_disable */
22662306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD0C1, 0x0), 0x0);
22762306a36Sopenharmony_ci	err = ufs_hisi_check_hibern8(hba);
22862306a36Sopenharmony_ci	if (err)
22962306a36Sopenharmony_ci		dev_err(hba->dev, "ufs_hisi_check_hibern8 error\n");
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (!(host->caps & UFS_HISI_CAP_PHY10nm))
23262306a36Sopenharmony_ci		ufshcd_writel(hba, UFS_HCLKDIV_NORMAL_VALUE, UFS_REG_HCLKDIV);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* disable auto H8 */
23562306a36Sopenharmony_ci	reg = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER);
23662306a36Sopenharmony_ci	reg = reg & (~UFS_AHIT_AH8ITV_MASK);
23762306a36Sopenharmony_ci	ufshcd_writel(hba, reg, REG_AUTO_HIBERNATE_IDLE_TIMER);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* Unipro PA_Local_TX_LCC_Enable */
24062306a36Sopenharmony_ci	ufshcd_disable_host_tx_lcc(hba);
24162306a36Sopenharmony_ci	/* close Unipro VS_Mk2ExtnSupport */
24262306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xD0AB, 0x0), 0x0);
24362306a36Sopenharmony_ci	ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(0xD0AB, 0x0), &value);
24462306a36Sopenharmony_ci	if (value != 0) {
24562306a36Sopenharmony_ci		/* Ensure close success */
24662306a36Sopenharmony_ci		dev_info(hba->dev, "WARN: close VS_Mk2ExtnSupport failed\n");
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return err;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int ufs_hisi_link_startup_post_change(struct ufs_hba *hba)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct ufs_hisi_host *host = ufshcd_get_variant(hba);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* Unipro DL_AFC0CreditThreshold */
25762306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x2044), 0x0);
25862306a36Sopenharmony_ci	/* Unipro DL_TC0OutAckThreshold */
25962306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x2045), 0x0);
26062306a36Sopenharmony_ci	/* Unipro DL_TC0TXFCThreshold */
26162306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x2040), 0x9);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* not bypass ufs clk gate */
26462306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, MASK_UFS_CLK_GATE_BYPASS,
26562306a36Sopenharmony_ci						CLOCK_GATE_BYPASS);
26662306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, MASK_UFS_SYSCRTL_BYPASS,
26762306a36Sopenharmony_ci						UFS_SYSCTRL);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* select received symbol cnt */
27062306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0xd09a), 0x80000000);
27162306a36Sopenharmony_ci	 /* reset counter0 and enable */
27262306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0xd09c), 0x00000005);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic int ufs_hisi_link_startup_notify(struct ufs_hba *hba,
27862306a36Sopenharmony_ci					  enum ufs_notify_change_status status)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	int err = 0;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	switch (status) {
28362306a36Sopenharmony_ci	case PRE_CHANGE:
28462306a36Sopenharmony_ci		err = ufs_hisi_link_startup_pre_change(hba);
28562306a36Sopenharmony_ci		break;
28662306a36Sopenharmony_ci	case POST_CHANGE:
28762306a36Sopenharmony_ci		err = ufs_hisi_link_startup_post_change(hba);
28862306a36Sopenharmony_ci		break;
28962306a36Sopenharmony_ci	default:
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return err;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	ufshcd_init_pwr_dev_param(hisi_param);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct ufs_hisi_host *host = ufshcd_get_variant(hba);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (host->caps & UFS_HISI_CAP_PHY10nm) {
30662306a36Sopenharmony_ci		/*
30762306a36Sopenharmony_ci		 * Boston platform need to set SaveConfigTime to 0x13,
30862306a36Sopenharmony_ci		 * and change sync length to maximum value
30962306a36Sopenharmony_ci		 */
31062306a36Sopenharmony_ci		/* VS_DebugSaveConfigTime */
31162306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0xD0A0), 0x13);
31262306a36Sopenharmony_ci		/* g1 sync length */
31362306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x1552), 0x4f);
31462306a36Sopenharmony_ci		/* g2 sync length */
31562306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x1554), 0x4f);
31662306a36Sopenharmony_ci		/* g3 sync length */
31762306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x1556), 0x4f);
31862306a36Sopenharmony_ci		/* PA_Hibern8Time */
31962306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x15a7), 0xA);
32062306a36Sopenharmony_ci		/* PA_Tactivate */
32162306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB((u32)0x15a8), 0xA);
32262306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xd085, 0x0), 0x01);
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_VS_DEBUGSAVECONFIGTIME) {
32662306a36Sopenharmony_ci		pr_info("ufs flash device must set VS_DebugSaveConfigTime 0x10\n");
32762306a36Sopenharmony_ci		/* VS_DebugSaveConfigTime */
32862306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB(0xD0A0), 0x10);
32962306a36Sopenharmony_ci		/* sync length */
33062306a36Sopenharmony_ci		ufshcd_dme_set(hba, UIC_ARG_MIB(0x1556), 0x48);
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* update */
33462306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x15A8), 0x1);
33562306a36Sopenharmony_ci	/* PA_TxSkip */
33662306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x155c), 0x0);
33762306a36Sopenharmony_ci	/*PA_PWRModeUserData0 = 8191, default is 0*/
33862306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b0), SZ_8K - 1);
33962306a36Sopenharmony_ci	/*PA_PWRModeUserData1 = 65535, default is 0*/
34062306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b1), SZ_64K - 1);
34162306a36Sopenharmony_ci	/*PA_PWRModeUserData2 = 32767, default is 0*/
34262306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b2), SZ_32K - 1);
34362306a36Sopenharmony_ci	/*DME_FC0ProtectionTimeOutVal = 8191, default is 0*/
34462306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0xd041), SZ_8K - 1);
34562306a36Sopenharmony_ci	/*DME_TC0ReplayTimeOutVal = 65535, default is 0*/
34662306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0xd042), SZ_64K - 1);
34762306a36Sopenharmony_ci	/*DME_AFC0ReqTimeOutVal = 32767, default is 0*/
34862306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0xd043), SZ_32K - 1);
34962306a36Sopenharmony_ci	/*PA_PWRModeUserData3 = 8191, default is 0*/
35062306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b3), SZ_8K - 1);
35162306a36Sopenharmony_ci	/*PA_PWRModeUserData4 = 65535, default is 0*/
35262306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b4), SZ_64K - 1);
35362306a36Sopenharmony_ci	/*PA_PWRModeUserData5 = 32767, default is 0*/
35462306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0x15b5), SZ_32K - 1);
35562306a36Sopenharmony_ci	/*DME_FC1ProtectionTimeOutVal = 8191, default is 0*/
35662306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0xd044), SZ_8K - 1);
35762306a36Sopenharmony_ci	/*DME_TC1ReplayTimeOutVal = 65535, default is 0*/
35862306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0xd045), SZ_64K - 1);
35962306a36Sopenharmony_ci	/*DME_AFC1ReqTimeOutVal = 32767, default is 0*/
36062306a36Sopenharmony_ci	ufshcd_dme_set(hba, UIC_ARG_MIB(0xd046), SZ_32K - 1);
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic int ufs_hisi_pwr_change_notify(struct ufs_hba *hba,
36462306a36Sopenharmony_ci				       enum ufs_notify_change_status status,
36562306a36Sopenharmony_ci				       struct ufs_pa_layer_attr *dev_max_params,
36662306a36Sopenharmony_ci				       struct ufs_pa_layer_attr *dev_req_params)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct ufs_dev_params ufs_hisi_cap;
36962306a36Sopenharmony_ci	int ret = 0;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (!dev_req_params) {
37262306a36Sopenharmony_ci		dev_err(hba->dev,
37362306a36Sopenharmony_ci			    "%s: incoming dev_req_params is NULL\n", __func__);
37462306a36Sopenharmony_ci		ret = -EINVAL;
37562306a36Sopenharmony_ci		goto out;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	switch (status) {
37962306a36Sopenharmony_ci	case PRE_CHANGE:
38062306a36Sopenharmony_ci		ufs_hisi_set_dev_cap(&ufs_hisi_cap);
38162306a36Sopenharmony_ci		ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap,
38262306a36Sopenharmony_ci					       dev_max_params, dev_req_params);
38362306a36Sopenharmony_ci		if (ret) {
38462306a36Sopenharmony_ci			dev_err(hba->dev,
38562306a36Sopenharmony_ci			    "%s: failed to determine capabilities\n", __func__);
38662306a36Sopenharmony_ci			goto out;
38762306a36Sopenharmony_ci		}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		ufs_hisi_pwr_change_pre_change(hba);
39062306a36Sopenharmony_ci		break;
39162306a36Sopenharmony_ci	case POST_CHANGE:
39262306a36Sopenharmony_ci		break;
39362306a36Sopenharmony_ci	default:
39462306a36Sopenharmony_ci		ret = -EINVAL;
39562306a36Sopenharmony_ci		break;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ciout:
39862306a36Sopenharmony_ci	return ret;
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic int ufs_hisi_suspend_prepare(struct device *dev)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	/* RPM and SPM are different. Refer ufs_hisi_suspend() */
40462306a36Sopenharmony_ci	return __ufshcd_suspend_prepare(dev, false);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic int ufs_hisi_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
40862306a36Sopenharmony_ci	enum ufs_notify_change_status status)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct ufs_hisi_host *host = ufshcd_get_variant(hba);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (status == PRE_CHANGE)
41362306a36Sopenharmony_ci		return 0;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (pm_op == UFS_RUNTIME_PM)
41662306a36Sopenharmony_ci		return 0;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if (host->in_suspend) {
41962306a36Sopenharmony_ci		WARN_ON(1);
42062306a36Sopenharmony_ci		return 0;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	ufs_sys_ctrl_clr_bits(host, BIT_SYSCTRL_REF_CLOCK_EN, PHY_CLK_CTRL);
42462306a36Sopenharmony_ci	udelay(10);
42562306a36Sopenharmony_ci	/* set ref_dig_clk override of PHY PCS to 0 */
42662306a36Sopenharmony_ci	ufs_sys_ctrl_writel(host, 0x00100000, UFS_DEVICE_RESET_CTRL);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	host->in_suspend = true;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	return 0;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic int ufs_hisi_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct ufs_hisi_host *host = ufshcd_get_variant(hba);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (!host->in_suspend)
43862306a36Sopenharmony_ci		return 0;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	/* set ref_dig_clk override of PHY PCS to 1 */
44162306a36Sopenharmony_ci	ufs_sys_ctrl_writel(host, 0x00100010, UFS_DEVICE_RESET_CTRL);
44262306a36Sopenharmony_ci	udelay(10);
44362306a36Sopenharmony_ci	ufs_sys_ctrl_set_bits(host, BIT_SYSCTRL_REF_CLOCK_EN, PHY_CLK_CTRL);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	host->in_suspend = false;
44662306a36Sopenharmony_ci	return 0;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic int ufs_hisi_get_resource(struct ufs_hisi_host *host)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct device *dev = host->hba->dev;
45262306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* get resource of ufs sys ctrl */
45562306a36Sopenharmony_ci	host->ufs_sys_ctrl = devm_platform_ioremap_resource(pdev, 1);
45662306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(host->ufs_sys_ctrl);
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic void ufs_hisi_set_pm_lvl(struct ufs_hba *hba)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	hba->rpm_lvl = UFS_PM_LVL_1;
46262306a36Sopenharmony_ci	hba->spm_lvl = UFS_PM_LVL_3;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci/**
46662306a36Sopenharmony_ci * ufs_hisi_init_common
46762306a36Sopenharmony_ci * @hba: host controller instance
46862306a36Sopenharmony_ci */
46962306a36Sopenharmony_cistatic int ufs_hisi_init_common(struct ufs_hba *hba)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	int err = 0;
47262306a36Sopenharmony_ci	struct device *dev = hba->dev;
47362306a36Sopenharmony_ci	struct ufs_hisi_host *host;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
47662306a36Sopenharmony_ci	if (!host)
47762306a36Sopenharmony_ci		return -ENOMEM;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	host->hba = hba;
48062306a36Sopenharmony_ci	ufshcd_set_variant(hba, host);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	host->rst = devm_reset_control_get(dev, "rst");
48362306a36Sopenharmony_ci	if (IS_ERR(host->rst)) {
48462306a36Sopenharmony_ci		dev_err(dev, "%s: failed to get reset control\n", __func__);
48562306a36Sopenharmony_ci		err = PTR_ERR(host->rst);
48662306a36Sopenharmony_ci		goto error;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	ufs_hisi_set_pm_lvl(hba);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	err = ufs_hisi_get_resource(host);
49262306a36Sopenharmony_ci	if (err)
49362306a36Sopenharmony_ci		goto error;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	return 0;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cierror:
49862306a36Sopenharmony_ci	ufshcd_set_variant(hba, NULL);
49962306a36Sopenharmony_ci	return err;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic int ufs_hi3660_init(struct ufs_hba *hba)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	int ret = 0;
50562306a36Sopenharmony_ci	struct device *dev = hba->dev;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	ret = ufs_hisi_init_common(hba);
50862306a36Sopenharmony_ci	if (ret) {
50962306a36Sopenharmony_ci		dev_err(dev, "%s: ufs common init fail\n", __func__);
51062306a36Sopenharmony_ci		return ret;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	ufs_hisi_clk_init(hba);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	ufs_hisi_soc_init(hba);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	return 0;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int ufs_hi3670_init(struct ufs_hba *hba)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	int ret = 0;
52362306a36Sopenharmony_ci	struct device *dev = hba->dev;
52462306a36Sopenharmony_ci	struct ufs_hisi_host *host;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	ret = ufs_hisi_init_common(hba);
52762306a36Sopenharmony_ci	if (ret) {
52862306a36Sopenharmony_ci		dev_err(dev, "%s: ufs common init fail\n", __func__);
52962306a36Sopenharmony_ci		return ret;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	ufs_hisi_clk_init(hba);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ufs_hisi_soc_init(hba);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* Add cap for 10nm PHY variant on HI3670 SoC */
53762306a36Sopenharmony_ci	host = ufshcd_get_variant(hba);
53862306a36Sopenharmony_ci	host->caps |= UFS_HISI_CAP_PHY10nm;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	return 0;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic const struct ufs_hba_variant_ops ufs_hba_hi3660_vops = {
54462306a36Sopenharmony_ci	.name = "hi3660",
54562306a36Sopenharmony_ci	.init = ufs_hi3660_init,
54662306a36Sopenharmony_ci	.link_startup_notify = ufs_hisi_link_startup_notify,
54762306a36Sopenharmony_ci	.pwr_change_notify = ufs_hisi_pwr_change_notify,
54862306a36Sopenharmony_ci	.suspend = ufs_hisi_suspend,
54962306a36Sopenharmony_ci	.resume = ufs_hisi_resume,
55062306a36Sopenharmony_ci};
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic const struct ufs_hba_variant_ops ufs_hba_hi3670_vops = {
55362306a36Sopenharmony_ci	.name = "hi3670",
55462306a36Sopenharmony_ci	.init = ufs_hi3670_init,
55562306a36Sopenharmony_ci	.link_startup_notify = ufs_hisi_link_startup_notify,
55662306a36Sopenharmony_ci	.pwr_change_notify = ufs_hisi_pwr_change_notify,
55762306a36Sopenharmony_ci	.suspend = ufs_hisi_suspend,
55862306a36Sopenharmony_ci	.resume = ufs_hisi_resume,
55962306a36Sopenharmony_ci};
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic const struct of_device_id ufs_hisi_of_match[] = {
56262306a36Sopenharmony_ci	{ .compatible = "hisilicon,hi3660-ufs", .data = &ufs_hba_hi3660_vops },
56362306a36Sopenharmony_ci	{ .compatible = "hisilicon,hi3670-ufs", .data = &ufs_hba_hi3670_vops },
56462306a36Sopenharmony_ci	{},
56562306a36Sopenharmony_ci};
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ufs_hisi_of_match);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic int ufs_hisi_probe(struct platform_device *pdev)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	const struct of_device_id *of_id;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	of_id = of_match_node(ufs_hisi_of_match, pdev->dev.of_node);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return ufshcd_pltfrm_init(pdev, of_id->data);
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic int ufs_hisi_remove(struct platform_device *pdev)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct ufs_hba *hba =  platform_get_drvdata(pdev);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	ufshcd_remove(hba);
58362306a36Sopenharmony_ci	return 0;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic const struct dev_pm_ops ufs_hisi_pm_ops = {
58762306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume)
58862306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL)
58962306a36Sopenharmony_ci	.prepare	 = ufs_hisi_suspend_prepare,
59062306a36Sopenharmony_ci	.complete	 = ufshcd_resume_complete,
59162306a36Sopenharmony_ci};
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic struct platform_driver ufs_hisi_pltform = {
59462306a36Sopenharmony_ci	.probe	= ufs_hisi_probe,
59562306a36Sopenharmony_ci	.remove	= ufs_hisi_remove,
59662306a36Sopenharmony_ci	.driver	= {
59762306a36Sopenharmony_ci		.name	= "ufshcd-hisi",
59862306a36Sopenharmony_ci		.pm	= &ufs_hisi_pm_ops,
59962306a36Sopenharmony_ci		.of_match_table = ufs_hisi_of_match,
60062306a36Sopenharmony_ci	},
60162306a36Sopenharmony_ci};
60262306a36Sopenharmony_cimodule_platform_driver(ufs_hisi_pltform);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
60562306a36Sopenharmony_ciMODULE_ALIAS("platform:ufshcd-hisi");
60662306a36Sopenharmony_ciMODULE_DESCRIPTION("HiSilicon Hixxxx UFS Driver");
607