Message ID | 20220901044149.16782-9-rex-bc.chen@mediatek.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add MT8195 DisplayPort driver | expand |
Hi, Bo-Chen: On Thu, 2022-09-01 at 12:41 +0800, Bo-Chen Chen wrote: > From: Guillaume Ranquet <granquet@baylibre.com> > > Add External DisplayPort support to the MT8195 eDP driver. > > Signed-off-by: Guillaume Ranquet <granquet@baylibre.com> > Signed-off-by: Bo-Chen Chen <rex-bc.chen@mediatek.com> > --- > drivers/gpu/drm/mediatek/mtk_dp.c | 139 > ++++++++++++++++++++++++++++++ > 1 file changed, 139 insertions(+) > > diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c > b/drivers/gpu/drm/mediatek/mtk_dp.c > index e37c9185e4ec..11a94927c0d0 100644 > --- a/drivers/gpu/drm/mediatek/mtk_dp.c > +++ b/drivers/gpu/drm/mediatek/mtk_dp.c > @@ -35,6 +35,7 @@ > > #define MTK_DP_SIP_CONTROL_AARCH32 MTK_SIP_SMC_CMD(0x523) > #define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE (BIT(0) | BIT(5)) > +#define MTK_DP_SIP_ATF_VIDEO_UNMUTE BIT(5) > > #define MTK_DP_THREAD_CABLE_STATE_CHG BIT(0) > #define MTK_DP_THREAD_HPD_EVENT BIT(1) > @@ -199,6 +200,89 @@ static const struct mtk_dp_efuse_fmt > mt8195_edp_efuse_fmt[MTK_DP_CAL_MAX] = { > }, > }; > > +static const struct mtk_dp_efuse_fmt > mt8195_dp_efuse_fmt[MTK_DP_CAL_MAX] = { > + [MTK_DP_CAL_GLB_BIAS_TRIM] = { > + .idx = 0, > + .shift = 27, > + .mask = 0x1f, > + .min_val = 1, > + .max_val = 0x1e, > + .default_val = 0xf, > + }, > + [MTK_DP_CAL_CLKTX_IMPSE] = { > + .idx = 0, > + .shift = 13, > + .mask = 0xf, > + .min_val = 1, > + .max_val = 0xe, > + .default_val = 0x8, > + }, > + [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_0] = { > + .idx = 1, > + .shift = 28, > + .mask = 0xf, > + .min_val = 1, > + .max_val = 0xe, > + .default_val = 0x8, > + }, > + [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_1] = { > + .idx = 1, > + .shift = 20, > + .mask = 0xf, > + .min_val = 1, > + .max_val = 0xe, > + .default_val = 0x8, > + }, > + [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_2] = { > + .idx = 1, > + .shift = 12, > + .mask = 0xf, > + .min_val = 1, > + .max_val = 0xe, > + .default_val = 0x8, > + }, > + [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_3] = { > + .idx = 1, > + .shift = 4, > + .mask = 0xf, > + .min_val = 1, > + .max_val = 0xe, > + .default_val = 0x8, > + }, > + [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_0] = { > + .idx = 1, > + .shift = 24, > + .mask = 0xf, > + .min_val = 1, > + .max_val = 0xe, > + .default_val = 0x8, > + }, > + [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_1] = { > + .idx = 1, > + .shift = 16, > + .mask = 0xf, > + .min_val = 1, > + .max_val = 0xe, > + .default_val = 0x8, > + }, > + [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_2] = { > + .idx = 1, > + .shift = 8, > + .mask = 0xf, > + .min_val = 1, > + .max_val = 0xe, > + .default_val = 0x8, > + }, > + [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_3] = { > + .idx = 1, > + .shift = 0, > + .mask = 0xf, > + .min_val = 1, > + .max_val = 0xe, > + .default_val = 0x8, > + }, > +}; > + > static struct regmap_config mtk_dp_regmap_config = { > .reg_bits = 32, > .val_bits = 32, > @@ -1479,6 +1563,50 @@ static int mtk_dp_dt_parse(struct mtk_dp > *mtk_dp, > return 0; > } > > +static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge > *bridge) > +{ > + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge); > + enum drm_connector_status ret = connector_status_disconnected; > + bool enabled = mtk_dp->enabled; > + u8 sink_count = 0; > + > + if (mtk_dp->train_info.cable_plugged_in) { I would modify this as below when I apply this patch into my tree: if (!mtk_dp->train_info.cable_plugged_in) return ret; Reviewed-by: CK Hu <ck.hu@mediatek.com> > + if (!enabled) { > + /* power on aux */ > + mtk_dp_update_bits(mtk_dp, > MTK_DP_TOP_PWR_STATE, > + DP_PWR_STATE_BANDGAP_TPLL_LA > NE, > + DP_PWR_STATE_MASK); > + > + /* power on panel */ > + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, > DP_SET_POWER_D0); > + usleep_range(2000, 5000); > + } > + /* > + * Some dongles still source HPD when they do not > connect to any > + * sink device. To avoid this, we need to read the sink > count > + * to make sure we do connect to sink devices. After > this detect > + * function, we just need to check the HPD connection > to check > + * whether we connect to a sink device. > + */ > + drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT, > &sink_count); > + if (DP_GET_SINK_COUNT(sink_count)) > + ret = connector_status_connected; > + > + if (!enabled) { > + /* power off panel */ > + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, > DP_SET_POWER_D3); > + usleep_range(2000, 3000); > + > + /* power off aux */ > + mtk_dp_update_bits(mtk_dp, > MTK_DP_TOP_PWR_STATE, > + DP_PWR_STATE_BANDGAP_TPLL, > + DP_PWR_STATE_MASK); > + } > + } > + > + return ret; > +} > + > static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, > struct drm_connector *connector) > { > @@ -1865,6 +1993,7 @@ static const struct drm_bridge_funcs > mtk_dp_bridge_funcs = { > .atomic_disable = mtk_dp_bridge_atomic_disable, > .mode_valid = mtk_dp_bridge_mode_valid, > .get_edid = mtk_dp_get_edid, > + .detect = mtk_dp_bdg_detect, > }; > > static int mtk_dp_probe(struct platform_device *pdev) > @@ -1991,11 +2120,21 @@ static const struct mtk_dp_data > mt8195_edp_data = { > .efuse_fmt = mt8195_edp_efuse_fmt, > }; > > +static const struct mtk_dp_data mt8195_dp_data = { > + .bridge_type = DRM_MODE_CONNECTOR_DisplayPort, > + .smc_cmd = MTK_DP_SIP_ATF_VIDEO_UNMUTE, > + .efuse_fmt = mt8195_dp_efuse_fmt, > +}; > + > static const struct of_device_id mtk_dp_of_match[] = { > { > .compatible = "mediatek,mt8195-edp-tx", > .data = &mt8195_edp_data, > }, > + { > + .compatible = "mediatek,mt8195-dp-tx", > + .data = &mt8195_dp_data, > + }, > {}, > }; > MODULE_DEVICE_TABLE(of, mtk_dp_of_match);
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index e37c9185e4ec..11a94927c0d0 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -35,6 +35,7 @@ #define MTK_DP_SIP_CONTROL_AARCH32 MTK_SIP_SMC_CMD(0x523) #define MTK_DP_SIP_ATF_EDP_VIDEO_UNMUTE (BIT(0) | BIT(5)) +#define MTK_DP_SIP_ATF_VIDEO_UNMUTE BIT(5) #define MTK_DP_THREAD_CABLE_STATE_CHG BIT(0) #define MTK_DP_THREAD_HPD_EVENT BIT(1) @@ -199,6 +200,89 @@ static const struct mtk_dp_efuse_fmt mt8195_edp_efuse_fmt[MTK_DP_CAL_MAX] = { }, }; +static const struct mtk_dp_efuse_fmt mt8195_dp_efuse_fmt[MTK_DP_CAL_MAX] = { + [MTK_DP_CAL_GLB_BIAS_TRIM] = { + .idx = 0, + .shift = 27, + .mask = 0x1f, + .min_val = 1, + .max_val = 0x1e, + .default_val = 0xf, + }, + [MTK_DP_CAL_CLKTX_IMPSE] = { + .idx = 0, + .shift = 13, + .mask = 0xf, + .min_val = 1, + .max_val = 0xe, + .default_val = 0x8, + }, + [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_0] = { + .idx = 1, + .shift = 28, + .mask = 0xf, + .min_val = 1, + .max_val = 0xe, + .default_val = 0x8, + }, + [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_1] = { + .idx = 1, + .shift = 20, + .mask = 0xf, + .min_val = 1, + .max_val = 0xe, + .default_val = 0x8, + }, + [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_2] = { + .idx = 1, + .shift = 12, + .mask = 0xf, + .min_val = 1, + .max_val = 0xe, + .default_val = 0x8, + }, + [MTK_DP_CAL_LN_TX_IMPSEL_PMOS_3] = { + .idx = 1, + .shift = 4, + .mask = 0xf, + .min_val = 1, + .max_val = 0xe, + .default_val = 0x8, + }, + [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_0] = { + .idx = 1, + .shift = 24, + .mask = 0xf, + .min_val = 1, + .max_val = 0xe, + .default_val = 0x8, + }, + [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_1] = { + .idx = 1, + .shift = 16, + .mask = 0xf, + .min_val = 1, + .max_val = 0xe, + .default_val = 0x8, + }, + [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_2] = { + .idx = 1, + .shift = 8, + .mask = 0xf, + .min_val = 1, + .max_val = 0xe, + .default_val = 0x8, + }, + [MTK_DP_CAL_LN_TX_IMPSEL_NMOS_3] = { + .idx = 1, + .shift = 0, + .mask = 0xf, + .min_val = 1, + .max_val = 0xe, + .default_val = 0x8, + }, +}; + static struct regmap_config mtk_dp_regmap_config = { .reg_bits = 32, .val_bits = 32, @@ -1479,6 +1563,50 @@ static int mtk_dp_dt_parse(struct mtk_dp *mtk_dp, return 0; } +static enum drm_connector_status mtk_dp_bdg_detect(struct drm_bridge *bridge) +{ + struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge); + enum drm_connector_status ret = connector_status_disconnected; + bool enabled = mtk_dp->enabled; + u8 sink_count = 0; + + if (mtk_dp->train_info.cable_plugged_in) { + if (!enabled) { + /* power on aux */ + mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, + DP_PWR_STATE_BANDGAP_TPLL_LANE, + DP_PWR_STATE_MASK); + + /* power on panel */ + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); + usleep_range(2000, 5000); + } + /* + * Some dongles still source HPD when they do not connect to any + * sink device. To avoid this, we need to read the sink count + * to make sure we do connect to sink devices. After this detect + * function, we just need to check the HPD connection to check + * whether we connect to a sink device. + */ + drm_dp_dpcd_readb(&mtk_dp->aux, DP_SINK_COUNT, &sink_count); + if (DP_GET_SINK_COUNT(sink_count)) + ret = connector_status_connected; + + if (!enabled) { + /* power off panel */ + drm_dp_dpcd_writeb(&mtk_dp->aux, DP_SET_POWER, DP_SET_POWER_D3); + usleep_range(2000, 3000); + + /* power off aux */ + mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE, + DP_PWR_STATE_BANDGAP_TPLL, + DP_PWR_STATE_MASK); + } + } + + return ret; +} + static struct edid *mtk_dp_get_edid(struct drm_bridge *bridge, struct drm_connector *connector) { @@ -1865,6 +1993,7 @@ static const struct drm_bridge_funcs mtk_dp_bridge_funcs = { .atomic_disable = mtk_dp_bridge_atomic_disable, .mode_valid = mtk_dp_bridge_mode_valid, .get_edid = mtk_dp_get_edid, + .detect = mtk_dp_bdg_detect, }; static int mtk_dp_probe(struct platform_device *pdev) @@ -1991,11 +2120,21 @@ static const struct mtk_dp_data mt8195_edp_data = { .efuse_fmt = mt8195_edp_efuse_fmt, }; +static const struct mtk_dp_data mt8195_dp_data = { + .bridge_type = DRM_MODE_CONNECTOR_DisplayPort, + .smc_cmd = MTK_DP_SIP_ATF_VIDEO_UNMUTE, + .efuse_fmt = mt8195_dp_efuse_fmt, +}; + static const struct of_device_id mtk_dp_of_match[] = { { .compatible = "mediatek,mt8195-edp-tx", .data = &mt8195_edp_data, }, + { + .compatible = "mediatek,mt8195-dp-tx", + .data = &mt8195_dp_data, + }, {}, }; MODULE_DEVICE_TABLE(of, mtk_dp_of_match);