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