@@ -68,19 +68,22 @@
#define TXn_TRAN_DRVR_EMP_EN 0x0078
-struct qcom_edp_cfg {
- bool is_dp;
-
- /* DP PHY swing and pre_emphasis tables */
+struct qcom_edp_swing_pre_emph_cfg {
const u8 (*swing_hbr_rbr)[4][4];
const u8 (*swing_hbr3_hbr2)[4][4];
const u8 (*pre_emphasis_hbr_rbr)[4][4];
const u8 (*pre_emphasis_hbr3_hbr2)[4][4];
};
+struct qcom_edp_phy_cfg {
+ int type;
+ bool needs_swing_pre_emph_cfg;
+};
+
struct qcom_edp {
struct device *dev;
- const struct qcom_edp_cfg *cfg;
+ const struct qcom_edp_phy_cfg *cfg;
+ const struct qcom_edp_swing_pre_emph_cfg *swing_pre_emph_cfg;
struct phy *phy;
@@ -96,6 +99,8 @@ struct qcom_edp {
struct clk_bulk_data clks[2];
struct regulator_bulk_data supplies[2];
+
+ bool is_dp;
};
static const u8 dp_swing_hbr_rbr[4][4] = {
@@ -126,8 +131,7 @@ static const u8 dp_pre_emp_hbr2_hbr3[4][4] = {
{ 0x04, 0xff, 0xff, 0xff }
};
-static const struct qcom_edp_cfg dp_phy_cfg = {
- .is_dp = true,
+static const struct qcom_edp_swing_pre_emph_cfg dp_phy_swing_pre_emph_cfg = {
.swing_hbr_rbr = &dp_swing_hbr_rbr,
.swing_hbr3_hbr2 = &dp_swing_hbr2_hbr3,
.pre_emphasis_hbr_rbr = &dp_pre_emp_hbr_rbr,
@@ -162,18 +166,30 @@ static const u8 edp_pre_emp_hbr2_hbr3[4][4] = {
{ 0x00, 0xff, 0xff, 0xff }
};
-static const struct qcom_edp_cfg edp_phy_cfg = {
- .is_dp = false,
+static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg = {
.swing_hbr_rbr = &edp_swing_hbr_rbr,
.swing_hbr3_hbr2 = &edp_swing_hbr2_hbr3,
.pre_emphasis_hbr_rbr = &edp_pre_emp_hbr_rbr,
.pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3,
};
+static struct qcom_edp_phy_cfg sc7280_dp_phy_cfg = {
+ .type = PHY_TYPE_DP,
+};
+
+static struct qcom_edp_phy_cfg sc8280xp_dp_phy_cfg = {
+ .type = PHY_TYPE_DP,
+ .needs_swing_pre_emph_cfg = true,
+};
+
+static struct qcom_edp_phy_cfg sc8280xp_edp_phy_cfg = {
+ .type = PHY_TYPE_EDP,
+ .needs_swing_pre_emph_cfg = true,
+};
+
static int qcom_edp_phy_init(struct phy *phy)
{
struct qcom_edp *edp = phy_get_drvdata(phy);
- const struct qcom_edp_cfg *cfg = edp->cfg;
int ret;
u8 cfg8;
@@ -200,7 +216,7 @@ static int qcom_edp_phy_init(struct phy *phy)
DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
edp->edp + DP_PHY_PD_CTL);
- if (cfg && cfg->is_dp)
+ if (edp->cfg->needs_swing_pre_emph_cfg && edp->is_dp)
cfg8 = 0xb7;
else
cfg8 = 0x37;
@@ -234,7 +250,7 @@ static int qcom_edp_phy_init(struct phy *phy)
static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configure_opts_dp *dp_opts)
{
- const struct qcom_edp_cfg *cfg = edp->cfg;
+ const struct qcom_edp_swing_pre_emph_cfg *cfg = edp->swing_pre_emph_cfg;
unsigned int v_level = 0;
unsigned int p_level = 0;
u8 ldo_config;
@@ -242,7 +258,7 @@ static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configur
u8 emph;
int i;
- if (!cfg)
+ if (!edp->cfg->needs_swing_pre_emph_cfg)
return 0;
for (i = 0; i < dp_opts->lanes; i++) {
@@ -261,7 +277,7 @@ static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configur
if (swing == 0xff || emph == 0xff)
return -EINVAL;
- ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0;
+ ldo_config = edp->is_dp ? 0x1 : 0x0;
writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG);
writel(swing, edp->tx0 + TXn_TX_DRV_LVL);
@@ -447,10 +463,9 @@ static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel
static int qcom_edp_phy_power_on(struct phy *phy)
{
const struct qcom_edp *edp = phy_get_drvdata(phy);
- const struct qcom_edp_cfg *cfg = edp->cfg;
u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
unsigned long pixel_freq;
- u8 ldo_config;
+ u8 ldo_config = 0x0;
int timeout;
int ret;
u32 val;
@@ -468,7 +483,8 @@ static int qcom_edp_phy_power_on(struct phy *phy)
return timeout;
- ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0;
+ if (edp->cfg->needs_swing_pre_emph_cfg && edp->is_dp)
+ ldo_config = 0x1;
writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG);
writel(ldo_config, edp->tx1 + TXn_LDO_CONFIG);
@@ -768,6 +784,33 @@ static int qcom_edp_clks_register(struct qcom_edp *edp, struct device_node *np)
return devm_of_clk_add_hw_provider(edp->dev, of_clk_hw_onecell_get, data);
}
+static struct phy *qcom_edp_phy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct qcom_edp *edp = dev_get_drvdata(dev);
+ int type = edp->cfg->type;
+
+ if (args->args_count == 1)
+ type = args->args[0];
+
+ if (type != PHY_TYPE_DP && type != PHY_TYPE_EDP)
+ return ERR_PTR(-EINVAL);
+
+ if (type == PHY_TYPE_EDP) {
+ edp->phy->attrs.mode = PHY_MODE_EDP;
+ } else {
+ edp->phy->attrs.mode = PHY_MODE_DP;
+ edp->is_dp = true;
+ }
+
+ if (edp->cfg->needs_swing_pre_emph_cfg)
+ edp->swing_pre_emph_cfg = edp->is_dp ?
+ &dp_phy_swing_pre_emph_cfg:
+ &edp_phy_swing_pre_emph_cfg;
+
+ return edp->phy;
+}
+
static int qcom_edp_phy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
@@ -832,17 +875,19 @@ static int qcom_edp_phy_probe(struct platform_device *pdev)
return PTR_ERR(edp->phy);
}
+ dev_set_drvdata(edp->dev, edp);
phy_set_drvdata(edp->phy, edp);
- phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ phy_provider = devm_of_phy_provider_register(dev, qcom_edp_phy_xlate);
+
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id qcom_edp_phy_match_table[] = {
- { .compatible = "qcom,sc7280-edp-phy" },
- { .compatible = "qcom,sc8180x-edp-phy" },
- { .compatible = "qcom,sc8280xp-dp-phy", .data = &dp_phy_cfg },
- { .compatible = "qcom,sc8280xp-edp-phy", .data = &edp_phy_cfg },
+ { .compatible = "qcom,sc7280-edp-phy" , .data = &sc7280_dp_phy_cfg, },
+ { .compatible = "qcom,sc8180x-edp-phy", .data = &sc7280_dp_phy_cfg, },
+ { .compatible = "qcom,sc8280xp-dp-phy", .data = &sc8280xp_dp_phy_cfg, },
+ { .compatible = "qcom,sc8280xp-edp-phy", .data = &sc8280xp_edp_phy_cfg, },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_edp_phy_match_table);