diff --git a/drivers/scsi/ufs/ufsfeature.c b/drivers/scsi/ufs/ufsfeature.c index 7f65f74efb04..3cb57d2d412a 100755 --- a/drivers/scsi/ufs/ufsfeature.c +++ b/drivers/scsi/ufs/ufsfeature.c @@ -212,7 +212,8 @@ static int ufsf_read_dev_desc(struct ufsf_feature *ufsf, u8 selector) #if defined(CONFIG_UFSHPB) - ufshpb_get_dev_info(ufsf, desc_buf); + if (IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) + ufshpb_get_dev_info(ufsf, desc_buf); #endif #if defined(CONFIG_UFSTW) ufstw_get_dev_info(ufsf, desc_buf); @@ -231,7 +232,7 @@ static int ufsf_read_geo_desc(struct ufsf_feature *ufsf, u8 selector) return ret; #if defined(CONFIG_UFSHPB) - if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) + if ((ufshpb_get_state(ufsf) == HPB_NEED_INIT) && IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) ufshpb_get_geo_info(ufsf, geo_buf); #endif @@ -259,7 +260,7 @@ static void ufsf_read_unit_desc(struct ufsf_feature *ufsf, int lun, u8 selector) return; #if defined(CONFIG_UFSHPB) - if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) + if ((ufshpb_get_state(ufsf) == HPB_NEED_INIT) && IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) ufshpb_get_lu_info(ufsf, lun, unit_buf); #endif @@ -531,7 +532,7 @@ inline void ufsf_slave_configure(struct ufsf_feature *ufsf, ufsf->slave_conf_cnt, ufsf->num_lu); #if defined(CONFIG_UFSHPB) - if (ufsf->num_lu == ufsf->slave_conf_cnt) { + if (ufsf->num_lu == ufsf->slave_conf_cnt && IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) { if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) { INFO_MSG("wakeup ufshpb_init_handler"); wake_up(&ufsf->hpb_wait); @@ -546,7 +547,7 @@ inline void ufsf_prep_fn(struct ufsf_feature *ufsf, { #if defined(CONFIG_UFSHPB) if (ufshpb_get_state(ufsf) == HPB_PRESENT && - ufsf->issue_ioctl == false) + ufsf->issue_ioctl == false && IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) ufshpb_prep_fn(ufsf, lrbp); #endif @@ -569,10 +570,12 @@ inline void ufsf_reset_lu(struct ufsf_feature *ufsf) inline void ufsf_reset_host(struct ufsf_feature *ufsf) { #if defined(CONFIG_UFSHPB) - INFO_MSG("run reset_host.. hpb_state(%d) -> HPB_RESET", - ufshpb_get_state(ufsf)); - if (ufshpb_get_state(ufsf) == HPB_PRESENT) - ufshpb_reset_host(ufsf); + if (IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) { + INFO_MSG("run reset_host.. hpb_state(%d) -> HPB_RESET", + ufshpb_get_state(ufsf)); + if (ufshpb_get_state(ufsf) == HPB_PRESENT) + ufshpb_reset_host(ufsf); + } #endif #if defined(CONFIG_UFSTW) @@ -586,7 +589,7 @@ inline void ufsf_reset_host(struct ufsf_feature *ufsf) inline void ufsf_init(struct ufsf_feature *ufsf) { #if defined(CONFIG_UFSHPB) - if (ufshpb_get_state(ufsf) == HPB_NEED_INIT) { + if ((ufshpb_get_state(ufsf) == HPB_NEED_INIT) && IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) { INFO_MSG("init start.. hpb_state (%d)", HPB_NEED_INIT); schedule_work(&ufsf->hpb_init_work); } @@ -601,7 +604,7 @@ inline void ufsf_init(struct ufsf_feature *ufsf) inline void ufsf_reset(struct ufsf_feature *ufsf) { #if defined(CONFIG_UFSHPB) - if (ufshpb_get_state(ufsf) == HPB_RESET) { + if ((ufshpb_get_state(ufsf) == HPB_RESET) && IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) { INFO_MSG("reset start.. hpb_state %d", HPB_RESET); ufshpb_reset(ufsf); } @@ -620,7 +623,7 @@ inline void ufsf_reset(struct ufsf_feature *ufsf) inline void ufsf_remove(struct ufsf_feature *ufsf) { #if defined(CONFIG_UFSHPB) - if (ufshpb_get_state(ufsf) == HPB_PRESENT) + if ((ufshpb_get_state(ufsf) == HPB_PRESENT) && IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) ufshpb_remove(ufsf, HPB_NEED_INIT); #endif @@ -635,9 +638,13 @@ inline void ufsf_set_init_state(struct ufsf_feature *ufsf) ufsf->slave_conf_cnt = 0; ufsf->issue_ioctl = false; #if defined(CONFIG_UFSHPB) - ufshpb_set_state(ufsf, HPB_NEED_INIT); - INIT_WORK(&ufsf->hpb_init_work, ufshpb_init_handler); - init_waitqueue_head(&ufsf->hpb_wait); + if (IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) { + INFO_MSG("enable HPB feature, init start!"); + INFO_MSG("ram size is %d", ram_size); + ufshpb_set_state(ufsf, HPB_NEED_INIT); + INIT_WORK(&ufsf->hpb_init_work, ufshpb_init_handler); + init_waitqueue_head(&ufsf->hpb_wait); + } #endif #if defined(CONFIG_UFSTW) ufstw_set_state(ufsf, TW_NEED_INIT); @@ -652,7 +659,7 @@ inline void ufsf_suspend(struct ufsf_feature *ufsf) * in this case, ufshpb state already had been changed to SUSPEND state. * so, we will not call ufshpb_suspend. */ - if (ufshpb_get_state(ufsf) == HPB_PRESENT) + if ((ufshpb_get_state(ufsf) == HPB_PRESENT) && IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) ufshpb_suspend(ufsf); #endif } @@ -660,8 +667,9 @@ inline void ufsf_suspend(struct ufsf_feature *ufsf) inline void ufsf_resume(struct ufsf_feature *ufsf) { #if defined(CONFIG_UFSHPB) - if (ufshpb_get_state(ufsf) == HPB_SUSPEND || - ufshpb_get_state(ufsf) == HPB_PRESENT) { + if ((ufshpb_get_state(ufsf) == HPB_SUSPEND || + ufshpb_get_state(ufsf) == HPB_PRESENT) && + IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) { if (ufshpb_get_state(ufsf) == HPB_PRESENT) WARN_MSG("warning.. hpb state PRESENT in resuming"); ufshpb_resume(ufsf); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c66f206410bd..16bbe73f36fb 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -55,6 +55,36 @@ #define CREATE_TRACE_POINTS #include +#if defined(CONFIG_SCSI_SKHPB) || defined(CONFIG_UFSHPB) +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) +#include +#define SMEM_SDRAM_INFO 135 +#else +#include +#define SMEM_SDRAM_INFO SMEM_ID_VENDOR1 +#endif + +struct { + unsigned int mr5; + unsigned int mr6; + unsigned int mr7; + unsigned int mr8; + unsigned int ramsize; +} *smem_ddr_info; + +struct storage_info { + char type[16]; /* UFS or eMMC */ + char size[16]; /* size in GB */ + char card_manufacturer[32]; + char product_name[32]; /* model ID */ + char firmware_version[32]; +}; +unsigned int ram_size; +#endif + #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ UTP_TASK_REQ_COMPL |\ UFSHCD_ERROR_MASK) @@ -303,6 +333,10 @@ static struct ufs_dev_fix ufs_fixups[] = { END_FIX }; +#if defined(CONFIG_SCSI_SKHPB) || defined(CONFIG_UFSHPB) +static int get_dram_info(struct ufs_hba *hba); +static int get_storage_info(struct ufs_hba *hba); +#endif static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba); static void ufshcd_async_scan(void *data, async_cookie_t cookie); static int ufshcd_reset_and_restore(struct ufs_hba *hba); @@ -9782,13 +9816,18 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) */ ufshcd_set_ufs_dev_active(hba); +#if defined(CONFIG_UFSHPB) || defined(CONFIG_SCSI_SKHPB) + get_storage_info(hba); + get_dram_info(hba); +#endif + #if defined(CONFIG_UFSFEATURE) - if (is_support_hpb_200_device(storage_mfrid)){ + if (is_support_hpb_200_device(storage_mfrid)) { ufsf_set_init_state(&hba->ufsf); } #endif #if defined(CONFIG_SCSI_SKHPB) - if (is_support_hpb_100_device(storage_mfrid)){ + if (is_support_hpb_100_device(storage_mfrid) && IS_RAM_SIZE_GREATER_THAN_4G(ram_size)) { /* initialize hpb structures */ ufshcd_init_hpb(hba); } @@ -9816,6 +9855,81 @@ static int __init storage_mfrid_setup(char *str) return 1; } __setup("storage_mfrid=",storage_mfrid_setup); + +#if defined(CONFIG_SCSI_SKHPB) || defined(CONFIG_UFSHPB) +static int get_storage_info(struct ufs_hba *hba) +{ + int ret = 0; + struct property *p; + struct device_node *n; + struct storage_info *info; + unsigned int mfrid; + + n = of_find_node_by_path("/chosen/mmi,storage"); + if (n == NULL) { + ret = 1; + goto err; + } + + info = kzalloc(sizeof(struct storage_info), GFP_KERNEL); + if (!info) { + dev_err(hba->dev,"%s: failed to allocate space for mmi_storage_info\n", + __func__); + ret = 1; + goto err; + } + + for_each_property_of_node(n, p) { + if (!strcmp(p->name, "type") && p->value) + strlcpy(info->type, (char *)p->value, sizeof(info->type)); + if (!strcmp(p->name, "size") && p->value) + strlcpy(info->size, (char *)p->value, sizeof(info->size)); + if (!strcmp(p->name, "manufacturer") && p->value) + strlcpy(info->card_manufacturer, (char *)p->value, sizeof(info->card_manufacturer)); + if (!strcmp(p->name, "product") && p->value) + strlcpy(info->product_name, (char *)p->value, sizeof(info->product_name)); + if (!strcmp(p->name, "firmware") && p->value) + strlcpy(info->firmware_version, (char *)p->value, sizeof(info->firmware_version)); + } + + of_node_put(n); + + mfrid = simple_strtol(info->card_manufacturer, NULL, 16); + dev_info(hba->dev, "manufacturer parsed from choosen is %s\n",mfrid); +err: + return ret; +} + +static int get_dram_info(struct ufs_hba *hba) +{ + int ret = -1; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) + ssize_t ddr_info_size = 0; + smem_ddr_info = qcom_smem_get(QCOM_SMEM_HOST_ANY, + SMEM_SDRAM_INFO, + &ddr_info_size); + + if(smem_ddr_info) { + if(ddr_info_size < sizeof(*smem_ddr_info)) { + dev_err(hba->dev,"%s: Invalid SMEM size, cannot get RAM info\n", __func__); + goto err; + } + } +#endif + if (smem_ddr_info == NULL) { + dev_err(hba->dev,"%s: failed to access RAM info in SMEM\n", __func__); + goto err; + } + + ram_size = (smem_ddr_info->ramsize / 1024); + dev_info(hba->dev, "ram_size parsed from SMEM is %d\n",ram_size); + return ram_size; +err: + return ret; +} +#endif + EXPORT_SYMBOL_GPL(ufshcd_init); MODULE_AUTHOR("Santosh Yaragnavi "); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index ce44b1db6e5b..b292854b0d78 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -89,7 +89,10 @@ extern unsigned int storage_mfrid; #define IS_SAMSUNG_DEVICE(mfrid) (UFS_VENDOR_SAMSUNG == (mfrid)) #define IS_SKHYNIX_DEVICE(mfrid) (UFS_VENDOR_SKHYNIX == (mfrid)) #define IS_MICRON_DEVICE(mfrid) (UFS_VENDOR_MICRON == (mfrid)) - +#if defined(CONFIG_SCSI_SKHPB) || defined(CONFIG_UFSHPB) +extern unsigned int ram_size; +#define IS_RAM_SIZE_GREATER_THAN_4G(ram_size) (ram_size > 4) +#endif struct ufs_hba; enum dev_cmd_type {