diff options
| author | Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> | 2026-01-07 20:15:02 +0200 |
|---|---|---|
| committer | Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> | 2026-01-19 13:11:46 +0200 |
| commit | b626b1a1c9ccadd8861870a2a450f02e0c61ab88 (patch) | |
| tree | 7297ae1fe3ea7ed78bd1c733c50ae65668c4e1da /drivers/gpu/drm/bridge/adv7511 | |
| parent | afc399f7a5ea7bf405b2ef85c7470529b1a9e47c (diff) | |
drm/bridge: refactor HDMI InfoFrame callbacks
Having only a single set of callbacks, hdmi_clear_infoframe and
hdmi_write_infoframe, bridge drivers don't have an easy way to signal to
the DRM framework, which InfoFrames are actually supported by the
hardware and by the driver and which are not. Also, it makes it
extremely easy for HDMI bridge drivers to skip implementing the
seemingly required InfoFrames (e.g. HDMI VSI). Last, but not least,
those callbacks take a single 'type' parameter, which makes it
impossible to implement support for multiple VSIs (which will be
required once we start working on HDMI Forum VSI).
Split the callbacks into a per-InfoFrame-kind pairs, letting the bridge
drivers actually signal supported features. The implementation follows
the overall drm_bridge design, where the bridge has a single
drm_bridge_funcs implementation and signals, which functions are to be
called using the drm_bridge->ops flags.
The AVI and HDMI VSI are assumed to be required for a normal HDMI
operation (with the drivers getting a drm_warn_once() stub
implementation if one is missing). The Audio InfoFrame is handled by the
existing DRM_BRIDGE_OP_HDMI_AUDIO, while the SPD and HDR DRM InfoFrames
got new drm_bridge_ops values.
Acked-by: Maxime Ripard <mripard@kernel.org>
Link: https://patch.msgid.link/20260107-limit-infoframes-2-v4-5-213d0d3bd490@oss.qualcomm.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Diffstat (limited to 'drivers/gpu/drm/bridge/adv7511')
| -rw-r--r-- | drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 180 |
1 files changed, 105 insertions, 75 deletions
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index b9be86541307..1050bb62280b 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -887,88 +887,111 @@ static const struct drm_edid *adv7511_bridge_edid_read(struct drm_bridge *bridge return adv7511_edid_read(adv, connector); } -static int adv7511_bridge_hdmi_clear_infoframe(struct drm_bridge *bridge, - enum hdmi_infoframe_type type) +static int adv7511_bridge_hdmi_clear_audio_infoframe(struct drm_bridge *bridge) { struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - switch (type) { - case HDMI_INFOFRAME_TYPE_AUDIO: - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); - break; - case HDMI_INFOFRAME_TYPE_AVI: - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); - break; - case HDMI_INFOFRAME_TYPE_SPD: - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD); - break; - case HDMI_INFOFRAME_TYPE_VENDOR: - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); - break; - default: - drm_dbg_driver(adv7511->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type); - break; - } + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); return 0; } -static int adv7511_bridge_hdmi_write_infoframe(struct drm_bridge *bridge, - enum hdmi_infoframe_type type, - const u8 *buffer, size_t len) +static int adv7511_bridge_hdmi_clear_avi_infoframe(struct drm_bridge *bridge) { struct adv7511 *adv7511 = bridge_to_adv7511(bridge); - switch (type) { - case HDMI_INFOFRAME_TYPE_AUDIO: - /* send current Audio infoframe values while updating */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, - BIT(5), BIT(5)); - - /* The Audio infoframe id is not configurable */ - regmap_bulk_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_VERSION, - buffer + 1, len - 1); - - /* use Audio infoframe updated info */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, - BIT(5), 0); - - adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); - break; - case HDMI_INFOFRAME_TYPE_AVI: - /* send current AVI infoframe values while updating */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, - BIT(6), BIT(6)); - - /* The AVI infoframe id is not configurable */ - regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION, - buffer + 1, len - 1); - - regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_LENGTH, 0x2); - regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(1), 0x1); - - /* use AVI infoframe updated info */ - regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, - BIT(6), 0); - - adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); - break; - case HDMI_INFOFRAME_TYPE_SPD: - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD); - regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPD(0), - buffer, len); - adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPD); - break; - case HDMI_INFOFRAME_TYPE_VENDOR: - adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); - regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPARE1(0), - buffer, len); - adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); - break; - default: - drm_dbg_driver(adv7511->bridge.dev, "Unsupported HDMI InfoFrame %x\n", type); - break; - } + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); + + return 0; +} + +static int adv7511_bridge_hdmi_clear_spd_infoframe(struct drm_bridge *bridge) +{ + struct adv7511 *adv7511 = bridge_to_adv7511(bridge); + + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD); + + return 0; +} + +static int adv7511_bridge_hdmi_clear_hdmi_infoframe(struct drm_bridge *bridge) +{ + struct adv7511 *adv7511 = bridge_to_adv7511(bridge); + + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); + + return 0; +} + +static int adv7511_bridge_hdmi_write_audio_infoframe(struct drm_bridge *bridge, + const u8 *buffer, size_t len) +{ + struct adv7511 *adv7511 = bridge_to_adv7511(bridge); + + /* send current Audio infoframe values while updating */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, + BIT(5), BIT(5)); + + /* The Audio infoframe id is not configurable */ + regmap_bulk_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_VERSION, + buffer + 1, len - 1); + + /* use Audio infoframe updated info */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, + BIT(5), 0); + + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME); + + return 0; +} + +static int adv7511_bridge_hdmi_write_avi_infoframe(struct drm_bridge *bridge, + const u8 *buffer, size_t len) +{ + struct adv7511 *adv7511 = bridge_to_adv7511(bridge); + + /* send current AVI infoframe values while updating */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, + BIT(6), BIT(6)); + + /* The AVI infoframe id is not configurable */ + regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION, + buffer + 1, len - 1); + + regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME_LENGTH, 0x2); + regmap_write(adv7511->regmap, ADV7511_REG_AUDIO_INFOFRAME(1), 0x1); + + /* use AVI infoframe updated info */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE, + BIT(6), 0); + + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); + + return 0; +} + +static int adv7511_bridge_hdmi_write_spd_infoframe(struct drm_bridge *bridge, + const u8 *buffer, size_t len) +{ + struct adv7511 *adv7511 = bridge_to_adv7511(bridge); + + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPD); + regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPD(0), + buffer, len); + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPD); + + return 0; +} + +static int adv7511_bridge_hdmi_write_hdmi_infoframe(struct drm_bridge *bridge, + const u8 *buffer, size_t len) +{ + struct adv7511 *adv7511 = bridge_to_adv7511(bridge); + + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); + regmap_bulk_write(adv7511->regmap_packet, ADV7511_PACKET_SPARE1(0), + buffer, len); + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_SPARE1); return 0; } @@ -986,8 +1009,14 @@ static const struct drm_bridge_funcs adv7511_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset, .hdmi_tmds_char_rate_valid = adv7511_bridge_hdmi_tmds_char_rate_valid, - .hdmi_clear_infoframe = adv7511_bridge_hdmi_clear_infoframe, - .hdmi_write_infoframe = adv7511_bridge_hdmi_write_infoframe, + .hdmi_clear_audio_infoframe = adv7511_bridge_hdmi_clear_audio_infoframe, + .hdmi_write_audio_infoframe = adv7511_bridge_hdmi_write_audio_infoframe, + .hdmi_clear_avi_infoframe = adv7511_bridge_hdmi_clear_avi_infoframe, + .hdmi_write_avi_infoframe = adv7511_bridge_hdmi_write_avi_infoframe, + .hdmi_clear_spd_infoframe = adv7511_bridge_hdmi_clear_spd_infoframe, + .hdmi_write_spd_infoframe = adv7511_bridge_hdmi_write_spd_infoframe, + .hdmi_clear_hdmi_infoframe = adv7511_bridge_hdmi_clear_hdmi_infoframe, + .hdmi_write_hdmi_infoframe = adv7511_bridge_hdmi_write_hdmi_infoframe, .hdmi_audio_startup = adv7511_hdmi_audio_startup, .hdmi_audio_prepare = adv7511_hdmi_audio_prepare, @@ -1322,7 +1351,8 @@ static int adv7511_probe(struct i2c_client *i2c) adv7511->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | - DRM_BRIDGE_OP_HDMI; + DRM_BRIDGE_OP_HDMI | + DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME; if (adv7511->i2c_main->irq) adv7511->bridge.ops |= DRM_BRIDGE_OP_HPD; |
