diff options
Diffstat (limited to 'drivers/scsi/ufs/ufshcd-pltfrm.c')
-rw-r--r-- | drivers/scsi/ufs/ufshcd-pltfrm.c | 112 |
1 files changed, 101 insertions, 11 deletions
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 27213676329c..8a74ec30c3d2 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -39,6 +39,7 @@ #include "ufshcd.h" #include "ufshcd-pltfrm.h" +#include "unipro.h" #define UFSHCD_DEFAULT_LANES_PER_DIRECTION 2 @@ -151,20 +152,12 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name, vreg->name = kstrdup(name, GFP_KERNEL); - /* if fixed regulator no need further initialization */ - snprintf(prop_name, MAX_PROP_SIZE, "%s-fixed-regulator", name); - if (of_property_read_bool(np, prop_name)) - goto out; - snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name); - ret = of_property_read_u32(np, prop_name, &vreg->max_uA); - if (ret) { - dev_err(dev, "%s: unable to find %s err %d\n", - __func__, prop_name, ret); - goto out; + if (of_property_read_u32(np, prop_name, &vreg->max_uA)) { + dev_info(dev, "%s: unable to find %s\n", __func__, prop_name); + vreg->max_uA = 0; } - vreg->min_uA = 0; if (!strcmp(name, "vcc")) { if (of_property_read_bool(np, "vcc-supply-1p8")) { vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV; @@ -290,6 +283,103 @@ static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba) } /** + * ufshcd_get_pwr_dev_param - get finally agreed attributes for + * power mode change + * @pltfrm_param: pointer to platform parameters + * @dev_max: pointer to device attributes + * @agreed_pwr: returned agreed attributes + * + * Returns 0 on success, non-zero value on failure + */ +int ufshcd_get_pwr_dev_param(struct ufs_dev_params *pltfrm_param, + struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr) +{ + int min_pltfrm_gear; + int min_dev_gear; + bool is_dev_sup_hs = false; + bool is_pltfrm_max_hs = false; + + if (dev_max->pwr_rx == FAST_MODE) + is_dev_sup_hs = true; + + if (pltfrm_param->desired_working_mode == UFS_HS_MODE) { + is_pltfrm_max_hs = true; + min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear, + pltfrm_param->hs_tx_gear); + } else { + min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear, + pltfrm_param->pwm_tx_gear); + } + + /* + * device doesn't support HS but + * pltfrm_param->desired_working_mode is HS, + * thus device and pltfrm_param don't agree + */ + if (!is_dev_sup_hs && is_pltfrm_max_hs) { + pr_info("%s: device doesn't support HS\n", + __func__); + return -ENOTSUPP; + } else if (is_dev_sup_hs && is_pltfrm_max_hs) { + /* + * since device supports HS, it supports FAST_MODE. + * since pltfrm_param->desired_working_mode is also HS + * then final decision (FAST/FASTAUTO) is done according + * to pltfrm_params as it is the restricting factor + */ + agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs; + agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; + } else { + /* + * here pltfrm_param->desired_working_mode is PWM. + * it doesn't matter whether device supports HS or PWM, + * in both cases pltfrm_param->desired_working_mode will + * determine the mode + */ + agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm; + agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; + } + + /* + * we would like tx to work in the minimum number of lanes + * between device capability and vendor preferences. + * the same decision will be made for rx + */ + agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, + pltfrm_param->tx_lanes); + agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, + pltfrm_param->rx_lanes); + + /* device maximum gear is the minimum between device rx and tx gears */ + min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); + + /* + * if both device capabilities and vendor pre-defined preferences are + * both HS or both PWM then set the minimum gear to be the chosen + * working gear. + * if one is PWM and one is HS then the one that is PWM get to decide + * what is the gear, as it is the one that also decided previously what + * pwr the device will be configured to. + */ + if ((is_dev_sup_hs && is_pltfrm_max_hs) || + (!is_dev_sup_hs && !is_pltfrm_max_hs)) { + agreed_pwr->gear_rx = + min_t(u32, min_dev_gear, min_pltfrm_gear); + } else if (!is_dev_sup_hs) { + agreed_pwr->gear_rx = min_dev_gear; + } else { + agreed_pwr->gear_rx = min_pltfrm_gear; + } + agreed_pwr->gear_tx = agreed_pwr->gear_rx; + + agreed_pwr->hs_rate = pltfrm_param->hs_rate; + + return 0; +} +EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param); + +/** * ufshcd_pltfrm_init - probe routine of the driver * @pdev: pointer to Platform device handle * @vops: pointer to variant ops |