Commit f06fcc71 authored by Yaniv Gardi's avatar Yaniv Gardi Committed by Martin K. Petersen

scsi: ufs-qcom: add QUniPro hardware support and power optimizations

New revisions of UFS host controller supports the new UniPro
hardware controller (referred as QUniPro). This patch adds
the support to enable this new UniPro controller hardware.

This change also adds power optimization for bus scaling feature,
as well as support for HS-G3 power mode.
Reviewed-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
Reviewed-by: default avatarGilad Broner <gbroner@codeaurora.org>
Signed-off-by: default avatarYaniv Gardi <ygardi@codeaurora.org>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 6e3fd44d
This diff is collapsed.
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
#define UFS_QCOM_LIMIT_NUM_LANES_RX 2 #define UFS_QCOM_LIMIT_NUM_LANES_RX 2
#define UFS_QCOM_LIMIT_NUM_LANES_TX 2 #define UFS_QCOM_LIMIT_NUM_LANES_TX 2
#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G2 #define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G3
#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G2 #define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G3
#define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4 #define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4
#define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4 #define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4
#define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE #define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE
...@@ -64,6 +64,11 @@ enum { ...@@ -64,6 +64,11 @@ enum {
UFS_TEST_BUS_CTRL_2 = 0xF4, UFS_TEST_BUS_CTRL_2 = 0xF4,
UFS_UNIPRO_CFG = 0xF8, UFS_UNIPRO_CFG = 0xF8,
/*
* QCOM UFS host controller vendor specific registers
* added in HW Version 3.0.0
*/
UFS_AH8_CFG = 0xFC,
}; };
/* QCOM UFS host controller vendor specific debug registers */ /* QCOM UFS host controller vendor specific debug registers */
...@@ -83,6 +88,11 @@ enum { ...@@ -83,6 +88,11 @@ enum {
UFS_UFS_DBG_RD_EDTL_RAM = 0x1900, UFS_UFS_DBG_RD_EDTL_RAM = 0x1900,
}; };
#define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x) (0x000 + x)
#define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x)
/* bit definitions for REG_UFS_CFG1 register */
#define QUNIPRO_SEL UFS_BIT(0)
#define TEST_BUS_EN BIT(18) #define TEST_BUS_EN BIT(18)
#define TEST_BUS_SEL GENMASK(22, 19) #define TEST_BUS_SEL GENMASK(22, 19)
...@@ -131,6 +141,12 @@ enum ufs_qcom_phy_init_type { ...@@ -131,6 +141,12 @@ enum ufs_qcom_phy_init_type {
(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \
UFS_QCOM_DBG_PRINT_TEST_BUS_EN) UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
/* QUniPro Vendor specific attributes */
#define DME_VS_CORE_CLK_CTRL 0xD002
/* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */
#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8)
#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF
static inline void static inline void
ufs_qcom_get_controller_revision(struct ufs_hba *hba, ufs_qcom_get_controller_revision(struct ufs_hba *hba,
u8 *major, u16 *minor, u16 *step) u8 *major, u16 *minor, u16 *step)
...@@ -196,6 +212,12 @@ struct ufs_qcom_host { ...@@ -196,6 +212,12 @@ struct ufs_qcom_host {
* controller supports the QUniPro mode. * controller supports the QUniPro mode.
*/ */
#define UFS_QCOM_CAP_QUNIPRO UFS_BIT(0) #define UFS_QCOM_CAP_QUNIPRO UFS_BIT(0)
/*
* Set this capability if host controller can retain the secure
* configuration even after UFS controller core power collapse.
*/
#define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE UFS_BIT(1)
u32 caps; u32 caps;
struct phy *generic_phy; struct phy *generic_phy;
...@@ -208,7 +230,12 @@ struct ufs_qcom_host { ...@@ -208,7 +230,12 @@ struct ufs_qcom_host {
struct clk *tx_l1_sync_clk; struct clk *tx_l1_sync_clk;
bool is_lane_clks_enabled; bool is_lane_clks_enabled;
void __iomem *dev_ref_clk_ctrl_mmio;
bool is_dev_ref_clk_enabled;
struct ufs_hw_version hw_ver; struct ufs_hw_version hw_ver;
u32 dev_ref_clk_en_mask;
/* Bitmask for enabling debug prints */ /* Bitmask for enabling debug prints */
u32 dbg_print_en; u32 dbg_print_en;
struct ufs_qcom_testbus testbus; struct ufs_qcom_testbus testbus;
......
...@@ -5420,6 +5420,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) ...@@ -5420,6 +5420,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
if (!head || list_empty(head)) if (!head || list_empty(head))
goto out; goto out;
ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
if (ret)
return ret;
list_for_each_entry(clki, head, list) { list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) { if (!IS_ERR_OR_NULL(clki->clk)) {
if (scale_up && clki->max_freq) { if (scale_up && clki->max_freq) {
...@@ -5450,7 +5454,9 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) ...@@ -5450,7 +5454,9 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__, dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__,
clki->name, clk_get_rate(clki->clk)); clki->name, clk_get_rate(clki->clk));
} }
ufshcd_vops_clk_scale_notify(hba);
ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
out: out:
return ret; return ret;
} }
......
...@@ -223,8 +223,10 @@ struct ufs_clk_info { ...@@ -223,8 +223,10 @@ struct ufs_clk_info {
bool enabled; bool enabled;
}; };
#define PRE_CHANGE 0 enum ufs_notify_change_status {
#define POST_CHANGE 1 PRE_CHANGE,
POST_CHANGE,
};
struct ufs_pa_layer_attr { struct ufs_pa_layer_attr {
u32 gear_rx; u32 gear_rx;
...@@ -266,13 +268,17 @@ struct ufs_hba_variant_ops { ...@@ -266,13 +268,17 @@ struct ufs_hba_variant_ops {
int (*init)(struct ufs_hba *); int (*init)(struct ufs_hba *);
void (*exit)(struct ufs_hba *); void (*exit)(struct ufs_hba *);
u32 (*get_ufs_hci_version)(struct ufs_hba *); u32 (*get_ufs_hci_version)(struct ufs_hba *);
void (*clk_scale_notify)(struct ufs_hba *); int (*clk_scale_notify)(struct ufs_hba *, bool,
enum ufs_notify_change_status);
int (*setup_clocks)(struct ufs_hba *, bool); int (*setup_clocks)(struct ufs_hba *, bool);
int (*setup_regulators)(struct ufs_hba *, bool); int (*setup_regulators)(struct ufs_hba *, bool);
int (*hce_enable_notify)(struct ufs_hba *, bool); int (*hce_enable_notify)(struct ufs_hba *,
int (*link_startup_notify)(struct ufs_hba *, bool); enum ufs_notify_change_status);
int (*link_startup_notify)(struct ufs_hba *,
enum ufs_notify_change_status);
int (*pwr_change_notify)(struct ufs_hba *, int (*pwr_change_notify)(struct ufs_hba *,
bool, struct ufs_pa_layer_attr *, enum ufs_notify_change_status status,
struct ufs_pa_layer_attr *,
struct ufs_pa_layer_attr *); struct ufs_pa_layer_attr *);
int (*suspend)(struct ufs_hba *, enum ufs_pm_op); int (*suspend)(struct ufs_hba *, enum ufs_pm_op);
int (*resume)(struct ufs_hba *, enum ufs_pm_op); int (*resume)(struct ufs_hba *, enum ufs_pm_op);
...@@ -708,17 +714,18 @@ static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba) ...@@ -708,17 +714,18 @@ static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba)
return ufshcd_readl(hba, REG_UFS_VERSION); return ufshcd_readl(hba, REG_UFS_VERSION);
} }
static inline void ufshcd_vops_clk_scale_notify(struct ufs_hba *hba) static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba,
bool up, enum ufs_notify_change_status status)
{ {
if (hba->vops && hba->vops->clk_scale_notify) if (hba->vops && hba->vops->clk_scale_notify)
return hba->vops->clk_scale_notify(hba); return hba->vops->clk_scale_notify(hba, up, status);
return 0;
} }
static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on) static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on)
{ {
if (hba->vops && hba->vops->setup_clocks) if (hba->vops && hba->vops->setup_clocks)
return hba->vops->setup_clocks(hba, on); return hba->vops->setup_clocks(hba, on);
return 0; return 0;
} }
......
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