On Thu, 23 Nov 2023 at 10:47, Can Guo <quic_cang@xxxxxxxxxxx> wrote:
On SM8550, two sets of UFS PHY settings are provided, one set is to support
HS-G5, another set is to support HS-G4 and lower gears. The two sets of PHY
settings are programming different values to different registers, mixing
the two sets and/or overwriting one set with another set is definitely not
blessed by UFS PHY designers.
To add HS-G5 support for SM8550, split the two sets of PHY settings into
their dedicated overlay tables, only the common parts of the two sets of
PHY settings are left in the .tbls.
Consider we are going to add even higher gear support in future, to avoid
adding more tables with different names, rename the .tbls_hs_g4 and make it
an array, a size of 2 is enough as of now.
In this case, .tbls alone is not a complete set of PHY settings, so either
tbls_hs_overlay[0] or tbls_hs_overlay[1] must be applied on top of the
.tbls to become a complete set of PHY settings.
Signed-off-by: Can Guo <quic_cang@xxxxxxxxxxx>
-static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
+static bool qmp_ufs_match_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg, int *i)
You can simply return int from this function. -EINVAL would mean that
the setting was not found. Also this can make max_supported_gear
unused.
+{
+ u32 max_gear, floor_max_gear = cfg->max_supported_gear;
+ bool found = false;
+ int j;
+
+ for (j = 0; j < NUM_OVERLAY; j ++) {
+ max_gear = cfg->tbls_hs_overlay[j].max_gear;
+
+ if (max_gear == 0)
+ continue;
+
+ /* Direct matching, bail */
+ if (qmp->submode == max_gear) {
+ *i = j;
+ return true;
+ }
+
+ /* If no direct matching, the lowest gear is the best matching */
+ if (max_gear < floor_max_gear) {
+ *i = j;
+ found = true;
+ floor_max_gear = max_gear;
+ }
We know that the table is sorted. So we can return an index of the
first setting that fits.
+ }
+
+ return found;
+}
+
+static int qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
{
+ bool apply_overlay;
+ int i;
+
+ if (qmp->submode > cfg->max_supported_gear || qmp->submode == 0) {
+ dev_err(qmp->dev, "Invalid PHY submode %u\n", qmp->submode);
+ return -EINVAL;
+ }
+
+ apply_overlay = qmp_ufs_match_gear_overlay(qmp, cfg, &i);
+
qmp_ufs_serdes_init(qmp, &cfg->tbls);
+ if (apply_overlay)
+ qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[i]);
+
if (qmp->mode == PHY_MODE_UFS_HS_B)
qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b);
+
qmp_ufs_lanes_init(qmp, &cfg->tbls);
- if (qmp->submode == UFS_HS_G4)
- qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_g4);
+ if (apply_overlay)
+ qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[i]);
+
qmp_ufs_pcs_init(qmp, &cfg->tbls);
- if (qmp->submode == UFS_HS_G4)
- qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_g4);
+ if (apply_overlay)
+ qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_overlay[i]);
+
+ return 0;
}
static int qmp_ufs_com_init(struct qmp_ufs *qmp)
@@ -1331,7 +1461,9 @@ static int qmp_ufs_power_on(struct phy *phy)
unsigned int val;
int ret;
- qmp_ufs_init_registers(qmp, cfg);
+ ret = qmp_ufs_init_registers(qmp, cfg);
+ if (ret)
+ return ret;
ret = reset_control_deassert(qmp->ufs_reset);
if (ret)
--
2.7.4