Fix error message and present UFS variant
Subsystems (5)
v9 cover Fix error message and present UFS variant
V9: update commit message with Reviewed-by
and update commit message of patch 4/8
V8: add phy attributes to UFS devicetree documentation file
V7: removed additional dead code
V6: removed dead code from ufs-qcom.c and added calling to ufshcd_dealloc_host() in ufshcd-pltfrm.c in case of an error after a successfull ufshcd_alloc_host()
V5: removed a redundant null check
V4: add file Documentation/devicetree/bindings/ufs/ufs-qcom.txt and modify the compatible strings in Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
V3: fixes a few minor issues.
V2: fixes a few issues of unnecessary EXPORT_SYMBOL, types of parameters in routine definition, build errors in case CONFIG_PM is not defined and some other minor fixes.
Yaniv Gardi (8):
phy: qcom-ufs: fix build error when the component is built as a module
scsi: ufs-qcom: fix compilation warning if compiled as a module
scsi: ufs-qcom: update configuration option of SCSI_UFS_QCOM component
scsi: ufs: add ufshcd_get_variant ufshcd_set_variant
scsi: ufs: creates wrapper functions for vops
scsi: ufs: make the UFS variant a platform device
scsi: ufs-qcom: add debug prints for test bus
scsi: ufs-qcom: add QUniPro hardware support and power optimizations
Documentation/devicetree/bindings/ufs/ufs-qcom.txt | 58 ++ .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 11 +- drivers/phy/phy-qcom-ufs.c | 11 + drivers/scsi/ufs/Kconfig | 2 +- drivers/scsi/ufs/ufs-qcom.c | 905 ++++++++++++++++----- drivers/scsi/ufs/ufs-qcom.h | 68 +- drivers/scsi/ufs/ufshcd-pltfrm.c | 98 +-- drivers/scsi/ufs/ufshcd-pltfrm.h | 41 + drivers/scsi/ufs/ufshcd.c | 122 ++- drivers/scsi/ufs/ufshcd.h | 149 +++- 10 files changed, 1127 insertions(+), 338 deletions(-) create mode 100644 Documentation/devicetree/bindings/ufs/ufs-qcom.txt create mode 100644 drivers/scsi/ufs/ufshcd-pltfrm.h
Signature · 4 lines
1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
PATCH v9 1/8 phy: qcom-ufs: fix build error when the component is built as a module
Export the following functions in order to avoid build errors when the component PHY_QCOM_UFS is compiled as a module:
ERROR: "ufs_qcom_phy_disable_ref_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_enable_ref_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_is_pcs_ready"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_disable_iface_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_start_serdes"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_calibrate_phy"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_enable_dev_ref_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_set_tx_lane_enable"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_disable_dev_ref_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_save_controller_version"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_enable_iface_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
make[1]: *** [__modpost] Error 1
--- drivers/phy/phy-qcom-ufs.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/phy/phy-qcom-ufs.c +11 -0
@@ -432,6 +432,7 @@ out_disable_src: out:return ret; } +EXPORT_SYMBOL_GPL (ufs_qcom_phy_enable_ref_clk); static int ufs_qcom_phy_disable_vreg(struct phy *phy,
@@ -474,6 +475,7 @@ void ufs_qcom_phy_disable_ref_clk(struct phy *generic_phy) phy->is_ref_clk_enabled = false; } } +EXPORT_SYMBOL_GPL (ufs_qcom_phy_disable_ref_clk);#define UFS_REF_CLK_EN (1 << 5)
@@ -517,11 +519,13 @@ 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)
@@ -550,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)
@@ -562,6 +567,7 @@ 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_start_serdes (struct phy *generic_phy) {
@@ -578,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) {
@@ -595,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)
@@ -605,6 +613,7 @@ 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) {
@@ -625,6 +634,7 @@ 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)
@@ -662,6 +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); } +EXPORT_SYMBOL_GPL (ufs_qcom_phy_is_pcs_ready);int ufs_qcom_phy_power_on (struct phy *generic_phy) {
Signature · 4 lines
1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Re: [PATCH v9 1/8] phy: qcom-ufs: fix build error when the component is built as a module
Quoted 27 lines · Yaniv Gardi
Export the following functions in order to avoid build errors when the component
PHY_QCOM_UFSis compiled as a module:ERROR: "
ufs_qcom_phy_disable_ref_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_enable_ref_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_is_pcs_ready"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_disable_iface_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_start_serdes"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_calibrate_phy"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_enable_dev_ref_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_set_tx_lane_enable"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_disable_dev_ref_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_save_controller_version"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
ERROR: "ufs_qcom_phy_enable_iface_clk"
[drivers/scsi/ufs/ufs-qcom.ko] undefined!
make[1]: *** [__modpost] Error 1
Quoted 9 lines
Reviewed-by Akinobu Mita <[email protected]>Reviewed-by Subhash Jadavani <[email protected]>Reviewed-by Gilad Broner <[email protected]>Signed-off-by Yaniv Gardi <[email protected]>--- drivers/phy/phy-qcom-ufs.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
PATCH v9 2/8 scsi: ufs-qcom: fix compilation warning if compiled as a module
In reply to Yaniv GardiThis change fixes a compilation warning that happens if SCSI_UFS_QCOM is compiled as a module.
Also this patch fixes an error happens when insmod the module:
"ufs_qcom: module license 'unspecified' taints kernel."
--- drivers/scsi/ufs/ufs-qcom.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/scsi/ufs/ufs-qcom.c +6 -1
@@ -917,12 +917,15 @@ out:#define ANDROID_BOOT_DEV_MAX 30static char android_boot_dev[ANDROID_BOOT_DEV_MAX ]; -static int get_android_boot_dev (char *str) + +#ifndef MODULE +static int __init get_android_boot_dev (char *str) {strlcpy (android_boot_dev, str,ANDROID_BOOT_DEV_MAX );return 1 ; }__setup ("androidboot.bootdevice=" , get_android_boot_dev); +#endif /** * ufs_qcom_init - bind phy with controller
@@ -1047,3 +1050,5 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .resume = ufs_qcom_resume, };EXPORT_SYMBOL (ufs_hba_qcom_vops); + +MODULE_LICENSE ("GPL v2" );
Signature · 4 lines
1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Re: [PATCH v9 2/8] scsi: ufs-qcom: fix compilation warning if compiled as a module
Quoted 10 lines · Yaniv Gardi
This change fixes a compilation warning that happens if
SCSI_UFS_QCOMis compiled as a module.
Also this patch fixes an error happens when insmod the module:
"ufs_qcom: module license 'unspecified' taints kernel."Reviewed-by Akinobu Mita <[email protected]>Reviewed-by Subhash Jadavani <[email protected]>Reviewed-by Gilad Broner <[email protected]>Signed-off-by Yaniv Gardi <[email protected]>
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
PATCH v9 3/8 scsi: ufs-qcom: update configuration option of SCSI_UFS_QCOM component
In reply to Yaniv GardiThis change is required in order to be able to build the component as a module.
--- drivers/scsi/ufs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/ufs/Kconfig +1 -1
@@ -72,7 +72,7 @@ config SCSI_UFSHCD_PLATFORM If unsure, say N. config SCSI_UFS_QCOM - bool "QCOM specific hooks to UFS controller platform driver" + tristate "QCOM specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM select PHY_QCOM_UFS help
Signature · 4 lines
1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Re: [PATCH v9 3/8] scsi: ufs-qcom: update configuration option of SCSI_UFS_QCOM component
Quoted 18 lines · Yaniv Gardi
This change is required in order to be able to build the component as a module.
Reviewed-by Akinobu Mita <[email protected]>Reviewed-by Subhash Jadavani <[email protected]>Reviewed-by Gilad Broner <[email protected]>Signed-off-by Yaniv Gardi <[email protected]>--- drivers/scsi/ufs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/scsi/ufs/Kconfig +0
-0
drivers/scsi/ufs/Kconfig config SCSI_UFSHCD_PLATFORM · line 78
Quoted 8 lines
drivers/scsi/ufs/Kconfig +1
-1@@ -72,7 +72,7 @@ config SCSI_UFSHCD_PLATFORM If unsure, say N. config SCSI_UFS_QCOM - bool "QCOM specific hooks to UFS controller platform driver" + tristate "QCOM specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM select PHY_QCOM_UFS help
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
PATCH v9 4/8 scsi: ufs: add ufshcd_get_variant ufshcd_set_variant
In reply to Yaniv GardiThis patch adds ufshcd_get_variant() and ufshcd_set_variant() routines in order to get/set the variant specific data.
--- drivers/scsi/ufs/ufs-qcom.c | 34 +++++++++++++++++----------------- drivers/scsi/ufs/ufshcd.h | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+), 17 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +17 -17
@@ -155,7 +155,7 @@ out:static int ufs_qcom_link_startup_post_change (struct ufs_hba *hba) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);struct phy *phy = host->generic_phy;u32 tx_lanes;int err =0 ;
@@ -211,7 +211,7 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba)static int ufs_qcom_power_up_sequence (struct ufs_hba *hba) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);struct phy *phy = host->generic_phy;int ret =0 ;bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE ==PA_HS_MODE_B )
@@ -273,7 +273,7 @@ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)static int ufs_qcom_hce_enable_notify (struct ufs_hba *hba,bool status) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);int err =0 ;switch (status) {
@@ -307,7 +307,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status)static unsigned long ufs_qcom_cfg_timers (struct ufs_hba *hba,u32 gear,u32 hs,u32 rate) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);struct ufs_clk_info *clki;u32 core_clk_period_in_ns;u32 tx_clk_cycles_per_us =0 ;
@@ -448,7 +448,7 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status)static int ufs_qcom_suspend (struct ufs_hba *hba,enum ufs_pm_op pm_op) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);struct phy *phy = host->generic_phy;int ret =0 ;
@@ -479,7 +479,7 @@ out:static int ufs_qcom_resume (struct ufs_hba *hba,enum ufs_pm_op pm_op) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);struct phy *phy = host->generic_phy;int err;
@@ -621,7 +621,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) {u32 val; -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);struct phy *phy = host->generic_phy;struct ufs_qcom_dev_params ufs_qcom_cap;int ret =0 ;
@@ -696,7 +696,7 @@ out:static u32 ufs_qcom_get_ufs_hci_version (struct ufs_hba *hba) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);if (host->hw_ver.major ==0x1 )return UFSHCI_VERSION_11 ;
@@ -715,7 +715,7 @@ static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba)*/ static void ufs_qcom_advertise_quirks (struct ufs_hba *hba) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);if (host->hw_ver.major ==0x01 ) { hba->quirks |=UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
@@ -740,7 +740,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)static void ufs_qcom_set_caps (struct ufs_hba *hba) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);if (host->hw_ver.major >=0x2 ) host->caps =UFS_QCOM_CAP_QUNIPRO ;
@@ -811,7 +811,7 @@ static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result)static int ufs_qcom_setup_clocks (struct ufs_hba *hba,bool on) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);int err =0 ;int vote =0 ;
@@ -866,7 +866,7 @@ show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, char *buf) {struct ufs_hba *hba =dev_get_drvdata (dev); -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);return snprintf (buf,PAGE_SIZE ,"%u\n" , host->bus_vote.is_max_bw_needed);
@@ -877,7 +877,7 @@ store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) {struct ufs_hba *hba =dev_get_drvdata (dev); -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);uint32_t value;if (!kstrtou32 (buf,0 , &value)) {
@@ -954,7 +954,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) } host->hba = hba; - hba->priv = (void *)host; +ufshcd_set_variant (hba, host); host->generic_phy =devm_phy_get (dev,"ufsphy" );
@@ -1003,14 +1003,14 @@ out_unregister_bus:phy_exit (host->generic_phy); out_host_free:devm_kfree (dev, host); - hba->priv =NULL ; +ufshcd_set_variant (hba,NULL ); out:return err; }static void ufs_qcom_exit (struct ufs_hba *hba) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);ufs_qcom_disable_lane_clks (host);phy_power_off (host->generic_phy);
@@ -1019,7 +1019,7 @@ static void ufs_qcom_exit(struct ufs_hba *hba)static void ufs_qcom_clk_scale_notify (struct ufs_hba *hba) { -struct ufs_qcom_host *host = hba->priv; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params;if (!dev_req_params)
drivers/scsi/ufs/ufshcd.h +21 -0
@@ -594,6 +594,27 @@ static inline void check_upiu_size(void) GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE); } +/** +* ufshcd_set_variant - set variant specific data to the hba +* @hba - per adapter instance +* @variant - pointer to variant specific data +*/ +static inline void ufshcd_set_variant (struct ufs_hba *hba,void *variant) +{ +BUG_ON (!hba); + hba->priv = variant; +} + +/** +* ufshcd_get_variant - get variant specific data from the hba +* @hba - per adapter instance +*/ +static inline void *ufshcd_get_variant (struct ufs_hba *hba) +{ +BUG_ON (!hba); +return hba->priv; +} +extern int ufshcd_runtime_suspend (struct ufs_hba *hba);extern int ufshcd_runtime_resume (struct ufs_hba *hba);extern int ufshcd_runtime_idle (struct ufs_hba *hba);
Signature · 4 lines
1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Re: [PATCH v9 4/8] scsi: ufs: add ufshcd_get_variant ufshcd_set_variant
Quoted 8 lines · Yaniv Gardi
This patch adds
ufshcd_get_variant()andufshcd_set_variant()routines in order to get/set the variant specific data.Reviewed-by Akinobu Mita <[email protected]>Reviewed-by Subhash Jadavani <[email protected]>Reviewed-by Gilad Broner <[email protected]>Signed-off-by Yaniv Gardi <[email protected]>
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
PATCH v9 5/8 scsi: ufs: creates wrapper functions for vops
In reply to Yaniv GardiIn order to simplify the code a set of wrapper functions is created to test and call each of the variant operations.
--- drivers/scsi/ufs/ufs-qcom.c | 1 - drivers/scsi/ufs/ufshcd.c | 104 +++++++++++++++++--------------------------- drivers/scsi/ufs/ufshcd.h | 98 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 66 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +0 -1
@@ -1049,6 +1049,5 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .suspend = ufs_qcom_suspend, .resume = ufs_qcom_resume, }; -EXPORT_SYMBOL (ufs_hba_qcom_vops);MODULE_LICENSE ("GPL v2" );
drivers/scsi/ufs/ufshcd.c +39 -65
211 lines not on this page · raw message
drivers/scsi/ufs/ufshcd.h +98 -0
102 lines not on this page · raw message
Signature · 4 lines
1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Re: [PATCH v9 5/8] scsi: ufs: creates wrapper functions for vops
Quoted 8 lines · Yaniv Gardi
In order to simplify the code a set of wrapper functions is created to test and call each of the variant operations.
Reviewed-by Akinobu Mita <[email protected]>Reviewed-by Subhash Jadavani <[email protected]>Reviewed-by Gilad Broner <[email protected]>Signed-off-by Yaniv Gardi <[email protected]>
Quoted 6 lines
--- drivers/scsi/ufs/ufs-qcom.c | 1 - drivers/scsi/ufs/ufshcd.c | 104 +++++++++++++++++--------------------------- drivers/scsi/ufs/ufshcd.h | 98 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 66 deletions(-)
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
PATCH v9 6/8 scsi: ufs: make the UFS variant a platform device
In reply to Yaniv GardiThis change turns the UFS variant (SCSI_UFS_QCOM) into a UFS a platform device.
In order to do so a few additional changes are required:
1. The ufshcd-pltfrm is no longer serves as a platform device. Now it only serves as a group of platform APIs such as PM APIs (runtime suspend/resume, system suspend/resume etc), parsers of clocks, regulators and pm_levels from DT.
2. What used to be the old platform "probe" is now "only" a pltfrm_init() routine, that does exactly the same, but only being called by the new probe function of the UFS variant.
--- Documentation/devicetree/bindings/ufs/ufs-qcom.txt | 58 +++++++++++++ .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 11 ++- drivers/scsi/ufs/ufs-qcom.c | 62 +++++++++++++- drivers/scsi/ufs/ufshcd-pltfrm.c | 98 ++++++---------------- drivers/scsi/ufs/ufshcd-pltfrm.h | 41 +++++++++ drivers/scsi/ufs/ufshcd.c | 10 +++ drivers/scsi/ufs/ufshcd.h | 1 + 7 files changed, 207 insertions(+), 74 deletions(-) create mode 100644 Documentation/devicetree/bindings/ufs/ufs-qcom.txt create mode 100644 drivers/scsi/ufs/ufshcd-pltfrm.h
Documentation/devicetree/bindings/ufs/ufs-qcom.txt new file +58 -0
@@ -0,0 +1,58 @@ +* Qualcomm Technologies Inc Universal Flash Storage (UFS) PHY + +UFSPHY nodes are defined to describe on-chip UFS PHY hardware macro. +Each UFS PHY node should have its own node. + +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,ufs-phy-qmp-20nm" + or "qcom,ufs-phy-qmp-14nm" according to the relevant phy in use. +- reg : should contain PHY register address space (mandatory), +- reg-names : indicates various resources passed to driver (via reg proptery) by name. + Required "reg-names" is "phy_mem". +- #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 +- clocks : List of phandle and clock specifier pairs +- clock-names : List of clock input name strings sorted in the same + order as the clocks property. "ref_clk_src", "ref_clk", + "tx_iface_clk" & "rx_iface_clk" are mandatory but + "ref_clk_parent" is optional + +Optional properties: +- vdda-phy-max-microamp : specifies max. load that can be drawn from phy supply +- vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply +- vddp-ref-clk-supply : phandle to UFS device ref_clk pad power supply +- vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply +- vddp-ref-clk-always-on : specifies if this supply needs to be kept always on + +Example: + + ufsphy1: ufsphy@0xfc597000 { + compatible = "qcom,ufs-phy-qmp-20nm"; + reg = <0xfc597000 0x800>; + reg-names = "phy_mem"; + #phy-cells = <0>; + vdda-phy-supply = <&pma8084_l4>; + vdda-pll-supply = <&pma8084_l12>; + vdda-phy-max-microamp = <50000>; + vdda-pll-max-microamp = <1000>; + clock-names = "ref_clk_src", + "ref_clk_parent", + "ref_clk", + "tx_iface_clk", + "rx_iface_clk"; + clocks = <&clock_rpm clk_ln_bb_clk>, + <&clock_gcc clk_pcie_1_phy_ldo >, + <&clock_gcc clk_ufs_phy_ldo>, + <&clock_gcc clk_gcc_ufs_tx_cfg_clk>, + <&clock_gcc clk_gcc_ufs_rx_cfg_clk>; + }; + + ufshc@0xfc598000 { + ... + phys = <&ufsphy1>; + phy-names = "ufsphy"; + };
Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +10 -1
@@ -4,11 +4,18 @@ UFSHC nodes are defined to describe on-chip UFS host controllers. Each UFS controller instance should have its own node. Required properties: -- compatible : compatible list, contains "jedec,ufs-1.1" +- compatible : must contain "jedec,ufs-1.1", may also list one or more + of the following: + "qcom,msm8994-ufshc" + "qcom,msm8996-ufshc" + "qcom,ufshc" - interrupts : <interrupt mapping for UFS host controller IRQ> - reg : <registers mapping> Optional properties: +- phys : phandle to UFS PHY node +- phy-names : the string "ufsphy" when is found in a node, along + with "phys" attribute, provides phandle to UFS PHY node - vdd-hba-supply : phandle to UFS host controller supply regulator node - vcc-supply : phandle to VCC supply regulator node - vccq-supply : phandle to VCCQ supply regulator node
@@ -54,4 +61,6 @@ Example: clocks = <&core 0>, <&ref 0>, <&iface 0>; clock-names = "core_clk", "ref_clk", "iface_clk"; freq-table-hz = <100000000 200000000>, <0 0>, <0 0>; + phys = <&ufsphy1>; + phy-names = "ufsphy"; };
drivers/scsi/ufs/ufs-qcom.c +61 -1
78 lines not on this page · raw message
drivers/scsi/ufs/ufshcd-pltfrm.c +26 -72
168 lines not on this page · raw message
drivers/scsi/ufs/ufshcd-pltfrm.h new file +41 -0
41 lines not on this page · raw message
drivers/scsi/ufs/ufshcd.c +10 -0
@@ -5348,6 +5348,16 @@ void ufshcd_remove(struct ufs_hba *hba)EXPORT_SYMBOL_GPL (ufshcd_remove);/** +* ufshcd_dealloc_host - deallocate Host Bus Adapter (HBA) +* @hba: pointer to Host Bus Adapter (HBA) +*/ +void ufshcd_dealloc_host (struct ufs_hba *hba) +{ +scsi_host_put (hba->host); +} +EXPORT_SYMBOL_GPL (ufshcd_dealloc_host); + +/** * ufshcd_set_dma_mask - Set dma mask based on the controller * addressing capability * @hba: per adapter instance
drivers/scsi/ufs/ufshcd.h +1 -0
@@ -576,6 +576,7 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg) }int ufshcd_alloc_host (struct device *,struct ufs_hba **); +void ufshcd_dealloc_host (struct ufs_hba *);int ufshcd_init (struct ufs_hba * ,void __iomem * ,unsigned int );void ufshcd_remove (struct ufs_hba *);
Signature · 4 lines
1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Re: [PATCH v9 6/8] scsi: ufs: make the UFS variant a platform device
Quoted 11 lines · Yaniv Gardi
This change turns the UFS variant (
SCSI_UFS_QCOM) into a UFS a platform device.
In order to do so a few additional changes are required:
1. The ufshcd-pltfrm is no longer serves as a platform device. Now it only serves as a group of platform APIs such as PM APIs (runtime suspend/resume, system suspend/resume etc), parsers of clocks, regulators andpm_levelsfrom DT.
2. What used to be the old platform "probe" is now "only" apltfrm_init()routine, that does exactly the same, but only being called by the new probe function of the UFS variant.
Quoted 4 lines
Reviewed-by Rob Herring <[email protected]>Reviewed-by Gilad Broner <[email protected]>Signed-off-by Yaniv Gardi <[email protected]>
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
PATCH v9 7/8 scsi: ufs-qcom: add debug prints for test bus
In reply to Yaniv GardiAdds support for configuring and reading the test bus and debug registers. This change also adds another vops in order to print the debug registers.
--- drivers/scsi/ufs/ufs-qcom.c | 165 +++++++++++++++++++++++++++++++++++++++++++- drivers/scsi/ufs/ufs-qcom.h | 37 +++++++++- drivers/scsi/ufs/ufshcd.c | 2 + drivers/scsi/ufs/ufshcd.h | 8 +++ 4 files changed, 208 insertions(+), 4 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +162 -3
@@ -23,6 +23,24 @@#include "unipro.h" #include "ufs-qcom.h" #include "ufshci.h" +#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ + (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) + +enum { +TSTBUS_UAWM , +TSTBUS_UARM , +TSTBUS_TXUC , +TSTBUS_RXUC , +TSTBUS_DFC , +TSTBUS_TRLUT , +TSTBUS_TMRLUT , +TSTBUS_OCSC , +TSTBUS_UTP_HCI , +TSTBUS_COMBINED , +TSTBUS_WRAPPER , +TSTBUS_UNIPRO , +TSTBUS_MAX , +};static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS ];
@@ -30,6 +48,15 @@ static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result);static int ufs_qcom_get_bus_vote (struct ufs_qcom_host *host,const char *speed_mode);static int ufs_qcom_set_bus_vote (struct ufs_qcom_host *host,int vote); +static void ufs_qcom_get_default_testbus_cfg (struct ufs_qcom_host *host); +static void ufs_qcom_dump_regs (struct ufs_hba *hba,int offset,int len, +char *prefix) +{ +print_hex_dump (KERN_ERR , prefix, + len >4 ?DUMP_PREFIX_OFFSET :DUMP_PREFIX_NONE , +16 ,4 , (void __force *)hba->mmio_base + offset, + len *4 , false); +}static int ufs_qcom_get_connected_tx_lanes (struct ufs_hba *hba,u32 *tx_lanes) {
@@ -996,6 +1023,15 @@ static int ufs_qcom_init(struct ufs_hba *hba)if (hba->dev->id <MAX_UFS_QCOM_HOSTS ) ufs_qcom_hosts[hba->dev->id] = host; + host->dbg_print_en |=UFS_QCOM_DEFAULT_DBG_PRINT_EN ; +ufs_qcom_get_default_testbus_cfg (host); + err =ufs_qcom_testbus_config (host); +if (err) { +dev_warn (dev,"%s: failed to configure the testbus %d\n" , + __func__, err); + err =0 ; + } + goto out; out_disable_phy:
@@ -1025,12 +1061,134 @@ void ufs_qcom_clk_scale_notify(struct ufs_hba *hba)if (!dev_req_params)return ; +} + +static void ufs_qcom_get_default_testbus_cfg (struct ufs_qcom_host *host) +{ +/* provide a legal default configuration */ + host->testbus.select_major =TSTBUS_UAWM ; + host->testbus.select_minor =1 ; +} + +static bool ufs_qcom_testbus_cfg_is_ok (struct ufs_qcom_host *host) +{ +if (host->testbus.select_major >=TSTBUS_MAX ) { +dev_err (host->hba->dev, +"%s: UFS_CFG1[TEST_BUS_SEL} may not equal 0x%05X\n" , + __func__, host->testbus.select_major); +return false; + } + +/* +* Not performing check for each individual select_major +* mappings of select_minor, since there is no harm in +* configuring a non-existent select_minor +*/ +if (host->testbus.select_minor >0x1F ) { +dev_err (host->hba->dev, +"%s: 0x%05X is not a legal testbus option\n" , + __func__, host->testbus.select_minor); +return false; + } + +return true; +} + +int ufs_qcom_testbus_config (struct ufs_qcom_host *host) +{ +int reg; +int offset; +u32 mask =TEST_BUS_SUB_SEL_MASK ; + +if (!host) +return -EINVAL ; -ufs_qcom_cfg_timers (hba, dev_req_params->gear_rx, - dev_req_params->pwr_rx, - dev_req_params->hs_rate); +if (!ufs_qcom_testbus_cfg_is_ok (host)) +return -EPERM ; + +switch (host->testbus.select_major) { +case TSTBUS_UAWM : + reg =UFS_TEST_BUS_CTRL_0 ; + offset =24 ; +break ; +case TSTBUS_UARM : + reg =UFS_TEST_BUS_CTRL_0 ; + offset =16 ; +break ; +case TSTBUS_TXUC : + reg =UFS_TEST_BUS_CTRL_0 ; + offset =8 ; +break ; +case TSTBUS_RXUC : + reg =UFS_TEST_BUS_CTRL_0 ; + offset =0 ; +break ; +case TSTBUS_DFC : + reg =UFS_TEST_BUS_CTRL_1 ; + offset =24 ; +break ; +case TSTBUS_TRLUT : + reg =UFS_TEST_BUS_CTRL_1 ; + offset =16 ; +break ; +case TSTBUS_TMRLUT : + reg =UFS_TEST_BUS_CTRL_1 ; + offset =8 ; +break ; +case TSTBUS_OCSC : + reg =UFS_TEST_BUS_CTRL_1 ; + offset =0 ; +break ; +case TSTBUS_WRAPPER : + reg =UFS_TEST_BUS_CTRL_2 ; + offset =16 ; +break ; +case TSTBUS_COMBINED : + reg =UFS_TEST_BUS_CTRL_2 ; + offset =8 ; +break ; +case TSTBUS_UTP_HCI : + reg =UFS_TEST_BUS_CTRL_2 ; + offset =0 ; +break ; +case TSTBUS_UNIPRO : + reg =UFS_UNIPRO_CFG ; + offset =1 ; +break ; +/* +* No need for a default case, since +* ufs_qcom_testbus_cfg_is_ok() checks that the configuration +* is legal +*/ + } + mask <<= offset; + +pm_runtime_get_sync (host->hba->dev); +ufshcd_hold (host->hba, false); +ufshcd_rmwl (host->hba,TEST_BUS_SEL , + (u32 )host->testbus.select_major <<19 , +REG_UFS_CFG1 ); +ufshcd_rmwl (host->hba, mask, + (u32 )host->testbus.select_minor << offset, + reg); +ufshcd_release (host->hba); +pm_runtime_put_sync (host->hba->dev); + +return 0 ; } +static void ufs_qcom_testbus_read (struct ufs_hba *hba) +{ +ufs_qcom_dump_regs (hba,UFS_TEST_BUS ,1 ,"UFS_TEST_BUS " ); +} + +static void ufs_qcom_dump_dbg_regs (struct ufs_hba *hba) +{ +ufs_qcom_dump_regs (hba,REG_UFS_SYS1CLK_1US ,16 , +"HCI Vendor Specific Registers " ); + +ufs_qcom_testbus_read (hba); +}/** * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations *
@@ -1049,6 +1207,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .pwr_change_notify = ufs_qcom_pwr_change_notify, .suspend = ufs_qcom_suspend, .resume = ufs_qcom_resume, + .dbg_register_dump = ufs_qcom_dump_dbg_regs, };/**
drivers/scsi/ufs/ufs-qcom.h +36 -1
@@ -58,6 +58,16 @@ enum {REG_UFS_CFG2 =0xE0 ,REG_UFS_HW_VERSION =0xE4 , +UFS_TEST_BUS =0xE8 , +UFS_TEST_BUS_CTRL_0 =0xEC , +UFS_TEST_BUS_CTRL_1 =0xF0 , +UFS_TEST_BUS_CTRL_2 =0xF4 , + UFS_UNIPRO_CFG = 0xF8, + +}; + +/* QCOM UFS host controller vendor specific debug registers */ +enum {UFS_DBG_RD_REG_UAWM =0x100 ,UFS_DBG_RD_REG_UARM =0x200 , UFS_DBG_RD_REG_TXUC = 0x300,
@@ -73,6 +83,9 @@ enum { UFS_UFS_DBG_RD_EDTL_RAM = 0x1900, }; +#define TEST_BUS_EN BIT(18) +#define TEST_BUS_SEL GENMASK(22, 19) +/* bit definitions for REG_UFS_CFG2 register */ #define UAWM_HW_CGC_EN (1 << 0)#define UARM_HW_CGC_EN (1 << 1)
@@ -83,6 +96,9 @@ enum {#define TMRLUT_HW_CGC_EN (1 << 6)#define OCSC_HW_CGC_EN (1 << 7) +/* 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 REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\ TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\ DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\
@@ -106,6 +122,15 @@ enum ufs_qcom_phy_init_type { UFS_PHY_INIT_CFG_RESTORE, }; +/* QCOM UFS debug print bit mask */ +#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0) +#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1) +#define UFS_QCOM_DBG_PRINT_TEST_BUS_EN BIT(2) + +#define UFS_QCOM_DBG_PRINT_ALL \ + (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \ + UFS_QCOM_DBG_PRINT_TEST_BUS_EN) +static inline void ufs_qcom_get_controller_revision (struct ufs_hba *hba,u8 *major,u16 *minor,u16 *step)
@@ -157,8 +182,13 @@ struct ufs_hw_version {u16 minor;u8 major; }; -struct ufs_qcom_host { +struct ufs_qcom_testbus { +u8 select_major; +u8 select_minor; +}; + +struct ufs_qcom_host {/* * Set this capability if host controller supports the QUniPro mode * and if driver wants the Host controller to operate in QUniPro mode.
@@ -179,12 +209,17 @@ struct ufs_qcom_host {bool is_lane_clks_enabled;struct ufs_hw_version hw_ver; +/* Bitmask for enabling debug prints */ +u32 dbg_print_en; +struct ufs_qcom_testbus testbus; };#define ufs_qcom_is_link_off (hba) ufshcd_is_link_off(hba)#define ufs_qcom_is_link_active (hba) ufshcd_is_link_active(hba)#define ufs_qcom_is_link_hibern8 (hba) ufshcd_is_link_hibern8(hba) +int ufs_qcom_testbus_config (struct ufs_qcom_host *host); +static inline bool ufs_qcom_cap_qunipro (struct ufs_qcom_host *host) {if (host->caps &UFS_QCOM_CAP_QUNIPRO )
drivers/scsi/ufs/ufshcd.c +2 -0
@@ -625,6 +625,7 @@ start: out:return rc; } +EXPORT_SYMBOL_GPL (ufshcd_hold);static void ufshcd_gate_work (struct work_struct *work) {
@@ -712,6 +713,7 @@ void ufshcd_release(struct ufs_hba *hba)__ufshcd_release (hba);spin_unlock_irqrestore (hba->host->host_lock, flags); } +EXPORT_SYMBOL_GPL (ufshcd_release);static ssize_t ufshcd_clkgate_delay_show (struct device *dev,struct device_attribute *attr,char *buf)
drivers/scsi/ufs/ufshcd.h +8 -0
@@ -259,6 +259,7 @@ struct ufs_pwr_mode_info {* to be set. * @suspend: called during host controller PM callback * @resume: called during host controller PM callback +* @dbg_register_dump: used to dump controller debug information */ struct ufs_hba_variant_ops {const char *name;
@@ -275,6 +276,7 @@ struct ufs_hba_variant_ops { struct ufs_pa_layer_attr *);int (*suspend)(struct ufs_hba *,enum ufs_pm_op );int (*resume)(struct ufs_hba *,enum ufs_pm_op ); +void (*dbg_register_dump)(struct ufs_hba *hba); };/* clock gating state */
@@ -773,4 +775,10 @@ static inline int ufshcd_vops_resume(struct ufs_hba *hba, enum ufs_pm_op op) return 0; } +static inline void ufshcd_vops_dbg_register_dump (struct ufs_hba *hba) +{ +if (hba->vops && hba->vops->dbg_register_dump) + hba->vops->dbg_register_dump (hba); +} +#endif /* End of Header */
Signature · 4 lines
1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Re: [PATCH v9 7/8] scsi: ufs-qcom: add debug prints for test bus
Quoted 8 lines · Yaniv Gardi
Adds support for configuring and reading the test bus and debug registers. This change also adds another vops in order to print the debug registers.
Reviewed-by Subhash Jadavani <[email protected]>Reviewed-by Gilad Broner <[email protected]>Signed-off-by Yaniv Gardi <[email protected]>
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
PATCH v9 8/8 scsi: ufs-qcom: add QUniPro hardware support and power optimizations
In reply to Yaniv GardiNew 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.
--- drivers/scsi/ufs/ufs-qcom.c | 640 ++++++++++++++++++++++++++++++++------------ drivers/scsi/ufs/ufs-qcom.h | 31 ++- drivers/scsi/ufs/ufshcd.c | 8 +- drivers/scsi/ufs/ufshcd.h | 27 +- 4 files changed, 525 insertions(+), 181 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +472 -168
@@ -44,11 +44,11 @@ enum {static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS ]; -static void ufs_qcom_get_speed_mode (struct ufs_pa_layer_attr *p,char *result); -static int ufs_qcom_get_bus_vote (struct ufs_qcom_host *host, -const char *speed_mode);static int ufs_qcom_set_bus_vote (struct ufs_qcom_host *host,int vote);static void ufs_qcom_get_default_testbus_cfg (struct ufs_qcom_host *host); +static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div (struct ufs_hba *hba, +u32 clk_cycles); +static void ufs_qcom_dump_regs (struct ufs_hba *hba,int offset,int len,char *prefix) {
@@ -177,6 +177,7 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) err =ufs_qcom_host_clk_get (dev,"tx_lane1_sync_clk" , &host->tx_l1_sync_clk); + out:return err; }
@@ -209,7 +210,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) do { err = ufshcd_dme_get(hba, - UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val); + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); if (err || tx_fsm_val == TX_FSM_HIBERN8) break;
@@ -223,7 +226,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba)*/ if (time_after (jiffies, timeout)) err =ufshcd_dme_get (hba, -UIC_ARG_MIB (MPHY_TX_FSM_STATE ), &tx_fsm_val); +UIC_ARG_MIB_SEL (MPHY_TX_FSM_STATE , +UIC_ARG_MPHY_TX_GEN_SEL_INDEX (0 )), + &tx_fsm_val);if (err) { dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n",
@@ -237,6 +242,15 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba)return err; } +static void ufs_qcom_select_unipro_mode (struct ufs_qcom_host *host) +{ +ufshcd_rmwl (host->hba,QUNIPRO_SEL , +ufs_qcom_cap_qunipro (host) ?QUNIPRO_SEL :0 , +REG_UFS_CFG1 ); +/* make sure above configuration is applied before we return */ +mb (); +} +static int ufs_qcom_power_up_sequence (struct ufs_hba *hba) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);
@@ -251,9 +265,11 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)usleep_range (1000 ,1100 ); ret =ufs_qcom_phy_calibrate_phy (phy, is_rate_B); +if (ret) { -dev_err (hba->dev,"%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n" , - __func__, ret); +dev_err (hba->dev, +"%s: ufs_qcom_phy_calibrate_phy()failed, ret = %d\n" , + __func__, ret); goto out; }
@@ -274,9 +290,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) ret =ufs_qcom_phy_is_pcs_ready (phy);if (ret) -dev_err (hba->dev,"%s: is_physical_coding_sublayer_ready() failed, ret = %d\n" , +dev_err (hba->dev, +"%s: is_physical_coding_sublayer_ready() failed, ret = %d\n" , __func__, ret); +ufs_qcom_select_unipro_mode (host); + out:return ret; }
@@ -299,7 +318,8 @@ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)mb (); } -static int ufs_qcom_hce_enable_notify (struct ufs_hba *hba,bool status) +static int ufs_qcom_hce_enable_notify (struct ufs_hba *hba, +enum ufs_notify_change_status status) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);int err =0 ;
@@ -329,12 +349,12 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status) }/** -* Returns non-zero for success (which rate of core_clk) and 0 -* in case of a failure +* Returns zero for success and non-zero in case of a failure */ -static unsigned long -ufs_qcom_cfg_timers (struct ufs_hba *hba,u32 gear,u32 hs,u32 rate) +static int ufs_qcom_cfg_timers (struct ufs_hba *hba,u32 gear, +u32 hs,u32 rate,bool update_link_startup_timer) { +int ret =0 ;struct ufs_qcom_host *host =ufshcd_get_variant (hba);struct ufs_clk_info *clki;u32 core_clk_period_in_ns;
@@ -352,11 +372,13 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)static u32 hs_fr_table_rA[][2 ] = { {UFS_HS_G1 ,0x1F }, {UFS_HS_G2 ,0x3e }, + {UFS_HS_G3 ,0x7D }, };static u32 hs_fr_table_rB[][2 ] = { {UFS_HS_G1 ,0x24 }, {UFS_HS_G2 ,0x49 }, + {UFS_HS_G3 ,0x92 }, };/*
@@ -384,7 +406,17 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) core_clk_rate =DEFAULT_CLK_RATE_HZ ; core_clk_cycles_per_us = core_clk_rate /USEC_PER_SEC ; -ufshcd_writel (hba, core_clk_cycles_per_us,REG_UFS_SYS1CLK_1US ); +if (ufshcd_readl (hba,REG_UFS_SYS1CLK_1US ) != core_clk_cycles_per_us) { +ufshcd_writel (hba, core_clk_cycles_per_us,REG_UFS_SYS1CLK_1US ); +/* +* make sure above write gets applied before we return from +* this function. +*/ +mb (); + } + +if (ufs_qcom_cap_qunipro (host)) + goto out; core_clk_period_in_ns =NSEC_PER_SEC / core_clk_rate; core_clk_period_in_ns <<=OFFSET_CLK_NS_REG ;
@@ -434,35 +466,59 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) goto out_error; } -/* this register 2 fields shall be written at once */ -ufshcd_writel (hba, core_clk_period_in_ns | tx_clk_cycles_per_us, -REG_UFS_TX_SYMBOL_CLK_NS_US ); +if (ufshcd_readl (hba,REG_UFS_TX_SYMBOL_CLK_NS_US ) != + (core_clk_period_in_ns | tx_clk_cycles_per_us)) { +/* this register 2 fields shall be written at once */ +ufshcd_writel (hba, core_clk_period_in_ns | tx_clk_cycles_per_us, +REG_UFS_TX_SYMBOL_CLK_NS_US ); +/* +* make sure above write gets applied before we return from +* this function. +*/ +mb (); + } + +if (update_link_startup_timer) { +ufshcd_writel (hba, ((core_clk_rate /MSEC_PER_SEC ) *100 ), +REG_UFS_PA_LINK_STARTUP_TIMER ); +/* +* make sure that this configuration is applied before +* we return +*/ +mb (); + } goto out; out_error: - core_clk_rate =0 ; + ret = -EINVAL ; out: -return core_clk_rate; +return ret; } -static int ufs_qcom_link_startup_notify (struct ufs_hba *hba,bool status) +static int ufs_qcom_link_startup_notify (struct ufs_hba *hba, +enum ufs_notify_change_status status) { -unsigned long core_clk_rate =0 ; -u32 core_clk_cycles_per_100ms; +int err =0 ; +struct ufs_qcom_host *host =ufshcd_get_variant (hba);switch (status) {case PRE_CHANGE : - core_clk_rate =ufs_qcom_cfg_timers (hba,UFS_PWM_G1 , -SLOWAUTO_MODE ,0 ); -if (!core_clk_rate) { +if (ufs_qcom_cfg_timers (hba,UFS_PWM_G1 ,SLOWAUTO_MODE , +0 , true)) {dev_err (hba->dev,"%s: ufs_qcom_cfg_timers() failed\n" , __func__); -return -EINVAL ; + err = -EINVAL ; + goto out; } - core_clk_cycles_per_100ms = - (core_clk_rate /MSEC_PER_SEC ) *100 ; -ufshcd_writel (hba, core_clk_cycles_per_100ms, -REG_UFS_PA_LINK_STARTUP_TIMER ); + +if (ufs_qcom_cap_qunipro (host)) +/* +* set unipro core clock cycles to 150 & clear clock +* divider +*/ + err =ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div (hba, +150 ); +break ;case POST_CHANGE :ufs_qcom_link_startup_post_change (hba);
@@ -471,7 +527,8 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status)break ; } -return 0 ; +out: +return err; }static int ufs_qcom_suspend (struct ufs_hba *hba,enum ufs_pm_op pm_op)
@@ -498,8 +555,10 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)* If UniPro link is not active, PHY ref_clk, main PHY analog power * rail and low noise analog power rail for PLL can be switched off. */ -if (!ufs_qcom_is_link_active (hba)) +if (!ufs_qcom_is_link_active (hba)) { +ufs_qcom_disable_lane_clks (host);phy_power_off (phy); + } out:return ret;
@@ -518,6 +577,10 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto out; } + err =ufs_qcom_enable_lane_clks (host); +if (err) + goto out; + hba->is_sys_suspended = false; out:
@@ -622,6 +685,81 @@ static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param,return 0 ; } +#ifdef CONFIG_MSM_BUS_SCALING +static int ufs_qcom_get_bus_vote (struct ufs_qcom_host *host, +const char *speed_mode) +{ +struct device *dev = host->hba->dev; +struct device_node *np = dev->of_node; +int err; +const char *key ="qcom,bus-vector-names" ; + +if (!speed_mode) { + err = -EINVAL ; + goto out; + } + +if (host->bus_vote.is_max_bw_needed && !!strcmp (speed_mode,"MIN" )) + err =of_property_match_string (np, key,"MAX" ); +else + err =of_property_match_string (np, key, speed_mode); + +out: +if (err <0 ) +dev_err (dev,"%s: Invalid %s mode %d\n" , + __func__, speed_mode, err); +return err; +} + +static void ufs_qcom_get_speed_mode (struct ufs_pa_layer_attr *p,char *result) +{ +int gear =max_t (u32, p->gear_rx, p->gear_tx); +int lanes =max_t (u32, p->lane_rx, p->lane_tx); +int pwr; + +/* default to PWM Gear 1, Lane 1 if power mode is not initialized */ +if (!gear) + gear =1 ; + +if (!lanes) + lanes =1 ; + +if (!p->pwr_rx && !p->pwr_tx) { + pwr =SLOWAUTO_MODE ; +snprintf (result,BUS_VECTOR_NAME_LEN ,"MIN" ); + }else if (p->pwr_rx ==FAST_MODE || p->pwr_rx ==FASTAUTO_MODE || + p->pwr_tx ==FAST_MODE || p->pwr_tx ==FASTAUTO_MODE ) { + pwr =FAST_MODE ; +snprintf (result,BUS_VECTOR_NAME_LEN ,"%s_R%s_G%d_L%d" ,"HS" , + p->hs_rate ==PA_HS_MODE_B ?"B" :"A" , gear, lanes); + }else { + pwr =SLOW_MODE ; +snprintf (result,BUS_VECTOR_NAME_LEN ,"%s_G%d_L%d" , +"PWM" , gear, lanes); + } +} + +static int ufs_qcom_set_bus_vote (struct ufs_qcom_host *host,int vote) +{ +int err =0 ; + +if (vote != host->bus_vote.curr_vote) { + err =msm_bus_scale_client_update_request ( + host->bus_vote.client_handle, vote); +if (err) { +dev_err (host->hba->dev, +"%s: msm_bus_scale_client_update_request() failed: bus_client_handle=0x%x, vote=%d, err=%d\n" , + __func__, host->bus_vote.client_handle, + vote, err); + goto out; + } + + host->bus_vote.curr_vote = vote; + } +out: +return err; +} +static int ufs_qcom_update_bus_bw_vote (struct ufs_qcom_host *host) {int vote;
@@ -643,8 +781,132 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)return err; } +static ssize_t +show_ufs_to_mem_max_bus_bw (struct device *dev,struct device_attribute *attr, +char *buf) +{ +struct ufs_hba *hba =dev_get_drvdata (dev); +struct ufs_qcom_host *host =ufshcd_get_variant (hba); + +return snprintf (buf,PAGE_SIZE ,"%u\n" , + host->bus_vote.is_max_bw_needed); +} + +static ssize_t +store_ufs_to_mem_max_bus_bw (struct device *dev,struct device_attribute *attr, +const char *buf,size_t count) +{ +struct ufs_hba *hba =dev_get_drvdata (dev); +struct ufs_qcom_host *host =ufshcd_get_variant (hba); +uint32_t value; + +if (!kstrtou32 (buf,0 , &value)) { + host->bus_vote.is_max_bw_needed = !!value; +ufs_qcom_update_bus_bw_vote (host); + } + +return count; +} + +static int ufs_qcom_bus_register (struct ufs_qcom_host *host) +{ +int err; +struct msm_bus_scale_pdata *bus_pdata; +struct device *dev = host->hba->dev; +struct platform_device *pdev =to_platform_device (dev); +struct device_node *np = dev->of_node; + + bus_pdata =msm_bus_cl_get_pdata (pdev); +if (!bus_pdata) { +dev_err (dev,"%s: failed to get bus vectors\n" , __func__); + err = -ENODATA ; + goto out; + } + + err =of_property_count_strings (np,"qcom,bus-vector-names" ); +if (err <0 || err != bus_pdata->num_usecases) { +dev_err (dev,"%s: qcom,bus-vector-names not specified correctly %d\n" , + __func__, err); + goto out; + } + + host->bus_vote.client_handle =msm_bus_scale_register_client (bus_pdata); +if (!host->bus_vote.client_handle) { +dev_err (dev,"%s: msm_bus_scale_register_client failed\n" , + __func__); + err = -EFAULT ; + goto out; + } + +/* cache the vote index for minimum and maximum bandwidth */ + host->bus_vote.min_bw_vote =ufs_qcom_get_bus_vote (host,"MIN" ); + host->bus_vote.max_bw_vote =ufs_qcom_get_bus_vote (host,"MAX" ); + + host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw; + host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw; +sysfs_attr_init (&host->bus_vote.max_bus_bw.attr); + host->bus_vote.max_bus_bw.attr.name ="max_bus_bw" ; + host->bus_vote.max_bus_bw.attr.mode =S_IRUGO |S_IWUSR ; + err =device_create_file (dev, &host->bus_vote.max_bus_bw); +out: +return err; +} +#else /* CONFIG_MSM_BUS_SCALING */ +static int ufs_qcom_update_bus_bw_vote (struct ufs_qcom_host *host) +{ +return 0 ; +} + +static int ufs_qcom_set_bus_vote (struct ufs_qcom_host *host,int vote) +{ +return 0 ; +} + +static int ufs_qcom_bus_register (struct ufs_qcom_host *host) +{ +return 0 ; +} +#endif /* CONFIG_MSM_BUS_SCALING */ + +static void ufs_qcom_dev_ref_clk_ctrl (struct ufs_qcom_host *host,bool enable) +{ +if (host->dev_ref_clk_ctrl_mmio && + (enable ^ host->is_dev_ref_clk_enabled)) { +u32 temp =readl_relaxed (host->dev_ref_clk_ctrl_mmio); + +if (enable) + temp |= host->dev_ref_clk_en_mask; +else + temp &= ~host->dev_ref_clk_en_mask; + +/* +* If we are here to disable this clock it might be immediately +* after entering into hibern8 in which case we need to make +* sure that device ref_clk is active at least 1us after the +* hibern8 enter. +*/ +if (!enable) +udelay (1 ); + +writel_relaxed (temp, host->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 at least 1us before the hibern8 +* exit command. +*/ +if (enable) +udelay (1 ); + + host->is_dev_ref_clk_enabled = enable; + } +} +static int ufs_qcom_pwr_change_notify (struct ufs_hba *hba, -bool status, +enum ufs_notify_change_status status,struct ufs_pa_layer_attr *dev_max_params,struct ufs_pa_layer_attr *dev_req_params) {
@@ -677,6 +939,20 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, ufs_qcom_cap.desired_working_mode =UFS_QCOM_LIMIT_DESIRED_MODE ; +if (host->hw_ver.major ==0x1 ) { +/* +* HS-G3 operations may not reliably work on legacy QCOM +* UFS host controller hardware even though capability +* exchange during link startup phase may end up +* negotiating maximum supported gear as G3. +* Hence downgrade the maximum supported gear to HS-G2. +*/ +if (ufs_qcom_cap.hs_tx_gear >UFS_HS_G2 ) + ufs_qcom_cap.hs_tx_gear =UFS_HS_G2 ; +if (ufs_qcom_cap.hs_rx_gear >UFS_HS_G2 ) + ufs_qcom_cap.hs_rx_gear =UFS_HS_G2 ; + } + ret =ufs_qcom_get_pwr_dev_param (&ufs_qcom_cap, dev_max_params, dev_req_params);
@@ -688,9 +964,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,break ;case POST_CHANGE : -if (!ufs_qcom_cfg_timers (hba, dev_req_params->gear_rx, +if (ufs_qcom_cfg_timers (hba, dev_req_params->gear_rx, dev_req_params->pwr_rx, - dev_req_params->hs_rate)) { + dev_req_params->hs_rate, false)) {dev_err (hba->dev,"%s: ufs_qcom_cfg_timers() failed\n" , __func__);/*
@@ -752,10 +1028,11 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)if (host->hw_ver.minor ==0x0001 && host->hw_ver.step ==0x0001 ) hba->quirks |=UFSHCD_QUIRK_BROKEN_INTR_AGGR ; + + hba->quirks |=UFSHCD_QUIRK_BROKEN_LCC ; }if (host->hw_ver.major >=0x2 ) { - hba->quirks |=UFSHCD_QUIRK_BROKEN_LCC ; hba->quirks |=UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION ;if (!ufs_qcom_cap_qunipro (host))
@@ -770,77 +1047,27 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba) {struct ufs_qcom_host *host =ufshcd_get_variant (hba); -if (host->hw_ver.major >=0x2 ) - host->caps =UFS_QCOM_CAP_QUNIPRO ; -} - -static int ufs_qcom_get_bus_vote (struct ufs_qcom_host *host, -const char *speed_mode) -{ -struct device *dev = host->hba->dev; -struct device_node *np = dev->of_node; -int err; -const char *key ="qcom,bus-vector-names" ; - -if (!speed_mode) { - err = -EINVAL ; - goto out; - } - -if (host->bus_vote.is_max_bw_needed && !!strcmp (speed_mode,"MIN" )) - err =of_property_match_string (np, key,"MAX" ); -else - err =of_property_match_string (np, key, speed_mode); - -out: -if (err <0 ) -dev_err (dev,"%s: Invalid %s mode %d\n" , - __func__, speed_mode, err); -return err; -} - -static int ufs_qcom_set_bus_vote (struct ufs_qcom_host *host,int vote) -{ -int err =0 ; - -if (vote != host->bus_vote.curr_vote) - host->bus_vote.curr_vote = vote; - -return err; -} - -static void ufs_qcom_get_speed_mode (struct ufs_pa_layer_attr *p,char *result) -{ -int gear =max_t (u32, p->gear_rx, p->gear_tx); -int lanes =max_t (u32, p->lane_rx, p->lane_tx); -int pwr; - -/* default to PWM Gear 1, Lane 1 if power mode is not initialized */ -if (!gear) - gear =1 ; - -if (!lanes) - lanes =1 ; + hba->caps |=UFSHCD_CAP_CLK_GATING |UFSHCD_CAP_HIBERN8_WITH_CLK_GATING ; + hba->caps |=UFSHCD_CAP_CLK_SCALING ; + hba->caps |=UFSHCD_CAP_AUTO_BKOPS_SUSPEND ; -if (!p->pwr_rx && !p->pwr_tx) { - pwr =SLOWAUTO_MODE ; -snprintf (result,BUS_VECTOR_NAME_LEN ,"MIN" ); - }else if (p->pwr_rx ==FAST_MODE || p->pwr_rx ==FASTAUTO_MODE || - p->pwr_tx ==FAST_MODE || p->pwr_tx ==FASTAUTO_MODE ) { - pwr =FAST_MODE ; -snprintf (result,BUS_VECTOR_NAME_LEN ,"%s_R%s_G%d_L%d" ,"HS" , - p->hs_rate ==PA_HS_MODE_B ?"B" :"A" , gear, lanes); - }else { - pwr =SLOW_MODE ; -snprintf (result,BUS_VECTOR_NAME_LEN ,"%s_G%d_L%d" , -"PWM" , gear, lanes); +if (host->hw_ver.major >=0x2 ) { + host->caps =UFS_QCOM_CAP_QUNIPRO | +UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE ; } } +/** +* ufs_qcom_setup_clocks - enables/disable clocks +* @hba: host controller instance +* @on: If true, enable clocks else disable them. +* +* Returns 0 on success, non-zero on failure. +*/ static int ufs_qcom_setup_clocks (struct ufs_hba *hba,bool on) {struct ufs_qcom_host *host =ufshcd_get_variant (hba); -int err =0 ; +int err;int vote =0 ;/*
@@ -863,20 +1090,18 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)ufs_qcom_phy_disable_iface_clk (host->generic_phy); goto out; } -/* enable the device ref clock */ -ufs_qcom_phy_enable_dev_ref_clk (host->generic_phy); vote = host->bus_vote.saved_vote;if (vote == host->bus_vote.min_bw_vote)ufs_qcom_update_bus_bw_vote (host); + }else { +/* M-PHY RMMI interface clocks can be turned off */ ufs_qcom_phy_disable_iface_clk (host->generic_phy); -if (!ufs_qcom_is_link_active (hba)) { -/* turn off UFS local PHY ref_clk */ -ufs_qcom_phy_disable_ref_clk (host->generic_phy); +if (!ufs_qcom_is_link_active (hba))/* disable device ref_clk */ -ufs_qcom_phy_disable_dev_ref_clk (host->generic_phy); - } +ufs_qcom_dev_ref_clk_ctrl (host, false); + vote = host->bus_vote.min_bw_vote; }
@@ -889,60 +1114,6 @@ out:return err; } -static ssize_t -show_ufs_to_mem_max_bus_bw (struct device *dev,struct device_attribute *attr, -char *buf) -{ -struct ufs_hba *hba =dev_get_drvdata (dev); -struct ufs_qcom_host *host =ufshcd_get_variant (hba); - -return snprintf (buf,PAGE_SIZE ,"%u\n" , - host->bus_vote.is_max_bw_needed); -} - -static ssize_t -store_ufs_to_mem_max_bus_bw (struct device *dev,struct device_attribute *attr, -const char *buf,size_t count) -{ -struct ufs_hba *hba =dev_get_drvdata (dev); -struct ufs_qcom_host *host =ufshcd_get_variant (hba); -uint32_t value; - -if (!kstrtou32 (buf,0 , &value)) { - host->bus_vote.is_max_bw_needed = !!value; -ufs_qcom_update_bus_bw_vote (host); - } - -return count; -} - -static int ufs_qcom_bus_register (struct ufs_qcom_host *host) -{ -int err; -struct device *dev = host->hba->dev; -struct device_node *np = dev->of_node; - - err =of_property_count_strings (np,"qcom,bus-vector-names" ); -if (err <0 ) { -dev_err (dev,"%s: qcom,bus-vector-names not specified correctly %d\n" , - __func__, err); - goto out; - } - -/* cache the vote index for minimum and maximum bandwidth */ - host->bus_vote.min_bw_vote =ufs_qcom_get_bus_vote (host,"MIN" ); - host->bus_vote.max_bw_vote =ufs_qcom_get_bus_vote (host,"MAX" ); - - host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw; - host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw; -sysfs_attr_init (&host->bus_vote.max_bus_bw.attr); - host->bus_vote.max_bus_bw.attr.name ="max_bus_bw" ; - host->bus_vote.max_bus_bw.attr.mode =S_IRUGO |S_IWUSR ; - err =device_create_file (dev, &host->bus_vote.max_bus_bw); -out: -return err; -} -#define ANDROID_BOOT_DEV_MAX 30static char android_boot_dev[ANDROID_BOOT_DEV_MAX ];
@@ -969,7 +1140,9 @@ static int ufs_qcom_init(struct ufs_hba *hba) {int err;struct device *dev = hba->dev; +struct platform_device *pdev =to_platform_device (dev);struct ufs_qcom_host *host; +struct resource *res;if (strlen (android_boot_dev) &&strcmp (android_boot_dev,dev_name (dev)))return -ENODEV ;
@@ -981,9 +1154,15 @@ static int ufs_qcom_init(struct ufs_hba *hba) goto out; } +/* Make a two way bind between the qcom host and the hba */ host->hba = hba;ufshcd_set_variant (hba, host); +/* +* voting/devoting device ref_clk source is time consuming hence +* skip devoting it during aggressive clock gating. This clock +* will still be gated off during runtime suspend. +*/ host->generic_phy =devm_phy_get (dev,"ufsphy" );if (IS_ERR (host->generic_phy)) {
@@ -999,6 +1178,30 @@ static int ufs_qcom_init(struct ufs_hba *hba)ufs_qcom_get_controller_revision (hba, &host->hw_ver.major, &host->hw_ver.minor, &host->hw_ver.step); +/* +* for newer controllers, device reference clock control bit has +* moved inside UFS controller register address space itself. +*/ +if (host->hw_ver.major >=0x02 ) { + host->dev_ref_clk_ctrl_mmio = hba->mmio_base +REG_UFS_CFG1 ; + host->dev_ref_clk_en_mask =BIT (26 ); + }else { +/* "dev_ref_clk_ctrl_mem" is optional resource */ + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); +if (res) { + host->dev_ref_clk_ctrl_mmio = +devm_ioremap_resource (dev, res); +if (IS_ERR (host->dev_ref_clk_ctrl_mmio)) { +dev_warn (dev, +"%s: could not map dev_ref_clk_ctrl_mmio, err %ld\n" , + __func__, +PTR_ERR (host->dev_ref_clk_ctrl_mmio)); + host->dev_ref_clk_ctrl_mmio =NULL ; + } + host->dev_ref_clk_en_mask =BIT (5 ); + } + } +/* update phy revision information before calling phy_init() */ ufs_qcom_phy_save_controller_version (host->generic_phy, host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
@@ -1015,9 +1218,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)ufs_qcom_set_caps (hba);ufs_qcom_advertise_quirks (hba); - hba->caps |=UFSHCD_CAP_CLK_GATING |UFSHCD_CAP_CLK_SCALING ; - hba->caps |=UFSHCD_CAP_AUTO_BKOPS_SUSPEND ; -ufs_qcom_setup_clocks (hba, true);if (hba->dev->id <MAX_UFS_QCOM_HOSTS )
@@ -1053,14 +1253,118 @@ static void ufs_qcom_exit(struct ufs_hba *hba)phy_power_off (host->generic_phy); } -static -void ufs_qcom_clk_scale_notify (struct ufs_hba *hba) +static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div (struct ufs_hba *hba, +u32 clk_cycles) +{ +int err; +u32 core_clk_ctrl_reg; + +if (clk_cycles >DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK ) +return -EINVAL ; + + err =ufshcd_dme_get (hba, +UIC_ARG_MIB (DME_VS_CORE_CLK_CTRL ), + &core_clk_ctrl_reg); +if (err) + goto out; + + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK ; + core_clk_ctrl_reg |= clk_cycles; + +/* Clear CORE_CLK_DIV_EN */ + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT ; + + err =ufshcd_dme_set (hba, +UIC_ARG_MIB (DME_VS_CORE_CLK_CTRL ), + core_clk_ctrl_reg); +out: +return err; +} + +static int ufs_qcom_clk_scale_up_pre_change (struct ufs_hba *hba) +{ +/* nothing to do as of now */ +return 0 ; +} + +static int ufs_qcom_clk_scale_up_post_change (struct ufs_hba *hba) +{ +struct ufs_qcom_host *host =ufshcd_get_variant (hba); + +if (!ufs_qcom_cap_qunipro (host)) +return 0 ; + +/* set unipro core clock cycles to 150 and clear clock divider */ +return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div (hba,150 ); +} + +static int ufs_qcom_clk_scale_down_pre_change (struct ufs_hba *hba) +{ +struct ufs_qcom_host *host =ufshcd_get_variant (hba); +int err; +u32 core_clk_ctrl_reg; + +if (!ufs_qcom_cap_qunipro (host)) +return 0 ; + + err =ufshcd_dme_get (hba, +UIC_ARG_MIB (DME_VS_CORE_CLK_CTRL ), + &core_clk_ctrl_reg); + +/* make sure CORE_CLK_DIV_EN is cleared */ +if (!err && + (core_clk_ctrl_reg &DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT )) { + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT ; + err =ufshcd_dme_set (hba, +UIC_ARG_MIB (DME_VS_CORE_CLK_CTRL ), + core_clk_ctrl_reg); + } + +return err; +} + +static int ufs_qcom_clk_scale_down_post_change (struct ufs_hba *hba) +{ +struct ufs_qcom_host *host =ufshcd_get_variant (hba); + +if (!ufs_qcom_cap_qunipro (host)) +return 0 ; + +/* set unipro core clock cycles to 75 and clear clock divider */ +return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div (hba,75 ); +} + +static int ufs_qcom_clk_scale_notify (struct ufs_hba *hba, +bool scale_up,enum ufs_notify_change_status status) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params; +int err =0 ; -if (!dev_req_params) -return ; +if (status ==PRE_CHANGE ) { +if (scale_up) + err =ufs_qcom_clk_scale_up_pre_change (hba); +else + err =ufs_qcom_clk_scale_down_pre_change (hba); + }else { +if (scale_up) + err =ufs_qcom_clk_scale_up_post_change (hba); +else + err =ufs_qcom_clk_scale_down_post_change (hba); + +if (err || !dev_req_params) + goto out; + +ufs_qcom_cfg_timers (hba, + dev_req_params->gear_rx, + dev_req_params->pwr_rx, + dev_req_params->hs_rate, + false); +ufs_qcom_update_bus_bw_vote (host); + } + +out: +return err; }static void ufs_qcom_get_default_testbus_cfg (struct ufs_qcom_host *host)
drivers/scsi/ufs/ufs-qcom.h +29 -2
@@ -35,8 +35,8 @@#define UFS_QCOM_LIMIT_NUM_LANES_RX 2#define UFS_QCOM_LIMIT_NUM_LANES_TX 2 -#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G2 -#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G2 +#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G3 +#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G3#define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4#define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4#define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE
@@ -64,6 +64,11 @@ enum {UFS_TEST_BUS_CTRL_2 =0xF4 ,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 */
@@ -83,6 +88,11 @@ enum { 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_SEL GENMASK(22, 19)
@@ -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_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 ufs_qcom_get_controller_revision (struct ufs_hba *hba,u8 *major,u16 *minor,u16 *step)
@@ -196,6 +212,12 @@ struct ufs_qcom_host {* controller supports the QUniPro mode. */ #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;struct phy *generic_phy;
@@ -208,7 +230,12 @@ struct ufs_qcom_host {struct clk *tx_l1_sync_clk;bool is_lane_clks_enabled; +void __iomem *dev_ref_clk_ctrl_mmio; +bool is_dev_ref_clk_enabled;struct ufs_hw_version hw_ver; + +u32 dev_ref_clk_en_mask; +/* Bitmask for enabling debug prints */ u32 dbg_print_en;struct ufs_qcom_testbus testbus;
drivers/scsi/ufs/ufshcd.c +7 -1
@@ -5420,6 +5420,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)if (!head ||list_empty (head)) goto out; + ret =ufshcd_vops_clk_scale_notify (hba, scale_up,PRE_CHANGE ); +if (ret) +return ret; +list_for_each_entry (clki, head, list) {if (!IS_ERR_OR_NULL (clki->clk)) {if (scale_up && clki->max_freq) {
@@ -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__, 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:return ret; }
drivers/scsi/ufs/ufshcd.h +17 -10
@@ -223,8 +223,10 @@ struct ufs_clk_info {bool enabled; }; -#define PRE_CHANGE 0 -#define POST_CHANGE 1 +enum ufs_notify_change_status { +PRE_CHANGE , +POST_CHANGE , +};struct ufs_pa_layer_attr {u32 gear_rx;
@@ -266,13 +268,17 @@ struct ufs_hba_variant_ops {int (*init)(struct ufs_hba *);void (*exit)(struct ufs_hba *);u32 (*get_ufs_hci_version)(struct ufs_hba *); -void (*clk_scale_notify)(struct ufs_hba *); -int (*setup_clocks)(struct ufs_hba *,bool ); +int (*clk_scale_notify)(struct ufs_hba *,bool , +enum ufs_notify_change_status ); +int (*setup_clocks)(struct ufs_hba *,bool );int (*setup_regulators)(struct ufs_hba *,bool ); -int (*hce_enable_notify)(struct ufs_hba *,bool ); -int (*link_startup_notify)(struct ufs_hba *,bool ); +int (*hce_enable_notify)(struct ufs_hba *, +enum ufs_notify_change_status ); +int (*link_startup_notify)(struct ufs_hba *, +enum ufs_notify_change_status );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 *);int (*suspend)(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)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) -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) {if (hba->vops && hba->vops->setup_clocks)return hba->vops->setup_clocks (hba, on); -return 0 ; }
Signature · 4 lines
1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Re: [PATCH v9 8/8] scsi: ufs-qcom: add QUniPro hardware support and power optimizations
Quoted 11 lines · Yaniv Gardi
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 Subhash Jadavani <[email protected]>Reviewed-by Gilad Broner <[email protected]>Signed-off-by Yaniv Gardi <[email protected]>
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
Hi Yaniv,
Quoted 25 lines · Yaniv Gardi
V9: update commit message with Reviewed-by
and update commit message of patch 4/8V8: add phy attributes to UFS devicetree documentation file
V7: removed additional dead code
V6: removed dead code from
ufs-qcom.cand added calling toufshcd_dealloc_host()inufshcd-pltfrm.cin case of an error after a successfullufshcd_alloc_host()V5: removed a redundant null check
V4: add file
Documentation/devicetree/bindings/ufs/ufs-qcom.txtand modify the compatible strings inDocumentation/devicetree/bindings/ufs/ufshcd-pltfrm.txtV3: fixes a few minor issues.
V2: fixes a few issues of unnecessary
EXPORT_SYMBOL, types of parameters in routine definition, build errors in caseCONFIG_PMis not defined and some other minor fixes.
Quoted 7 lines
Yaniv Gardi (8):
phy: qcom-ufs: fix build error when the component is built as a module
scsi: ufs-qcom: fix compilation warning if compiled as a module
scsi: ufs-qcom: update configuration option ofSCSI_UFS_QCOMcomponent
scsi: ufs: addufshcd_get_variantufshcd_set_variant
scsi: ufs: creates wrapper functions for vops
scsi: ufs: make the UFS variant a platform device
for patch 4 ~ 6, ufshcd bits, have tested on a exynos variant, so feel free to add
Quoted 26 lines
scsi: ufs-qcom: add debug prints for test bus
scsi: ufs-qcom: add QUniPro hardware support and power optimizationsDocumentation/devicetree/bindings/ufs/ufs-qcom.txt | 58 ++ .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 11 +- drivers/phy/phy-qcom-ufs.c | 11 + drivers/scsi/ufs/Kconfig | 2 +- drivers/scsi/ufs/ufs-qcom.c | 905 ++++++++++++++++----- drivers/scsi/ufs/ufs-qcom.h | 68 +- drivers/scsi/ufs/ufshcd-pltfrm.c | 98 +-- drivers/scsi/ufs/ufshcd-pltfrm.h | 41 + drivers/scsi/ufs/ufshcd.c | 122 ++- drivers/scsi/ufs/ufshcd.h | 149 +++- 10 files changed, 1127 insertions(+), 338 deletions(-) create mode 100644 Documentation/devicetree/bindings/ufs/ufs-qcom.txt create mode 100644 drivers/scsi/ufs/ufshcd-pltfrm.h--
1.8.5.2--
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation --
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Regards, Alim
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
"Yaniv" == Yaniv Gardi <[email protected]> writes:
I have applied this series.
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering