phy: relocate and rename phy ufs files

This change contains:
1. Relocating the phy ufs files to reside under the phy driver since
this is the location of any file that implements the APIs presented in
the generic phy framework
2. Renaming ufs-msm-phy*.* files to be phy-qcom-ufs*.* files.
Since UFS is not used strictly in a specific set of targets but rather
its code is applicable to MSM, APQ, IPQ etc, any mentioning of "msm" in
the file name should be changed to "qcom".
Also, prefix of "phy-" is the naming convention of platform driver files
that reside in the phy driver.
3. As a result of the relocation of files into the phy driver,
a new path is created (include/linux/scsi/ufs) and there we expose ufs
header files that are being used also from the drivers/scsi/ufs
and from drivers/phy as well.

Change-Id: Ie5cb47718911ff711d9401a389f56fa508fcddf3
Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
[gbroner@codeaurora.org: fix merge conflicts]
Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
[venkatg@codeaurora.org: resolved merge conflicts by keeping
upstream version]
Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
This commit is contained in:
Yaniv Gardi 2014-09-03 15:31:52 +03:00 committed by David Keitel
parent 948f549fbf
commit ad03d1f91b
26 changed files with 2498 additions and 2618 deletions

View file

@ -36,6 +36,9 @@ obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_SCSI_UFS_QCOM) += phy-qcom-ufs.o
obj-$(CONFIG_SCSI_UFS_QCOM) += phy-qcom-ufs-qmp-28nm.o
obj-$(CONFIG_SCSI_UFS_QCOM) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
* 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
@ -17,40 +17,26 @@
#define UFS_PHY_NAME "ufs_phy_qmp_20nm"
static
int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
bool is_rate_B)
int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy)
{
struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
int tbl_size_A, tbl_size_B;
u8 major = ufs_qcom_phy->host_ctrl_rev_major;
u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
u16 step = ufs_qcom_phy->host_ctrl_rev_step;
int rate = UFS_QCOM_LIMIT_HS_RATE;
int err;
if ((major == 0x1) && (minor == 0x002) && (step == 0x0000)) {
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0);
tbl_A = phy_cal_table_rate_A_1_2_0;
} else if ((major == 0x1) && (minor == 0x003) && (step == 0x0000)) {
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0);
tbl_A = phy_cal_table_rate_A_1_3_0;
} else {
dev_err(ufs_qcom_phy->dev, "%s: Unknown UFS-PHY version, no calibration values\n",
__func__);
err = -ENODEV;
goto out;
}
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A);
tbl_A = phy_cal_table_rate_A;
tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
tbl_B = phy_cal_table_rate_B;
err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A,
tbl_B, tbl_size_B, is_rate_B);
tbl_B, tbl_size_B, rate);
if (err)
dev_err(ufs_qcom_phy->dev, "%s: ufs_qcom_phy_calibrate() failed %d\n",
__func__, err);
out:
return err;
}
@ -171,7 +157,7 @@ static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
return err;
}
static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
.init = ufs_qcom_phy_qmp_20nm_init,
.exit = ufs_qcom_phy_exit,
.power_on = ufs_qcom_phy_power_on,
@ -179,7 +165,7 @@ static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
.owner = THIS_MODULE,
};
static struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
.calibrate_phy = ufs_qcom_phy_qmp_20nm_phy_calibrate,
.start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes,
.is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready,

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
* Copyright (c) 2013-2015, 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
@ -12,42 +12,45 @@
*
*/
#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 "ufs-msm-phy.h"
#include "ufs-msm-phy-qmp-20nm.h"
#include "phy-qcom-ufs-qmp-20nm.h"
#define UFS_PHY_NAME "ufs_phy_qmp_20nm"
static
int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy)
int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
bool is_rate_B)
{
struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
int tbl_size_A, tbl_size_B;
int rate = UFS_QCOM_LIMIT_HS_RATE;
u8 major = ufs_qcom_phy->host_ctrl_rev_major;
u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
u16 step = ufs_qcom_phy->host_ctrl_rev_step;
int err;
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A);
tbl_A = phy_cal_table_rate_A;
if ((major == 0x1) && (minor == 0x002) && (step == 0x0000)) {
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0);
tbl_A = phy_cal_table_rate_A_1_2_0;
} else if ((major == 0x1) && (minor == 0x003) && (step == 0x0000)) {
tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0);
tbl_A = phy_cal_table_rate_A_1_3_0;
} else {
dev_err(ufs_qcom_phy->dev, "%s: Unknown UFS-PHY version, no calibration values\n",
__func__);
err = -ENODEV;
goto out;
}
tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
tbl_B = phy_cal_table_rate_B;
err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A,
tbl_B, tbl_size_B, rate);
tbl_B, tbl_size_B, is_rate_B);
if (err)
dev_err(ufs_qcom_phy->dev, "%s: ufs_qcom_phy_calibrate() failed %d\n",
__func__, err);
out:
return err;
}
@ -168,7 +171,7 @@ static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
return err;
}
struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
.init = ufs_qcom_phy_qmp_20nm_init,
.exit = ufs_qcom_phy_exit,
.power_on = ufs_qcom_phy_power_on,
@ -176,7 +179,7 @@ struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
.owner = THIS_MODULE,
};
struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
static struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
.calibrate_phy = ufs_qcom_phy_qmp_20nm_phy_calibrate,
.start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes,
.is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready,
@ -244,7 +247,6 @@ static struct platform_driver ufs_qcom_phy_qmp_20nm_driver = {
.driver = {
.of_match_table = ufs_qcom_phy_qmp_20nm_of_match,
.name = "ufs_qcom_phy_qmp_20nm",
.owner = THIS_MODULE,
},
};

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
* 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
@ -30,7 +30,6 @@
#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_BIAS_EN_CLKBUFLR_EN COM_OFF(0x30)
#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)
@ -44,8 +43,6 @@
#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_RES_CODE_UP_OFFSET COM_OFF(0xD8)
#define QSERDES_COM_RES_CODE_DN_OFFSET COM_OFF(0xDC)
#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)
@ -101,7 +98,6 @@
#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_RX_SIGDET_CTRL3 PHY_OFF(0x14c)
#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)
@ -131,9 +127,8 @@ struct ufs_qcom_phy_qmp_20nm {
struct ufs_qcom_phy common_cfg;
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_2_0[] = {
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = {
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08),
@ -176,28 +171,24 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_2_0[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3),
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_3_0[] = {
static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x98),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0x65),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x1e),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL2, 0x03),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12),
@ -212,24 +203,14 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_3_0[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x2b),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x38),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x3c),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_UP_OFFSET, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_DN_OFFSET, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x3f),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x1b),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x0f),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CNTRL, 0x40),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3),
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x98),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0x65),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x1e),
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
* Copyright (c) 2013-2015, 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
@ -15,7 +15,7 @@
#ifndef UFS_QCOM_PHY_QMP_20NM_H_
#define UFS_QCOM_PHY_QMP_20NM_H_
#include "ufs-msm-phy.h"
#include "phy-qcom-ufs-i.h"
/* QCOM UFS PHY control registers */
@ -30,6 +30,7 @@
#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_BIAS_EN_CLKBUFLR_EN COM_OFF(0x30)
#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)
@ -43,6 +44,8 @@
#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_RES_CODE_UP_OFFSET COM_OFF(0xD8)
#define QSERDES_COM_RES_CODE_DN_OFFSET COM_OFF(0xDC)
#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)
@ -98,6 +101,7 @@
#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_RX_SIGDET_CTRL3 PHY_OFF(0x14c)
#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)
@ -127,8 +131,9 @@ struct ufs_qcom_phy_qmp_20nm {
struct ufs_qcom_phy common_cfg;
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = {
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_2_0[] = {
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08),
@ -171,24 +176,28 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3),
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_3_0[] = {
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x98),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0x65),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x1e),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL2, 0x03),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12),
@ -203,14 +212,24 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x3f),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x1b),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x0f),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x2b),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x38),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x3c),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_UP_OFFSET, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_DN_OFFSET, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CNTRL, 0x40),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3),
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x98),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0x65),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x1e),
};
#endif

View file

@ -23,8 +23,8 @@
#include <linux/msm-bus.h>
#include <linux/phy/phy.h>
#include "ufs-msm-phy.h"
#include "ufs-msm-phy-qmp-28nm.h"
#include <linux/phy/phy-qcom-ufs.h>
#include "phy-qcom-ufs-qmp-28nm.h"
#define UFS_PHY_NAME "ufs_qcom_phy_qmp_28nm"

View file

@ -15,7 +15,7 @@
#ifndef UFS_QCOM_PHY_QMP_28NM_H_
#define UFS_QCOM_PHY_QMP_28NM_H_
#include "ufs-msm-phy.h"
#include <linux/phy/phy-qcom-ufs.h>
/* QCOM UFS PHY control registers */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
* 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
@ -33,7 +33,7 @@ int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
struct ufs_qcom_phy_calibration *tbl_A,
int tbl_size_A,
struct ufs_qcom_phy_calibration *tbl_B,
int tbl_size_B, bool is_rate_B)
int tbl_size_B, int rate)
{
int i;
int ret = 0;
@ -54,7 +54,7 @@ int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
* with registers of rate B table.
* table.
*/
if (is_rate_B) {
if (rate == PA_HS_MODE_B) {
if (!tbl_B) {
dev_err(ufs_qcom_phy->dev, "%s: tbl_B is NULL",
__func__);
@ -73,7 +73,6 @@ int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
out:
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate);
struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
struct ufs_qcom_phy *common_cfg,
@ -112,7 +111,6 @@ struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
out:
return generic_phy;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_generic_probe);
/*
* This assumes the embedded phy structure inside generic_phy is of type
@ -124,7 +122,6 @@ struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy)
{
return (struct ufs_qcom_phy *)phy_get_drvdata(generic_phy);
}
EXPORT_SYMBOL_GPL(get_ufs_qcom_phy);
static
int ufs_qcom_phy_base_init(struct platform_device *pdev,
@ -134,14 +131,21 @@ int ufs_qcom_phy_base_init(struct platform_device *pdev,
struct resource *res;
int err = 0;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem");
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((void const *)phy_common->mmio)) {
err = PTR_ERR((void const *)phy_common->mmio);
phy_common->mmio = NULL;
dev_err(dev, "%s: ioremap for phy_mem resource failed %d\n",
__func__, err);
return err;
goto out;
}
/* "dev_ref_clk_ctrl_mem" is optional resource */
@ -151,11 +155,12 @@ int ufs_qcom_phy_base_init(struct platform_device *pdev,
if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio))
phy_common->dev_ref_clk_ctrl_mmio = NULL;
return 0;
out:
return err;
}
static int __ufs_qcom_phy_clk_get(struct phy *phy,
const char *name, struct clk **clk_out, bool err_print)
int ufs_qcom_phy_clk_get(struct phy *phy,
const char *name, struct clk **clk_out)
{
struct clk *clk;
int err = 0;
@ -165,8 +170,7 @@ static int __ufs_qcom_phy_clk_get(struct phy *phy,
clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) {
err = PTR_ERR(clk);
if (err_print)
dev_err(dev, "failed to get %s err %d", name, err);
dev_err(dev, "failed to get %s err %d", name, err);
} else {
*clk_out = clk;
}
@ -202,12 +206,10 @@ ufs_qcom_phy_init_clks(struct phy *generic_phy,
if (err)
goto out;
/*
* "ref_clk_parent" is optional hence don't abort init if it's not
* found.
*/
__ufs_qcom_phy_clk_get(generic_phy, "ref_clk_parent",
&phy_common->ref_clk_parent, false);
err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk_parent",
&phy_common->ref_clk_parent);
if (err)
goto out;
err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk",
&phy_common->ref_clk);
@ -215,7 +217,6 @@ ufs_qcom_phy_init_clks(struct phy *generic_phy,
out:
return err;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_clks);
int
ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
@ -230,20 +231,12 @@ ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
err = ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vdda_phy,
"vdda-phy");
if (err)
goto out;
/* vddp-ref-clk-* properties are optional */
__ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vddp_ref_clk,
"vddp-ref-clk", true);
out:
return err;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_vregulators);
static int __ufs_qcom_phy_init_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional)
int ufs_qcom_phy_init_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg, const char *name)
{
int err = 0;
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy);
@ -260,9 +253,7 @@ static int __ufs_qcom_phy_init_vreg(struct phy *phy,
vreg->reg = devm_regulator_get(dev, name);
if (IS_ERR(vreg->reg)) {
err = PTR_ERR(vreg->reg);
vreg->reg = NULL;
if (!optional)
dev_err(dev, "failed to get %s, %d\n", name, err);
dev_err(dev, "failed to get %s, %d\n", name, err);
goto out;
}
@ -282,11 +273,6 @@ static int __ufs_qcom_phy_init_vreg(struct phy *phy,
}
err = 0;
}
snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name);
if (of_get_property(dev->of_node, prop_name, NULL))
vreg->is_always_on = true;
else
vreg->is_always_on = false;
}
if (!strcmp(name, "vdda-pll")) {
@ -295,9 +281,6 @@ static int __ufs_qcom_phy_init_vreg(struct phy *phy,
} else if (!strcmp(name, "vdda-phy")) {
vreg->max_uV = VDDA_PHY_MAX_UV;
vreg->min_uV = VDDA_PHY_MIN_UV;
} else if (!strcmp(name, "vddp-ref-clk")) {
vreg->max_uV = VDDP_REF_CLK_MAX_UV;
vreg->min_uV = VDDP_REF_CLK_MIN_UV;
}
out:
@ -401,17 +384,11 @@ int ufs_qcom_phy_enable_ref_clk(struct phy *generic_phy)
goto out;
}
/*
* "ref_clk_parent" is optional clock hence make sure that clk reference
* is available before trying to enable the clock.
*/
if (phy->ref_clk_parent) {
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_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);
@ -425,14 +402,12 @@ int ufs_qcom_phy_enable_ref_clk(struct phy *generic_phy)
goto out;
out_disable_parent:
if (phy->ref_clk_parent)
clk_disable_unprepare(phy->ref_clk_parent);
clk_disable_unprepare(phy->ref_clk_parent);
out_disable_src:
clk_disable_unprepare(phy->ref_clk_src);
out:
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_ref_clk);
static
int ufs_qcom_phy_disable_vreg(struct phy *phy,
@ -442,7 +417,7 @@ int ufs_qcom_phy_disable_vreg(struct phy *phy,
struct device *dev = ufs_qcom_phy->dev;
int ret = 0;
if (!vreg || !vreg->enabled || vreg->is_always_on)
if (!vreg || !vreg->enabled)
goto out;
ret = regulator_disable(vreg->reg);
@ -465,67 +440,27 @@ void ufs_qcom_phy_disable_ref_clk(struct phy *generic_phy)
if (phy->is_ref_clk_enabled) {
clk_disable_unprepare(phy->ref_clk);
/*
* "ref_clk_parent" is optional clock hence make sure that clk
* reference is available before trying to disable the clock.
*/
if (phy->ref_clk_parent)
clk_disable_unprepare(phy->ref_clk_parent);
clk_disable_unprepare(phy->ref_clk_parent);
clk_disable_unprepare(phy->ref_clk_src);
phy->is_ref_clk_enabled = false;
}
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_ref_clk);
#define UFS_REF_CLK_EN (1 << 5)
static void ufs_qcom_phy_dev_ref_clk_ctrl(struct phy *generic_phy, bool enable)
void ufs_qcom_phy_restore_swi_regs(struct phy *generic_phy)
{
int i;
struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
if (phy->dev_ref_clk_ctrl_mmio &&
(enable ^ phy->is_dev_ref_clk_enabled)) {
u32 temp = readl_relaxed(phy->dev_ref_clk_ctrl_mmio);
if (enable)
temp |= UFS_REF_CLK_EN;
else
temp &= ~UFS_REF_CLK_EN;
/*
* If we are here to disable this clock immediately after
* entering into hibern8, we need to make sure that device
* ref_clk is active atleast 1us after the hibern8 enter.
*/
if (!enable)
udelay(1);
writel_relaxed(temp, phy->dev_ref_clk_ctrl_mmio);
/* ensure that ref_clk is enabled/disabled before we return */
wmb();
/*
* If we call hibern8 exit after this, we need to make sure that
* device ref_clk is stable for atleast 1us before the hibern8
* exit command.
*/
if (enable)
udelay(1);
phy->is_dev_ref_clk_enabled = enable;
for (i = 0; i < phy->cached_regs_table_size; i++) {
struct ufs_qcom_phy_calibration *table =
(struct ufs_qcom_phy_calibration *)phy->cached_regs;
writel_relaxed(table[i].cfg_value, phy->mmio +
table[i].reg_offset);
}
}
void ufs_qcom_phy_enable_dev_ref_clk(struct phy *generic_phy)
{
ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, true);
/* flush buffered writes */
mb();
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_dev_ref_clk);
void ufs_qcom_phy_disable_dev_ref_clk(struct phy *generic_phy)
{
ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, false);
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_dev_ref_clk);
/* Turn ON M-PHY RMMI interface clocks */
int ufs_qcom_phy_enable_iface_clk(struct phy *generic_phy)
@ -554,7 +489,6 @@ int ufs_qcom_phy_enable_iface_clk(struct phy *generic_phy)
out:
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_iface_clk);
/* Turn OFF M-PHY RMMI interface clocks */
void ufs_qcom_phy_disable_iface_clk(struct phy *generic_phy)
@ -567,7 +501,13 @@ void ufs_qcom_phy_disable_iface_clk(struct phy *generic_phy)
phy->is_iface_clk_enabled = false;
}
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_iface_clk);
int ufs_qcom_phy_is_cfg_restore_quirk_enabled(struct phy *phy)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy);
return ufs_qcom_phy->quirks & UFS_QCOM_PHY_QUIRK_CFG_RESTORE;
}
int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
{
@ -584,7 +524,6 @@ int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_start_serdes);
int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes)
{
@ -602,7 +541,6 @@ int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes)
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_set_tx_lane_enable);
void ufs_qcom_phy_save_controller_version(struct phy *generic_phy,
u8 major, u16 minor, u16 step)
@ -613,9 +551,8 @@ void ufs_qcom_phy_save_controller_version(struct phy *generic_phy,
ufs_qcom_phy->host_ctrl_rev_minor = minor;
ufs_qcom_phy->host_ctrl_rev_step = step;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_save_controller_version);
int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy, bool is_rate_B)
int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;
@ -626,7 +563,7 @@ int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy, bool is_rate_B)
ret = -ENOTSUPP;
} else {
ret = ufs_qcom_phy->phy_spec_ops->
calibrate_phy(ufs_qcom_phy, is_rate_B);
calibrate_phy(ufs_qcom_phy);
if (ret)
dev_err(ufs_qcom_phy->dev, "%s: calibrate_phy() failed %d\n",
__func__, ret);
@ -634,7 +571,6 @@ int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy, bool is_rate_B)
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate_phy);
int ufs_qcom_phy_remove(struct phy *generic_phy,
struct ufs_qcom_phy *ufs_qcom_phy)
@ -646,7 +582,6 @@ int ufs_qcom_phy_remove(struct phy *generic_phy,
return 0;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_remove);
int ufs_qcom_phy_exit(struct phy *generic_phy)
{
@ -657,7 +592,6 @@ int ufs_qcom_phy_exit(struct phy *generic_phy)
return 0;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_exit);
int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
{
@ -672,7 +606,38 @@ int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
return ufs_qcom_phy->phy_spec_ops->
is_physical_coding_sublayer_ready(ufs_qcom_phy);
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_is_pcs_ready);
int ufs_qcom_phy_save_configuration(struct phy *generic_phy)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;
if (!ufs_qcom_phy->phy_spec_ops->save_configuration) {
dev_err(ufs_qcom_phy->dev, "%s: save_configuration() callback is not supported\n",
__func__);
ret = -ENOTSUPP;
} else {
ufs_qcom_phy->phy_spec_ops->save_configuration(ufs_qcom_phy);
}
return ret;
}
int ufs_qcom_phy_restore_configuration(struct phy *generic_phy)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;
if (!ufs_qcom_phy->phy_spec_ops->restore_configuration) {
dev_err(ufs_qcom_phy->dev, "%s: restore_configuration() callback is not supported\n",
__func__);
ret = -ENOTSUPP;
} else {
ufs_qcom_phy->phy_spec_ops->restore_configuration(ufs_qcom_phy);
}
return ret;
}
int ufs_qcom_phy_power_on(struct phy *generic_phy)
{
@ -704,22 +669,9 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
goto out_disable_pll;
}
/* enable device PHY ref_clk pad rail */
if (phy_common->vddp_ref_clk.reg) {
err = ufs_qcom_phy_enable_vreg(generic_phy,
&phy_common->vddp_ref_clk);
if (err) {
dev_err(dev, "%s enable vddp_ref_clk failed, err=%d\n",
__func__, err);
goto out_disable_ref_clk;
}
}
phy_common->is_powered_on = true;
goto out;
out_disable_ref_clk:
ufs_qcom_phy_disable_ref_clk(generic_phy);
out_disable_pll:
ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);
out_disable_phy:
@ -727,7 +679,6 @@ out_disable_phy:
out:
return err;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_on);
int ufs_qcom_phy_power_off(struct phy *generic_phy)
{
@ -735,9 +686,6 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
phy_common->phy_spec_ops->power_control(phy_common, false);
if (phy_common->vddp_ref_clk.reg)
ufs_qcom_phy_disable_vreg(generic_phy,
&phy_common->vddp_ref_clk);
ufs_qcom_phy_disable_ref_clk(generic_phy);
ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);
@ -746,4 +694,3 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
return 0;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2014, Linux Foundation. All rights reserved.
* Copyright (c) 2013-2015, 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
@ -12,23 +12,28 @@
*
*/
#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 "phy-qcom-ufs-i.h"
#include "ufs-msm-phy.h"
#define MAX_PROP_NAME 32
#define VDDA_PHY_MIN_UV 1000000
#define VDDA_PHY_MAX_UV 1000000
#define VDDA_PLL_MIN_UV 1800000
#define VDDA_PLL_MAX_UV 1800000
#define VDDP_REF_CLK_MIN_UV 1200000
#define VDDP_REF_CLK_MAX_UV 1200000
static int __ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *,
const char *, bool);
static int ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *,
const char *);
static int ufs_qcom_phy_base_init(struct platform_device *pdev,
struct ufs_qcom_phy *phy_common);
int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
struct ufs_qcom_phy_calibration *tbl_A,
int tbl_size_A,
struct ufs_qcom_phy_calibration *tbl_B,
int tbl_size_B, int rate)
int tbl_size_B, bool is_rate_B)
{
int i;
int ret = 0;
@ -49,7 +54,7 @@ int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
* with registers of rate B table.
* table.
*/
if (rate == PA_HS_MODE_B) {
if (is_rate_B) {
if (!tbl_B) {
dev_err(ufs_qcom_phy->dev, "%s: tbl_B is NULL",
__func__);
@ -68,10 +73,11 @@ int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
out:
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate);
struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
struct ufs_qcom_phy *common_cfg,
struct phy_ops *ufs_qcom_phy_gen_ops,
const struct phy_ops *ufs_qcom_phy_gen_ops,
struct ufs_qcom_phy_specific_ops *phy_spec_ops)
{
int err;
@ -92,10 +98,11 @@ struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
goto out;
}
generic_phy = devm_phy_create(dev, NULL, ufs_qcom_phy_gen_ops, NULL);
generic_phy = devm_phy_create(dev, NULL, ufs_qcom_phy_gen_ops);
if (IS_ERR(generic_phy)) {
err = PTR_ERR(generic_phy);
dev_err(dev, "%s: failed to create phy %d\n", __func__, err);
generic_phy = NULL;
goto out;
}
@ -105,6 +112,7 @@ struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
out:
return generic_phy;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_generic_probe);
/*
* This assumes the embedded phy structure inside generic_phy is of type
@ -116,7 +124,9 @@ struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy)
{
return (struct ufs_qcom_phy *)phy_get_drvdata(generic_phy);
}
EXPORT_SYMBOL_GPL(get_ufs_qcom_phy);
static
int ufs_qcom_phy_base_init(struct platform_device *pdev,
struct ufs_qcom_phy *phy_common)
{
@ -124,26 +134,28 @@ int ufs_qcom_phy_base_init(struct platform_device *pdev,
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;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem");
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);
if (IS_ERR((void const *)phy_common->mmio)) {
err = PTR_ERR((void const *)phy_common->mmio);
phy_common->mmio = NULL;
dev_err(dev, "%s: ioremap for phy_mem resource failed %d\n",
__func__, err);
return err;
}
out:
return err;
/* "dev_ref_clk_ctrl_mem" is optional resource */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"dev_ref_clk_ctrl_mem");
phy_common->dev_ref_clk_ctrl_mmio = devm_ioremap_resource(dev, res);
if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio))
phy_common->dev_ref_clk_ctrl_mmio = NULL;
return 0;
}
int ufs_qcom_phy_clk_get(struct phy *phy,
const char *name, struct clk **clk_out)
static int __ufs_qcom_phy_clk_get(struct phy *phy,
const char *name, struct clk **clk_out, bool err_print)
{
struct clk *clk;
int err = 0;
@ -153,7 +165,8 @@ int ufs_qcom_phy_clk_get(struct phy *phy,
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);
if (err_print)
dev_err(dev, "failed to get %s err %d", name, err);
} else {
*clk_out = clk;
}
@ -161,6 +174,13 @@ int ufs_qcom_phy_clk_get(struct phy *phy,
return err;
}
static
int ufs_qcom_phy_clk_get(struct phy *phy,
const char *name, struct clk **clk_out)
{
return __ufs_qcom_phy_clk_get(phy, name, clk_out, true);
}
int
ufs_qcom_phy_init_clks(struct phy *generic_phy,
struct ufs_qcom_phy *phy_common)
@ -182,10 +202,12 @@ ufs_qcom_phy_init_clks(struct phy *generic_phy,
if (err)
goto out;
err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk_parent",
&phy_common->ref_clk_parent);
if (err)
goto out;
/*
* "ref_clk_parent" is optional hence don't abort init if it's not
* found.
*/
__ufs_qcom_phy_clk_get(generic_phy, "ref_clk_parent",
&phy_common->ref_clk_parent, false);
err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk",
&phy_common->ref_clk);
@ -193,6 +215,7 @@ ufs_qcom_phy_init_clks(struct phy *generic_phy,
out:
return err;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_clks);
int
ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
@ -207,12 +230,20 @@ ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
err = ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vdda_phy,
"vdda-phy");
if (err)
goto out;
/* vddp-ref-clk-* properties are optional */
__ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vddp_ref_clk,
"vddp-ref-clk", true);
out:
return err;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_vregulators);
int ufs_qcom_phy_init_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg, const char *name)
static int __ufs_qcom_phy_init_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional)
{
int err = 0;
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy);
@ -229,7 +260,9 @@ int ufs_qcom_phy_init_vreg(struct phy *phy,
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);
vreg->reg = NULL;
if (!optional)
dev_err(dev, "failed to get %s, %d\n", name, err);
goto out;
}
@ -249,6 +282,11 @@ int ufs_qcom_phy_init_vreg(struct phy *phy,
}
err = 0;
}
snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name);
if (of_get_property(dev->of_node, prop_name, NULL))
vreg->is_always_on = true;
else
vreg->is_always_on = false;
}
if (!strcmp(name, "vdda-pll")) {
@ -257,6 +295,9 @@ int ufs_qcom_phy_init_vreg(struct phy *phy,
} else if (!strcmp(name, "vdda-phy")) {
vreg->max_uV = VDDA_PHY_MAX_UV;
vreg->min_uV = VDDA_PHY_MIN_UV;
} else if (!strcmp(name, "vddp-ref-clk")) {
vreg->max_uV = VDDP_REF_CLK_MAX_UV;
vreg->min_uV = VDDP_REF_CLK_MIN_UV;
}
out:
@ -265,6 +306,13 @@ out:
return err;
}
static int ufs_qcom_phy_init_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg, const char *name)
{
return __ufs_qcom_phy_init_vreg(phy, vreg, name, false);
}
static
int ufs_qcom_phy_cfg_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg, bool on)
{
@ -287,10 +335,10 @@ int ufs_qcom_phy_cfg_vreg(struct phy *phy,
goto out;
}
uA_load = on ? vreg->max_uA : 0;
ret = regulator_set_optimum_mode(reg, uA_load);
ret = regulator_set_load(reg, uA_load);
if (ret >= 0) {
/*
* regulator_set_optimum_mode() returns new regulator
* regulator_set_load() returns new regulator
* mode upon success.
*/
ret = 0;
@ -304,6 +352,7 @@ out:
return ret;
}
static
int ufs_qcom_phy_enable_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg)
{
@ -352,11 +401,17 @@ int ufs_qcom_phy_enable_ref_clk(struct phy *generic_phy)
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;
/*
* "ref_clk_parent" is optional clock hence make sure that clk reference
* is available before trying to enable the clock.
*/
if (phy->ref_clk_parent) {
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);
@ -370,13 +425,16 @@ int ufs_qcom_phy_enable_ref_clk(struct phy *generic_phy)
goto out;
out_disable_parent:
clk_disable_unprepare(phy->ref_clk_parent);
if (phy->ref_clk_parent)
clk_disable_unprepare(phy->ref_clk_parent);
out_disable_src:
clk_disable_unprepare(phy->ref_clk_src);
out:
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_ref_clk);
static
int ufs_qcom_phy_disable_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg)
{
@ -384,7 +442,7 @@ int ufs_qcom_phy_disable_vreg(struct phy *phy,
struct device *dev = ufs_qcom_phy->dev;
int ret = 0;
if (!vreg || !vreg->enabled)
if (!vreg || !vreg->enabled || vreg->is_always_on)
goto out;
ret = regulator_disable(vreg->reg);
@ -407,28 +465,68 @@ void ufs_qcom_phy_disable_ref_clk(struct phy *generic_phy)
if (phy->is_ref_clk_enabled) {
clk_disable_unprepare(phy->ref_clk);
clk_disable_unprepare(phy->ref_clk_parent);
/*
* "ref_clk_parent" is optional clock hence make sure that clk
* reference is available before trying to disable the clock.
*/
if (phy->ref_clk_parent)
clk_disable_unprepare(phy->ref_clk_parent);
clk_disable_unprepare(phy->ref_clk_src);
phy->is_ref_clk_enabled = false;
}
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_ref_clk);
void ufs_qcom_phy_restore_swi_regs(struct phy *generic_phy)
#define UFS_REF_CLK_EN (1 << 5)
static void ufs_qcom_phy_dev_ref_clk_ctrl(struct phy *generic_phy, bool enable)
{
int i;
struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
for (i = 0; i < phy->cached_regs_table_size; i++) {
struct ufs_qcom_phy_calibration *table =
(struct ufs_qcom_phy_calibration *)phy->cached_regs;
writel_relaxed(table[i].cfg_value, phy->mmio +
table[i].reg_offset);
}
if (phy->dev_ref_clk_ctrl_mmio &&
(enable ^ phy->is_dev_ref_clk_enabled)) {
u32 temp = readl_relaxed(phy->dev_ref_clk_ctrl_mmio);
/* flush buffered writes */
mb();
if (enable)
temp |= UFS_REF_CLK_EN;
else
temp &= ~UFS_REF_CLK_EN;
/*
* If we are here to disable this clock immediately after
* entering into hibern8, we need to make sure that device
* ref_clk is active atleast 1us after the hibern8 enter.
*/
if (!enable)
udelay(1);
writel_relaxed(temp, phy->dev_ref_clk_ctrl_mmio);
/* ensure that ref_clk is enabled/disabled before we return */
wmb();
/*
* If we call hibern8 exit after this, we need to make sure that
* device ref_clk is stable for atleast 1us before the hibern8
* exit command.
*/
if (enable)
udelay(1);
phy->is_dev_ref_clk_enabled = enable;
}
}
void ufs_qcom_phy_enable_dev_ref_clk(struct phy *generic_phy)
{
ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, true);
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_dev_ref_clk);
void ufs_qcom_phy_disable_dev_ref_clk(struct phy *generic_phy)
{
ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, false);
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_dev_ref_clk);
/* Turn ON M-PHY RMMI interface clocks */
int ufs_qcom_phy_enable_iface_clk(struct phy *generic_phy)
{
@ -456,6 +554,7 @@ int ufs_qcom_phy_enable_iface_clk(struct phy *generic_phy)
out:
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_iface_clk);
/* Turn OFF M-PHY RMMI interface clocks */
void ufs_qcom_phy_disable_iface_clk(struct phy *generic_phy)
@ -468,13 +567,7 @@ void ufs_qcom_phy_disable_iface_clk(struct phy *generic_phy)
phy->is_iface_clk_enabled = false;
}
}
int ufs_qcom_phy_is_cfg_restore_quirk_enabled(struct phy *phy)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy);
return ufs_qcom_phy->quirks & UFS_QCOM_PHY_QUIRK_CFG_RESTORE;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_iface_clk);
int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
{
@ -491,6 +584,7 @@ int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_start_serdes);
int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes)
{
@ -508,6 +602,7 @@ int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes)
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_set_tx_lane_enable);
void ufs_qcom_phy_save_controller_version(struct phy *generic_phy,
u8 major, u16 minor, u16 step)
@ -518,8 +613,9 @@ void ufs_qcom_phy_save_controller_version(struct phy *generic_phy,
ufs_qcom_phy->host_ctrl_rev_minor = minor;
ufs_qcom_phy->host_ctrl_rev_step = step;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_save_controller_version);
int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy)
int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy, bool is_rate_B)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;
@ -530,7 +626,7 @@ int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy)
ret = -ENOTSUPP;
} else {
ret = ufs_qcom_phy->phy_spec_ops->
calibrate_phy(ufs_qcom_phy);
calibrate_phy(ufs_qcom_phy, is_rate_B);
if (ret)
dev_err(ufs_qcom_phy->dev, "%s: calibrate_phy() failed %d\n",
__func__, ret);
@ -538,6 +634,7 @@ int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy)
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate_phy);
int ufs_qcom_phy_remove(struct phy *generic_phy,
struct ufs_qcom_phy *ufs_qcom_phy)
@ -549,6 +646,7 @@ int ufs_qcom_phy_remove(struct phy *generic_phy,
return 0;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_remove);
int ufs_qcom_phy_exit(struct phy *generic_phy)
{
@ -559,6 +657,7 @@ int ufs_qcom_phy_exit(struct phy *generic_phy)
return 0;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_exit);
int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
{
@ -573,38 +672,7 @@ int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
return ufs_qcom_phy->phy_spec_ops->
is_physical_coding_sublayer_ready(ufs_qcom_phy);
}
int ufs_qcom_phy_save_configuration(struct phy *generic_phy)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;
if (!ufs_qcom_phy->phy_spec_ops->save_configuration) {
dev_err(ufs_qcom_phy->dev, "%s: save_configuration() callback is not supported\n",
__func__);
ret = -ENOTSUPP;
} else {
ufs_qcom_phy->phy_spec_ops->save_configuration(ufs_qcom_phy);
}
return ret;
}
int ufs_qcom_phy_restore_configuration(struct phy *generic_phy)
{
struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
int ret = 0;
if (!ufs_qcom_phy->phy_spec_ops->restore_configuration) {
dev_err(ufs_qcom_phy->dev, "%s: restore_configuration() callback is not supported\n",
__func__);
ret = -ENOTSUPP;
} else {
ufs_qcom_phy->phy_spec_ops->restore_configuration(ufs_qcom_phy);
}
return ret;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_is_pcs_ready);
int ufs_qcom_phy_power_on(struct phy *generic_phy)
{
@ -636,9 +704,22 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
goto out_disable_pll;
}
/* enable device PHY ref_clk pad rail */
if (phy_common->vddp_ref_clk.reg) {
err = ufs_qcom_phy_enable_vreg(generic_phy,
&phy_common->vddp_ref_clk);
if (err) {
dev_err(dev, "%s enable vddp_ref_clk failed, err=%d\n",
__func__, err);
goto out_disable_ref_clk;
}
}
phy_common->is_powered_on = true;
goto out;
out_disable_ref_clk:
ufs_qcom_phy_disable_ref_clk(generic_phy);
out_disable_pll:
ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);
out_disable_phy:
@ -646,6 +727,7 @@ out_disable_phy:
out:
return err;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_on);
int ufs_qcom_phy_power_off(struct phy *generic_phy)
{
@ -653,6 +735,9 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
phy_common->phy_spec_ops->power_control(phy_common, false);
if (phy_common->vddp_ref_clk.reg)
ufs_qcom_phy_disable_vreg(generic_phy,
&phy_common->vddp_ref_clk);
ufs_qcom_phy_disable_ref_clk(generic_phy);
ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);
@ -661,3 +746,4 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
return 0;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);

View file

@ -1,8 +1,5 @@
# UFSHCD makefile
obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-msm-phy.o
obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-msm-phy-qmp-28nm.o
obj-$(CONFIG_SCSI_UFS_QCOM) += 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

View file

@ -19,7 +19,8 @@
#include <linux/random.h>
#include "debugfs.h"
#include "unipro.h"
#include <linux/scsi/ufs/unipro.h>
#include "ufshci.h"
enum field_width {
BYTE = 1,

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2014, The 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
@ -21,7 +21,7 @@
#define _UFS_DEBUGFS_H
#include <linux/debugfs.h>
#include "ufshcd.h"
#include <linux/scsi/ufs/ufshcd.h>
#ifdef CONFIG_DEBUG_FS
void ufsdbg_add_debugfs(struct ufs_hba *hba);

View file

@ -1,195 +0,0 @@
/*
* 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_QCOM_PHY_H_
#define UFS_QCOM_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_QCOM_PHY_CAL_ENTRY(reg, val) \
{ \
.reg_offset = reg, \
.cfg_value = val, \
}
#define UFS_QCOM_PHY_NAME_LEN 30
struct ufs_qcom_phy_stored_attributes {
u32 att;
u32 value;
};
struct ufs_qcom_phy_calibration {
u32 reg_offset;
u32 cfg_value;
};
struct ufs_qcom_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_qcom_phy_vreg vdda_pll;
struct ufs_qcom_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 UFS_QCOM_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 UFS_QCOM_PHY_DIS_SIGDET_BEFORE_PWR_COLLAPSE (1 << 1)
/*
* If UFS link is put into Hibern8 and if UFS PHY analog hardware is
* power collapsed (by clearing UFS_PHY_POWER_DOWN_CONTROL), Hibern8
* exit might fail even after powering on UFS PHY analog hardware.
* Enabling this quirk will help to solve above issue by doing
* custom PHY settings just before PHY analog power collapse.
*/
#define UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE (1 << 2)
char name[UFS_QCOM_PHY_NAME_LEN];
struct ufs_qcom_phy_calibration *cached_regs;
int cached_regs_table_size;
bool is_powered_on;
struct ufs_qcom_phy_specific_ops *phy_spec_ops;
};
/**
* struct ufs_qcom_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_qcom_phy_specific_ops {
int (*calibrate_phy) (struct ufs_qcom_phy *phy);
void (*start_serdes) (struct ufs_qcom_phy *phy);
void (*save_configuration)(struct ufs_qcom_phy *phy);
void (*restore_configuration)(struct ufs_qcom_phy *phy);
int (*is_physical_coding_sublayer_ready) (struct ufs_qcom_phy *phy);
void (*set_tx_lane_enable) (struct ufs_qcom_phy *phy, u32 val);
void (*power_control) (struct ufs_qcom_phy *phy, bool val);
};
int ufs_qcom_phy_init_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg, const char *name);
int ufs_qcom_phy_cfg_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg, bool on);
int ufs_qcom_phy_enable_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg);
int ufs_qcom_phy_disable_vreg(struct phy *phy,
struct ufs_qcom_phy_vreg *vreg);
int ufs_qcom_phy_enable_ref_clk(struct phy *phy);
void ufs_qcom_phy_disable_ref_clk(struct phy *phy);
int ufs_qcom_phy_enable_iface_clk(struct phy *phy);
void ufs_qcom_phy_disable_iface_clk(struct phy *phy);
void ufs_qcom_phy_restore_swi_regs(struct phy *phy);
int ufs_qcom_phy_link_startup_post_change(struct phy *phy,
struct ufs_hba *hba);
int ufs_qcom_phy_base_init(struct platform_device *pdev,
struct ufs_qcom_phy *ufs_qcom_phy_ops);
int ufs_qcom_phy_is_cfg_restore_quirk_enabled(struct phy *phy);
struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy);
int ufs_qcom_phy_start_serdes(struct phy *generic_phy);
int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes);
int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy);
int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy);
int ufs_qcom_phy_save_configuration(struct phy *generic_phy);
int ufs_qcom_phy_restore_configuration(struct phy *generic_phy);
void ufs_qcom_phy_save_controller_version(struct phy *generic_phy,
u8 major, u16 minor, u16 step);
int ufs_qcom_phy_power_on(struct phy *generic_phy);
int ufs_qcom_phy_power_off(struct phy *generic_phy);
int ufs_qcom_phy_exit(struct phy *generic_phy);
int ufs_qcom_phy_init_clks(struct phy *generic_phy,
struct ufs_qcom_phy *phy_common);
int ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
struct ufs_qcom_phy *phy_common);
int ufs_qcom_phy_remove(struct phy *generic_phy,
struct ufs_qcom_phy *ufs_qcom_phy);
struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
struct ufs_qcom_phy *common_cfg,
struct phy_ops *ufs_qcom_phy_gen_ops,
struct ufs_qcom_phy_specific_ops *phy_spec_ops);
int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A,
struct ufs_qcom_phy_calibration *tbl_B, int tbl_size_B,
int rate);
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
/*
* Copyright (c) 2013-2014, The 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
@ -10,7 +11,7 @@
* GNU General Public License for more details.
*/
#include "ufshcd.h"
#include <linux/scsi/ufs/ufshcd.h>
#include "ufs_quirks.h"

View file

@ -17,7 +17,9 @@
#include <linux/test-iosched.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <../sd.h>
#include <scsi/scsi_host.h>
#include <linux/scsi/ufs/ufshcd.h>
#include <linux/scsi/ufs/ufs.h>
#define MODULE_NAME "ufs_test"

View file

@ -33,7 +33,7 @@
* this program.
*/
#include "ufshcd.h"
#include <linux/scsi/ufs/ufshcd.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>

View file

@ -39,6 +39,7 @@
#include "ufshcd.h"
#include "ufshcd-pltfrm.h"
#include <linux/scsi/ufs/ufshcd.h>
static int ufshcd_parse_clock_info(struct ufs_hba *hba)
{

View file

@ -42,8 +42,10 @@
#include <linux/devfreq.h>
#include <linux/nls.h>
#include "ufshcd.h"
#include "unipro.h"
#include <linux/scsi/ufs/ufshcd.h>
#include <linux/scsi/ufs/unipro.h>
#include "ufshci.h"
#include "ufs_quirks.h"
#include "debugfs.h"
#define CREATE_TRACE_POINTS
@ -3134,6 +3136,23 @@ out:
return err;
}
/**
* ufshcd_hba_stop - Send controller to reset state
* @hba: per adapter instance
* @can_sleep: perform sleep or just spin
*/
static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep)
{
int err;
ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE,
CONTROLLER_ENABLE, CONTROLLER_DISABLE,
10, 1, can_sleep);
if (err)
dev_err(hba->dev, "%s: Controller disable failed\n", __func__);
}
/**
* ufshcd_hba_enable - initialize the controller
* @hba: per adapter instance

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
* 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
@ -15,7 +15,9 @@
#ifndef PHY_QCOM_UFS_H_
#define PHY_QCOM_UFS_H_
#include "phy.h"
#include <linux/scsi/ufs/ufshcd.h>
#include <linux/scsi/ufs/unipro.h>
#include <linux/scsi/ufs/ufs-qcom.h>
/**
* ufs_qcom_phy_enable_ref_clk() - Enable the phy

View file

@ -139,15 +139,6 @@ struct ufs_qcom_host {
#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
enum {
MASK_SERDES_START = 0x1,
MASK_PCS_READY = 0x1,
};
enum {
OFFSET_SERDES_START = 0x0,
};
#define MAX_PROP_NAME 32
#define VDDA_PHY_MIN_UV 1000000
#define VDDA_PHY_MAX_UV 1000000

View file

@ -65,10 +65,7 @@
#include <scsi/scsi_eh.h>
#include <linux/fault-inject.h>
#include "ufs.h"
#include "ufshci.h"
#include "ufs_quirks.h"
#define UFSHCD "ufshcd"
#define UFSHCD_DRIVER_VERSION "0.2"
@ -640,9 +637,9 @@ static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba)
}
#define ufshcd_writel(hba, val, reg) \
writel((val), (hba)->mmio_base + (reg))
writel_relaxed((val), (hba)->mmio_base + (reg))
#define ufshcd_readl(hba, reg) \
readl((hba)->mmio_base + (reg))
readl_relaxed((hba)->mmio_base + (reg))
/**
* ufshcd_rmwl - read modify write into a register
@ -668,28 +665,6 @@ void ufshcd_remove(struct ufs_hba *);
int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
u32 val, unsigned long interval_us,
unsigned long timeout_ms, bool can_sleep);
/**
* ufshcd_hba_stop - Send controller to reset state
* @hba: per adapter instance
* @can_sleep: perform sleep or just spin
*/
static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep)
{
int err;
ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE,
CONTROLLER_ENABLE, CONTROLLER_DISABLE,
10, 1, can_sleep);
if (err)
dev_err(hba->dev, "%s: Controller disable failed\n", __func__);
}
static inline void check_upiu_size(void)
{
BUILD_BUG_ON(ALIGNED_UPIU_SIZE <
GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE);
}
/**
* ufshcd_set_variant - set variant specific data to the hba

View file

@ -1,6 +1,4 @@
/*
* drivers/scsi/ufs/unipro.h
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify