ufs: Add Micron UFS HID support

As Micron said, Micron UFS HID could reuse SamSung HID driver, but need
change some flags and attibutes definitions.

Change-Id: If485cd01b6b69f1f14947fe84520c190262d966f
Reviewed-on: https://gerrit.mot.com/2085180
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Dongliang Yue <yuedl1@motorola.com>
Reviewed-by: Huosheng Liao <liaohs@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
zhucc2 2021-10-08 12:51:14 +08:00 • committed by Xiaojun Ji
commit f04f8628d3
4 changed files with 192 additions and 53 deletions

View file

@ -269,10 +269,16 @@ config SCSI_SKHID
bool "UFS Host Initiated Defrag supportr"
depends on (SCSI_UFSHCD || SCSI_UFSHCD_QTI)
help
Activate or deactive SKHPB driver
Activate or deactive SKHID driver
config MICRON_HPB
bool "Activate micron HPB Host-aware Performance Booster"
depends on SCSI_UFSHCD && UFSFEATURE && UFSHPB
help
Activate or deactive micron HPB driver
config MICRON_UFSHID
bool "UFS Host Initiated Defrag supportr"
depends on (SCSI_UFSHCD || SCSI_UFSHCD_QTI)
help
Activate or deactive micron hid driver

View file

@ -160,6 +160,9 @@ enum flag_idn {
QUERY_FLAG_IDN_TW_BUF_FLUSH_EN = 0x0F,
QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN = 0x10,
#endif
#if defined(CONFIG_MICRON_UFSHID)
QUERY_FLAG_IDN_HID_EN = 0x13
#endif
};
/* Attribute idn for Query requests */
@ -210,6 +213,10 @@ enum attr_idn {
#if defined(CONFIG_UFSFEATURE)
QUERY_ATTR_IDN_SUP_VENDOR_OPTIONS = 0xFF,
#endif
#if defined(CONFIG_MICRON_UFSHID)
QUERY_ATTR_IDN_HID_FRAG_STATUS = 0x31,
QUERY_ATTR_IDN_HID_PROGRESS = 0x32,
#endif
};
#define QUERY_ATTR_IDN_BOOT_LU_EN_MAX 0x02

View file

@ -113,6 +113,54 @@ err_out:
return ret;
}
#if defined(CONFIG_MICRON_UFSHID)
static int ufshid_set_flag(struct ufshid_dev *hid, u8 idn)
{
struct ufs_hba *hba = hid->ufsf->hba;
int ret = 0;
bool flag_result;
pm_runtime_get_sync(hba->dev);
ret = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, idn, 0,
&flag_result);
if (ret) {
ERR_MSG("set flag [0x%.2X] fail. (%d)", idn, ret);
goto err_out;
}
HID_DEBUG(hid, "hid_flag set [0x%.2X] result [0x%.2X] ", idn, flag_result);
err_out:
pm_runtime_mark_last_busy(hba->dev);
pm_runtime_put_noidle(hba->dev);
return ret;
}
static int ufshid_clear_flag(struct ufshid_dev *hid, u8 idn)
{
struct ufs_hba *hba = hid->ufsf->hba;
int ret = 0;
pm_runtime_get_sync(hba->dev);
ret = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG, idn, 0,
NULL);
if (ret) {
ERR_MSG("clear flag [0x%.2X] fail. (%d)", idn, ret);
goto err_out;
}
HID_DEBUG(hid, "hid_flag set [0x%.2X] ", idn);
err_out:
pm_runtime_mark_last_busy(hba->dev);
pm_runtime_put_noidle(hba->dev);
return ret;
}
#endif
static inline int ufshid_version_check(int spec_version)
{
INFO_MSG("Support HID Spec : Driver = (%.4x), Device = (%.4x)",
@ -133,18 +181,27 @@ void ufshid_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf)
ufsf->hid_dev = NULL;
if (!(LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_EX_FEAT_SUP]) &
UFS_FEATURE_SUPPORT_HID_BIT)) {
INFO_MSG("bUFSExFeaturesSupport: HID not support");
goto err_out;
if(IS_SAMSUNG_DEVICE(storage_mfrid)) {
if (!(LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_EX_FEAT_SUP]) &
UFS_FEATURE_SUPPORT_HID_BIT)) {
INFO_MSG("bUFSExFeaturesSupport: HID not support");
goto err_out;
}
INFO_MSG("bUFSExFeaturesSupport: HID support");
spec_version =
LI_EN_16(&desc_buf[DEVICE_DESC_PARAM_HID_VER]);
ret = ufshid_version_check(spec_version);
if (ret)
goto err_out;
}
INFO_MSG("bUFSExFeaturesSupport: HID support");
spec_version =
LI_EN_16(&desc_buf[DEVICE_DESC_PARAM_HID_VER]);
ret = ufshid_version_check(spec_version);
if (ret)
#ifndef CONFIG_MICRON_UFSHID
if(IS_MICRON_DEVICE(storage_mfrid)){
INFO_MSG("micron: HID not support");
goto err_out;
}
#endif
ufsf->hid_dev = kzalloc(sizeof(struct ufshid_dev), GFP_KERNEL);
if (!ufsf->hid_dev) {
@ -163,39 +220,79 @@ static int ufshid_get_analyze_and_issue_execute(struct ufshid_dev *hid)
u32 attr_val;
int frag_level;
if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION,
HID_OP_EXECUTE))
if(IS_MICRON_DEVICE(storage_mfrid)) {
#if defined(CONFIG_MICRON_UFSHID)
//get micron ufs frag level
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_STATUS, &frag_level))
return -EINVAL;
//get micron ufs hid execution progress
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_PROGRESS, &attr_val))
return -EINVAL;
HID_DEBUG(hid, "micron frag_level= %d attr_val= %d",frag_level,attr_val);
if (attr_val != HID_PROG_ONGOING) {
if(frag_level!= HID_LEV_GREEN_MICRON) {
ufshid_set_flag(hid, QUERY_FLAG_IDN_HID_EN);
return HID_REQUIRED;
} else {
return HID_NOT_REQUIRED;
}
} else {
return HID_REQUIRED;
}
#else
return HID_NOT_REQUIRED;
#endif
} else if(IS_SAMSUNG_DEVICE(storage_mfrid)) {
if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION,
HID_OP_EXECUTE))
return -EINVAL;
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val))
return -EINVAL;
frag_level = attr_val & HID_FRAG_LEVEL_MASK;
HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d",
frag_level, HID_FRAG_UPDATE_STAT(attr_val),
HID_EXECUTE_REQ_STAT(attr_val));
if (frag_level == HID_LEV_GRAY)
return -EAGAIN;
return (HID_EXECUTE_REQ_STAT(attr_val)) ?
HID_REQUIRED : HID_NOT_REQUIRED;
} else {
return -EINVAL;
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val))
return -EINVAL;
frag_level = attr_val & HID_FRAG_LEVEL_MASK;
HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d",
frag_level, HID_FRAG_UPDATE_STAT(attr_val),
HID_EXECUTE_REQ_STAT(attr_val));
if (frag_level == HID_LEV_GRAY)
return -EAGAIN;
return (HID_EXECUTE_REQ_STAT(attr_val)) ?
HID_REQUIRED : HID_NOT_REQUIRED;
}
}
static int ufshid_issue_disable(struct ufshid_dev *hid)
{
u32 attr_val;
if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION,
HID_OP_DISABLE))
return -EINVAL;
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val))
return -EINVAL;
if(IS_MICRON_DEVICE(storage_mfrid)) {
#if defined(CONFIG_MICRON_UFSHID)
//get micron ufs hid execution progress
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_PROGRESS, &attr_val))
return -EINVAL;
HID_DEBUG(hid, "micron hid progress = %d",attr_val);
HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d",
attr_val & HID_FRAG_LEVEL_MASK,
HID_FRAG_UPDATE_STAT(attr_val),
HID_EXECUTE_REQ_STAT(attr_val));
if(attr_val == HID_PROG_ONGOING) {
if (ufshid_clear_flag(hid, QUERY_FLAG_IDN_HID_EN))
return -EINVAL;
}
#endif
}else if(IS_SAMSUNG_DEVICE(storage_mfrid)) {
if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION,
HID_OP_DISABLE))
return -EINVAL;
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val))
return -EINVAL;
HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d",
attr_val & HID_FRAG_LEVEL_MASK,
HID_FRAG_UPDATE_STAT(attr_val),
HID_EXECUTE_REQ_STAT(attr_val));
}
return 0;
}
@ -706,27 +803,42 @@ static ssize_t ufshid_sysfs_show_color(struct ufshid_dev *hid, char *buf)
u32 attr_val;
int frag_level;
if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION,
HID_OP_ANALYZE)) {
ERR_MSG("query HID_OPERATION fail");
return -EINVAL;
if(IS_MICRON_DEVICE(storage_mfrid)){
#if defined(CONFIG_MICRON_UFSHID)
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_STATUS, &attr_val))
return -EINVAL;
frag_level = attr_val;
/*Micron only has two levels RED & GREEN*/
return snprintf(buf, PAGE_SIZE, "%s\n",
((frag_level == HID_LEV_GREEN_MICRON)) ? "GREEN" :
((frag_level ==HID_LEV_RED_MICRON))?"RED":"UNKNOWN");
return snprintf(buf, PAGE_SIZE, "%s\n","Error.");
#endif
} else if(IS_SAMSUNG_DEVICE(storage_mfrid)) {
if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION,
HID_OP_ANALYZE)) {
ERR_MSG("query HID_OPERATION fail");
return -EINVAL;
}
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) {
ERR_MSG("query HID_FRAG_LEVEL fail");
return -EINVAL;
}
frag_level = attr_val & HID_FRAG_LEVEL_MASK;
INFO_MSG("Frag_lv %d Freg_stat %d HID_need_exec %d", frag_level,
HID_FRAG_UPDATE_STAT(attr_val),
HID_EXECUTE_REQ_STAT(attr_val));
return snprintf(buf, PAGE_SIZE, "%s\n",
frag_level == HID_LEV_RED ? "RED" :
frag_level == HID_LEV_YELLOW ? "YELLOW" :
frag_level == HID_LEV_GREEN ? "GREEN" :
frag_level == HID_LEV_GRAY ? "GRAY" : "UNKNOWN");
}
if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) {
ERR_MSG("query HID_FRAG_LEVEL fail");
return -EINVAL;
}
frag_level = attr_val & HID_FRAG_LEVEL_MASK;
INFO_MSG("Frag_lv %d Freg_stat %d HID_need_exec %d", frag_level,
HID_FRAG_UPDATE_STAT(attr_val),
HID_EXECUTE_REQ_STAT(attr_val));
return snprintf(buf, PAGE_SIZE, "%s\n",
frag_level == HID_LEV_RED ? "RED" :
frag_level == HID_LEV_YELLOW ? "YELLOW" :
frag_level == HID_LEV_GREEN ? "GREEN" :
frag_level == HID_LEV_GRAY ? "GRAY" : "UNKNOWN");
return -EINVAL;
}
#if defined(CONFIG_UFSHID_POC)

View file

@ -103,6 +103,20 @@ enum {
HID_LEV_RED = 3,
};
#if defined(CONFIG_MICRON_UFSHID)
enum {
HID_LEV_GREEN_MICRON = 0,
HID_LEV_RED_MICRON = 1,
};
enum {
HID_PROG_IDLE = 0,
HID_PROG_ONGOING = 1,
HID_PROG_STOP = 2, //stopped by Host
HID_PROG_COMPLETE = 3,
};
#endif
struct ufshid_dev {
struct ufsf_feature *ufsf;