Since commit b626b1a1c9cc ("drm/bridge: refactor HDMI InfoFrame
callbacks"), the following warning is generated:
[ 13.654149] rockchip-drm display-subsystem: [drm] HDMI VSI not supported
Add the missing support for sending HDMI Vendor-Specific Infoframes.
Additionally, introduce the dw_hdmi_qp_write_pkt() utility function, as
a prerequisite to rework the *_write_*_infoframe() callbacks and get rid
of some boilerplate code.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 32 +++++++++++++++++++++++++---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h | 2 ++
2 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 036316e2b60d..b37af6a7e194 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -11,6 +11,7 @@
#include <linux/export.h>
#include <linux/i2c.h>
#include <linux/irq.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
@@ -969,9 +970,9 @@ static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
static int dw_hdmi_qp_bridge_clear_hdmi_infoframe(struct drm_bridge *bridge)
{
- /* FIXME: add support for this InfoFrame */
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
- drm_warn_once(bridge->encoder->dev, "HDMI VSI not supported\n");
+ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_VSI_TX_EN, PKTSCHED_PKT_EN);
return 0;
}
@@ -998,6 +999,18 @@ static int dw_hdmi_qp_bridge_clear_audio_infoframe(struct drm_bridge *bridge)
return 0;
}
+static void dw_hdmi_qp_write_pkt(struct dw_hdmi_qp *hdmi, const u8 *buffer,
+ size_t start, size_t len, unsigned int reg)
+{
+ u32 val = 0;
+ size_t i;
+
+ for (i = start; i < start + len; i++)
+ val |= buffer[i] << ((i % 4) * 8);
+
+ dw_hdmi_qp_write(hdmi, val, reg);
+}
+
static int dw_hdmi_qp_bridge_write_avi_infoframe(struct drm_bridge *bridge,
const u8 *buffer, size_t len)
{
@@ -1011,9 +1024,22 @@ static int dw_hdmi_qp_bridge_write_avi_infoframe(struct drm_bridge *bridge,
static int dw_hdmi_qp_bridge_write_hdmi_infoframe(struct drm_bridge *bridge,
const u8 *buffer, size_t len)
{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+ size_t i;
+
dw_hdmi_qp_bridge_clear_hdmi_infoframe(bridge);
- /* FIXME: add support for the HDMI VSI */
+ /* VSI packet header */
+ dw_hdmi_qp_write_pkt(hdmi, buffer, 1, 2, PKT_VSI_CONTENTS0);
+
+ /* VSI packet body */
+ for (i = 0; i < len - 3; i += 4)
+ dw_hdmi_qp_write_pkt(hdmi, buffer + 3, i, min(len - i - 3, 4),
+ PKT_VSI_CONTENTS1 + i);
+
+ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_VSI_FIELDRATE, PKTSCHED_PKT_CONFIG1);
+ dw_hdmi_qp_mod(hdmi, PKTSCHED_VSI_TX_EN, PKTSCHED_VSI_TX_EN,
+ PKTSCHED_PKT_EN);
return 0;
}
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h
index 91a15f82e32a..53688eae8dba 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h
@@ -198,6 +198,7 @@
#define PKTSCHED_PRQUEUE2_CONFIG2 0xa94
#define PKTSCHED_PKT_CONFIG0 0xa98
#define PKTSCHED_PKT_CONFIG1 0xa9c
+#define PKTSCHED_VSI_FIELDRATE BIT(14)
#define PKTSCHED_DRMI_FIELDRATE BIT(13)
#define PKTSCHED_AVI_FIELDRATE BIT(12)
#define PKTSCHED_PKT_CONFIG2 0xaa0
@@ -206,6 +207,7 @@
#define PKTSCHED_DRMI_TX_EN BIT(17)
#define PKTSCHED_AUDI_TX_EN BIT(15)
#define PKTSCHED_AVI_TX_EN BIT(13)
+#define PKTSCHED_VSI_TX_EN BIT(12)
#define PKTSCHED_EMP_CVTEM_TX_EN BIT(10)
#define PKTSCHED_AMD_TX_EN BIT(8)
#define PKTSCHED_GCP_TX_EN BIT(3)
--
2.52.0
Hi Cristian, On Sun, 25 Jan 2026 at 00:23, Cristian Ciocaltea <cristian.ciocaltea@collabora.com> wrote: > + /* VSI packet body */ > + for (i = 0; i < len - 3; i += 4) > + dw_hdmi_qp_write_pkt(hdmi, buffer + 3, i, min(len - i - 3, 4), > + PKT_VSI_CONTENTS1 + i); Given that this for loop occurs in all the users (other than when len < 4 where it's not required), why not move it into the dw_hdmi_qp_write_pkt() helper itself, such that the calls for each infoframe could be dw_hdmi_qp_write_pkt(hdmi, buffer + 3, len, PKT_VSI_CONTENTS1 /* base reg, incremented by helper */)? Cheers, Daniel
Hi Daniel, On 1/28/26 2:11 PM, Daniel Stone wrote: > Hi Cristian, > > On Sun, 25 Jan 2026 at 00:23, Cristian Ciocaltea > <cristian.ciocaltea@collabora.com> wrote: >> + /* VSI packet body */ >> + for (i = 0; i < len - 3; i += 4) >> + dw_hdmi_qp_write_pkt(hdmi, buffer + 3, i, min(len - i - 3, 4), >> + PKT_VSI_CONTENTS1 + i); > > Given that this for loop occurs in all the users (other than when len > < 4 where it's not required), why not move it into the > dw_hdmi_qp_write_pkt() helper itself, such that the calls for each > infoframe could be dw_hdmi_qp_write_pkt(hdmi, buffer + 3, len, > PKT_VSI_CONTENTS1 /* base reg, incremented by helper */)? Yeah, initially planned to keep the helper simple and allow more flexibility in the callbacks. Probably now it makes sense to also write the packet header via the helper, not just the body, since this is also handled similarly in all cases. Thanks, Cristian
© 2016 - 2026 Red Hat, Inc.