Commit 3d2f12b4 authored by Martin K. Petersen's avatar Martin K. Petersen

Merge patch series "ufs: qcom: Add HS-G4 support"

Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> says:

This series adds HS-G4 support to the Qcom UFS driver and PHY driver.
The newer Qcom platforms support configuring the UFS controller and
PHY in dual gears (i.e., controller/PHY can be configured to run in
two gear speeds). This is accomplished by adding two different PHY
init sequences to the PHY driver and the UFS driver requesting the one
that's required based on the platform configuration.

Initially the ufs-qcom driver will use the default gear G2 for
enumerating the UFS device. Afer enumeration, the max gear supported
by both the controller and device would be found out and that will be
used thereafter.  But for using the max gear after enumeration, the
ufs-qcom driver requires the UFS device to be reinitialized. For this
purpose, a separate quirk has been introduced in the UFS core along
with a callback and those will be used by the ufs-qcom driver.

This series has been tested on following platforms:

 * Qcom RB5 development platform powered by SM8250 SoC
 * SM8450 based dev board
 * Qdrive3/sa8540p-ride board based on SC8280XP (derivative)

Link: https://lore.kernel.org/r/20221222141001.54849-1-manivannan.sadhasivam@linaro.orgSigned-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parents b8c32872 39beef59
......@@ -21393,6 +21393,14 @@ L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: drivers/ufs/host/ufs-mediatek*
UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER QUALCOMM HOOKS
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
L: linux-arm-msm@vger.kernel.org
L: linux-scsi@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/ufs/qcom,ufs.yaml
F: drivers/ufs/host/ufs-qcom*
UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER RENESAS HOOKS
M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
L: linux-renesas-soc@vger.kernel.org
......
......@@ -223,6 +223,12 @@ static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba,
hba->vops->config_scaling_param(hba, p, data);
}
static inline void ufshcd_vops_reinit_notify(struct ufs_hba *hba)
{
if (hba->vops && hba->vops->reinit_notify)
hba->vops->reinit_notify(hba);
}
extern const struct ufs_pm_lvl_states ufs_pm_lvl_states[];
/**
......
......@@ -8231,27 +8231,18 @@ static int ufshcd_add_lus(struct ufs_hba *hba)
return ret;
}
/**
* ufshcd_probe_hba - probe hba to detect device and initialize it
* @hba: per-adapter instance
* @init_dev_params: whether or not to call ufshcd_device_params_init().
*
* Execute link-startup and verify device initialization
*/
static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params)
{
int ret;
unsigned long flags;
ktime_t start = ktime_get();
hba->ufshcd_state = UFSHCD_STATE_RESET;
ret = ufshcd_link_startup(hba);
if (ret)
goto out;
return ret;
if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION)
goto out;
return ret;
/* Debug counters initialization */
ufshcd_clear_dbg_ufs_stats(hba);
......@@ -8262,12 +8253,12 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
/* Verify device initialization by sending NOP OUT UPIU */
ret = ufshcd_verify_dev_init(hba);
if (ret)
goto out;
return ret;
/* Initiate UFS initialization, and waiting until completion */
ret = ufshcd_complete_dev_init(hba);
if (ret)
goto out;
return ret;
/*
* Initialize UFS device parameters used by driver, these
......@@ -8276,7 +8267,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
if (init_dev_params) {
ret = ufshcd_device_params_init(hba);
if (ret)
goto out;
return ret;
}
ufshcd_tune_unipro_params(hba);
......@@ -8297,11 +8288,51 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
if (ret) {
dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n",
__func__, ret);
return ret;
}
}
return 0;
}
/**
* ufshcd_probe_hba - probe hba to detect device and initialize it
* @hba: per-adapter instance
* @init_dev_params: whether or not to call ufshcd_device_params_init().
*
* Execute link-startup and verify device initialization
*/
static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
{
ktime_t start = ktime_get();
unsigned long flags;
int ret;
ret = ufshcd_device_init(hba, init_dev_params);
if (ret)
goto out;
if (hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) {
/* Reset the device and controller before doing reinit */
ufshcd_device_reset(hba);
ufshcd_hba_stop(hba);
ufshcd_vops_reinit_notify(hba);
ret = ufshcd_hba_enable(hba);
if (ret) {
dev_err(hba->dev, "Host controller enable failed\n");
ufshcd_print_evt_hist(hba);
ufshcd_print_host_state(hba);
goto out;
}
ufshcd_print_pwr_info(hba);
/* Reinit the device */
ret = ufshcd_device_init(hba, init_dev_params);
if (ret)
goto out;
}
ufshcd_print_pwr_info(hba);
/*
* bActiveICCLevel is volatile for UFS device (as per latest v2.1 spec)
* and for removable UFS card as well, hence always set the parameter.
......
This diff is collapsed.
......@@ -17,12 +17,9 @@
#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)
#define UFS_HW_VER_MAJOR_MASK GENMASK(31, 28)
#define UFS_HW_VER_MINOR_MASK GENMASK(27, 16)
#define UFS_HW_VER_STEP_MASK GENMASK(15, 0)
/* vendor specific pre-defined parameters */
#define SLOW 1
......@@ -36,7 +33,8 @@ enum {
REG_UFS_TX_SYMBOL_CLK_NS_US = 0xC4,
REG_UFS_LOCAL_PORT_ID_REG = 0xC8,
REG_UFS_PA_ERR_CODE = 0xCC,
REG_UFS_RETRY_TIMER_REG = 0xD0,
/* On older UFS revisions, this register is called "RETRY_TIMER_REG" */
REG_UFS_PARAM0 = 0xD0,
REG_UFS_PA_LINK_STARTUP_TIMER = 0xD8,
REG_UFS_CFG1 = 0xDC,
REG_UFS_CFG2 = 0xE0,
......@@ -76,24 +74,32 @@ enum {
#define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x)
/* bit definitions for REG_UFS_CFG1 register */
#define QUNIPRO_SEL 0x1
#define UTP_DBG_RAMS_EN 0x20000
#define QUNIPRO_SEL BIT(0)
#define UFS_PHY_SOFT_RESET BIT(1)
#define UTP_DBG_RAMS_EN BIT(17)
#define TEST_BUS_EN BIT(18)
#define TEST_BUS_SEL GENMASK(22, 19)
#define UFS_REG_TEST_BUS_EN BIT(30)
#define UFS_PHY_RESET_ENABLE 1
#define UFS_PHY_RESET_DISABLE 0
/* bit definitions for REG_UFS_CFG2 register */
#define UAWM_HW_CGC_EN (1 << 0)
#define UARM_HW_CGC_EN (1 << 1)
#define TXUC_HW_CGC_EN (1 << 2)
#define RXUC_HW_CGC_EN (1 << 3)
#define DFC_HW_CGC_EN (1 << 4)
#define TRLUT_HW_CGC_EN (1 << 5)
#define TMRLUT_HW_CGC_EN (1 << 6)
#define OCSC_HW_CGC_EN (1 << 7)
#define UAWM_HW_CGC_EN BIT(0)
#define UARM_HW_CGC_EN BIT(1)
#define TXUC_HW_CGC_EN BIT(2)
#define RXUC_HW_CGC_EN BIT(3)
#define DFC_HW_CGC_EN BIT(4)
#define TRLUT_HW_CGC_EN BIT(5)
#define TMRLUT_HW_CGC_EN BIT(6)
#define OCSC_HW_CGC_EN BIT(7)
/* bit definitions for REG_UFS_PARAM0 */
#define MAX_HS_GEAR_MASK GENMASK(6, 4)
#define UFS_QCOM_MAX_GEAR(x) FIELD_GET(MAX_HS_GEAR_MASK, (x))
/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */
#define TEST_BUS_SUB_SEL_MASK 0x1F /* All XXX_SEL fields are 5 bits wide */
#define TEST_BUS_SUB_SEL_MASK GENMASK(4, 0) /* All XXX_SEL fields are 5 bits wide */
#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\
TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\
......@@ -101,17 +107,11 @@ enum {
TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN)
/* bit offset */
enum {
OFFSET_UFS_PHY_SOFT_RESET = 1,
OFFSET_CLK_NS_REG = 10,
};
#define OFFSET_CLK_NS_REG 0xa
/* bit masks */
enum {
MASK_UFS_PHY_SOFT_RESET = 0x2,
MASK_TX_SYMBOL_CLK_1US_REG = 0x3FF,
MASK_CLK_NS_REG = 0xFFFC00,
};
#define MASK_TX_SYMBOL_CLK_1US_REG GENMASK(9, 0)
#define MASK_CLK_NS_REG GENMASK(23, 10)
/* QUniPro Vendor specific attributes */
#define PA_VS_CONFIG_REG1 0x9000
......@@ -126,15 +126,15 @@ ufs_qcom_get_controller_revision(struct ufs_hba *hba,
{
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;
*major = FIELD_GET(UFS_HW_VER_MAJOR_MASK, ver);
*minor = FIELD_GET(UFS_HW_VER_MINOR_MASK, ver);
*step = FIELD_GET(UFS_HW_VER_STEP_MASK, ver);
};
static inline void ufs_qcom_assert_reset(struct ufs_hba *hba)
{
ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET,
1 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1);
ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_ENABLE),
REG_UFS_CFG1);
/*
* Make sure assertion of ufs phy reset is written to
......@@ -145,8 +145,8 @@ static inline void ufs_qcom_assert_reset(struct ufs_hba *hba)
static inline void ufs_qcom_deassert_reset(struct ufs_hba *hba)
{
ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET,
0 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1);
ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_DISABLE),
REG_UFS_CFG1);
/*
* Make sure de-assertion of ufs phy reset is written to
......@@ -210,6 +210,8 @@ struct ufs_qcom_host {
struct reset_controller_dev rcdev;
struct gpio_desc *device_reset;
u32 hs_gear;
};
static inline u32
......
......@@ -298,6 +298,7 @@ struct ufs_pwr_mode_info {
* @config_scaling_param: called to configure clock scaling parameters
* @program_key: program or evict an inline encryption key
* @event_notify: called to notify important events
* @reinit_notify: called to notify reinit of UFSHCD during max gear switch
*/
struct ufs_hba_variant_ops {
const char *name;
......@@ -336,6 +337,7 @@ struct ufs_hba_variant_ops {
const union ufs_crypto_cfg_entry *cfg, int slot);
void (*event_notify)(struct ufs_hba *hba,
enum ufs_event_type evt, void *data);
void (*reinit_notify)(struct ufs_hba *);
};
/* clock gating state */
......@@ -594,6 +596,12 @@ enum ufshcd_quirks {
* auto-hibernate capability but it's FASTAUTO only.
*/
UFSHCD_QUIRK_HIBERN_FASTAUTO = 1 << 18,
/*
* This quirk needs to be enabled if the host controller needs
* to reinit the device after switching to maximum gear.
*/
UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH = 1 << 19,
};
enum ufshcd_caps {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment