[PATCH RFC 04/25] video/hdmi: Add VTEM EMP packing
Nicolas Frattaroli
nicolas.frattaroli at collabora.com
Mon Sep 21 08:51:30 PDT 2026
From: Derek Foreman <derek.foreman at collabora.com>
VTEM EMPs are a type of infoframe that is required for Variable Refresh
Rate. Add code to pack them.
Signed-off-by: Derek Foreman <derek.foreman at collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
drivers/video/hdmi.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/hdmi.h | 19 ++++++++++
2 files changed, 115 insertions(+), 1 deletion(-)
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 45b42f14a750..ed9abc7ad228 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -983,6 +983,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
buffer, size);
break;
+ case HDMI_INFOFRAME_TYPE_EMP:
+ length = hdmi_emp_infoframe_vtem_pack(&frame->vtem,
+ buffer, size);
+ break;
default:
WARN(1, "Bad infoframe type %d\n", frame->any.type);
length = -EINVAL;
@@ -994,9 +998,11 @@ EXPORT_SYMBOL(hdmi_infoframe_pack);
static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
{
- if (type < 0x80 || type > 0x9f)
+ if (type < 0x7F || type > 0x9f)
return "Invalid";
switch (type) {
+ case HDMI_INFOFRAME_TYPE_EMP:
+ return "EMP";
case HDMI_INFOFRAME_TYPE_VENDOR:
return "Vendor";
case HDMI_INFOFRAME_TYPE_AVI:
@@ -1516,6 +1522,29 @@ hdmi_vendor_any_infoframe_log(const char *level,
}
}
+static void
+hdmi_emp_infoframe_vtem_log(const char *level,
+ struct device *dev,
+ const struct hdmi_emp_infoframe_vtem *frame)
+{
+ hdmi_infoframe_log_header(level, dev,
+ (const struct hdmi_any_infoframe *)frame);
+
+ hdmi_log(" game vrr enabled: %u\n", frame->game_vrr_en);
+ hdmi_log(" fva factor minus 1: %u\n", frame->fva_factor_m1);
+ hdmi_log(" m_const: %u\n", frame->m_const);
+ hdmi_log(" base vertical front porch: %u\n", frame->base_vfront);
+ hdmi_log(" base refresh rate: %u\n", frame->base_refresh_rate);
+}
+
+static void
+hdmi_emp_infoframe_log(const char *level,
+ struct device *dev,
+ const union hdmi_infoframe *frame)
+{
+ /* Only support VTEM for now */
+ hdmi_emp_infoframe_vtem_log(level, dev, &frame->vtem);
+}
/**
* hdmi_infoframe_log() - log info of HDMI infoframe
* @level: logging level
@@ -1542,6 +1571,9 @@ void hdmi_infoframe_log(const char *level,
case HDMI_INFOFRAME_TYPE_DRM:
hdmi_drm_infoframe_log(level, dev, &frame->drm);
break;
+ case HDMI_INFOFRAME_TYPE_EMP:
+ hdmi_emp_infoframe_log(level, dev, frame);
+ break;
}
}
EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1919,3 +1951,66 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
return ret;
}
EXPORT_SYMBOL(hdmi_infoframe_unpack);
+
+/**
+ * hdmi_emp_infoframe_vtem_init() - initialize an HDMI VTEM EMP
+ * @emp: HDMI VTEM EMP
+ */
+void hdmi_emp_infoframe_vtem_init(struct hdmi_emp_infoframe_vtem *emp)
+{
+ memset(emp, 0, sizeof(*emp));
+ emp->type = HDMI_INFOFRAME_TYPE_EMP;
+}
+EXPORT_SYMBOL(hdmi_emp_infoframe_vtem_init);
+
+/**
+ * hdmi_emp_infoframe_vtem_pack() - pack a vtem into a binary buffer
+ * @vtem: pointer to &struct hdmi_emp_infoframe_vtem to pack
+ * @buffer: pointer to pre-allocated output buffer
+ * @size: maximum size in bytes of @buffer
+ *
+ * Pack a VTEM infoframe struct into a binary buffer in a way that's suitable
+ * to be sent out over the wire.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_emp_infoframe_vtem_pack(struct hdmi_emp_infoframe_vtem *vtem,
+ void *buffer, size_t size)
+{
+ u8 *ptr = buffer;
+
+ if (size < HDMI_INFOFRAME_SIZE(VTEM))
+ return -EINVAL;
+
+ /* 4 bits max */
+ if (vtem->fva_factor_m1 > 0xF)
+ return -EINVAL;
+
+ memset(buffer, 0, size);
+
+ /* Header Data */
+ ptr[0] = vtem->type;
+ ptr[1] = BIT(7) | BIT(6);
+ ptr[2] = 0;
+
+ ptr[3] = BIT(7) | BIT(2);
+
+ ptr[4] = 0;
+ ptr[5] = 1;
+ ptr[6] = 0;
+ ptr[7] = 1;
+ ptr[8] = 0;
+ ptr[9] = 4;
+
+ /* This is where the VTEM part starts */
+ ptr[10] = (vtem->fva_factor_m1 << 4) |
+ (vtem->m_const ? BIT(1) : 0) |
+ (vtem->game_vrr_en ? BIT(0) : 0);
+ ptr[11] = vtem->base_vfront;
+ ptr[12] = vtem->base_refresh_rate >> 8 & 0x3;
+ ptr[13] = vtem->base_refresh_rate & 0xFF;
+
+ return 14;
+}
+EXPORT_SYMBOL(hdmi_emp_infoframe_vtem_pack);
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index b80a5ee63bb2..71e2b36896af 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -55,6 +55,7 @@ enum hdmi_packet_type {
};
enum hdmi_infoframe_type {
+ HDMI_INFOFRAME_TYPE_EMP = 0x7F,
HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
HDMI_INFOFRAME_TYPE_AVI = 0x82,
HDMI_INFOFRAME_TYPE_SPD = 0x83,
@@ -76,6 +77,7 @@ enum hdmi_infoframe_type {
#define HDMI_AUDIO_INFOFRAME_SIZE 10
#define HDMI_DRM_INFOFRAME_SIZE 26
#define HDMI_VENDOR_INFOFRAME_SIZE 4
+#define HDMI_VTEM_INFOFRAME_SIZE 10
/*
* HDMI 1.3a table 5-14 states that the largest InfoFrame_length is 27,
@@ -235,6 +237,18 @@ struct hdmi_drm_infoframe {
u16 max_fall;
};
+struct hdmi_emp_infoframe_vtem {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+
+ bool game_vrr_en;
+ bool m_const;
+ unsigned char fva_factor_m1;
+ unsigned char base_vfront;
+ u16 base_refresh_rate;
+};
+
void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
size_t size);
@@ -249,6 +263,10 @@ ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame,
int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame);
int hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe *frame,
const void *buffer, size_t size);
+void hdmi_emp_infoframe_vtem_init(struct hdmi_emp_infoframe_vtem *frame);
+ssize_t hdmi_emp_infoframe_vtem_pack(struct hdmi_emp_infoframe_vtem *frame,
+ void *buffer,
+ size_t size);
enum hdmi_spd_sdi {
HDMI_SPD_SDI_UNKNOWN,
@@ -457,6 +475,7 @@ union hdmi_infoframe {
union hdmi_vendor_any_infoframe vendor;
struct hdmi_audio_infoframe audio;
struct hdmi_drm_infoframe drm;
+ struct hdmi_emp_infoframe_vtem vtem;
};
ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
--
2.55.0
More information about the linux-arm-kernel
mailing list