scsi: ufs-msm: re-factoring the ufs phy to support various phys
This re-factor is required in order to provide a robust way to support multiple ufs phys. It also creates a better separation between ufs-msm block, ufs-msm-phy block and the specific phy blocks. In this change a generic phy handle is created, using the phy driver framework. Two ufs phys are currently supported: 28nm and 20nm This change also includes the required DT changes as in this case, the driver changes and the DT changes must be placed within the same change. Change-Id: I3aa7ed942ed7b54f3a29c9b9dbdeff1861079066 Signed-off-by: Noa Rubens <noag@codeaurora.org> Signed-off-by: Gilad Broner <gbroner@codeaurora.org> Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org> [gbroner@codeaurora.org: fix merge conflicts in apq8084 and msm8994 device tree files] Signed-off-by: Gilad Broner <gbroner@codeaurora.org> [subhashj@codeaurora.org: resolved merge conflicts, dropped changes to msm8994.dtsi and fixed compilation errors] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org> [venkatg@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
This commit is contained in:
parent
47bce9e8ba
commit
b06e5004fb
10 changed files with 2644 additions and 2519 deletions
|
@ -7,8 +7,11 @@ To bind UFS PHY with UFS host controller, the controller node should
|
|||
contain a phandle reference to UFS PHY node.
|
||||
|
||||
Required properties:
|
||||
- compatible : compatible list, contains "qcom,ufsphy"
|
||||
- compatible : compatible list, contains "qcom,ufs-msm-phy-qmp-28nm"
|
||||
or "qcom,ufs-msm-phy-qmp-20nm" according to the relevant
|
||||
phy in use
|
||||
- reg : <registers mapping>
|
||||
- #phy-cells : This property shall be set to 0
|
||||
- vdda-phy-supply : phandle to main PHY supply for analog domain
|
||||
- vdda-pll-supply : phandle to PHY PLL and Power-Gen block power supply
|
||||
|
||||
|
@ -19,8 +22,9 @@ Optional properties:
|
|||
Example:
|
||||
|
||||
ufsphy1: ufsphy@0xfc597000 {
|
||||
compatible = "qcom,ufsphy";
|
||||
compatible = "qcom,ufs-msm-phy-qmp-28nm";
|
||||
reg = <0xfc597000 0x800>;
|
||||
#phy-cells = <0>;
|
||||
vdda-phy-supply = <&pma8084_l4>;
|
||||
vdda-pll-supply = <&pma8084_l12>;
|
||||
vdda-phy-max-microamp = <50000>;
|
||||
|
@ -29,5 +33,5 @@ Example:
|
|||
|
||||
ufshc@0xfc598000 {
|
||||
...
|
||||
ufs-phy = <&ufsphy1>;
|
||||
phys = <&ufsphy1>;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# UFSHCD makefile
|
||||
obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
|
||||
obj-$(CONFIG_SCSI_UFS_MSM) += ufs-msm-phy.o
|
||||
obj-$(CONFIG_SCSI_UFS_MSM) += ufs-msm-phy-qmp-28nm.o
|
||||
obj-$(CONFIG_SCSI_UFS_MSM) += ufs-msm-phy-qmp-20nm.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o ufs_quirks.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
|
||||
|
|
273
drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c
Normal file
273
drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/msm-bus.h>
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include "unipro.h"
|
||||
#include "ufs-msm.h"
|
||||
#include "ufs-msm-phy.h"
|
||||
#include "ufs-msm-phy-qmp-20nm.h"
|
||||
|
||||
#define UFS_PHY_NAME "ufs_msm_phy_qmp_20nm"
|
||||
|
||||
static void ufs_msm_phy_qmp_20nm_phy_calibrate(struct ufs_msm_phy *phy)
|
||||
{
|
||||
struct ufs_msm_phy_calibration *tbl;
|
||||
int tbl_size;
|
||||
int i;
|
||||
|
||||
tbl_size = ARRAY_SIZE(phy_cal_table_rate_A);
|
||||
tbl = phy_cal_table_rate_A;
|
||||
|
||||
/*
|
||||
* calibration according phy_cal_table_rate_A happens
|
||||
* regardless of the rate we intend to work with.
|
||||
* Only in case we would like to work in rate B, we need
|
||||
* to override a subset of registers of phy_cal_table_rate_A
|
||||
* table, with phy_cal_table_rate_B table.
|
||||
*/
|
||||
for (i = 0; i < tbl_size; i++)
|
||||
writel_relaxed(tbl[i].cfg_value, phy->mmio + tbl[i].reg_offset);
|
||||
|
||||
if (UFS_MSM_LIMIT_HS_RATE == PA_HS_MODE_B) {
|
||||
tbl = phy_cal_table_rate_B;
|
||||
tbl_size = ARRAY_SIZE(phy_cal_table_rate_B);
|
||||
|
||||
for (i = 0; i < tbl_size; i++)
|
||||
writel_relaxed(tbl[i].cfg_value,
|
||||
phy->mmio + tbl[i].reg_offset);
|
||||
}
|
||||
|
||||
/* flush buffered writes */
|
||||
mb();
|
||||
}
|
||||
|
||||
static int ufs_msm_phy_qmp_20nm_init(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy_qmp_20nm *phy = phy_get_drvdata(generic_phy);
|
||||
struct ufs_msm_phy *phy_common = &phy->common_cfg;
|
||||
int err = 0;
|
||||
|
||||
err = ufs_msm_phy_init_clks(generic_phy, phy_common);
|
||||
if (err) {
|
||||
dev_err(phy_common->dev, "%s: ufs_msm_phy_init_clks() failed %d\n",
|
||||
__func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufs_msm_phy_init_vregulators(generic_phy, phy_common);
|
||||
if (err)
|
||||
dev_err(phy_common->dev, "%s: ufs_msm_phy_init_vregulators() failed %d\n",
|
||||
__func__, err);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static
|
||||
void ufs_msm_phy_qmp_20nm_power_control(struct ufs_msm_phy *phy, bool val)
|
||||
{
|
||||
if (val) {
|
||||
writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
|
||||
/*
|
||||
* Before any transactions involving PHY, ensure PHY knows
|
||||
* that it's analog rail is powered ON. This also ensures
|
||||
* that PHY is out of power collapse before enabling the
|
||||
* SIGDET.
|
||||
*/
|
||||
mb();
|
||||
if (phy->quirks &
|
||||
MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE) {
|
||||
writel_relaxed(0xC0,
|
||||
phy->mmio + QSERDES_RX_SIGDET_CNTRL(0));
|
||||
writel_relaxed(0xC0,
|
||||
phy->mmio + QSERDES_RX_SIGDET_CNTRL(1));
|
||||
/*
|
||||
* make sure that SIGDET is enabled before proceeding
|
||||
* further.
|
||||
*/
|
||||
mb();
|
||||
}
|
||||
} else {
|
||||
if (phy->quirks &
|
||||
MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE) {
|
||||
writel_relaxed(0x0,
|
||||
phy->mmio + QSERDES_RX_SIGDET_CNTRL(0));
|
||||
writel_relaxed(0x0,
|
||||
phy->mmio + QSERDES_RX_SIGDET_CNTRL(1));
|
||||
/*
|
||||
* Ensure that SIGDET is disabled before PHY power
|
||||
* collapse
|
||||
*/
|
||||
mb();
|
||||
}
|
||||
writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
|
||||
/*
|
||||
* ensure that PHY knows its PHY analog rail is going
|
||||
* to be powered down
|
||||
*/
|
||||
mb();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void ufs_msm_phy_qmp_20nm_set_tx_lane_enable(struct ufs_msm_phy *phy, u32 val)
|
||||
{
|
||||
writel_relaxed(val & UFS_PHY_TX_LANE_ENABLE_MASK,
|
||||
phy->mmio + UFS_PHY_TX_LANE_ENABLE);
|
||||
mb();
|
||||
}
|
||||
|
||||
static inline void ufs_msm_phy_qmp_20nm_start_serdes(struct ufs_msm_phy *phy)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
|
||||
tmp &= ~MASK_SERDES_START;
|
||||
tmp |= (1 << OFFSET_SERDES_START);
|
||||
writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
|
||||
mb();
|
||||
}
|
||||
|
||||
static int ufs_msm_phy_qmp_20nm_is_pcs_ready(struct ufs_msm_phy *phy_common)
|
||||
{
|
||||
int err = 0;
|
||||
u32 val;
|
||||
|
||||
err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
|
||||
val, (val & MASK_PCS_READY), 10, 1000000);
|
||||
if (err)
|
||||
dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
|
||||
__func__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ufs_msm_phy_qmp_20nm_advertise_quirks(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy_qmp_20nm *phy = phy_get_drvdata(generic_phy);
|
||||
struct ufs_msm_phy *phy_common = &(phy->common_cfg);
|
||||
|
||||
phy_common->quirks = 0;
|
||||
}
|
||||
|
||||
struct phy_ops ufs_msm_phy_qmp_20nm_phy_ops = {
|
||||
.init = ufs_msm_phy_qmp_20nm_init,
|
||||
.exit = ufs_msm_phy_exit,
|
||||
.power_on = ufs_msm_phy_power_on,
|
||||
.power_off = ufs_msm_phy_power_off,
|
||||
.advertise_quirks = ufs_msm_phy_qmp_20nm_advertise_quirks,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
struct ufs_msm_phy_specific_ops phy_20nm_ops = {
|
||||
.calibrate_phy = ufs_msm_phy_qmp_20nm_phy_calibrate,
|
||||
.start_serdes = ufs_msm_phy_qmp_20nm_start_serdes,
|
||||
.is_physical_coding_sublayer_ready = ufs_msm_phy_qmp_20nm_is_pcs_ready,
|
||||
.set_tx_lane_enable = ufs_msm_phy_qmp_20nm_set_tx_lane_enable,
|
||||
.power_control = ufs_msm_phy_qmp_20nm_power_control,
|
||||
};
|
||||
|
||||
static int ufs_msm_phy_qmp_20nm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct phy *generic_phy;
|
||||
struct ufs_msm_phy_qmp_20nm *phy;
|
||||
struct phy_provider *phy_provider;
|
||||
int err = 0;
|
||||
|
||||
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy) {
|
||||
dev_err(dev, "%s: failed to allocate phy\n", __func__);
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufs_msm_phy_base_init(pdev, &phy->common_cfg);
|
||||
if (err) {
|
||||
dev_err(dev, "%s: phy base init failed %d\n", __func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
phy->common_cfg.phy_spec_ops = &phy_20nm_ops;
|
||||
phy->common_cfg.cached_regs = NULL;
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider)) {
|
||||
err = PTR_ERR(phy_provider);
|
||||
dev_err(dev, "%s: failed to register phy %d\n", __func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
generic_phy = devm_phy_create(dev, NULL, &ufs_msm_phy_qmp_20nm_phy_ops, NULL);
|
||||
if (IS_ERR(generic_phy)) {
|
||||
devm_of_phy_provider_unregister(dev, phy_provider);
|
||||
err = PTR_ERR(generic_phy);
|
||||
dev_err(dev, "%s: failed to create phy %d\n", __func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
phy->common_cfg.dev = dev;
|
||||
phy_set_drvdata(generic_phy, phy);
|
||||
|
||||
strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
|
||||
sizeof(phy->common_cfg.name));
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ufs_msm_phy_qmp_20nm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct phy *generic_phy = to_phy(dev);
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(generic_phy);
|
||||
int err = 0;
|
||||
|
||||
err = ufs_msm_phy_remove(generic_phy, ufs_msm_phy);
|
||||
if (err)
|
||||
dev_err(dev, "%s: ufs_msm_phy_remove failed = %d\n",
|
||||
__func__, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id ufs_msm_phy_qmp_20nm_of_match[] = {
|
||||
{.compatible = "qcom,ufs-msm-phy-qmp-20nm"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ufs_msm_phy_qmp_20nm_of_match);
|
||||
|
||||
static struct platform_driver ufs_msm_phy_qmp_20nm_driver = {
|
||||
.probe = ufs_msm_phy_qmp_20nm_probe,
|
||||
.remove = ufs_msm_phy_qmp_20nm_remove,
|
||||
.driver = {
|
||||
.of_match_table = ufs_msm_phy_qmp_20nm_of_match,
|
||||
.name = "ufs_msm_phy_qmp_20nm",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ufs_msm_phy_qmp_20nm_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Universal Flash Storage (UFS) MSM PHY QMP 20nm");
|
||||
MODULE_LICENSE("GPL v2");
|
216
drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.h
Normal file
216
drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.h
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UFS_MSM_PHY_QMP_20NM_H_
|
||||
#define UFS_MSM_PHY_QMP_20NM_H_
|
||||
|
||||
#include "ufs-msm-phy.h"
|
||||
|
||||
/* MSM UFS PHY control registers */
|
||||
|
||||
#define COM_OFF(x) (0x000 + x)
|
||||
#define PHY_OFF(x) (0xC00 + x)
|
||||
#define TX_OFF(n, x) (0x400 + (0x400 * n) + x)
|
||||
#define RX_OFF(n, x) (0x600 + (0x400 * n) + x)
|
||||
|
||||
/* UFS PHY PLL block registers */
|
||||
#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x0)
|
||||
#define QSERDES_COM_PLL_VCOTAIL_EN COM_OFF(0x04)
|
||||
#define QSERDES_COM_PLL_CNTRL COM_OFF(0x14)
|
||||
#define QSERDES_COM_PLL_IP_SETI COM_OFF(0x24)
|
||||
#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL COM_OFF(0x28)
|
||||
#define QSERDES_COM_PLL_CP_SETI COM_OFF(0x34)
|
||||
#define QSERDES_COM_PLL_IP_SETP COM_OFF(0x38)
|
||||
#define QSERDES_COM_PLL_CP_SETP COM_OFF(0x3C)
|
||||
#define QSERDES_COM_SYSCLK_EN_SEL_TXBAND COM_OFF(0x48)
|
||||
#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0x4C)
|
||||
#define QSERDES_COM_RESETSM_CNTRL2 COM_OFF(0x50)
|
||||
#define QSERDES_COM_PLLLOCK_CMP1 COM_OFF(0x90)
|
||||
#define QSERDES_COM_PLLLOCK_CMP2 COM_OFF(0x94)
|
||||
#define QSERDES_COM_PLLLOCK_CMP3 COM_OFF(0x98)
|
||||
#define QSERDES_COM_PLLLOCK_CMP_EN COM_OFF(0x9C)
|
||||
#define QSERDES_COM_BGTC COM_OFF(0xA0)
|
||||
#define QSERDES_COM_DEC_START1 COM_OFF(0xAC)
|
||||
#define QSERDES_COM_PLL_AMP_OS COM_OFF(0xB0)
|
||||
#define QSERDES_COM_DIV_FRAC_START1 COM_OFF(0x100)
|
||||
#define QSERDES_COM_DIV_FRAC_START2 COM_OFF(0x104)
|
||||
#define QSERDES_COM_DIV_FRAC_START3 COM_OFF(0x108)
|
||||
#define QSERDES_COM_DEC_START2 COM_OFF(0x10C)
|
||||
#define QSERDES_COM_PLL_RXTXEPCLK_EN COM_OFF(0x110)
|
||||
#define QSERDES_COM_PLL_CRCTRL COM_OFF(0x114)
|
||||
#define QSERDES_COM_PLL_CLKEPDIV COM_OFF(0x118)
|
||||
|
||||
/* TX LANE n (0, 1) registers */
|
||||
#define QSERDES_TX_EMP_POST1_LVL(n) TX_OFF(n, 0x08)
|
||||
#define QSERDES_TX_DRV_LVL(n) TX_OFF(n, 0x0C)
|
||||
#define QSERDES_TX_LANE_MODE(n) TX_OFF(n, 0x54)
|
||||
|
||||
/* RX LANE n (0, 1) registers */
|
||||
#define QSERDES_RX_CDR_CONTROL1(n) RX_OFF(n, 0x0)
|
||||
#define QSERDES_RX_CDR_CONTROL_HALF(n) RX_OFF(n, 0x8)
|
||||
#define QSERDES_RX_RX_EQ_GAIN1_LSB(n) RX_OFF(n, 0xA8)
|
||||
#define QSERDES_RX_RX_EQ_GAIN1_MSB(n) RX_OFF(n, 0xAC)
|
||||
#define QSERDES_RX_RX_EQ_GAIN2_LSB(n) RX_OFF(n, 0xB0)
|
||||
#define QSERDES_RX_RX_EQ_GAIN2_MSB(n) RX_OFF(n, 0xB4)
|
||||
#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(n) RX_OFF(n, 0xBC)
|
||||
#define QSERDES_RX_CDR_CONTROL_QUARTER(n) RX_OFF(n, 0xC)
|
||||
#define QSERDES_RX_SIGDET_CNTRL(n) RX_OFF(n, 0x100)
|
||||
|
||||
/* UFS PHY registers */
|
||||
#define UFS_PHY_PHY_START PHY_OFF(0x00)
|
||||
#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x4)
|
||||
#define UFS_PHY_TX_LANE_ENABLE PHY_OFF(0x44)
|
||||
#define UFS_PHY_PWM_G1_CLK_DIVIDER PHY_OFF(0x08)
|
||||
#define UFS_PHY_PWM_G2_CLK_DIVIDER PHY_OFF(0x0C)
|
||||
#define UFS_PHY_PWM_G3_CLK_DIVIDER PHY_OFF(0x10)
|
||||
#define UFS_PHY_PWM_G4_CLK_DIVIDER PHY_OFF(0x14)
|
||||
#define UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER PHY_OFF(0x34)
|
||||
#define UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER PHY_OFF(0x38)
|
||||
#define UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER PHY_OFF(0x3C)
|
||||
#define UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER PHY_OFF(0x40)
|
||||
#define UFS_PHY_OMC_STATUS_RDVAL PHY_OFF(0x68)
|
||||
#define UFS_PHY_LINE_RESET_TIME PHY_OFF(0x28)
|
||||
#define UFS_PHY_LINE_RESET_GRANULARITY PHY_OFF(0x2C)
|
||||
#define UFS_PHY_TSYNC_RSYNC_CNTL PHY_OFF(0x48)
|
||||
#define UFS_PHY_PLL_CNTL PHY_OFF(0x50)
|
||||
#define UFS_PHY_TX_LARGE_AMP_DRV_LVL PHY_OFF(0x54)
|
||||
#define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x5C)
|
||||
#define UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL PHY_OFF(0x58)
|
||||
#define UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL PHY_OFF(0x60)
|
||||
#define UFS_PHY_CFG_CHANGE_CNT_VAL PHY_OFF(0x64)
|
||||
#define UFS_PHY_RX_SYNC_WAIT_TIME PHY_OFF(0x6C)
|
||||
#define UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB4)
|
||||
#define UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE0)
|
||||
#define UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB8)
|
||||
#define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE4)
|
||||
#define UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xBC)
|
||||
#define UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xE8)
|
||||
#define UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY PHY_OFF(0xFC)
|
||||
#define UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY PHY_OFF(0x100)
|
||||
#define UFS_PHY_RMMI_ATTR_CTRL PHY_OFF(0x160)
|
||||
#define UFS_PHY_RMMI_RX_CFGUPDT_L1 (1 << 7)
|
||||
#define UFS_PHY_RMMI_TX_CFGUPDT_L1 (1 << 6)
|
||||
#define UFS_PHY_RMMI_CFGWR_L1 (1 << 5)
|
||||
#define UFS_PHY_RMMI_CFGRD_L1 (1 << 4)
|
||||
#define UFS_PHY_RMMI_RX_CFGUPDT_L0 (1 << 3)
|
||||
#define UFS_PHY_RMMI_TX_CFGUPDT_L0 (1 << 2)
|
||||
#define UFS_PHY_RMMI_CFGWR_L0 (1 << 1)
|
||||
#define UFS_PHY_RMMI_CFGRD_L0 (1 << 0)
|
||||
#define UFS_PHY_RMMI_ATTRID PHY_OFF(0x164)
|
||||
#define UFS_PHY_RMMI_ATTRWRVAL PHY_OFF(0x168)
|
||||
#define UFS_PHY_RMMI_ATTRRDVAL_L0_STATUS PHY_OFF(0x16C)
|
||||
#define UFS_PHY_RMMI_ATTRRDVAL_L1_STATUS PHY_OFF(0x170)
|
||||
#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x174)
|
||||
|
||||
#define UFS_PHY_TX_LANE_ENABLE_MASK 0x3
|
||||
|
||||
/*
|
||||
* This structure represents the 20nm specific phy.
|
||||
* common_cfg MUST remain the first field in this structure
|
||||
* in case extra fields are added. This way, when calling
|
||||
* get_ufs_msm_phy() of generic phy, we can extract the
|
||||
* common phy structure (struct ufs_msm_phy) out of it
|
||||
* regardless of the relevant specific phy.
|
||||
*/
|
||||
struct ufs_msm_phy_qmp_20nm {
|
||||
struct ufs_msm_phy common_cfg;
|
||||
};
|
||||
|
||||
static struct ufs_msm_phy_calibration phy_cal_table_rate_A[] = {
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL2, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(1), 0xf2),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x0c),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x12),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(0), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(0), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(0), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(1), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x3f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x1b),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_EMP_POST1_LVL(0), 0x2F),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_DRV_LVL(0), 0x20),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_EMP_POST1_LVL(1), 0x2F),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_DRV_LVL(1), 0x20),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc),
|
||||
};
|
||||
|
||||
static struct ufs_msm_phy_calibration phy_cal_table_rate_B[] = {
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x98),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0x65),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x1e),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(1), 0xf2),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x0c),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x12),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(0), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(0), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(0), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(1), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x3f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x1b),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc),
|
||||
};
|
||||
|
||||
#endif
|
393
drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c
Normal file
393
drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c
Normal file
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/msm-bus.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include "unipro.h"
|
||||
#include "ufs-msm.h"
|
||||
#include "ufs-msm-phy.h"
|
||||
#include "ufs-msm-phy-qmp-28nm.h"
|
||||
|
||||
#define UFS_PHY_NAME "ufs_msm_phy_qmp_28nm"
|
||||
|
||||
static
|
||||
void ufs_msm_phy_qmp_28nm_power_control(struct ufs_msm_phy *phy, bool val)
|
||||
{
|
||||
if (val) {
|
||||
writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
|
||||
/*
|
||||
* Before any transactions involving PHY, ensure PHY knows
|
||||
* that it's analog rail is powered ON. This also ensures
|
||||
* that PHY is out of power collapse before enabling the
|
||||
* SIGDET.
|
||||
*/
|
||||
mb();
|
||||
if (phy->quirks & MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE) {
|
||||
writel_relaxed(0xC0,
|
||||
phy->mmio + QSERDES_RX_SIGDET_CNTRL(0));
|
||||
writel_relaxed(0xC0,
|
||||
phy->mmio + QSERDES_RX_SIGDET_CNTRL(1));
|
||||
/*
|
||||
* make sure that SIGDET is enabled before proceeding
|
||||
* further.
|
||||
*/
|
||||
mb();
|
||||
}
|
||||
} else {
|
||||
if (phy->quirks & MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE) {
|
||||
writel_relaxed(0x0,
|
||||
phy->mmio + QSERDES_RX_SIGDET_CNTRL(0));
|
||||
writel_relaxed(0x0,
|
||||
phy->mmio + QSERDES_RX_SIGDET_CNTRL(1));
|
||||
/*
|
||||
* Ensure that SIGDET is disabled before PHY power
|
||||
* collapse
|
||||
*/
|
||||
mb();
|
||||
}
|
||||
writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
|
||||
/*
|
||||
* ensure that PHY knows its PHY analog rail is going
|
||||
* to be powered down
|
||||
*/
|
||||
mb();
|
||||
}
|
||||
}
|
||||
|
||||
static int ufs_msm_phy_qmp_28nm_init(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy_qmp_28nm *phy = phy_get_drvdata(generic_phy);
|
||||
struct ufs_msm_phy *phy_common = &phy->common_cfg;
|
||||
int err = 0;
|
||||
|
||||
err = ufs_msm_phy_init_clks(generic_phy, phy_common);
|
||||
if (err) {
|
||||
dev_err(phy_common->dev, "%s: ufs_msm_phy_init_clks() failed %d\n",
|
||||
__func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufs_msm_phy_init_vregulators(generic_phy, phy_common);
|
||||
if (err)
|
||||
dev_err(phy_common->dev, "%s: ufs_msm_phy_init_vregulators() failed %d\n",
|
||||
__func__, err);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ufs_msm_phy_qmp_28nm_calibrate(struct ufs_msm_phy *ufs_msm_phy)
|
||||
{
|
||||
struct ufs_msm_phy_calibration *tbl;
|
||||
int tbl_size;
|
||||
int i;
|
||||
u8 major = ufs_msm_phy->host_ctrl_rev_major;
|
||||
u16 minor = ufs_msm_phy->host_ctrl_rev_minor;
|
||||
u16 step = ufs_msm_phy->host_ctrl_rev_step;
|
||||
|
||||
if ((major == 0x1) && (minor == 0x001) && (step == 0x0000)) {
|
||||
tbl_size = ARRAY_SIZE(phy_cal_table_ctrl_1_1_0_rate_A);
|
||||
tbl = phy_cal_table_ctrl_1_1_0_rate_A;
|
||||
} else if ((major == 0x1) && (minor == 0x001) && (step == 0x0001)) {
|
||||
tbl_size = ARRAY_SIZE(phy_cal_table_ctrl_1_1_1_rate_A);
|
||||
tbl = phy_cal_table_ctrl_1_1_1_rate_A;
|
||||
}
|
||||
|
||||
/*
|
||||
* calibration according phy_cal_table_ctrl_x_x_x_rate_A
|
||||
* happens regardless of the rate we intend to work with.
|
||||
* Only in case we would like to work in rate B, we need
|
||||
* to override a subset of registers of
|
||||
* phy_cal_table_ctrl_x_x_x_rate_A table, with phy_cal_table_rate_B
|
||||
* table.
|
||||
*/
|
||||
for (i = 0; i < tbl_size; i++)
|
||||
writel_relaxed(tbl[i].cfg_value,
|
||||
ufs_msm_phy->mmio + tbl[i].reg_offset);
|
||||
|
||||
if (UFS_MSM_LIMIT_HS_RATE == PA_HS_MODE_B) {
|
||||
tbl = phy_cal_table_rate_B;
|
||||
tbl_size = ARRAY_SIZE(phy_cal_table_rate_B);
|
||||
|
||||
for (i = 0; i < tbl_size; i++)
|
||||
writel_relaxed(tbl[i].cfg_value,
|
||||
ufs_msm_phy->mmio + tbl[i].reg_offset);
|
||||
}
|
||||
|
||||
/* flush buffered writes */
|
||||
mb();
|
||||
}
|
||||
|
||||
static
|
||||
u32 ufs_msm_phy_qmp_28nm_read_attr(struct ufs_msm_phy *phy_common, u32 attr)
|
||||
|
||||
{
|
||||
u32 l0, l1;
|
||||
|
||||
writel_relaxed(attr, phy_common->mmio + UFS_PHY_RMMI_ATTRID);
|
||||
/* Read attribute value for both lanes */
|
||||
writel_relaxed((UFS_PHY_RMMI_CFGRD_L0 | UFS_PHY_RMMI_CFGRD_L1),
|
||||
phy_common->mmio + UFS_PHY_RMMI_ATTR_CTRL);
|
||||
|
||||
l0 = readl_relaxed(phy_common->mmio + UFS_PHY_RMMI_ATTRRDVAL_L0_STATUS);
|
||||
l1 = readl_relaxed(phy_common->mmio + UFS_PHY_RMMI_ATTRRDVAL_L1_STATUS);
|
||||
/* Both lanes should have the same value for same attribute type */
|
||||
if (unlikely(l0 != l1))
|
||||
dev_warn(phy_common->dev, "%s: attr 0x%x values are not same for Lane-0 and Lane-1, l0=0x%x, l1=0x%x",
|
||||
__func__, attr, l0, l1);
|
||||
|
||||
/* must clear now */
|
||||
writel_relaxed(0x00, phy_common->mmio + UFS_PHY_RMMI_ATTR_CTRL);
|
||||
|
||||
return l0;
|
||||
}
|
||||
|
||||
static
|
||||
void ufs_msm_phy_qmp_28nm_save_configuration(struct ufs_msm_phy *phy_common)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cached_phy_regs); i++)
|
||||
cached_phy_regs[i].cfg_value =
|
||||
readl_relaxed(phy_common->mmio +
|
||||
cached_phy_regs[i].reg_offset);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cached_phy_attr); i++)
|
||||
cached_phy_attr[i].value =
|
||||
ufs_msm_phy_qmp_28nm_read_attr(phy_common,
|
||||
cached_phy_attr[i].att);
|
||||
}
|
||||
|
||||
static
|
||||
void ufs_msm_phy_qmp_28nm_set_tx_lane_enable(struct ufs_msm_phy *phy, u32 val)
|
||||
{
|
||||
writel_relaxed(val & UFS_PHY_TX_LANE_ENABLE_MASK,
|
||||
phy->mmio + UFS_PHY_TX_LANE_ENABLE);
|
||||
mb();
|
||||
}
|
||||
|
||||
static inline void ufs_msm_phy_qmp_28nm_start_serdes(struct ufs_msm_phy *phy)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
|
||||
tmp &= ~MASK_SERDES_START;
|
||||
tmp |= (1 << OFFSET_SERDES_START);
|
||||
writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
|
||||
mb();
|
||||
}
|
||||
|
||||
static void
|
||||
ufs_msm_phy_qmp_28nm_write_attr(struct phy *generic_phy, u32 attr, u32 val)
|
||||
{
|
||||
struct ufs_msm_phy_qmp_28nm *phy = phy_get_drvdata(generic_phy);
|
||||
struct ufs_msm_phy *phy_common = &(phy->common_cfg);
|
||||
|
||||
writel_relaxed(attr, phy_common->mmio + UFS_PHY_RMMI_ATTRID);
|
||||
writel_relaxed(val, phy_common->mmio + UFS_PHY_RMMI_ATTRWRVAL);
|
||||
/* update attribute for both lanes */
|
||||
writel_relaxed((UFS_PHY_RMMI_CFGWR_L0 | UFS_PHY_RMMI_CFGWR_L1),
|
||||
phy_common->mmio + UFS_PHY_RMMI_ATTR_CTRL);
|
||||
if (is_mphy_tx_attr(attr))
|
||||
writel_relaxed((UFS_PHY_RMMI_TX_CFGUPDT_L0 |
|
||||
UFS_PHY_RMMI_TX_CFGUPDT_L1),
|
||||
phy_common->mmio + UFS_PHY_RMMI_ATTR_CTRL);
|
||||
else
|
||||
writel_relaxed((UFS_PHY_RMMI_RX_CFGUPDT_L0 |
|
||||
UFS_PHY_RMMI_RX_CFGUPDT_L1),
|
||||
phy_common->mmio + UFS_PHY_RMMI_ATTR_CTRL);
|
||||
|
||||
writel_relaxed(0x00, phy_common->mmio + UFS_PHY_RMMI_ATTR_CTRL);
|
||||
}
|
||||
|
||||
static void ufs_msm_phy_qmp_28nm_restore_attrs(struct phy *generic_phy)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cached_phy_attr); i++)
|
||||
ufs_msm_phy_qmp_28nm_write_attr(generic_phy,
|
||||
cached_phy_attr[i].att, cached_phy_attr[i].value);
|
||||
}
|
||||
|
||||
static int ufs_msm_phy_qmp_28nm_is_pcs_ready(struct ufs_msm_phy *phy_common)
|
||||
{
|
||||
int err = 0;
|
||||
u32 val;
|
||||
|
||||
err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
|
||||
val, (val & MASK_PCS_READY), 10, 1000000);
|
||||
if (err)
|
||||
dev_err(phy_common->dev, "%s: phy init failed, %d\n",
|
||||
__func__, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static
|
||||
void ufs_msm_phy_qmp_28nm_advertise_quirks(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy_qmp_28nm *phy = phy_get_drvdata(generic_phy);
|
||||
struct ufs_msm_phy *phy_common = &(phy->common_cfg);
|
||||
|
||||
phy_common->quirks = MSM_UFS_PHY_QUIRK_CFG_RESTORE
|
||||
| MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE;
|
||||
}
|
||||
|
||||
static int ufs_msm_phy_qmp_28nm_suspend(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy_qmp_28nm *phy = phy_get_drvdata(generic_phy);
|
||||
struct ufs_msm_phy *phy_common = &(phy->common_cfg);
|
||||
|
||||
ufs_msm_phy_disable_ref_clk(generic_phy);
|
||||
ufs_msm_phy_qmp_28nm_power_control(phy_common, false);
|
||||
|
||||
ufs_msm_phy_disable_vreg(generic_phy, &phy_common->vdda_phy);
|
||||
ufs_msm_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ufs_msm_phy_qmp_28nm_resume(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy_qmp_28nm *phy = phy_get_drvdata(generic_phy);
|
||||
struct ufs_msm_phy *phy_common = &phy->common_cfg;
|
||||
int err = 0;
|
||||
|
||||
ufs_msm_phy_qmp_28nm_start_serdes(phy_common);
|
||||
|
||||
ufs_msm_phy_qmp_28nm_restore_attrs(generic_phy);
|
||||
|
||||
err = ufs_msm_phy_qmp_28nm_is_pcs_ready(phy_common);
|
||||
if (err)
|
||||
dev_err(phy_common->dev, "%s: failed to init phy = %d\n",
|
||||
__func__, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct phy_ops ufs_msm_phy_ops = {
|
||||
.init = ufs_msm_phy_qmp_28nm_init,
|
||||
.exit = ufs_msm_phy_exit,
|
||||
.power_on = ufs_msm_phy_power_on,
|
||||
.power_off = ufs_msm_phy_power_off,
|
||||
.advertise_quirks = ufs_msm_phy_qmp_28nm_advertise_quirks,
|
||||
.suspend = ufs_msm_phy_qmp_28nm_suspend,
|
||||
.resume = ufs_msm_phy_qmp_28nm_resume,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
struct ufs_msm_phy_specific_ops phy_28nm_ops = {
|
||||
.calibrate_phy = ufs_msm_phy_qmp_28nm_calibrate,
|
||||
.start_serdes = ufs_msm_phy_qmp_28nm_start_serdes,
|
||||
.save_configuration = ufs_msm_phy_qmp_28nm_save_configuration,
|
||||
.is_physical_coding_sublayer_ready = ufs_msm_phy_qmp_28nm_is_pcs_ready,
|
||||
.set_tx_lane_enable = ufs_msm_phy_qmp_28nm_set_tx_lane_enable,
|
||||
.power_control = ufs_msm_phy_qmp_28nm_power_control,
|
||||
};
|
||||
|
||||
static int ufs_msm_phy_qmp_28nm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ufs_msm_phy_qmp_28nm *phy;
|
||||
struct device *dev = &pdev->dev;
|
||||
int err = 0;
|
||||
struct phy *generic_phy;
|
||||
struct phy_provider *phy_provider;
|
||||
|
||||
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy) {
|
||||
err = -ENOMEM;
|
||||
dev_err(dev, "%s: failed to allocate phy\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufs_msm_phy_base_init(pdev, &phy->common_cfg);
|
||||
if (err) {
|
||||
dev_err(dev, "%s: phy base init failed %d\n", __func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
phy->common_cfg.phy_spec_ops = &phy_28nm_ops;
|
||||
phy->common_cfg.cached_regs =
|
||||
(struct ufs_msm_phy_calibration *)cached_phy_regs;
|
||||
phy->common_cfg.cached_regs_table_size =
|
||||
ARRAY_SIZE(cached_phy_regs);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider)) {
|
||||
err = PTR_ERR(phy_provider);
|
||||
dev_err(dev, "%s: failed to register phy %d\n", __func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
generic_phy = devm_phy_create(dev, NULL, &ufs_msm_phy_ops, NULL);
|
||||
if (IS_ERR(generic_phy)) {
|
||||
err = PTR_ERR(generic_phy);
|
||||
dev_err(dev, "%s: failed to create phy %d\n", __func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
phy->common_cfg.dev = dev;
|
||||
phy_set_drvdata(generic_phy, phy);
|
||||
|
||||
strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
|
||||
sizeof(phy->common_cfg.name));
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ufs_msm_phy_qmp_28nm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct phy *generic_phy = to_phy(dev);
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(generic_phy);
|
||||
int err = 0;
|
||||
|
||||
err = ufs_msm_phy_remove(generic_phy, ufs_msm_phy);
|
||||
if (err)
|
||||
dev_err(dev, "%s: ufs_msm_phy_remove failed = %d\n",
|
||||
__func__, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id ufs_msm_phy_qmp_28nm_of_match[] = {
|
||||
{.compatible = "qcom,ufs-msm-phy-qmp-28nm"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ufs_msm_phy_qmp_28nm_of_match);
|
||||
|
||||
static struct platform_driver ufs_msm_phy_qmp_28nm_driver = {
|
||||
.probe = ufs_msm_phy_qmp_28nm_probe,
|
||||
.remove = ufs_msm_phy_qmp_28nm_remove,
|
||||
.driver = {
|
||||
.of_match_table = ufs_msm_phy_qmp_28nm_of_match,
|
||||
.name = "ufs_msm_phy_qmp_28nm",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ufs_msm_phy_qmp_28nm_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Universal Flash Storage (UFS) MSM PHY QMP 28nm");
|
||||
MODULE_LICENSE("GPL v2");
|
735
drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.h
Normal file
735
drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.h
Normal file
|
@ -0,0 +1,735 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UFS_MSM_PHY_QMP_28NM_H_
|
||||
#define UFS_MSM_PHY_QMP_28NM_H_
|
||||
|
||||
#include "ufs-msm-phy.h"
|
||||
|
||||
/* MSM UFS PHY control registers */
|
||||
|
||||
#define COM_OFF(x) (0x000 + x)
|
||||
#define PHY_OFF(x) (0x700 + x)
|
||||
#define TX_OFF(n, x) (0x100 + (0x400 * n) + x)
|
||||
#define RX_OFF(n, x) (0x200 + (0x400 * n) + x)
|
||||
|
||||
/* UFS PHY PLL block registers */
|
||||
#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x00)
|
||||
#define QSERDES_COM_PLL_VCOTAIL_EN COM_OFF(0x04)
|
||||
#define QSERDES_COM_CMN_MODE COM_OFF(0x08)
|
||||
#define QSERDES_COM_IE_TRIM COM_OFF(0x0C)
|
||||
#define QSERDES_COM_IP_TRIM COM_OFF(0x10)
|
||||
#define QSERDES_COM_PLL_CNTRL COM_OFF(0x14)
|
||||
#define QSERDES_COM_PLL_IP_SETI COM_OFF(0x18)
|
||||
#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL COM_OFF(0x1C)
|
||||
#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x20)
|
||||
#define QSERDES_COM_PLL_CP_SETI COM_OFF(0x24)
|
||||
#define QSERDES_COM_PLL_IP_SETP COM_OFF(0x28)
|
||||
#define QSERDES_COM_PLL_CP_SETP COM_OFF(0x2C)
|
||||
#define QSERDES_COM_ATB_SEL1 COM_OFF(0x30)
|
||||
#define QSERDES_COM_ATB_SEL2 COM_OFF(0x34)
|
||||
#define QSERDES_COM_SYSCLK_EN_SEL COM_OFF(0x38)
|
||||
#define QSERDES_COM_RES_CODE_TXBAND COM_OFF(0x3C)
|
||||
#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0x40)
|
||||
#define QSERDES_COM_PLLLOCK_CMP1 COM_OFF(0x44)
|
||||
#define QSERDES_COM_PLLLOCK_CMP2 COM_OFF(0x48)
|
||||
#define QSERDES_COM_PLLLOCK_CMP3 COM_OFF(0x4C)
|
||||
#define QSERDES_COM_PLLLOCK_CMP_EN COM_OFF(0x50)
|
||||
#define QSERDES_COM_RES_TRIM_OFFSET COM_OFF(0x54)
|
||||
#define QSERDES_COM_BGTC COM_OFF(0x58)
|
||||
#define QSERDES_COM_PLL_TEST_UPDN_RESTRIMSTEP COM_OFF(0x5C)
|
||||
#define QSERDES_COM_PLL_VCO_TUNE COM_OFF(0x60)
|
||||
#define QSERDES_COM_DEC_START1 COM_OFF(0x64)
|
||||
#define QSERDES_COM_PLL_AMP_OS COM_OFF(0x68)
|
||||
#define QSERDES_COM_SSC_EN_CENTER COM_OFF(0x6C)
|
||||
#define QSERDES_COM_SSC_ADJ_PER1 COM_OFF(0x70)
|
||||
#define QSERDES_COM_SSC_ADJ_PER2 COM_OFF(0x74)
|
||||
#define QSERDES_COM_SSC_PER1 COM_OFF(0x78)
|
||||
#define QSERDES_COM_SSC_PER2 COM_OFF(0x7C)
|
||||
#define QSERDES_COM_SSC_STEP_SIZE1 COM_OFF(0x80)
|
||||
#define QSERDES_COM_SSC_STEP_SIZE2 COM_OFF(0x84)
|
||||
#define QSERDES_COM_RES_TRIM_SEARCH COM_OFF(0x88)
|
||||
#define QSERDES_COM_RES_TRIM_FREEZE COM_OFF(0x8C)
|
||||
#define QSERDES_COM_RES_TRIM_EN_VCOCALDONE COM_OFF(0x90)
|
||||
#define QSERDES_COM_FAUX_EN COM_OFF(0x94)
|
||||
#define QSERDES_COM_DIV_FRAC_START1 COM_OFF(0x98)
|
||||
#define QSERDES_COM_DIV_FRAC_START2 COM_OFF(0x9C)
|
||||
#define QSERDES_COM_DIV_FRAC_START3 COM_OFF(0xA0)
|
||||
#define QSERDES_COM_DEC_START2 COM_OFF(0xA4)
|
||||
#define QSERDES_COM_PLL_RXTXEPCLK_EN COM_OFF(0xA8)
|
||||
#define QSERDES_COM_PLL_CRCTRL COM_OFF(0xAC)
|
||||
#define QSERDES_COM_PLL_CLKEPDIV COM_OFF(0xB0)
|
||||
#define QSERDES_COM_PLL_FREQUPDATE COM_OFF(0xB4)
|
||||
#define QSERDES_COM_PLL_VCO_HIGH COM_OFF(0xB8)
|
||||
#define QSERDES_COM_RESET_SM COM_OFF(0xBC)
|
||||
|
||||
/* UFS PHY registers */
|
||||
#define UFS_PHY_PHY_START PHY_OFF(0x00)
|
||||
#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x04)
|
||||
#define UFS_PHY_PWM_G1_CLK_DIVIDER PHY_OFF(0x08)
|
||||
#define UFS_PHY_PWM_G2_CLK_DIVIDER PHY_OFF(0x0C)
|
||||
#define UFS_PHY_PWM_G3_CLK_DIVIDER PHY_OFF(0x10)
|
||||
#define UFS_PHY_PWM_G4_CLK_DIVIDER PHY_OFF(0x14)
|
||||
#define UFS_PHY_TIMER_100US_SYSCLK_STEPS_MSB PHY_OFF(0x18)
|
||||
#define UFS_PHY_TIMER_100US_SYSCLK_STEPS_LSB PHY_OFF(0x1C)
|
||||
#define UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB PHY_OFF(0x20)
|
||||
#define UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB PHY_OFF(0x24)
|
||||
#define UFS_PHY_LINE_RESET_TIME PHY_OFF(0x28)
|
||||
#define UFS_PHY_LINE_RESET_GRANULARITY PHY_OFF(0x2C)
|
||||
#define UFS_PHY_CONTROLSYM_ONE_HOT_DISABLE PHY_OFF(0x30)
|
||||
#define UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER PHY_OFF(0x34)
|
||||
#define UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER PHY_OFF(0x38)
|
||||
#define UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER PHY_OFF(0x3C)
|
||||
#define UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER PHY_OFF(0x40)
|
||||
#define UFS_PHY_TX_LANE_ENABLE PHY_OFF(0x44)
|
||||
#define UFS_PHY_TSYNC_RSYNC_CNTL PHY_OFF(0x48)
|
||||
#define UFS_PHY_RETIME_BUFFER_EN PHY_OFF(0x4C)
|
||||
#define UFS_PHY_PLL_CNTL PHY_OFF(0x50)
|
||||
#define UFS_PHY_TX_LARGE_AMP_DRV_LVL PHY_OFF(0x54)
|
||||
#define UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL PHY_OFF(0x58)
|
||||
#define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x5C)
|
||||
#define UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL PHY_OFF(0x60)
|
||||
#define UFS_PHY_CFG_CHANGE_CNT_VAL PHY_OFF(0x64)
|
||||
#define UFS_PHY_OMC_STATUS_RDVAL PHY_OFF(0x68)
|
||||
#define UFS_PHY_RX_SYNC_WAIT_TIME PHY_OFF(0x6C)
|
||||
#define UFS_PHY_L0_BIST_CTRL PHY_OFF(0x70)
|
||||
#define UFS_PHY_L1_BIST_CTRL PHY_OFF(0x74)
|
||||
#define UFS_PHY_BIST_PRBS_POLY0 PHY_OFF(0x78)
|
||||
#define UFS_PHY_BIST_PRBS_POLY1 PHY_OFF(0x7C)
|
||||
#define UFS_PHY_BIST_PRBS_SEED0 PHY_OFF(0x80)
|
||||
#define UFS_PHY_BIST_PRBS_SEED1 PHY_OFF(0x84)
|
||||
#define UFS_PHY_BIST_FIXED_PAT_CTRL PHY_OFF(0x88)
|
||||
#define UFS_PHY_BIST_FIXED_PAT0_DATA PHY_OFF(0x8C)
|
||||
#define UFS_PHY_BIST_FIXED_PAT1_DATA PHY_OFF(0x90)
|
||||
#define UFS_PHY_BIST_FIXED_PAT2_DATA PHY_OFF(0x94)
|
||||
#define UFS_PHY_BIST_FIXED_PAT3_DATA PHY_OFF(0x98)
|
||||
#define UFS_PHY_TX_HSGEAR_CAPABILITY PHY_OFF(0x9C)
|
||||
#define UFS_PHY_TX_PWMGEAR_CAPABILITY PHY_OFF(0xA0)
|
||||
#define UFS_PHY_TX_AMPLITUDE_CAPABILITY PHY_OFF(0xA4)
|
||||
#define UFS_PHY_TX_EXTERNALSYNC_CAPABILITY PHY_OFF(0xA8)
|
||||
#define UFS_PHY_TX_HS_UNTERMINATED_LINE_DRIVE_CAPABILITY PHY_OFF(0xAC)
|
||||
#define UFS_PHY_TX_LS_TERMINATED_LINE_DRIVE_CAPABILITY PHY_OFF(0xB0)
|
||||
#define UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB4)
|
||||
#define UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB8)
|
||||
#define UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xBC)
|
||||
#define UFS_PHY_TX_REF_CLOCK_SHARED_CAPABILITY PHY_OFF(0xC0)
|
||||
#define UFS_PHY_TX_PHY_MAJORMINOR_RELEASE_CAPABILITY PHY_OFF(0xC4)
|
||||
#define UFS_PHY_TX_PHY_EDITORIAL_RELEASE_CAPABILITY PHY_OFF(0xC8)
|
||||
#define UFS_PHY_TX_HIBERN8TIME_CAPABILITY PHY_OFF(0xCC)
|
||||
#define UFS_PHY_RX_HSGEAR_CAPABILITY PHY_OFF(0xD0)
|
||||
#define UFS_PHY_RX_PWMGEAR_CAPABILITY PHY_OFF(0xD4)
|
||||
#define UFS_PHY_RX_HS_UNTERMINATED_CAPABILITY PHY_OFF(0xD8)
|
||||
#define UFS_PHY_RX_LS_TERMINATED_CAPABILITY PHY_OFF(0xDC)
|
||||
#define UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE0)
|
||||
#define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE4)
|
||||
#define UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xE8)
|
||||
#define UFS_PHY_RX_REF_CLOCK_SHARED_CAPABILITY PHY_OFF(0xEC)
|
||||
#define UFS_PHY_RX_HS_G1_SYNC_LENGTH_CAPABILITY PHY_OFF(0xF0)
|
||||
#define UFS_PHY_RX_HS_G1_PREPARE_LENGTH_CAPABILITY PHY_OFF(0xF4)
|
||||
#define UFS_PHY_RX_LS_PREPARE_LENGTH_CAPABILITY PHY_OFF(0xF8)
|
||||
#define UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY PHY_OFF(0xFC)
|
||||
#define UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY PHY_OFF(0x100)
|
||||
#define UFS_PHY_RX_PHY_MAJORMINOR_RELEASE_CAPABILITY PHY_OFF(0x104)
|
||||
#define UFS_PHY_RX_PHY_EDITORIAL_RELEASE_CAPABILITY PHY_OFF(0x108)
|
||||
#define UFS_PHY_RX_HIBERN8TIME_CAPABILITY PHY_OFF(0x10C)
|
||||
#define UFS_PHY_RX_HS_G2_SYNC_LENGTH_CAPABILITY PHY_OFF(0x110)
|
||||
#define UFS_PHY_RX_HS_G3_SYNC_LENGTH_CAPABILITY PHY_OFF(0x114)
|
||||
#define UFS_PHY_RX_HS_G2_PREPARE_LENGTH_CAPABILITY PHY_OFF(0x118)
|
||||
#define UFS_PHY_RX_HS_G3_PREPARE_LENGTH_CAPABILITY PHY_OFF(0x11C)
|
||||
#define UFS_PHY_DEBUG_BUS_SEL PHY_OFF(0x120)
|
||||
#define UFS_PHY_DEBUG_BUS_0_STATUS_CHK PHY_OFF(0x124)
|
||||
#define UFS_PHY_DEBUG_BUS_1_STATUS_CHK PHY_OFF(0x128)
|
||||
#define UFS_PHY_DEBUG_BUS_2_STATUS_CHK PHY_OFF(0x12C)
|
||||
#define UFS_PHY_DEBUG_BUS_3_STATUS_CHK PHY_OFF(0x130)
|
||||
#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x134)
|
||||
#define UFS_PHY_L0_BIST_CHK_ERR_CNT_L_STATUS PHY_OFF(0x138)
|
||||
#define UFS_PHY_L0_BIST_CHK_ERR_CNT_H_STATUS PHY_OFF(0x13C)
|
||||
#define UFS_PHY_L1_BIST_CHK_ERR_CNT_L_STATUS PHY_OFF(0x140)
|
||||
#define UFS_PHY_L1_BIST_CHK_ERR_CNT_H_STATUS PHY_OFF(0x144)
|
||||
#define UFS_PHY_L0_BIST_CHK_STATUS PHY_OFF(0x148)
|
||||
#define UFS_PHY_L1_BIST_CHK_STATUS PHY_OFF(0x14C)
|
||||
#define UFS_PHY_DEBUG_BUS_0_STATUS PHY_OFF(0x150)
|
||||
#define UFS_PHY_DEBUG_BUS_1_STATUS PHY_OFF(0x154)
|
||||
#define UFS_PHY_DEBUG_BUS_2_STATUS PHY_OFF(0x158)
|
||||
#define UFS_PHY_DEBUG_BUS_3_STATUS PHY_OFF(0x15C)
|
||||
#define UFS_PHY_RMMI_ATTR_CTRL PHY_OFF(0x16C)
|
||||
#define UFS_PHY_RMMI_RX_CFGUPDT_L1 (1 << 7)
|
||||
#define UFS_PHY_RMMI_TX_CFGUPDT_L1 (1 << 6)
|
||||
#define UFS_PHY_RMMI_CFGWR_L1 (1 << 5)
|
||||
#define UFS_PHY_RMMI_CFGRD_L1 (1 << 4)
|
||||
#define UFS_PHY_RMMI_RX_CFGUPDT_L0 (1 << 3)
|
||||
#define UFS_PHY_RMMI_TX_CFGUPDT_L0 (1 << 2)
|
||||
#define UFS_PHY_RMMI_CFGWR_L0 (1 << 1)
|
||||
#define UFS_PHY_RMMI_CFGRD_L0 (1 << 0)
|
||||
#define UFS_PHY_RMMI_ATTRID PHY_OFF(0x170)
|
||||
#define UFS_PHY_RMMI_ATTRWRVAL PHY_OFF(0x174)
|
||||
#define UFS_PHY_RMMI_ATTRRDVAL_L0_STATUS PHY_OFF(0x178)
|
||||
#define UFS_PHY_RMMI_ATTRRDVAL_L1_STATUS PHY_OFF(0x17C)
|
||||
|
||||
/* TX LANE n (0, 1) registers */
|
||||
#define QSERDES_TX_BIST_MODE_LANENO(n) TX_OFF(n, 0x00)
|
||||
#define QSERDES_TX_CLKBUF_ENABLE(n) TX_OFF(n, 0x04)
|
||||
#define QSERDES_TX_TX_EMP_POST1_LVL(n) TX_OFF(n, 0x08)
|
||||
#define QSERDES_TX_TX_DRV_LVL(n) TX_OFF(n, 0x0C)
|
||||
#define QSERDES_TX_RESET_TSYNC_EN(n) TX_OFF(n, 0x10)
|
||||
#define QSERDES_TX_LPB_EN(n) TX_OFF(n, 0x14)
|
||||
#define QSERDES_TX_RES_CODE(n) TX_OFF(n, 0x18)
|
||||
#define QSERDES_TX_PERL_LENGTH1(n) TX_OFF(n, 0x1C)
|
||||
#define QSERDES_TX_PERL_LENGTH2(n) TX_OFF(n, 0x20)
|
||||
#define QSERDES_TX_SERDES_BYP_EN_OUT(n) TX_OFF(n, 0x24)
|
||||
#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_EN(n) TX_OFF(n, 0x28)
|
||||
#define QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN(n) TX_OFF(n, 0x2C)
|
||||
#define QSERDES_TX_BIST_PATTERN1(n) TX_OFF(n, 0x30)
|
||||
#define QSERDES_TX_BIST_PATTERN2(n) TX_OFF(n, 0x34)
|
||||
#define QSERDES_TX_BIST_PATTERN3(n) TX_OFF(n, 0x38)
|
||||
#define QSERDES_TX_BIST_PATTERN4(n) TX_OFF(n, 0x3C)
|
||||
#define QSERDES_TX_BIST_PATTERN5(n) TX_OFF(n, 0x40)
|
||||
#define QSERDES_TX_BIST_PATTERN6(n) TX_OFF(n, 0x44)
|
||||
#define QSERDES_TX_BIST_PATTERN7(n) TX_OFF(n, 0x48)
|
||||
#define QSERDES_TX_BIST_PATTERN8(n) TX_OFF(n, 0x4C)
|
||||
#define QSERDES_TX_LANE_MODE(n) TX_OFF(n, 0x50)
|
||||
#define QSERDES_TX_ATB_SEL(n) TX_OFF(n, 0x54)
|
||||
#define QSERDES_TX_REC_DETECT_LVL(n) TX_OFF(n, 0x58)
|
||||
#define QSERDES_TX_PRBS_SEED1(n) TX_OFF(n, 0x5C)
|
||||
#define QSERDES_TX_PRBS_SEED2(n) TX_OFF(n, 0x60)
|
||||
#define QSERDES_TX_PRBS_SEED3(n) TX_OFF(n, 0x64)
|
||||
#define QSERDES_TX_PRBS_SEED4(n) TX_OFF(n, 0x68)
|
||||
#define QSERDES_TX_RESET_GEN(n) TX_OFF(n, 0x6C)
|
||||
#define QSERDES_TX_TRAN_DRVR_EMP_EN(n) TX_OFF(n, 0x70)
|
||||
#define QSERDES_TX_TX_INTERFACE_MODE(n) TX_OFF(n, 0x74)
|
||||
#define QSERDES_TX_BIST_STATUS(n) TX_OFF(n, 0x78)
|
||||
#define QSERDES_TX_BIST_ERROR_COUNT1(n) TX_OFF(n, 0x7C)
|
||||
#define QSERDES_TX_BIST_ERROR_COUNT2(n) TX_OFF(n, 0x80)
|
||||
|
||||
/* RX LANE n (0, 1) registers */
|
||||
#define QSERDES_RX_CDR_CONTROL(n) RX_OFF(n, 0x00)
|
||||
#define QSERDES_RX_AUX_CONTROL(n) RX_OFF(n, 0x04)
|
||||
#define QSERDES_RX_AUX_DATA_TCODE(n) RX_OFF(n, 0x08)
|
||||
#define QSERDES_RX_RCLK_AUXDATA_SEL(n) RX_OFF(n, 0x0C)
|
||||
#define QSERDES_RX_EQ_CONTROL(n) RX_OFF(n, 0x10)
|
||||
#define QSERDES_RX_RX_EQ_GAIN2(n) RX_OFF(n, 0x14)
|
||||
#define QSERDES_RX_AC_JTAG_INIT(n) RX_OFF(n, 0x18)
|
||||
#define QSERDES_RX_AC_JTAG_LVL_EN(n) RX_OFF(n, 0x1C)
|
||||
#define QSERDES_RX_AC_JTAG_MODE(n) RX_OFF(n, 0x20)
|
||||
#define QSERDES_RX_AC_JTAG_RESET(n) RX_OFF(n, 0x24)
|
||||
#define QSERDES_RX_RX_IQ_RXDET_EN(n) RX_OFF(n, 0x28)
|
||||
#define QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE(n) RX_OFF(n, 0x2C)
|
||||
#define QSERDES_RX_RX_EQ_GAIN1(n) RX_OFF(n, 0x30)
|
||||
#define QSERDES_RX_SIGDET_CNTRL(n) RX_OFF(n, 0x34)
|
||||
#define QSERDES_RX_RX_BAND(n) RX_OFF(n, 0x38)
|
||||
#define QSERDES_RX_CDR_FREEZE_UP_DN(n) RX_OFF(n, 0x3C)
|
||||
#define QSERDES_RX_RX_INTERFACE_MODE(n) RX_OFF(n, 0x40)
|
||||
#define QSERDES_RX_JITTER_GEN_MODE(n) RX_OFF(n, 0x44)
|
||||
#define QSERDES_RX_BUJ_AMP(n) RX_OFF(n, 0x48)
|
||||
#define QSERDES_RX_SJ_AMP1(n) RX_OFF(n, 0x4C)
|
||||
#define QSERDES_RX_SJ_AMP2(n) RX_OFF(n, 0x50)
|
||||
#define QSERDES_RX_SJ_PER1(n) RX_OFF(n, 0x54)
|
||||
#define QSERDES_RX_SJ_PER2(n) RX_OFF(n, 0x58)
|
||||
#define QSERDES_RX_BUJ_STEP_FREQ1(n) RX_OFF(n, 0x5C)
|
||||
#define QSERDES_RX_BUJ_STEP_FREQ2(n) RX_OFF(n, 0x60)
|
||||
#define QSERDES_RX_PPM_OFFSET1(n) RX_OFF(n, 0x64)
|
||||
#define QSERDES_RX_PPM_OFFSET2(n) RX_OFF(n, 0x68)
|
||||
#define QSERDES_RX_SIGN_PPM_PERIOD1(n) RX_OFF(n, 0x6C)
|
||||
#define QSERDES_RX_SIGN_PPM_PERIOD2(n) RX_OFF(n, 0x70)
|
||||
#define QSERDES_RX_SSC_CTRL(n) RX_OFF(n, 0x74)
|
||||
#define QSERDES_RX_SSC_COUNT1(n) RX_OFF(n, 0x78)
|
||||
#define QSERDES_RX_SSC_COUNT2(n) RX_OFF(n, 0x7C)
|
||||
#define QSERDES_RX_PWM_CNTRL1(n) RX_OFF(n, 0x80)
|
||||
#define QSERDES_RX_PWM_CNTRL2(n) RX_OFF(n, 0x84)
|
||||
#define QSERDES_RX_PWM_NDIV(n) RX_OFF(n, 0x88)
|
||||
#define QSERDES_RX_SIGDET_CNTRL2(n) RX_OFF(n, 0x8C)
|
||||
#define QSERDES_RX_UFS_CNTRL(n) RX_OFF(n, 0x90)
|
||||
#define QSERDES_RX_CDR_CONTROL3(n) RX_OFF(n, 0x94)
|
||||
#define QSERDES_RX_CDR_CONTROL_HALF(n) RX_OFF(n, 0x98)
|
||||
#define QSERDES_RX_CDR_CONTROL_QUARTER(n) RX_OFF(n, 0x9C)
|
||||
#define QSERDES_RX_CDR_CONTROL_EIGHTH(n) RX_OFF(n, 0xA0)
|
||||
#define QSERDES_RX_UCDR_FO_GAIN(n) RX_OFF(n, 0xA4)
|
||||
#define QSERDES_RX_UCDR_SO_GAIN(n) RX_OFF(n, 0xA8)
|
||||
#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE(n) RX_OFF(n, 0xAC)
|
||||
#define QSERDES_RX_UCDR_FO_TO_SO_DELAY(n) RX_OFF(n, 0xB0)
|
||||
#define QSERDES_RX_PI_CTRL1(n) RX_OFF(n, 0xB4)
|
||||
#define QSERDES_RX_PI_CTRL2(n) RX_OFF(n, 0xB8)
|
||||
#define QSERDES_RX_PI_QUAD(n) RX_OFF(n, 0xBC)
|
||||
#define QSERDES_RX_IDATA1(n) RX_OFF(n, 0xC0)
|
||||
#define QSERDES_RX_IDATA2(n) RX_OFF(n, 0xC4)
|
||||
#define QSERDES_RX_AUX_DATA1(n) RX_OFF(n, 0xC8)
|
||||
#define QSERDES_RX_AUX_DATA2(n) RX_OFF(n, 0xCC)
|
||||
#define QSERDES_RX_AC_JTAG_OUTP(n) RX_OFF(n, 0xD0)
|
||||
#define QSERDES_RX_AC_JTAG_OUTN(n) RX_OFF(n, 0xD4)
|
||||
#define QSERDES_RX_RX_SIGDET_PWMDECSTATUS(n) RX_OFF(n, 0xD8)
|
||||
|
||||
#define UFS_PHY_TX_LANE_ENABLE_MASK 0x3
|
||||
|
||||
/*
|
||||
* This structure represents the 28nm specific phy.
|
||||
* common_cfg MUST remain the first field in this structure
|
||||
* in case extra fields are added. This way, when calling
|
||||
* get_ufs_msm_phy() of generic phy, we can extract the
|
||||
* common phy structure (struct ufs_msm_phy) out of it
|
||||
* regardless of the relevant specific phy.
|
||||
*/
|
||||
struct ufs_msm_phy_qmp_28nm {
|
||||
struct ufs_msm_phy common_cfg;
|
||||
};
|
||||
|
||||
static struct ufs_msm_phy_calibration phy_cal_table_ctrl_1_1_0_rate_A[] = {
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xFF),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CNTRL, 0x24),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0x08),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x67),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x13),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_PWM_CNTRL1(0), 0x43),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_PWM_CNTRL1(1), 0x43),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL(0), 0x22),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x12),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x2a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL(1), 0x22),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x12),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x2a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL(0), 0xC0),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL(1), 0xC0),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL2(0), 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL2(1), 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PWM_G1_CLK_DIVIDER, 0x50),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PWM_G2_CLK_DIVIDER, 0x28),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PWM_G3_CLK_DIVIDER, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PWM_G4_CLK_DIVIDER, 0x08),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER, 0xa8),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER, 0x54),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER, 0x2a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER, 0x15),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_OMC_STATUS_RDVAL, 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_LINE_RESET_TIME, 0x1f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_LINE_RESET_GRANULARITY, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TSYNC_RSYNC_CNTL, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PLL_CNTL, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x1a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CFG_CHANGE_CNT_VAL, 0x09),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_SYNC_WAIT_TIME, 0x30),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY, 0x08),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY, 0x04),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY, 0xc8),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1(0), 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2(0), 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1(1), 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2(1), 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL3(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL3(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x3f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_RES_TRIM_OFFSET, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_BGTC, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_AMP_OS, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TX_DRV_LVL(0), 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TX_DRV_LVL(1), 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_BIST_MODE_LANENO(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_BIST_MODE_LANENO(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TX_EMP_POST1_LVL(0), 0x04),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TX_EMP_POST1_LVL(1), 0x04),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_EN(0), 0x05),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_EN(1), 0x05),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TIMER_100US_SYSCLK_STEPS_MSB, 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TIMER_100US_SYSCLK_STEPS_LSB, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB, 0x27),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CONTROLSYM_ONE_HOT_DISABLE, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RETIME_BUFFER_EN, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_HSGEAR_CAPABILITY, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_PWMGEAR_CAPABILITY, 0x04),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_AMPLITUDE_CAPABILITY, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_EXTERNALSYNC_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_HS_UNTERMINATED_LINE_DRIVE_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_LS_TERMINATED_LINE_DRIVE_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_REF_CLOCK_SHARED_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_HIBERN8TIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HSGEAR_CAPABILITY, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_PWMGEAR_CAPABILITY, 0x04),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_UNTERMINATED_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_LS_TERMINATED_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_REF_CLOCK_SHARED_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_G1_SYNC_LENGTH_CAPABILITY, 0x48),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_HS_G1_PREPARE_LENGTH_CAPABILITY, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_LS_PREPARE_LENGTH_CAPABILITY, 0x09),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HIBERN8TIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_G2_SYNC_LENGTH_CAPABILITY, 0x48),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_G3_SYNC_LENGTH_CAPABILITY, 0x48),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_HS_G2_PREPARE_LENGTH_CAPABILITY, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_HS_G3_PREPARE_LENGTH_CAPABILITY, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_CLKBUF_ENABLE(0), 0x09),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_RESET_TSYNC_EN(0), 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_RES_CODE(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_SERDES_BYP_EN_OUT(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_REC_DETECT_LVL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TRAN_DRVR_EMP_EN(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_AUX_CONTROL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_AUX_DATA_TCODE(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RCLK_AUXDATA_SEL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_EQ_CONTROL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_IQ_RXDET_EN(0), 0x73),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE(0), 0x05),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_FREEZE_UP_DN(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UFS_CNTRL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_EIGHTH(0), 0x22),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FO_GAIN(0), 0x0a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SO_GAIN(0), 0x06),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE(0), 0x35),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FO_TO_SO_DELAY(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_CLKBUF_ENABLE(1), 0x09),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_RESET_TSYNC_EN(1), 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_RES_CODE(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_SERDES_BYP_EN_OUT(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_REC_DETECT_LVL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TRAN_DRVR_EMP_EN(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_AUX_CONTROL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_AUX_DATA_TCODE(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RCLK_AUXDATA_SEL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_EQ_CONTROL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_IQ_RXDET_EN(1), 0x73),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE(1), 0x05),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_FREEZE_UP_DN(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UFS_CNTRL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_EIGHTH(1), 0x22),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FO_GAIN(1), 0x0a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SO_GAIN(1), 0x06),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE(1), 0x35),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FO_TO_SO_DELAY(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_CMN_MODE, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_IE_TRIM, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_IP_TRIM, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_IN_SYNC_SEL, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_TEST_UPDN_RESTRIMSTEP, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_FAUX_EN, 0x00),
|
||||
};
|
||||
|
||||
static struct ufs_msm_phy_calibration phy_cal_table_ctrl_1_1_1_rate_A[] = {
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0x43),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CNTRL, 0x24),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0x08),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_PWM_CNTRL1(0), 0x43),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_PWM_CNTRL1(1), 0x43),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL(0), 0x40),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL(1), 0x40),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x0c),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x12),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL(0), 0xC0),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL(1), 0xC0),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL2(0), 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL2(1), 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PWM_G1_CLK_DIVIDER, 0x30),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PWM_G2_CLK_DIVIDER, 0x18),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PWM_G3_CLK_DIVIDER, 0x0c),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PWM_G4_CLK_DIVIDER, 0x06),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER, 0xa8),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER, 0x54),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER, 0x2a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER, 0x15),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_OMC_STATUS_RDVAL, 0xff),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_LINE_RESET_TIME, 0x1f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_LINE_RESET_GRANULARITY, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TSYNC_RSYNC_CNTL, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_PLL_CNTL, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x1a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CFG_CHANGE_CNT_VAL, 0x09),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_SYNC_WAIT_TIME, 0x30),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY, 0x08),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY, 0x04),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY, 0xc8),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1(0), 0x1f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2(0), 0x17),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1(1), 0x1f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2(1), 0x17),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL3(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL3(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_RES_TRIM_OFFSET, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_BGTC, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_AMP_OS, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TX_DRV_LVL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TX_DRV_LVL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_BIST_MODE_LANENO(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_BIST_MODE_LANENO(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TX_EMP_POST1_LVL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TX_EMP_POST1_LVL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_EN(0), 0x05),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_EN(1), 0x05),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TIMER_100US_SYSCLK_STEPS_MSB, 0x07),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TIMER_100US_SYSCLK_STEPS_LSB, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB, 0x27),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_CONTROLSYM_ONE_HOT_DISABLE, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RETIME_BUFFER_EN, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_HSGEAR_CAPABILITY, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_PWMGEAR_CAPABILITY, 0x04),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_AMPLITUDE_CAPABILITY, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_EXTERNALSYNC_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_HS_UNTERMINATED_LINE_DRIVE_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
UFS_PHY_TX_LS_TERMINATED_LINE_DRIVE_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_REF_CLOCK_SHARED_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_TX_HIBERN8TIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HSGEAR_CAPABILITY, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_PWMGEAR_CAPABILITY, 0x04),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_UNTERMINATED_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_LS_TERMINATED_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_REF_CLOCK_SHARED_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_G1_SYNC_LENGTH_CAPABILITY, 0x48),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_G1_PREPARE_LENGTH_CAPABILITY, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_LS_PREPARE_LENGTH_CAPABILITY, 0x0a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HIBERN8TIME_CAPABILITY, 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_G2_SYNC_LENGTH_CAPABILITY, 0x48),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_G3_SYNC_LENGTH_CAPABILITY, 0x48),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_G2_PREPARE_LENGTH_CAPABILITY, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(UFS_PHY_RX_HS_G3_PREPARE_LENGTH_CAPABILITY, 0x0f),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_CLKBUF_ENABLE(0), 0x09),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_RESET_TSYNC_EN(0), 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_RES_CODE(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_SERDES_BYP_EN_OUT(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_REC_DETECT_LVL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TRAN_DRVR_EMP_EN(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_AUX_CONTROL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_AUX_DATA_TCODE(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RCLK_AUXDATA_SEL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_EQ_CONTROL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_IQ_RXDET_EN(0), 0x51),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE(0), 0x05),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_FREEZE_UP_DN(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UFS_CNTRL(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_EIGHTH(0), 0x22),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FO_GAIN(0), 0x0a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SO_GAIN(0), 0x06),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE(0), 0x35),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FO_TO_SO_DELAY(0), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_CLKBUF_ENABLE(1), 0x09),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_RESET_TSYNC_EN(1), 0x01),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_RES_CODE(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_SERDES_BYP_EN_OUT(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_REC_DETECT_LVL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_TRAN_DRVR_EMP_EN(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_AUX_CONTROL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_AUX_DATA_TCODE(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RCLK_AUXDATA_SEL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_EQ_CONTROL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_IQ_RXDET_EN(1), 0x51),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE(1), 0x05),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_FREEZE_UP_DN(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UFS_CNTRL(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_EIGHTH(1), 0x22),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FO_GAIN(1), 0x0a),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SO_GAIN(1), 0x06),
|
||||
UFS_MSM_PHY_CAL_ENTRY(
|
||||
QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE(1), 0x35),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FO_TO_SO_DELAY(1), 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_CMN_MODE, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_IE_TRIM, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_IP_TRIM, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_IN_SYNC_SEL, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_TEST_UPDN_RESTRIMSTEP, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_FAUX_EN, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x08),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x08),
|
||||
};
|
||||
|
||||
static struct ufs_msm_phy_calibration phy_cal_table_rate_B[] = {
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x98),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x10),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0x65),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x1E),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00),
|
||||
UFS_MSM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03),
|
||||
};
|
||||
|
||||
static struct ufs_msm_phy_calibration cached_phy_regs[] = {
|
||||
{QSERDES_COM_PLL_CRCTRL},
|
||||
{QSERDES_COM_PLL_CNTRL},
|
||||
{QSERDES_COM_SYSCLK_EN_SEL},
|
||||
{QSERDES_COM_SYS_CLK_CTRL},
|
||||
{QSERDES_COM_PLL_CLKEPDIV},
|
||||
{QSERDES_COM_DEC_START1},
|
||||
{QSERDES_COM_DEC_START2},
|
||||
{QSERDES_COM_DIV_FRAC_START1},
|
||||
{QSERDES_COM_DIV_FRAC_START2},
|
||||
{QSERDES_COM_DIV_FRAC_START3},
|
||||
{QSERDES_COM_PLLLOCK_CMP1},
|
||||
{QSERDES_COM_PLLLOCK_CMP2},
|
||||
{QSERDES_COM_PLLLOCK_CMP3},
|
||||
{QSERDES_COM_PLLLOCK_CMP_EN},
|
||||
{QSERDES_COM_RESETSM_CNTRL},
|
||||
{QSERDES_COM_PLL_RXTXEPCLK_EN},
|
||||
{QSERDES_RX_PWM_CNTRL1(0)},
|
||||
{QSERDES_RX_PWM_CNTRL1(1)},
|
||||
{QSERDES_RX_CDR_CONTROL(0)},
|
||||
{QSERDES_RX_CDR_CONTROL_HALF(0)},
|
||||
{QSERDES_RX_CDR_CONTROL_QUARTER(0)},
|
||||
{QSERDES_RX_CDR_CONTROL(1)},
|
||||
{QSERDES_RX_CDR_CONTROL_HALF(1)},
|
||||
{QSERDES_RX_CDR_CONTROL_QUARTER(1)},
|
||||
{QSERDES_RX_SIGDET_CNTRL(0)},
|
||||
{QSERDES_RX_SIGDET_CNTRL(1)},
|
||||
{QSERDES_RX_SIGDET_CNTRL2(0)},
|
||||
{QSERDES_RX_SIGDET_CNTRL2(1)},
|
||||
{QSERDES_RX_RX_EQ_GAIN1(0)},
|
||||
{QSERDES_RX_RX_EQ_GAIN2(0)},
|
||||
{QSERDES_RX_RX_EQ_GAIN1(1)},
|
||||
{QSERDES_RX_RX_EQ_GAIN2(1)},
|
||||
{QSERDES_COM_PLL_IP_SETI},
|
||||
{QSERDES_COM_PLL_CP_SETI},
|
||||
{QSERDES_COM_PLL_IP_SETP},
|
||||
{QSERDES_COM_PLL_CP_SETP},
|
||||
{UFS_PHY_PWM_G1_CLK_DIVIDER},
|
||||
{UFS_PHY_PWM_G2_CLK_DIVIDER},
|
||||
{UFS_PHY_PWM_G3_CLK_DIVIDER},
|
||||
{UFS_PHY_PWM_G4_CLK_DIVIDER},
|
||||
{UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER},
|
||||
{UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER},
|
||||
{UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER},
|
||||
{UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER},
|
||||
{UFS_PHY_OMC_STATUS_RDVAL},
|
||||
{UFS_PHY_LINE_RESET_TIME},
|
||||
{UFS_PHY_LINE_RESET_GRANULARITY},
|
||||
{UFS_PHY_TSYNC_RSYNC_CNTL},
|
||||
{UFS_PHY_PLL_CNTL},
|
||||
{UFS_PHY_TX_LARGE_AMP_DRV_LVL},
|
||||
{UFS_PHY_TX_SMALL_AMP_DRV_LVL},
|
||||
{UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL},
|
||||
{UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL},
|
||||
{UFS_PHY_CFG_CHANGE_CNT_VAL},
|
||||
{UFS_PHY_RX_SYNC_WAIT_TIME},
|
||||
{UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY},
|
||||
{UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY},
|
||||
{UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY},
|
||||
{UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY},
|
||||
{UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY},
|
||||
{UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY},
|
||||
{UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY},
|
||||
{UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY},
|
||||
{QSERDES_RX_CDR_CONTROL3(0)},
|
||||
{QSERDES_RX_CDR_CONTROL3(1)},
|
||||
{QSERDES_COM_RES_TRIM_OFFSET},
|
||||
{QSERDES_COM_BGTC},
|
||||
{QSERDES_COM_PLL_AMP_OS},
|
||||
};
|
||||
|
||||
static struct ufs_msm_phy_stored_attributes cached_phy_attr[] = {
|
||||
{TX_MODE},
|
||||
{TX_HSRATE_SERIES},
|
||||
{TX_HSGEAR},
|
||||
{TX_PWMGEAR},
|
||||
{TX_AMPLITUDE},
|
||||
{TX_HS_SLEWRATE},
|
||||
{TX_SYNC_SOURCE},
|
||||
{TX_HS_PREPARE_LENGTH},
|
||||
{TX_LS_PREPARE_LENGTH},
|
||||
{TX_LCC_ENABLE},
|
||||
{TX_PWM_BURST_CLOSURE_EXTENSION},
|
||||
{TX_BYPASS_8B10B_ENABLE},
|
||||
{TX_DRIVER_POLARITY},
|
||||
{TX_HS_UNTERMINATED_LINE_DRIVE_ENABLE},
|
||||
{TX_LS_TERMINATED_LINE_DRIVE_ENABLE},
|
||||
{TX_LCC_SEQUENCER},
|
||||
{TX_MIN_ACTIVATETIME},
|
||||
{TX_PWM_G6_G7_SYNC_LENGTH},
|
||||
{RX_MODE},
|
||||
{RX_HSRATE_SERIES},
|
||||
{RX_HSGEAR},
|
||||
{RX_PWMGEAR},
|
||||
{RX_LS_TERMINATED_ENABLE},
|
||||
{RX_HS_UNTERMINATED_ENABLE},
|
||||
{RX_ENTER_HIBERN8},
|
||||
{RX_BYPASS_8B10B_ENABLE},
|
||||
{RX_TERMINATION_FORCE_ENABLE},
|
||||
};
|
||||
|
||||
#endif
|
562
drivers/scsi/ufs/ufs-msm-phy.c
Normal file
562
drivers/scsi/ufs/ufs-msm-phy.c
Normal file
|
@ -0,0 +1,562 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/msm-bus.h>
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include "unipro.h"
|
||||
#include "ufs-msm.h"
|
||||
#include "ufs-msm-phy.h"
|
||||
|
||||
/*
|
||||
* This assumes the embedded phy structure inside generic_phy is of type
|
||||
* struct ufs_msm_phy. In order to function properly it's crucial
|
||||
* to keep the embedded struct "struct ufs_msm_phy common_cfg"
|
||||
* as the first inside generic_phy.
|
||||
*/
|
||||
struct ufs_msm_phy *get_ufs_msm_phy(struct phy *generic_phy)
|
||||
{
|
||||
return (struct ufs_msm_phy *)phy_get_drvdata(generic_phy);
|
||||
}
|
||||
|
||||
int ufs_msm_phy_base_init(struct platform_device *pdev,
|
||||
struct ufs_msm_phy *phy_common)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int err = 0;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "%s: platform_get_resource() failed. returned NULL\n",
|
||||
__func__);
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
phy_common->mmio = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(phy_common->mmio)) {
|
||||
err = PTR_ERR(phy_common->mmio);
|
||||
dev_err(dev, "ioremap resource failed %d\n", err);
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_clk_get(struct phy *phy,
|
||||
const char *name, struct clk **clk_out)
|
||||
{
|
||||
struct clk *clk;
|
||||
int err = 0;
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(phy);
|
||||
struct device *dev = ufs_msm_phy->dev;
|
||||
|
||||
clk = devm_clk_get(dev, name);
|
||||
if (IS_ERR(clk)) {
|
||||
err = PTR_ERR(clk);
|
||||
dev_err(dev, "failed to get %s err %d", name, err);
|
||||
} else {
|
||||
*clk_out = clk;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
ufs_msm_phy_init_clks(struct phy *generic_phy, struct ufs_msm_phy *phy_common)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ufs_msm_phy_clk_get(generic_phy, "tx_iface_clk",
|
||||
&phy_common->tx_iface_clk);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ufs_msm_phy_clk_get(generic_phy, "rx_iface_clk",
|
||||
&phy_common->rx_iface_clk);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ufs_msm_phy_clk_get(generic_phy, "ref_clk_src",
|
||||
&phy_common->ref_clk_src);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ufs_msm_phy_clk_get(generic_phy, "ref_clk_parent",
|
||||
&phy_common->ref_clk_parent);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ufs_msm_phy_clk_get(generic_phy, "ref_clk",
|
||||
&phy_common->ref_clk);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
ufs_msm_phy_init_vregulators(struct phy *generic_phy,
|
||||
struct ufs_msm_phy *phy_common)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ufs_msm_phy_init_vreg(generic_phy, &phy_common->vdda_pll,
|
||||
"vdda-pll");
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = ufs_msm_phy_init_vreg(generic_phy, &phy_common->vdda_phy,
|
||||
"vdda-phy");
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_init_vreg(struct phy *phy,
|
||||
struct ufs_msm_phy_vreg *vreg, const char *name)
|
||||
{
|
||||
int err = 0;
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(phy);
|
||||
struct device *dev = ufs_msm_phy->dev;
|
||||
|
||||
char prop_name[MAX_PROP_NAME];
|
||||
|
||||
vreg->name = kstrdup(name, GFP_KERNEL);
|
||||
if (!vreg->name) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vreg->reg = devm_regulator_get(dev, name);
|
||||
if (IS_ERR(vreg->reg)) {
|
||||
err = PTR_ERR(vreg->reg);
|
||||
dev_err(dev, "failed to get %s, %d\n", name, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dev->of_node) {
|
||||
snprintf(prop_name, MAX_PROP_NAME, "%s-max-microamp", name);
|
||||
err = of_property_read_u32(dev->of_node,
|
||||
prop_name, &vreg->max_uA);
|
||||
if (err && err != -EINVAL) {
|
||||
dev_err(dev, "%s: failed to read %s\n",
|
||||
__func__, prop_name);
|
||||
goto out;
|
||||
} else if (err == -EINVAL || !vreg->max_uA) {
|
||||
if (regulator_count_voltages(vreg->reg) > 0) {
|
||||
dev_err(dev, "%s: %s is mandatory\n",
|
||||
__func__, prop_name);
|
||||
goto out;
|
||||
}
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(name, "vdda-pll")) {
|
||||
vreg->max_uV = VDDA_PLL_MAX_UV;
|
||||
vreg->min_uV = VDDA_PLL_MIN_UV;
|
||||
} else if (!strcmp(name, "vdda-phy")) {
|
||||
vreg->max_uV = VDDA_PHY_MAX_UV;
|
||||
vreg->min_uV = VDDA_PHY_MIN_UV;
|
||||
}
|
||||
|
||||
out:
|
||||
if (err)
|
||||
kfree(vreg->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_cfg_vreg(struct phy *phy,
|
||||
struct ufs_msm_phy_vreg *vreg, bool on)
|
||||
{
|
||||
int ret = 0;
|
||||
struct regulator *reg = vreg->reg;
|
||||
const char *name = vreg->name;
|
||||
int min_uV;
|
||||
int uA_load;
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(phy);
|
||||
struct device *dev = ufs_msm_phy->dev;
|
||||
|
||||
BUG_ON(!vreg);
|
||||
|
||||
if (regulator_count_voltages(reg) > 0) {
|
||||
min_uV = on ? vreg->min_uV : 0;
|
||||
ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: %s set voltage failed, err=%d\n",
|
||||
__func__, name, ret);
|
||||
goto out;
|
||||
}
|
||||
uA_load = on ? vreg->max_uA : 0;
|
||||
ret = regulator_set_optimum_mode(reg, uA_load);
|
||||
if (ret >= 0) {
|
||||
/*
|
||||
* regulator_set_optimum_mode() returns new regulator
|
||||
* mode upon success.
|
||||
*/
|
||||
ret = 0;
|
||||
} else {
|
||||
dev_err(dev, "%s: %s set optimum mode(uA_load=%d) failed, err=%d\n",
|
||||
__func__, name, uA_load, ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_enable_vreg(struct phy *phy,
|
||||
struct ufs_msm_phy_vreg *vreg)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(phy);
|
||||
struct device *dev = ufs_msm_phy->dev;
|
||||
int ret = 0;
|
||||
|
||||
if (!vreg || vreg->enabled)
|
||||
goto out;
|
||||
|
||||
ret = ufs_msm_phy_cfg_vreg(phy, vreg, true);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: ufs_msm_phy_cfg_vreg() failed, err=%d\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = regulator_enable(vreg->reg);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: enable failed, err=%d\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
vreg->enabled = true;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_enable_ref_clk(struct phy *generic_phy)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ufs_msm_phy *phy = get_ufs_msm_phy(generic_phy);
|
||||
if (phy->is_ref_clk_enabled)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* reference clock is propagated in a daisy-chained manner from
|
||||
* source to phy, so ungate them at each stage.
|
||||
*/
|
||||
ret = clk_prepare_enable(phy->ref_clk_src);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "%s: ref_clk_src enable failed %d\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(phy->ref_clk_parent);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "%s: ref_clk_parent enable failed %d\n",
|
||||
__func__, ret);
|
||||
goto out_disable_src;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(phy->ref_clk);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "%s: ref_clk enable failed %d\n",
|
||||
__func__, ret);
|
||||
goto out_disable_parent;
|
||||
}
|
||||
|
||||
phy->is_ref_clk_enabled = true;
|
||||
goto out;
|
||||
|
||||
out_disable_parent:
|
||||
clk_disable_unprepare(phy->ref_clk_parent);
|
||||
out_disable_src:
|
||||
clk_disable_unprepare(phy->ref_clk_src);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_disable_vreg(struct phy *phy,
|
||||
struct ufs_msm_phy_vreg *vreg)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(phy);
|
||||
struct device *dev = ufs_msm_phy->dev;
|
||||
int ret = 0;
|
||||
|
||||
if (!vreg || !vreg->enabled)
|
||||
goto out;
|
||||
|
||||
ret = regulator_disable(vreg->reg);
|
||||
|
||||
if (!ret) {
|
||||
/* ignore errors on applying disable config */
|
||||
ufs_msm_phy_cfg_vreg(phy, vreg, false);
|
||||
vreg->enabled = false;
|
||||
} else {
|
||||
dev_err(dev, "%s: %s disable failed, err=%d\n",
|
||||
__func__, vreg->name, ret);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ufs_msm_phy_disable_ref_clk(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *phy = get_ufs_msm_phy(generic_phy);
|
||||
|
||||
if (phy->is_ref_clk_enabled) {
|
||||
clk_disable_unprepare(phy->ref_clk);
|
||||
clk_disable_unprepare(phy->ref_clk_parent);
|
||||
clk_disable_unprepare(phy->ref_clk_src);
|
||||
phy->is_ref_clk_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ufs_msm_phy_restore_swi_regs(struct phy *generic_phy)
|
||||
{
|
||||
int i;
|
||||
struct ufs_msm_phy *phy = get_ufs_msm_phy(generic_phy);
|
||||
|
||||
for (i = 0; i < phy->cached_regs_table_size; i++) {
|
||||
struct ufs_msm_phy_calibration *table =
|
||||
(struct ufs_msm_phy_calibration *)phy->cached_regs;
|
||||
writel_relaxed(table[i].cfg_value, phy->mmio +
|
||||
table[i].reg_offset);
|
||||
}
|
||||
|
||||
/* flush buffered writes */
|
||||
mb();
|
||||
}
|
||||
|
||||
/* Turn ON M-PHY RMMI interface clocks */
|
||||
int ufs_msm_phy_enable_iface_clk(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *phy = get_ufs_msm_phy(generic_phy);
|
||||
int ret = 0;
|
||||
if (phy->is_iface_clk_enabled)
|
||||
goto out;
|
||||
|
||||
ret = clk_prepare_enable(phy->tx_iface_clk);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "%s: tx_iface_clk enable failed %d\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
ret = clk_prepare_enable(phy->rx_iface_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(phy->tx_iface_clk);
|
||||
dev_err(phy->dev, "%s: rx_iface_clk enable failed %d. disabling also tx_iface_clk\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
phy->is_iface_clk_enabled = true;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Turn OFF M-PHY RMMI interface clocks */
|
||||
void ufs_msm_phy_disable_iface_clk(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *phy = get_ufs_msm_phy(generic_phy);
|
||||
|
||||
if (phy->is_iface_clk_enabled) {
|
||||
clk_disable_unprepare(phy->tx_iface_clk);
|
||||
clk_disable_unprepare(phy->rx_iface_clk);
|
||||
phy->is_iface_clk_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
int ufs_msm_phy_is_cfg_restore_quirk_enabled(struct phy *phy)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(phy);
|
||||
|
||||
return ufs_msm_phy->quirks & MSM_UFS_PHY_QUIRK_CFG_RESTORE;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_start_serdes(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(generic_phy);
|
||||
int ret = 0;
|
||||
|
||||
if (!ufs_msm_phy->phy_spec_ops->start_serdes) {
|
||||
dev_err(ufs_msm_phy->dev, "%s: start_serdes() callback is not supported\n",
|
||||
__func__);
|
||||
ret = -ENOTSUPP;
|
||||
} else {
|
||||
ufs_msm_phy->phy_spec_ops->start_serdes(ufs_msm_phy);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(generic_phy);
|
||||
int ret = 0;
|
||||
|
||||
if (!ufs_msm_phy->phy_spec_ops->set_tx_lane_enable) {
|
||||
dev_err(ufs_msm_phy->dev, "%s: set_tx_lane_enable() callback is not supported\n",
|
||||
__func__);
|
||||
ret = -ENOTSUPP;
|
||||
} else {
|
||||
ufs_msm_phy->phy_spec_ops->set_tx_lane_enable(ufs_msm_phy,
|
||||
tx_lanes);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ufs_msm_phy_save_controller_version(struct phy *generic_phy,
|
||||
u8 major, u16 minor, u16 step)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(generic_phy);
|
||||
|
||||
ufs_msm_phy->host_ctrl_rev_major = major;
|
||||
ufs_msm_phy->host_ctrl_rev_minor = minor;
|
||||
ufs_msm_phy->host_ctrl_rev_step = step;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_calibrate_phy(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(generic_phy);
|
||||
int ret = 0;
|
||||
|
||||
if (!ufs_msm_phy->phy_spec_ops->calibrate_phy) {
|
||||
dev_err(ufs_msm_phy->dev, "%s: calibrate_phy() callback is not supported\n",
|
||||
__func__);
|
||||
ret = -ENOTSUPP;
|
||||
} else {
|
||||
ufs_msm_phy->phy_spec_ops->
|
||||
calibrate_phy(ufs_msm_phy);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_remove(struct phy *generic_phy,
|
||||
struct ufs_msm_phy *ufs_msm_phy)
|
||||
{
|
||||
phy_power_off(generic_phy);
|
||||
|
||||
kfree(ufs_msm_phy->vdda_pll.name);
|
||||
kfree(ufs_msm_phy->vdda_phy.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_exit(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(generic_phy);
|
||||
|
||||
if (ufs_msm_phy->is_powered_on)
|
||||
phy_power_off(generic_phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_is_pcs_ready(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(generic_phy);
|
||||
|
||||
if (!ufs_msm_phy->phy_spec_ops->is_physical_coding_sublayer_ready) {
|
||||
dev_err(ufs_msm_phy->dev, "%s: is_physical_coding_sublayer_ready() callback is not supported\n",
|
||||
__func__);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return ufs_msm_phy->phy_spec_ops->
|
||||
is_physical_coding_sublayer_ready(ufs_msm_phy);
|
||||
}
|
||||
|
||||
int ufs_msm_phy_save_configuration(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *ufs_msm_phy = get_ufs_msm_phy(generic_phy);
|
||||
int ret = 0;
|
||||
|
||||
if (!ufs_msm_phy->phy_spec_ops->save_configuration) {
|
||||
dev_err(ufs_msm_phy->dev, "%s: save_configuration() callback is not supported\n",
|
||||
__func__);
|
||||
ret = -ENOTSUPP;
|
||||
} else {
|
||||
ufs_msm_phy->phy_spec_ops->save_configuration(ufs_msm_phy);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_power_on(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *phy_common = get_ufs_msm_phy(generic_phy);
|
||||
struct device *dev = phy_common->dev;
|
||||
int err;
|
||||
|
||||
err = ufs_msm_phy_enable_vreg(generic_phy, &phy_common->vdda_phy);
|
||||
if (err) {
|
||||
dev_err(dev, "%s enable vdda_phy failed, err=%d\n",
|
||||
__func__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
phy_common->phy_spec_ops->power_control(phy_common, true);
|
||||
|
||||
/* vdda_pll also enables ref clock LDOs so enable it first */
|
||||
err = ufs_msm_phy_enable_vreg(generic_phy, &phy_common->vdda_pll);
|
||||
if (err) {
|
||||
dev_err(dev, "%s enable vdda_pll failed, err=%d\n",
|
||||
__func__, err);
|
||||
goto out_disable_phy;
|
||||
}
|
||||
|
||||
err = ufs_msm_phy_enable_ref_clk(generic_phy);
|
||||
if (err) {
|
||||
dev_err(dev, "%s enable phy ref clock failed, err=%d\n",
|
||||
__func__, err);
|
||||
goto out_disable_pll;
|
||||
}
|
||||
|
||||
phy_common->is_powered_on = true;
|
||||
goto out;
|
||||
|
||||
out_disable_pll:
|
||||
ufs_msm_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);
|
||||
out_disable_phy:
|
||||
ufs_msm_phy_disable_vreg(generic_phy, &phy_common->vdda_phy);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int ufs_msm_phy_power_off(struct phy *generic_phy)
|
||||
{
|
||||
struct ufs_msm_phy *phy_common = get_ufs_msm_phy(generic_phy);
|
||||
|
||||
phy_common->phy_spec_ops->power_control(phy_common, false);
|
||||
|
||||
ufs_msm_phy_disable_ref_clk(generic_phy);
|
||||
|
||||
ufs_msm_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);
|
||||
ufs_msm_phy_disable_vreg(generic_phy, &phy_common->vdda_phy);
|
||||
phy_common->is_powered_on = false;
|
||||
|
||||
return 0;
|
||||
}
|
176
drivers/scsi/ufs/ufs-msm-phy.h
Normal file
176
drivers/scsi/ufs/ufs-msm-phy.h
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UFS_MSM_PHY_H_
|
||||
#define UFS_MSM_PHY_H_
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/msm-bus.h>
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include "unipro.h"
|
||||
#include "ufs-msm.h"
|
||||
|
||||
#define UFS_MSM_PHY_CAL_ENTRY(reg, val) \
|
||||
{ \
|
||||
.reg_offset = reg, \
|
||||
.cfg_value = val, \
|
||||
}
|
||||
|
||||
#define UFS_MSM_PHY_NAME_LEN 30
|
||||
|
||||
struct ufs_msm_phy_stored_attributes {
|
||||
u32 att;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct ufs_msm_phy_calibration {
|
||||
u32 reg_offset;
|
||||
u32 cfg_value;
|
||||
};
|
||||
|
||||
struct ufs_msm_phy {
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
void __iomem *mmio;
|
||||
struct clk *tx_iface_clk;
|
||||
struct clk *rx_iface_clk;
|
||||
bool is_iface_clk_enabled;
|
||||
struct clk *ref_clk_src;
|
||||
struct clk *ref_clk_parent;
|
||||
struct clk *ref_clk;
|
||||
bool is_ref_clk_enabled;
|
||||
struct ufs_msm_phy_vreg vdda_pll;
|
||||
struct ufs_msm_phy_vreg vdda_phy;
|
||||
unsigned int quirks;
|
||||
u8 host_ctrl_rev_major;
|
||||
u16 host_ctrl_rev_minor;
|
||||
u16 host_ctrl_rev_step;
|
||||
|
||||
/*
|
||||
* As part of UFS power management, UFS link would be put in hibernate
|
||||
* and UFS device would be put in SLEEP mode as part of runtime/system
|
||||
* suspend callback. But when system goes into suspend with VDD
|
||||
* minimization, UFS PHY states are being reset which means UFS link
|
||||
* hibernate exit command on system resume would fail.
|
||||
* If this quirk is enabled then above issue is workaround by saving
|
||||
* the UFS PHY state information before system goes into suspend and
|
||||
* restoring the saved state information during system resume but
|
||||
* before executing the hibern8 exit command.
|
||||
* Note that this quirk will help restoring the PHY state if even when
|
||||
* link in not kept in hibern8 during suspend.
|
||||
*
|
||||
* Here is the list of steps to save/restore the configuration:
|
||||
* Before entering into system suspend:
|
||||
* 1. Read Critical PCS SWI Registers + less critical PHY CSR
|
||||
* 2. Read RMMI Attributes
|
||||
* Enter into system suspend
|
||||
* After exiting from system suspend:
|
||||
* 1. Set UFS_PHY_SOFT_RESET bit in UFS_CFG1 register of the UFS
|
||||
* Controller
|
||||
* 2. Write 0x01 to the UFS_PHY_POWER_DOWN_CONTROL register in the
|
||||
* UFS PHY
|
||||
* 3. Write back the values of the PHY SWI registers
|
||||
* 4. Clear UFS_PHY_SOFT_RESET bit in UFS_CFG1 register of the UFS
|
||||
* Controller
|
||||
* 5. Write 0x01 to the UFS_PHY_PHY_START in the UFS PHY. This will
|
||||
* start the PLL calibration and bring-up of the PHY.
|
||||
* 6. Write back the values to the PHY RMMI Attributes
|
||||
* 7. Wait for UFS_PHY_PCS_READY_STATUS[0] to be '1'
|
||||
*/
|
||||
#define MSM_UFS_PHY_QUIRK_CFG_RESTORE (1 << 0)
|
||||
|
||||
/*
|
||||
* If UFS PHY power down is deasserted and power is restored to analog
|
||||
* circuits, the rx_sigdet can glitch. If the glitch is wide enough,
|
||||
* it can trigger the digital logic to think it saw a DIF-N and cause
|
||||
* it to exit Hibern8. Disabling the rx_sigdet during power-up masks
|
||||
* the glitch.
|
||||
*/
|
||||
#define MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE (1 << 1)
|
||||
|
||||
char name[UFS_MSM_PHY_NAME_LEN];
|
||||
struct ufs_msm_phy_calibration *cached_regs;
|
||||
int cached_regs_table_size;
|
||||
bool is_powered_on;
|
||||
struct ufs_msm_phy_specific_ops *phy_spec_ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ufs_msm_phy_specific_ops - set of pointers to functions which have a
|
||||
* specific implementation per phy. Each UFS phy, should implement
|
||||
* those functions according to its spec and requirements
|
||||
* @calibrate_phy: pointer to a function that calibrate the phy
|
||||
* @start_serdes: pointer to a function that starts the serdes
|
||||
* @save_configuration: pointer to a function that saves phy
|
||||
* configuration
|
||||
* @is_physical_coding_sublayer_ready: pointer to a function that
|
||||
* checks pcs readiness
|
||||
* @set_tx_lane_enable: pointer to a function that enable tx lanes
|
||||
* @power_control: pointer to a function that controls analog rail of phy
|
||||
* and writes to QSERDES_RX_SIGDET_CNTRL attribute
|
||||
*/
|
||||
struct ufs_msm_phy_specific_ops {
|
||||
void (*calibrate_phy) (struct ufs_msm_phy *phy);
|
||||
void (*start_serdes) (struct ufs_msm_phy *phy);
|
||||
void (*save_configuration)(struct ufs_msm_phy *phy);
|
||||
int (*is_physical_coding_sublayer_ready) (struct ufs_msm_phy *phy);
|
||||
void (*set_tx_lane_enable) (struct ufs_msm_phy *phy, u32 val);
|
||||
void (*power_control) (struct ufs_msm_phy *phy, bool val);
|
||||
};
|
||||
|
||||
int ufs_msm_phy_init_vreg(struct phy *phy,
|
||||
struct ufs_msm_phy_vreg *vreg, const char *name);
|
||||
int ufs_msm_phy_cfg_vreg(struct phy *phy,
|
||||
struct ufs_msm_phy_vreg *vreg, bool on);
|
||||
int ufs_msm_phy_enable_vreg(struct phy *phy,
|
||||
struct ufs_msm_phy_vreg *vreg);
|
||||
int ufs_msm_phy_disable_vreg(struct phy *phy,
|
||||
struct ufs_msm_phy_vreg *vreg);
|
||||
int ufs_msm_phy_enable_ref_clk(struct phy *phy);
|
||||
void ufs_msm_phy_disable_ref_clk(struct phy *phy);
|
||||
int ufs_msm_phy_enable_iface_clk(struct phy *phy);
|
||||
void ufs_msm_phy_disable_iface_clk(struct phy *phy);
|
||||
void ufs_msm_phy_restore_swi_regs(struct phy *phy);
|
||||
int ufs_msm_phy_link_startup_post_change(struct phy *phy,
|
||||
struct ufs_hba *hba);
|
||||
int ufs_msm_phy_base_init(struct platform_device *pdev,
|
||||
struct ufs_msm_phy *ufs_msm_phy_ops);
|
||||
int ufs_msm_phy_is_cfg_restore_quirk_enabled(struct phy *phy);
|
||||
struct ufs_msm_phy *get_ufs_msm_phy(struct phy *generic_phy);
|
||||
int ufs_msm_phy_start_serdes(struct phy *generic_phy);
|
||||
int ufs_msm_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes);
|
||||
int ufs_msm_phy_calibrate_phy(struct phy *generic_phy);
|
||||
int ufs_msm_phy_is_pcs_ready(struct phy *generic_phy);
|
||||
int ufs_msm_phy_save_configuration(struct phy *generic_phy);
|
||||
void ufs_msm_phy_save_controller_version(struct phy *generic_phy,
|
||||
u8 major, u16 minor, u16 step);
|
||||
int ufs_msm_phy_power_on(struct phy *generic_phy);
|
||||
int ufs_msm_phy_power_off(struct phy *generic_phy);
|
||||
int ufs_msm_phy_exit(struct phy *generic_phy);
|
||||
int ufs_msm_phy_init_clks(struct phy *generic_phy,
|
||||
struct ufs_msm_phy *phy_common);
|
||||
int ufs_msm_phy_init_vregulators(struct phy *generic_phy,
|
||||
struct ufs_msm_phy *phy_common);
|
||||
int ufs_msm_phy_remove(struct phy *generic_phy,
|
||||
struct ufs_msm_phy *ufs_msm_phy);
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,8 @@
|
|||
#ifndef UFS_MSM_H_
|
||||
#define UFS_MSM_H_
|
||||
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
#define MAX_U32 (~(u32)0)
|
||||
#define MPHY_TX_FSM_STATE 0x41
|
||||
#define TX_FSM_HIBERN8 0x1
|
||||
|
@ -21,6 +23,30 @@
|
|||
#define DEFAULT_CLK_RATE_HZ 1000000
|
||||
#define BUS_VECTOR_NAME_LEN 32
|
||||
|
||||
#define UFS_HW_VER_MAJOR_SHFT (28)
|
||||
#define UFS_HW_VER_MAJOR_MASK (0x000F << UFS_HW_VER_MAJOR_SHFT)
|
||||
#define UFS_HW_VER_MINOR_SHFT (16)
|
||||
#define UFS_HW_VER_MINOR_MASK (0x0FFF << UFS_HW_VER_MINOR_SHFT)
|
||||
#define UFS_HW_VER_STEP_SHFT (0)
|
||||
#define UFS_HW_VER_STEP_MASK (0xFFFF << UFS_HW_VER_STEP_SHFT)
|
||||
|
||||
/* vendor specific pre-defined parameters */
|
||||
#define SLOW 1
|
||||
#define FAST 2
|
||||
|
||||
#define UFS_MSM_LIMIT_NUM_LANES_RX 2
|
||||
#define UFS_MSM_LIMIT_NUM_LANES_TX 2
|
||||
#define UFS_MSM_LIMIT_HSGEAR_RX UFS_HS_G2
|
||||
#define UFS_MSM_LIMIT_HSGEAR_TX UFS_HS_G2
|
||||
#define UFS_MSM_LIMIT_PWMGEAR_RX UFS_PWM_G4
|
||||
#define UFS_MSM_LIMIT_PWMGEAR_TX UFS_PWM_G4
|
||||
#define UFS_MSM_LIMIT_RX_PWR_PWM SLOW_MODE
|
||||
#define UFS_MSM_LIMIT_TX_PWR_PWM SLOW_MODE
|
||||
#define UFS_MSM_LIMIT_RX_PWR_HS FAST_MODE
|
||||
#define UFS_MSM_LIMIT_TX_PWR_HS FAST_MODE
|
||||
#define UFS_MSM_LIMIT_HS_RATE PA_HS_MODE_A
|
||||
#define UFS_MSM_LIMIT_DESIRED_MODE FAST
|
||||
|
||||
/* MSM UFS host controller vendor specific registers */
|
||||
enum {
|
||||
REG_UFS_SYS1CLK_1US = 0xC0,
|
||||
|
@ -49,22 +75,12 @@ enum {
|
|||
|
||||
static LIST_HEAD(phy_list);
|
||||
|
||||
struct msm_ufs_phy_calibration {
|
||||
u32 reg_offset;
|
||||
u32 cfg_value;
|
||||
};
|
||||
|
||||
struct msm_ufs_stored_attributes {
|
||||
u32 att;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
enum msm_ufs_phy_init_type {
|
||||
enum ufs_msm_phy_init_type {
|
||||
UFS_PHY_INIT_FULL,
|
||||
UFS_PHY_INIT_CFG_RESTORE,
|
||||
};
|
||||
|
||||
struct msm_ufs_phy_vreg {
|
||||
struct ufs_msm_phy_vreg {
|
||||
const char *name;
|
||||
struct regulator *reg;
|
||||
int max_uA;
|
||||
|
@ -73,63 +89,32 @@ struct msm_ufs_phy_vreg {
|
|||
bool enabled;
|
||||
};
|
||||
|
||||
struct msm_ufs_phy {
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
void __iomem *mmio;
|
||||
struct clk *tx_iface_clk;
|
||||
struct clk *rx_iface_clk;
|
||||
bool is_iface_clk_enabled;
|
||||
struct clk *ref_clk_src;
|
||||
struct clk *ref_clk_parent;
|
||||
struct clk *ref_clk;
|
||||
bool is_ref_clk_enabled;
|
||||
struct msm_ufs_phy_vreg vdda_pll;
|
||||
struct msm_ufs_phy_vreg vdda_phy;
|
||||
unsigned int quirks;
|
||||
/*
|
||||
* As part of UFS power management, UFS link would be put in hibernate
|
||||
* and UFS device would be put in SLEEP mode as part of runtime/system
|
||||
* suspend callback. But when system goes into suspend with VDD
|
||||
* minimization, UFS PHY states are being reset which means UFS link
|
||||
* hibernate exit command on system resume would fail.
|
||||
* If this quirk is enabled then above issue is workaround by saving
|
||||
* the UFS PHY state information before system goes into suspend and
|
||||
* restoring the saved state information during system resume but
|
||||
* before executing the hibern8 exit command.
|
||||
* Note that this quirk will help restoring the PHY state if even when
|
||||
* link in not kept in hibern8 during suspend.
|
||||
*
|
||||
* Here is the list of steps to save/restore the configuration:
|
||||
* Before entering into system suspend:
|
||||
* 1. Read Critical PCS SWI Registers + less critical PHY CSR
|
||||
* 2. Read RMMI Attributes
|
||||
* Enter into system suspend
|
||||
* After exiting from system suspend:
|
||||
* 1. Set UFS_PHY_SOFT_RESET bit in UFS_CFG1 register of the UFS
|
||||
* Controller
|
||||
* 2. Write 0x01 to the UFS_PHY_POWER_DOWN_CONTROL register in the
|
||||
* UFS PHY
|
||||
* 3. Write back the values of the PHY SWI registers
|
||||
* 4. Clear UFS_PHY_SOFT_RESET bit in UFS_CFG1 register of the UFS
|
||||
* Controller
|
||||
* 5. Write 0x01 to the UFS_PHY_PHY_START in the UFS PHY. This will
|
||||
* start the PLL calibration and bring-up of the PHY.
|
||||
* 6. Write back the values to the PHY RMMI Attributes
|
||||
* 7. Wait for UFS_PHY_PCS_READY_STATUS[0] to be '1'
|
||||
*/
|
||||
#define MSM_UFS_PHY_QUIRK_CFG_RESTORE (1 << 0)
|
||||
/*
|
||||
* If UFS PHY power down is deasserted and power is restored to analog
|
||||
* circuits, the rx_sigdet can glitch. If the glitch is wide enough,
|
||||
* it can trigger the digital logic to think it saw a DIF-N and cause
|
||||
* it to exit Hibern8. Disabling the rx_sigdet during power-up masks
|
||||
* the glitch.
|
||||
*/
|
||||
#define MSM_UFS_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE (1 << 1)
|
||||
static inline void
|
||||
ufs_msm_get_controller_revision(struct ufs_hba *hba,
|
||||
u8 *major, u16 *minor, u16 *step)
|
||||
{
|
||||
u32 ver = ufshcd_readl(hba, REG_UFS_HW_VERSION);
|
||||
|
||||
*major = (ver & UFS_HW_VER_MAJOR_MASK) >> UFS_HW_VER_MAJOR_SHFT;
|
||||
*minor = (ver & UFS_HW_VER_MINOR_MASK) >> UFS_HW_VER_MINOR_SHFT;
|
||||
*step = (ver & UFS_HW_VER_STEP_MASK) >> UFS_HW_VER_STEP_SHFT;
|
||||
};
|
||||
|
||||
struct msm_ufs_bus_vote {
|
||||
static inline void ufs_msm_assert_reset(struct ufs_hba *hba)
|
||||
{
|
||||
ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET,
|
||||
1 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1);
|
||||
mb();
|
||||
}
|
||||
|
||||
static inline void ufs_msm_deassert_reset(struct ufs_hba *hba)
|
||||
{
|
||||
ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET,
|
||||
0 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1);
|
||||
mb();
|
||||
}
|
||||
|
||||
struct ufs_msm_bus_vote {
|
||||
uint32_t client_handle;
|
||||
uint32_t curr_vote;
|
||||
int min_bw_vote;
|
||||
|
@ -139,10 +124,10 @@ struct msm_ufs_bus_vote {
|
|||
struct device_attribute max_bus_bw;
|
||||
};
|
||||
|
||||
struct msm_ufs_host {
|
||||
struct msm_ufs_phy *phy;
|
||||
struct ufs_msm_host {
|
||||
struct phy *generic_phy;
|
||||
struct ufs_hba *hba;
|
||||
struct msm_ufs_bus_vote bus_vote;
|
||||
struct ufs_msm_bus_vote bus_vote;
|
||||
struct ufs_pa_layer_attr dev_req_params;
|
||||
struct clk *rx_l0_sync_clk;
|
||||
struct clk *tx_l0_sync_clk;
|
||||
|
@ -151,259 +136,9 @@ struct msm_ufs_host {
|
|||
bool is_lane_clks_enabled;
|
||||
};
|
||||
|
||||
static int msm_ufs_update_bus_bw_vote(struct msm_ufs_host *host);
|
||||
|
||||
/* MSM UFS PHY control registers */
|
||||
|
||||
#define COM_OFF(x) (0x000 + x)
|
||||
#define PHY_OFF(x) (0x700 + x)
|
||||
#define TX_OFF(n, x) (0x100 + (0x400 * n) + x)
|
||||
#define RX_OFF(n, x) (0x200 + (0x400 * n) + x)
|
||||
|
||||
/* UFS PHY PLL block registers */
|
||||
#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x00)
|
||||
#define QSERDES_COM_PLL_VCOTAIL_EN COM_OFF(0x04)
|
||||
#define QSERDES_COM_CMN_MODE COM_OFF(0x08)
|
||||
#define QSERDES_COM_IE_TRIM COM_OFF(0x0C)
|
||||
#define QSERDES_COM_IP_TRIM COM_OFF(0x10)
|
||||
#define QSERDES_COM_PLL_CNTRL COM_OFF(0x14)
|
||||
#define QSERDES_COM_PLL_IP_SETI COM_OFF(0x18)
|
||||
#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL COM_OFF(0x1C)
|
||||
#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x20)
|
||||
#define QSERDES_COM_PLL_CP_SETI COM_OFF(0x24)
|
||||
#define QSERDES_COM_PLL_IP_SETP COM_OFF(0x28)
|
||||
#define QSERDES_COM_PLL_CP_SETP COM_OFF(0x2C)
|
||||
#define QSERDES_COM_ATB_SEL1 COM_OFF(0x30)
|
||||
#define QSERDES_COM_ATB_SEL2 COM_OFF(0x34)
|
||||
#define QSERDES_COM_SYSCLK_EN_SEL COM_OFF(0x38)
|
||||
#define QSERDES_COM_RES_CODE_TXBAND COM_OFF(0x3C)
|
||||
#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0x40)
|
||||
#define QSERDES_COM_PLLLOCK_CMP1 COM_OFF(0x44)
|
||||
#define QSERDES_COM_PLLLOCK_CMP2 COM_OFF(0x48)
|
||||
#define QSERDES_COM_PLLLOCK_CMP3 COM_OFF(0x4C)
|
||||
#define QSERDES_COM_PLLLOCK_CMP_EN COM_OFF(0x50)
|
||||
#define QSERDES_COM_RES_TRIM_OFFSET COM_OFF(0x54)
|
||||
#define QSERDES_COM_BGTC COM_OFF(0x58)
|
||||
#define QSERDES_COM_PLL_TEST_UPDN_RESTRIMSTEP COM_OFF(0x5C)
|
||||
#define QSERDES_COM_PLL_VCO_TUNE COM_OFF(0x60)
|
||||
#define QSERDES_COM_DEC_START1 COM_OFF(0x64)
|
||||
#define QSERDES_COM_PLL_AMP_OS COM_OFF(0x68)
|
||||
#define QSERDES_COM_SSC_EN_CENTER COM_OFF(0x6C)
|
||||
#define QSERDES_COM_SSC_ADJ_PER1 COM_OFF(0x70)
|
||||
#define QSERDES_COM_SSC_ADJ_PER2 COM_OFF(0x74)
|
||||
#define QSERDES_COM_SSC_PER1 COM_OFF(0x78)
|
||||
#define QSERDES_COM_SSC_PER2 COM_OFF(0x7C)
|
||||
#define QSERDES_COM_SSC_STEP_SIZE1 COM_OFF(0x80)
|
||||
#define QSERDES_COM_SSC_STEP_SIZE2 COM_OFF(0x84)
|
||||
#define QSERDES_COM_RES_TRIM_SEARCH COM_OFF(0x88)
|
||||
#define QSERDES_COM_RES_TRIM_FREEZE COM_OFF(0x8C)
|
||||
#define QSERDES_COM_RES_TRIM_EN_VCOCALDONE COM_OFF(0x90)
|
||||
#define QSERDES_COM_FAUX_EN COM_OFF(0x94)
|
||||
#define QSERDES_COM_DIV_FRAC_START1 COM_OFF(0x98)
|
||||
#define QSERDES_COM_DIV_FRAC_START2 COM_OFF(0x9C)
|
||||
#define QSERDES_COM_DIV_FRAC_START3 COM_OFF(0xA0)
|
||||
#define QSERDES_COM_DEC_START2 COM_OFF(0xA4)
|
||||
#define QSERDES_COM_PLL_RXTXEPCLK_EN COM_OFF(0xA8)
|
||||
#define QSERDES_COM_PLL_CRCTRL COM_OFF(0xAC)
|
||||
#define QSERDES_COM_PLL_CLKEPDIV COM_OFF(0xB0)
|
||||
#define QSERDES_COM_PLL_FREQUPDATE COM_OFF(0xB4)
|
||||
#define QSERDES_COM_PLL_VCO_HIGH COM_OFF(0xB8)
|
||||
#define QSERDES_COM_RESET_SM COM_OFF(0xBC)
|
||||
|
||||
/* UFS PHY registers */
|
||||
#define UFS_PHY_PHY_START PHY_OFF(0x00)
|
||||
#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x04)
|
||||
#define UFS_PHY_PWM_G1_CLK_DIVIDER PHY_OFF(0x08)
|
||||
#define UFS_PHY_PWM_G2_CLK_DIVIDER PHY_OFF(0x0C)
|
||||
#define UFS_PHY_PWM_G3_CLK_DIVIDER PHY_OFF(0x10)
|
||||
#define UFS_PHY_PWM_G4_CLK_DIVIDER PHY_OFF(0x14)
|
||||
#define UFS_PHY_TIMER_100US_SYSCLK_STEPS_MSB PHY_OFF(0x18)
|
||||
#define UFS_PHY_TIMER_100US_SYSCLK_STEPS_LSB PHY_OFF(0x1C)
|
||||
#define UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB PHY_OFF(0x20)
|
||||
#define UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB PHY_OFF(0x24)
|
||||
#define UFS_PHY_LINE_RESET_TIME PHY_OFF(0x28)
|
||||
#define UFS_PHY_LINE_RESET_GRANULARITY PHY_OFF(0x2C)
|
||||
#define UFS_PHY_CONTROLSYM_ONE_HOT_DISABLE PHY_OFF(0x30)
|
||||
#define UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER PHY_OFF(0x34)
|
||||
#define UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER PHY_OFF(0x38)
|
||||
#define UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER PHY_OFF(0x3C)
|
||||
#define UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER PHY_OFF(0x40)
|
||||
#define UFS_PHY_TX_LANE_ENABLE PHY_OFF(0x44)
|
||||
#define UFS_PHY_TSYNC_RSYNC_CNTL PHY_OFF(0x48)
|
||||
#define UFS_PHY_RETIME_BUFFER_EN PHY_OFF(0x4C)
|
||||
#define UFS_PHY_PLL_CNTL PHY_OFF(0x50)
|
||||
#define UFS_PHY_TX_LARGE_AMP_DRV_LVL PHY_OFF(0x54)
|
||||
#define UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL PHY_OFF(0x58)
|
||||
#define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x5C)
|
||||
#define UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL PHY_OFF(0x60)
|
||||
#define UFS_PHY_CFG_CHANGE_CNT_VAL PHY_OFF(0x64)
|
||||
#define UFS_PHY_OMC_STATUS_RDVAL PHY_OFF(0x68)
|
||||
#define UFS_PHY_RX_SYNC_WAIT_TIME PHY_OFF(0x6C)
|
||||
#define UFS_PHY_L0_BIST_CTRL PHY_OFF(0x70)
|
||||
#define UFS_PHY_L1_BIST_CTRL PHY_OFF(0x74)
|
||||
#define UFS_PHY_BIST_PRBS_POLY0 PHY_OFF(0x78)
|
||||
#define UFS_PHY_BIST_PRBS_POLY1 PHY_OFF(0x7C)
|
||||
#define UFS_PHY_BIST_PRBS_SEED0 PHY_OFF(0x80)
|
||||
#define UFS_PHY_BIST_PRBS_SEED1 PHY_OFF(0x84)
|
||||
#define UFS_PHY_BIST_FIXED_PAT_CTRL PHY_OFF(0x88)
|
||||
#define UFS_PHY_BIST_FIXED_PAT0_DATA PHY_OFF(0x8C)
|
||||
#define UFS_PHY_BIST_FIXED_PAT1_DATA PHY_OFF(0x90)
|
||||
#define UFS_PHY_BIST_FIXED_PAT2_DATA PHY_OFF(0x94)
|
||||
#define UFS_PHY_BIST_FIXED_PAT3_DATA PHY_OFF(0x98)
|
||||
#define UFS_PHY_TX_HSGEAR_CAPABILITY PHY_OFF(0x9C)
|
||||
#define UFS_PHY_TX_PWMGEAR_CAPABILITY PHY_OFF(0xA0)
|
||||
#define UFS_PHY_TX_AMPLITUDE_CAPABILITY PHY_OFF(0xA4)
|
||||
#define UFS_PHY_TX_EXTERNALSYNC_CAPABILITY PHY_OFF(0xA8)
|
||||
#define UFS_PHY_TX_HS_UNTERMINATED_LINE_DRIVE_CAPABILITY PHY_OFF(0xAC)
|
||||
#define UFS_PHY_TX_LS_TERMINATED_LINE_DRIVE_CAPABILITY PHY_OFF(0xB0)
|
||||
#define UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB4)
|
||||
#define UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB8)
|
||||
#define UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xBC)
|
||||
#define UFS_PHY_TX_REF_CLOCK_SHARED_CAPABILITY PHY_OFF(0xC0)
|
||||
#define UFS_PHY_TX_PHY_MAJORMINOR_RELEASE_CAPABILITY PHY_OFF(0xC4)
|
||||
#define UFS_PHY_TX_PHY_EDITORIAL_RELEASE_CAPABILITY PHY_OFF(0xC8)
|
||||
#define UFS_PHY_TX_HIBERN8TIME_CAPABILITY PHY_OFF(0xCC)
|
||||
#define UFS_PHY_RX_HSGEAR_CAPABILITY PHY_OFF(0xD0)
|
||||
#define UFS_PHY_RX_PWMGEAR_CAPABILITY PHY_OFF(0xD4)
|
||||
#define UFS_PHY_RX_HS_UNTERMINATED_CAPABILITY PHY_OFF(0xD8)
|
||||
#define UFS_PHY_RX_LS_TERMINATED_CAPABILITY PHY_OFF(0xDC)
|
||||
#define UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE0)
|
||||
#define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE4)
|
||||
#define UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xE8)
|
||||
#define UFS_PHY_RX_REF_CLOCK_SHARED_CAPABILITY PHY_OFF(0xEC)
|
||||
#define UFS_PHY_RX_HS_G1_SYNC_LENGTH_CAPABILITY PHY_OFF(0xF0)
|
||||
#define UFS_PHY_RX_HS_G1_PREPARE_LENGTH_CAPABILITY PHY_OFF(0xF4)
|
||||
#define UFS_PHY_RX_LS_PREPARE_LENGTH_CAPABILITY PHY_OFF(0xF8)
|
||||
#define UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY PHY_OFF(0xFC)
|
||||
#define UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY PHY_OFF(0x100)
|
||||
#define UFS_PHY_RX_PHY_MAJORMINOR_RELEASE_CAPABILITY PHY_OFF(0x104)
|
||||
#define UFS_PHY_RX_PHY_EDITORIAL_RELEASE_CAPABILITY PHY_OFF(0x108)
|
||||
#define UFS_PHY_RX_HIBERN8TIME_CAPABILITY PHY_OFF(0x10C)
|
||||
#define UFS_PHY_RX_HS_G2_SYNC_LENGTH_CAPABILITY PHY_OFF(0x110)
|
||||
#define UFS_PHY_RX_HS_G3_SYNC_LENGTH_CAPABILITY PHY_OFF(0x114)
|
||||
#define UFS_PHY_RX_HS_G2_PREPARE_LENGTH_CAPABILITY PHY_OFF(0x118)
|
||||
#define UFS_PHY_RX_HS_G3_PREPARE_LENGTH_CAPABILITY PHY_OFF(0x11C)
|
||||
#define UFS_PHY_DEBUG_BUS_SEL PHY_OFF(0x120)
|
||||
#define UFS_PHY_DEBUG_BUS_0_STATUS_CHK PHY_OFF(0x124)
|
||||
#define UFS_PHY_DEBUG_BUS_1_STATUS_CHK PHY_OFF(0x128)
|
||||
#define UFS_PHY_DEBUG_BUS_2_STATUS_CHK PHY_OFF(0x12C)
|
||||
#define UFS_PHY_DEBUG_BUS_3_STATUS_CHK PHY_OFF(0x130)
|
||||
#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x134)
|
||||
#define UFS_PHY_L0_BIST_CHK_ERR_CNT_L_STATUS PHY_OFF(0x138)
|
||||
#define UFS_PHY_L0_BIST_CHK_ERR_CNT_H_STATUS PHY_OFF(0x13C)
|
||||
#define UFS_PHY_L1_BIST_CHK_ERR_CNT_L_STATUS PHY_OFF(0x140)
|
||||
#define UFS_PHY_L1_BIST_CHK_ERR_CNT_H_STATUS PHY_OFF(0x144)
|
||||
#define UFS_PHY_L0_BIST_CHK_STATUS PHY_OFF(0x148)
|
||||
#define UFS_PHY_L1_BIST_CHK_STATUS PHY_OFF(0x14C)
|
||||
#define UFS_PHY_DEBUG_BUS_0_STATUS PHY_OFF(0x150)
|
||||
#define UFS_PHY_DEBUG_BUS_1_STATUS PHY_OFF(0x154)
|
||||
#define UFS_PHY_DEBUG_BUS_2_STATUS PHY_OFF(0x158)
|
||||
#define UFS_PHY_DEBUG_BUS_3_STATUS PHY_OFF(0x15C)
|
||||
#define UFS_PHY_RMMI_ATTR_CTRL PHY_OFF(0x16C)
|
||||
#define UFS_PHY_RMMI_RX_CFGUPDT_L1 (1 << 7)
|
||||
#define UFS_PHY_RMMI_TX_CFGUPDT_L1 (1 << 6)
|
||||
#define UFS_PHY_RMMI_CFGWR_L1 (1 << 5)
|
||||
#define UFS_PHY_RMMI_CFGRD_L1 (1 << 4)
|
||||
#define UFS_PHY_RMMI_RX_CFGUPDT_L0 (1 << 3)
|
||||
#define UFS_PHY_RMMI_TX_CFGUPDT_L0 (1 << 2)
|
||||
#define UFS_PHY_RMMI_CFGWR_L0 (1 << 1)
|
||||
#define UFS_PHY_RMMI_CFGRD_L0 (1 << 0)
|
||||
#define UFS_PHY_RMMI_ATTRID PHY_OFF(0x170)
|
||||
#define UFS_PHY_RMMI_ATTRWRVAL PHY_OFF(0x174)
|
||||
#define UFS_PHY_RMMI_ATTRRDVAL_L0_STATUS PHY_OFF(0x178)
|
||||
#define UFS_PHY_RMMI_ATTRRDVAL_L1_STATUS PHY_OFF(0x17C)
|
||||
|
||||
/* TX LANE n (0, 1) registers */
|
||||
#define QSERDES_TX_BIST_MODE_LANENO(n) TX_OFF(n, 0x00)
|
||||
#define QSERDES_TX_CLKBUF_ENABLE(n) TX_OFF(n, 0x04)
|
||||
#define QSERDES_TX_TX_EMP_POST1_LVL(n) TX_OFF(n, 0x08)
|
||||
#define QSERDES_TX_TX_DRV_LVL(n) TX_OFF(n, 0x0C)
|
||||
#define QSERDES_TX_RESET_TSYNC_EN(n) TX_OFF(n, 0x10)
|
||||
#define QSERDES_TX_LPB_EN(n) TX_OFF(n, 0x14)
|
||||
#define QSERDES_TX_RES_CODE(n) TX_OFF(n, 0x18)
|
||||
#define QSERDES_TX_PERL_LENGTH1(n) TX_OFF(n, 0x1C)
|
||||
#define QSERDES_TX_PERL_LENGTH2(n) TX_OFF(n, 0x20)
|
||||
#define QSERDES_TX_SERDES_BYP_EN_OUT(n) TX_OFF(n, 0x24)
|
||||
#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_EN(n) TX_OFF(n, 0x28)
|
||||
#define QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN(n) TX_OFF(n, 0x2C)
|
||||
#define QSERDES_TX_BIST_PATTERN1(n) TX_OFF(n, 0x30)
|
||||
#define QSERDES_TX_BIST_PATTERN2(n) TX_OFF(n, 0x34)
|
||||
#define QSERDES_TX_BIST_PATTERN3(n) TX_OFF(n, 0x38)
|
||||
#define QSERDES_TX_BIST_PATTERN4(n) TX_OFF(n, 0x3C)
|
||||
#define QSERDES_TX_BIST_PATTERN5(n) TX_OFF(n, 0x40)
|
||||
#define QSERDES_TX_BIST_PATTERN6(n) TX_OFF(n, 0x44)
|
||||
#define QSERDES_TX_BIST_PATTERN7(n) TX_OFF(n, 0x48)
|
||||
#define QSERDES_TX_BIST_PATTERN8(n) TX_OFF(n, 0x4C)
|
||||
#define QSERDES_TX_LANE_MODE(n) TX_OFF(n, 0x50)
|
||||
#define QSERDES_TX_ATB_SEL(n) TX_OFF(n, 0x54)
|
||||
#define QSERDES_TX_REC_DETECT_LVL(n) TX_OFF(n, 0x58)
|
||||
#define QSERDES_TX_PRBS_SEED1(n) TX_OFF(n, 0x5C)
|
||||
#define QSERDES_TX_PRBS_SEED2(n) TX_OFF(n, 0x60)
|
||||
#define QSERDES_TX_PRBS_SEED3(n) TX_OFF(n, 0x64)
|
||||
#define QSERDES_TX_PRBS_SEED4(n) TX_OFF(n, 0x68)
|
||||
#define QSERDES_TX_RESET_GEN(n) TX_OFF(n, 0x6C)
|
||||
#define QSERDES_TX_TRAN_DRVR_EMP_EN(n) TX_OFF(n, 0x70)
|
||||
#define QSERDES_TX_TX_INTERFACE_MODE(n) TX_OFF(n, 0x74)
|
||||
#define QSERDES_TX_BIST_STATUS(n) TX_OFF(n, 0x78)
|
||||
#define QSERDES_TX_BIST_ERROR_COUNT1(n) TX_OFF(n, 0x7C)
|
||||
#define QSERDES_TX_BIST_ERROR_COUNT2(n) TX_OFF(n, 0x80)
|
||||
|
||||
/* RX LANE n (0, 1) registers */
|
||||
#define QSERDES_RX_CDR_CONTROL(n) RX_OFF(n, 0x00)
|
||||
#define QSERDES_RX_AUX_CONTROL(n) RX_OFF(n, 0x04)
|
||||
#define QSERDES_RX_AUX_DATA_TCODE(n) RX_OFF(n, 0x08)
|
||||
#define QSERDES_RX_RCLK_AUXDATA_SEL(n) RX_OFF(n, 0x0C)
|
||||
#define QSERDES_RX_EQ_CONTROL(n) RX_OFF(n, 0x10)
|
||||
#define QSERDES_RX_RX_EQ_GAIN2(n) RX_OFF(n, 0x14)
|
||||
#define QSERDES_RX_AC_JTAG_INIT(n) RX_OFF(n, 0x18)
|
||||
#define QSERDES_RX_AC_JTAG_LVL_EN(n) RX_OFF(n, 0x1C)
|
||||
#define QSERDES_RX_AC_JTAG_MODE(n) RX_OFF(n, 0x20)
|
||||
#define QSERDES_RX_AC_JTAG_RESET(n) RX_OFF(n, 0x24)
|
||||
#define QSERDES_RX_RX_IQ_RXDET_EN(n) RX_OFF(n, 0x28)
|
||||
#define QSERDES_RX_RX_TERM_HIGHZ_CM_AC_COUPLE(n) RX_OFF(n, 0x2C)
|
||||
#define QSERDES_RX_RX_EQ_GAIN1(n) RX_OFF(n, 0x30)
|
||||
#define QSERDES_RX_SIGDET_CNTRL(n) RX_OFF(n, 0x34)
|
||||
#define QSERDES_RX_RX_BAND(n) RX_OFF(n, 0x38)
|
||||
#define QSERDES_RX_CDR_FREEZE_UP_DN(n) RX_OFF(n, 0x3C)
|
||||
#define QSERDES_RX_RX_INTERFACE_MODE(n) RX_OFF(n, 0x40)
|
||||
#define QSERDES_RX_JITTER_GEN_MODE(n) RX_OFF(n, 0x44)
|
||||
#define QSERDES_RX_BUJ_AMP(n) RX_OFF(n, 0x48)
|
||||
#define QSERDES_RX_SJ_AMP1(n) RX_OFF(n, 0x4C)
|
||||
#define QSERDES_RX_SJ_AMP2(n) RX_OFF(n, 0x50)
|
||||
#define QSERDES_RX_SJ_PER1(n) RX_OFF(n, 0x54)
|
||||
#define QSERDES_RX_SJ_PER2(n) RX_OFF(n, 0x58)
|
||||
#define QSERDES_RX_BUJ_STEP_FREQ1(n) RX_OFF(n, 0x5C)
|
||||
#define QSERDES_RX_BUJ_STEP_FREQ2(n) RX_OFF(n, 0x60)
|
||||
#define QSERDES_RX_PPM_OFFSET1(n) RX_OFF(n, 0x64)
|
||||
#define QSERDES_RX_PPM_OFFSET2(n) RX_OFF(n, 0x68)
|
||||
#define QSERDES_RX_SIGN_PPM_PERIOD1(n) RX_OFF(n, 0x6C)
|
||||
#define QSERDES_RX_SIGN_PPM_PERIOD2(n) RX_OFF(n, 0x70)
|
||||
#define QSERDES_RX_SSC_CTRL(n) RX_OFF(n, 0x74)
|
||||
#define QSERDES_RX_SSC_COUNT1(n) RX_OFF(n, 0x78)
|
||||
#define QSERDES_RX_SSC_COUNT2(n) RX_OFF(n, 0x7C)
|
||||
#define QSERDES_RX_PWM_CNTRL1(n) RX_OFF(n, 0x80)
|
||||
#define QSERDES_RX_PWM_CNTRL2(n) RX_OFF(n, 0x84)
|
||||
#define QSERDES_RX_PWM_NDIV(n) RX_OFF(n, 0x88)
|
||||
#define QSERDES_RX_SIGDET_CNTRL2(n) RX_OFF(n, 0x8C)
|
||||
#define QSERDES_RX_UFS_CNTRL(n) RX_OFF(n, 0x90)
|
||||
#define QSERDES_RX_CDR_CONTROL3(n) RX_OFF(n, 0x94)
|
||||
#define QSERDES_RX_CDR_CONTROL_HALF(n) RX_OFF(n, 0x98)
|
||||
#define QSERDES_RX_CDR_CONTROL_QUARTER(n) RX_OFF(n, 0x9C)
|
||||
#define QSERDES_RX_CDR_CONTROL_EIGHTH(n) RX_OFF(n, 0xA0)
|
||||
#define QSERDES_RX_UCDR_FO_GAIN(n) RX_OFF(n, 0xA4)
|
||||
#define QSERDES_RX_UCDR_SO_GAIN(n) RX_OFF(n, 0xA8)
|
||||
#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE(n) RX_OFF(n, 0xAC)
|
||||
#define QSERDES_RX_UCDR_FO_TO_SO_DELAY(n) RX_OFF(n, 0xB0)
|
||||
#define QSERDES_RX_PI_CTRL1(n) RX_OFF(n, 0xB4)
|
||||
#define QSERDES_RX_PI_CTRL2(n) RX_OFF(n, 0xB8)
|
||||
#define QSERDES_RX_PI_QUAD(n) RX_OFF(n, 0xBC)
|
||||
#define QSERDES_RX_IDATA1(n) RX_OFF(n, 0xC0)
|
||||
#define QSERDES_RX_IDATA2(n) RX_OFF(n, 0xC4)
|
||||
#define QSERDES_RX_AUX_DATA1(n) RX_OFF(n, 0xC8)
|
||||
#define QSERDES_RX_AUX_DATA2(n) RX_OFF(n, 0xCC)
|
||||
#define QSERDES_RX_AC_JTAG_OUTP(n) RX_OFF(n, 0xD0)
|
||||
#define QSERDES_RX_AC_JTAG_OUTN(n) RX_OFF(n, 0xD4)
|
||||
#define QSERDES_RX_RX_SIGDET_PWMDECSTATUS(n) RX_OFF(n, 0xD8)
|
||||
#define ufs_msm_is_link_off(hba) ufshcd_is_link_off(hba)
|
||||
#define ufs_msm_is_link_active(hba) ufshcd_is_link_active(hba)
|
||||
#define ufs_msm_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
|
||||
|
||||
enum {
|
||||
MASK_SERDES_START = 0x1,
|
||||
|
|
Loading…
Add table
Reference in a new issue