diff --git a/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c b/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c index 1cacf2354e87..1e72dcc61ac9 100644 --- a/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c +++ b/drivers/scsi/ufs/ufs-msm-phy-qmp-20nm.c @@ -30,36 +30,27 @@ #define UFS_PHY_NAME "ufs_msm_phy_qmp_20nm" -static void ufs_msm_phy_qmp_20nm_phy_calibrate(struct ufs_msm_phy *phy) +static int ufs_msm_phy_qmp_20nm_phy_calibrate(struct ufs_msm_phy *ufs_msm_phy) { - struct ufs_msm_phy_calibration *tbl; - int tbl_size; - int i; + struct ufs_msm_phy_calibration *tbl_A, *tbl_B; + int tbl_size_A, tbl_size_B; + int rate = UFS_MSM_LIMIT_HS_RATE; + int err; - tbl_size = ARRAY_SIZE(phy_cal_table_rate_A); - tbl = phy_cal_table_rate_A; + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A); + tbl_A = phy_cal_table_rate_A; - /* - * calibration according phy_cal_table_rate_A happens - * regardless of the rate we intend to work with. - * Only in case we would like to work in rate B, we need - * to override a subset of registers of phy_cal_table_rate_A - * table, with phy_cal_table_rate_B table. - */ - for (i = 0; i < tbl_size; i++) - writel_relaxed(tbl[i].cfg_value, phy->mmio + tbl[i].reg_offset); + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); + tbl_B = phy_cal_table_rate_B; - if (UFS_MSM_LIMIT_HS_RATE == PA_HS_MODE_B) { - tbl = phy_cal_table_rate_B; - tbl_size = ARRAY_SIZE(phy_cal_table_rate_B); + err = ufs_msm_phy_calibrate(ufs_msm_phy, tbl_A, tbl_size_A, + tbl_B, tbl_size_B, rate); - for (i = 0; i < tbl_size; i++) - writel_relaxed(tbl[i].cfg_value, - phy->mmio + tbl[i].reg_offset); - } + if (err) + dev_err(ufs_msm_phy->dev, "%s: ufs_msm_phy_calibrate() failed %d\n", + __func__, err); - /* flush buffered writes */ - mb(); + return err; } static int ufs_msm_phy_qmp_20nm_init(struct phy *generic_phy) @@ -192,7 +183,6 @@ static int ufs_msm_phy_qmp_20nm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct phy *generic_phy; struct ufs_msm_phy_qmp_20nm *phy; - struct phy_provider *phy_provider; int err = 0; phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); @@ -202,35 +192,20 @@ static int ufs_msm_phy_qmp_20nm_probe(struct platform_device *pdev) goto out; } - err = ufs_msm_phy_base_init(pdev, &phy->common_cfg); - if (err) { - dev_err(dev, "%s: phy base init failed %d\n", __func__, err); + generic_phy = ufs_msm_phy_generic_probe(pdev, &phy->common_cfg, + &ufs_msm_phy_qmp_20nm_phy_ops, &phy_20nm_ops); + + if (!generic_phy) { + dev_err(dev, "%s: ufs_msm_phy_generic_probe() failed\n", + __func__); + err = -EIO; goto out; } - phy->common_cfg.phy_spec_ops = &phy_20nm_ops; - phy->common_cfg.cached_regs = NULL; - - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) { - err = PTR_ERR(phy_provider); - dev_err(dev, "%s: failed to register phy %d\n", __func__, err); - goto out; - } - - generic_phy = devm_phy_create(dev, &ufs_msm_phy_qmp_20nm_phy_ops, NULL); - if (IS_ERR(generic_phy)) { - devm_of_phy_provider_unregister(dev, phy_provider); - err = PTR_ERR(generic_phy); - dev_err(dev, "%s: failed to create phy %d\n", __func__, err); - goto out; - } - - phy->common_cfg.dev = dev; phy_set_drvdata(generic_phy, phy); strlcpy(phy->common_cfg.name, UFS_PHY_NAME, - sizeof(phy->common_cfg.name)); + sizeof(phy->common_cfg.name)); out: return err; diff --git a/drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c b/drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c index f01bafe32b0d..a75a6ca8fc2a 100644 --- a/drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c +++ b/drivers/scsi/ufs/ufs-msm-phy-qmp-28nm.c @@ -97,46 +97,34 @@ out: return err; } -static void ufs_msm_phy_qmp_28nm_calibrate(struct ufs_msm_phy *ufs_msm_phy) +static int ufs_msm_phy_qmp_28nm_calibrate(struct ufs_msm_phy *ufs_msm_phy) { - struct ufs_msm_phy_calibration *tbl; - int tbl_size; - int i; + struct ufs_msm_phy_calibration *tbl_A, *tbl_B; + int tbl_size_A, tbl_size_B; + int rate = UFS_MSM_LIMIT_HS_RATE; u8 major = ufs_msm_phy->host_ctrl_rev_major; u16 minor = ufs_msm_phy->host_ctrl_rev_minor; u16 step = ufs_msm_phy->host_ctrl_rev_step; + int err; if ((major == 0x1) && (minor == 0x001) && (step == 0x0000)) { - tbl_size = ARRAY_SIZE(phy_cal_table_ctrl_1_1_0_rate_A); - tbl = phy_cal_table_ctrl_1_1_0_rate_A; + tbl_size_A = ARRAY_SIZE(phy_cal_table_ctrl_1_1_0_rate_A); + tbl_A = phy_cal_table_ctrl_1_1_0_rate_A; } else if ((major == 0x1) && (minor == 0x001) && (step == 0x0001)) { - tbl_size = ARRAY_SIZE(phy_cal_table_ctrl_1_1_1_rate_A); - tbl = phy_cal_table_ctrl_1_1_1_rate_A; + tbl_size_A = ARRAY_SIZE(phy_cal_table_ctrl_1_1_1_rate_A); + tbl_A = phy_cal_table_ctrl_1_1_1_rate_A; } - /* - * calibration according phy_cal_table_ctrl_x_x_x_rate_A - * happens regardless of the rate we intend to work with. - * Only in case we would like to work in rate B, we need - * to override a subset of registers of - * phy_cal_table_ctrl_x_x_x_rate_A table, with phy_cal_table_rate_B - * table. - */ - for (i = 0; i < tbl_size; i++) - writel_relaxed(tbl[i].cfg_value, - ufs_msm_phy->mmio + tbl[i].reg_offset); + tbl_B = phy_cal_table_rate_B; + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); - if (UFS_MSM_LIMIT_HS_RATE == PA_HS_MODE_B) { - tbl = phy_cal_table_rate_B; - tbl_size = ARRAY_SIZE(phy_cal_table_rate_B); + err = ufs_msm_phy_calibrate(ufs_msm_phy, tbl_A, tbl_size_A, + tbl_B, tbl_size_B, rate); + if (err) + dev_err(ufs_msm_phy->dev, "%s: ufs_msm_phy_calibrate() failed %d\n", + __func__, err); - for (i = 0; i < tbl_size; i++) - writel_relaxed(tbl[i].cfg_value, - ufs_msm_phy->mmio + tbl[i].reg_offset); - } - - /* flush buffered writes */ - mb(); + return err; } static @@ -286,7 +274,7 @@ static int ufs_msm_phy_qmp_28nm_resume(struct phy *generic_phy) return err; } -struct phy_ops ufs_msm_phy_ops = { +struct phy_ops ufs_msm_phy_qmp_28nm_phy_ops = { .init = ufs_msm_phy_qmp_28nm_init, .exit = ufs_msm_phy_exit, .power_on = ufs_msm_phy_power_on, @@ -312,7 +300,6 @@ static int ufs_msm_phy_qmp_28nm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int err = 0; struct phy *generic_phy; - struct phy_provider *phy_provider; phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); if (!phy) { @@ -321,37 +308,26 @@ static int ufs_msm_phy_qmp_28nm_probe(struct platform_device *pdev) goto out; } - err = ufs_msm_phy_base_init(pdev, &phy->common_cfg); - if (err) { - dev_err(dev, "%s: phy base init failed %d\n", __func__, err); - goto out; - } - - phy->common_cfg.phy_spec_ops = &phy_28nm_ops; phy->common_cfg.cached_regs = (struct ufs_msm_phy_calibration *)cached_phy_regs; phy->common_cfg.cached_regs_table_size = ARRAY_SIZE(cached_phy_regs); - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) { - err = PTR_ERR(phy_provider); - dev_err(dev, "%s: failed to register phy %d\n", __func__, err); + generic_phy = ufs_msm_phy_generic_probe(pdev, &phy->common_cfg, + &ufs_msm_phy_qmp_28nm_phy_ops, &phy_28nm_ops); + + if (!generic_phy) { + dev_err(dev, "%s: ufs_msm_phy_generic_probe() failed\n", + __func__); + err = -EIO; goto out; } - generic_phy = devm_phy_create(dev, &ufs_msm_phy_ops, NULL); - if (IS_ERR(generic_phy)) { - err = PTR_ERR(generic_phy); - dev_err(dev, "%s: failed to create phy %d\n", __func__, err); - goto out; - } - - phy->common_cfg.dev = dev; phy_set_drvdata(generic_phy, phy); strlcpy(phy->common_cfg.name, UFS_PHY_NAME, sizeof(phy->common_cfg.name)); + out: return err; } diff --git a/drivers/scsi/ufs/ufs-msm-phy.c b/drivers/scsi/ufs/ufs-msm-phy.c index f04b2621e68f..45b355efe10e 100644 --- a/drivers/scsi/ufs/ufs-msm-phy.c +++ b/drivers/scsi/ufs/ufs-msm-phy.c @@ -27,6 +27,87 @@ #include "ufs-msm.h" #include "ufs-msm-phy.h" +int ufs_msm_phy_calibrate(struct ufs_msm_phy *ufs_msm_phy, + struct ufs_msm_phy_calibration *tbl_A, int tbl_size_A, + struct ufs_msm_phy_calibration *tbl_B, int tbl_size_B, + int rate) +{ + int i; + int ret = 0; + + if (!tbl_A) { + dev_err(ufs_msm_phy->dev, "%s: tbl_A is NULL", __func__); + ret = EINVAL; + goto out; + } + + for (i = 0; i < tbl_size_A; i++) + writel_relaxed(tbl_A[i].cfg_value, + ufs_msm_phy->mmio + tbl_A[i].reg_offset); + + /* + * In case we would like to work in rate B, we need + * to override a registers that were configured in rate A table + * with registers of rate B table. + * table. + */ + if (rate == PA_HS_MODE_B) { + if (!tbl_B) { + dev_err(ufs_msm_phy->dev, "%s: tbl_B is NULL", + __func__); + ret = EINVAL; + goto out; + } + + for (i = 0; i < tbl_size_B; i++) + writel_relaxed(tbl_B[i].cfg_value, + ufs_msm_phy->mmio + tbl_B[i].reg_offset); + } + + /* flush buffered writes */ + mb(); + +out: + return ret; +} + +struct phy *ufs_msm_phy_generic_probe(struct platform_device *pdev, + struct ufs_msm_phy *common_cfg, + struct phy_ops *ufs_msm_phy_gen_ops, + struct ufs_msm_phy_specific_ops *phy_spec_ops) +{ + int err; + struct device *dev = &pdev->dev; + struct phy *generic_phy = NULL; + struct phy_provider *phy_provider; + + err = ufs_msm_phy_base_init(pdev, common_cfg); + if (err) { + dev_err(dev, "%s: phy base init failed %d\n", __func__, err); + goto out; + } + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + err = PTR_ERR(phy_provider); + dev_err(dev, "%s: failed to register phy %d\n", __func__, err); + goto out; + } + + generic_phy = devm_phy_create(dev, ufs_msm_phy_gen_ops, NULL); + if (IS_ERR(generic_phy)) { + err = PTR_ERR(generic_phy); + dev_err(dev, "%s: failed to create phy %d\n", __func__, err); + goto out; + } + + common_cfg->phy_spec_ops = phy_spec_ops; + common_cfg->dev = dev; + +out: + return generic_phy; +} + /* * This assumes the embedded phy structure inside generic_phy is of type * struct ufs_msm_phy. In order to function properly it's crucial @@ -447,8 +528,10 @@ int ufs_msm_phy_calibrate_phy(struct phy *generic_phy) __func__); ret = -ENOTSUPP; } else { - ufs_msm_phy->phy_spec_ops-> - calibrate_phy(ufs_msm_phy); + ret = ufs_msm_phy->phy_spec_ops-> + calibrate_phy(ufs_msm_phy); + dev_err(ufs_msm_phy->dev, "%s: calibrate_phy() failed %d\n", + __func__, ret); } return ret; diff --git a/drivers/scsi/ufs/ufs-msm-phy.h b/drivers/scsi/ufs/ufs-msm-phy.h index 5edd9d2260a3..90eac935c161 100644 --- a/drivers/scsi/ufs/ufs-msm-phy.h +++ b/drivers/scsi/ufs/ufs-msm-phy.h @@ -130,7 +130,7 @@ struct ufs_msm_phy { * and writes to QSERDES_RX_SIGDET_CNTRL attribute */ struct ufs_msm_phy_specific_ops { - void (*calibrate_phy) (struct ufs_msm_phy *phy); + int (*calibrate_phy) (struct ufs_msm_phy *phy); void (*start_serdes) (struct ufs_msm_phy *phy); void (*save_configuration)(struct ufs_msm_phy *phy); int (*is_physical_coding_sublayer_ready) (struct ufs_msm_phy *phy); @@ -173,4 +173,12 @@ int ufs_msm_phy_init_vregulators(struct phy *generic_phy, struct ufs_msm_phy *phy_common); int ufs_msm_phy_remove(struct phy *generic_phy, struct ufs_msm_phy *ufs_msm_phy); +struct phy *ufs_msm_phy_generic_probe(struct platform_device *pdev, + struct ufs_msm_phy *common_cfg, + struct phy_ops *ufs_msm_phy_gen_ops, + struct ufs_msm_phy_specific_ops *phy_spec_ops); +int ufs_msm_phy_calibrate(struct ufs_msm_phy *ufs_msm_phy, + struct ufs_msm_phy_calibration *tbl_A, int tbl_size_A, + struct ufs_msm_phy_calibration *tbl_B, int tbl_size_B, + int rate); #endif