Add support for enabling a specifically requested number of lanes in the .configure() callback and disable all lanes in power off and reset callbacks for proper hardware cleanup.
Signed-off-by: AngeloGioacchino Del Regno <[email protected]> --- drivers/phy/mediatek/phy-mtk-dp.c | 49 ++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/drivers/phy/mediatek/phy-mtk-dp.c b/drivers/phy/mediatek/phy-mtk-dp.c index 586e72795633..a2cd22b9da06 100644 --- a/drivers/phy/mediatek/phy-mtk-dp.c +++ b/drivers/phy/mediatek/phy-mtk-dp.c @@ -45,6 +45,9 @@ #define PHYD_DIG_XTP_GLB_CKDET_EN BIT(1) #define PHYD_DIG_DPAUX_RX_DEGLITCH_EN BIT(2) +/* DP_PHYD_TX_CTL_0 */ +#define PHYD_TX_LN_EN GENMASK(7, 4) + #define XTP_LN_TX_LCTXC0_SW0_PRE0_DEFAULT BIT(4) #define XTP_LN_TX_LCTXC0_SW0_PRE1_DEFAULT (BIT(10) | BIT(12)) #define XTP_LN_TX_LCTXC0_SW0_PRE2_DEFAULT GENMASK(20, 19) @@ -108,6 +111,7 @@ enum mtk_dp_phyd_dig_glb_regidx { DP_PHYD_SW_RST, DP_PHYD_BIT_RATE, DP_PHYD_AUX_RX_CTL, + DP_PHYD_TX_CTL_0, DP_PHYD_GLOBAL_MAX }; @@ -126,6 +130,7 @@ static const u8 mt8195_phy_dig_glb_regs[DP_PHYD_GLOBAL_MAX] = { [DP_PHYD_SW_RST] = 0x38, [DP_PHYD_BIT_RATE] = 0x3c, [DP_PHYD_AUX_RX_CTL] = 0x40, + [DP_PHYD_TX_CTL_0] = 0x44, }; /** @@ -192,6 +197,7 @@ static int mtk_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts) struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy); const struct mtk_dp_phy_pdata *pdata = dp_phy->pdata; u32 val; + int i; if (opts->dp.set_rate) { const u32 reg_bit_rate = pdata->regs_dig_glb[DP_PHYD_BIT_RATE]; @@ -223,7 +229,7 @@ static int mtk_dp_phy_configure(struct phy *phy, union phy_configure_opts *opts) val = 0; for (i = 0; i < opts->dp.lanes; i++) - val |= FIELD_PREP(PHYD_TX_LN_EN, i); + val |= FIELD_PREP(PHYD_TX_LN_EN, BIT(i)); regmap_update_bits(dp_phy->regmap, pdata->off_dig_glb + reg_dig_tx_ctl, PHYD_TX_LN_EN, val); @@ -261,6 +267,35 @@ static int mtk_dp_phy_power_on(struct phy *phy) return 0; } +static int mtk_dp_phy_disable_all_lanes(struct mtk_dp_phy *dp_phy) +{ + const struct mtk_dp_phy_pdata *pdata = dp_phy->pdata; + const u8 *regs = pdata->regs_dig_glb; + int ret; + u32 val; + + ret = regmap_read(dp_phy->regmap, pdata->off_dig_glb + regs[DP_PHYD_TX_CTL_0], &val); + if (ret) + return ret; + + /* Get mask of currently enabled lane */ + val = FIELD_GET(PHYD_TX_LN_EN, val); + + /* Disable all lanes (needs to be done one by one, from last to first) */ + do { + u32 lane_num = fls(val) - 1; + val &= ~BIT(lane_num); + + ret = regmap_clear_bits(dp_phy->regmap, + pdata->off_dig_glb + regs[DP_PHYD_TX_CTL_0], + FIELD_PREP(PHYD_TX_LN_EN, lane_num)); + if (ret) + return ret; + } while (val); + + return 0; +} + static int mtk_dp_phy_power_off(struct phy *phy) { struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy); @@ -280,6 +315,12 @@ static int mtk_dp_phy_power_off(struct phy *phy) if (ret) return ret; + ret = mtk_dp_phy_disable_all_lanes(dp_phy); + if (ret) { + dev_err(dp_phy->dev, "Could not disable lanes for poweroff!\n"); + return ret; + } + return 0; } @@ -288,6 +329,7 @@ static int mtk_dp_phy_reset(struct phy *phy) struct mtk_dp_phy *dp_phy = phy_get_drvdata(phy); const struct mtk_dp_phy_pdata *pdata = dp_phy->pdata; const u32 reg_rst = pdata->regs_dig_glb[DP_PHYD_SW_RST]; + int ret; /* Clearing bits sets reset state */ regmap_clear_bits(dp_phy->regmap, pdata->off_dig_glb + reg_rst, DP_GLB_SW_RST_PHYD); @@ -298,6 +340,11 @@ static int mtk_dp_phy_reset(struct phy *phy) /* Setting bits means go out of reset */ regmap_set_bits(dp_phy->regmap, pdata->off_dig_glb + reg_rst, DP_GLB_SW_RST_PHYD); + /* Disable all lanes and continue reset even if this fails, but notify */ + ret = mtk_dp_phy_disable_all_lanes(dp_phy); + if (ret) + dev_err(dp_phy->dev, "Could not disable lanes during reset!\n"); + return 0; } -- 2.54.0
