All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/18] drm/i915: Infoframe precompute/check
@ 2018-09-20 18:51 ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Series aimed at precomputing the HDMI infoframes, and we also get
better validation by reading them back out from the hardware and
comparing with the expected data.

Looks like I typed these up about a year ago. Might be time to
get them in before the anniversary ;)

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org

Ville Syrjälä (18):
  video/hdmi: Constify 'buffer' to the unpack functions
  video/hdmi: Pass buffer size to infoframe unpack functions
  video/hdmi: Constify infoframe passed to the log functions
  video/hdmi: Constify infoframe passed to the pack functions
  video/hdmi: Add an enum for HDMI packet types
  video/hdmi: Handle the MPEG Source infoframe
  video/hdmi: Handle the NTSC VBI infoframe
  drm/i915: Use memmove() for punching the hole into infoframes
  drm/i915: Pass intel_encoder to infoframe functions
  drm/i915: Add the missing HDMI gamut metadata packet stuff
  drm/i915: Return the mask of enabled infoframes from
    ->inforame_enabled()
  drm/i915: Store mask of enabled infoframes in the crtc state
  drm/i915: Precompute HDMI infoframes
  drm/i915: Read out HDMI infoframes
  drm/i915/sdvo: Precompute HDMI infoframes
  drm/i915/sdvo: Read out HDMI infoframes
  drm/i915: Check infoframe state in intel_pipe_config_compare()
  drm/i915: Include infoframes in the crtc state dump

 drivers/gpu/drm/i915/i915_reg.h      |    4 +-
 drivers/gpu/drm/i915/intel_ddi.c     |   27 +-
 drivers/gpu/drm/i915/intel_display.c |   74 ++-
 drivers/gpu/drm/i915/intel_drv.h     |   27 +-
 drivers/gpu/drm/i915/intel_hdmi.c    |  651 ++++++++++++++++-----
 drivers/gpu/drm/i915/intel_psr.c     |    3 +-
 drivers/gpu/drm/i915/intel_sdvo.c    |  150 ++++-
 drivers/media/i2c/adv7511.c          |    2 +-
 drivers/media/i2c/adv7604.c          |    2 +-
 drivers/media/i2c/adv7842.c          |    2 +-
 drivers/media/i2c/tc358743.c         |    2 +-
 drivers/media/i2c/tda1997x.c         |    4 +-
 drivers/video/hdmi.c                 | 1032 ++++++++++++++++++++++++++++++----
 include/linux/hdmi.h                 |   84 ++-
 14 files changed, 1786 insertions(+), 278 deletions(-)

-- 
2.16.4

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH 00/18] drm/i915: Infoframe precompute/check
@ 2018-09-20 18:51 ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Series aimed at precomputing the HDMI infoframes, and we also get
better validation by reading them back out from the hardware and
comparing with the expected data.

Looks like I typed these up about a year ago. Might be time to
get them in before the anniversary ;)

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org

Ville Syrjälä (18):
  video/hdmi: Constify 'buffer' to the unpack functions
  video/hdmi: Pass buffer size to infoframe unpack functions
  video/hdmi: Constify infoframe passed to the log functions
  video/hdmi: Constify infoframe passed to the pack functions
  video/hdmi: Add an enum for HDMI packet types
  video/hdmi: Handle the MPEG Source infoframe
  video/hdmi: Handle the NTSC VBI infoframe
  drm/i915: Use memmove() for punching the hole into infoframes
  drm/i915: Pass intel_encoder to infoframe functions
  drm/i915: Add the missing HDMI gamut metadata packet stuff
  drm/i915: Return the mask of enabled infoframes from
    ->inforame_enabled()
  drm/i915: Store mask of enabled infoframes in the crtc state
  drm/i915: Precompute HDMI infoframes
  drm/i915: Read out HDMI infoframes
  drm/i915/sdvo: Precompute HDMI infoframes
  drm/i915/sdvo: Read out HDMI infoframes
  drm/i915: Check infoframe state in intel_pipe_config_compare()
  drm/i915: Include infoframes in the crtc state dump

 drivers/gpu/drm/i915/i915_reg.h      |    4 +-
 drivers/gpu/drm/i915/intel_ddi.c     |   27 +-
 drivers/gpu/drm/i915/intel_display.c |   74 ++-
 drivers/gpu/drm/i915/intel_drv.h     |   27 +-
 drivers/gpu/drm/i915/intel_hdmi.c    |  651 ++++++++++++++++-----
 drivers/gpu/drm/i915/intel_psr.c     |    3 +-
 drivers/gpu/drm/i915/intel_sdvo.c    |  150 ++++-
 drivers/media/i2c/adv7511.c          |    2 +-
 drivers/media/i2c/adv7604.c          |    2 +-
 drivers/media/i2c/adv7842.c          |    2 +-
 drivers/media/i2c/tc358743.c         |    2 +-
 drivers/media/i2c/tda1997x.c         |    4 +-
 drivers/video/hdmi.c                 | 1032 ++++++++++++++++++++++++++++++----
 include/linux/hdmi.h                 |   84 ++-
 14 files changed, 1786 insertions(+), 278 deletions(-)

-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions
  2018-09-20 18:51 ` Ville Syrjala
@ 2018-09-20 18:51   ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The unpack functions just read from the passed in buffer,
so make it const.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 23 ++++++++++++-----------
 include/linux/hdmi.h |  3 ++-
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 38716eb50408..65b915ea4936 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -31,7 +31,7 @@
 
 #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
 
-static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
+static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
 {
 	u8 csum = 0;
 	size_t i;
@@ -1016,9 +1016,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
-				     void *buffer)
+				     const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	int ret;
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
@@ -1079,9 +1079,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
-				     void *buffer)
+				     const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	int ret;
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
@@ -1117,9 +1117,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
-				       void *buffer)
+				       const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	int ret;
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
@@ -1163,9 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
  */
 static int
 hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
-				 void *buffer)
+				 const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	size_t length;
 	int ret;
 	u8 hdmi_video_format;
@@ -1234,10 +1234,11 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
  *
  * Returns 0 on success or a negative error code on failure.
  */
-int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+			  const void *buffer)
 {
 	int ret;
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 
 	switch (ptr[0]) {
 	case HDMI_INFOFRAME_TYPE_AVI:
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index d271ff23984f..d3816170c062 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -332,7 +332,8 @@ union hdmi_infoframe {
 
 ssize_t
 hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
-int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+			  const void *buffer);
 void hdmi_infoframe_log(const char *level, struct device *dev,
 			union hdmi_infoframe *frame);
 
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions
@ 2018-09-20 18:51   ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The unpack functions just read from the passed in buffer,
so make it const.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 23 ++++++++++++-----------
 include/linux/hdmi.h |  3 ++-
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 38716eb50408..65b915ea4936 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -31,7 +31,7 @@
 
 #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
 
-static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
+static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
 {
 	u8 csum = 0;
 	size_t i;
@@ -1016,9 +1016,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
-				     void *buffer)
+				     const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	int ret;
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
@@ -1079,9 +1079,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
-				     void *buffer)
+				     const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	int ret;
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
@@ -1117,9 +1117,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
-				       void *buffer)
+				       const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	int ret;
 
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
@@ -1163,9 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
  */
 static int
 hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
-				 void *buffer)
+				 const void *buffer)
 {
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 	size_t length;
 	int ret;
 	u8 hdmi_video_format;
@@ -1234,10 +1234,11 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
  *
  * Returns 0 on success or a negative error code on failure.
  */
-int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+			  const void *buffer)
 {
 	int ret;
-	u8 *ptr = buffer;
+	const u8 *ptr = buffer;
 
 	switch (ptr[0]) {
 	case HDMI_INFOFRAME_TYPE_AVI:
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index d271ff23984f..d3816170c062 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -332,7 +332,8 @@ union hdmi_infoframe {
 
 ssize_t
 hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
-int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+			  const void *buffer);
 void hdmi_infoframe_log(const char *level, struct device *dev,
 			union hdmi_infoframe *frame);
 
-- 
2.16.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 02/18] video/hdmi: Pass buffer size to infoframe unpack functions
  2018-09-20 18:51 ` Ville Syrjala
@ 2018-09-20 18:51   ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

To make sure the infoframe unpack functions don't end up examining
stack garbage or oopsing, let's pass in the size of the buffer.

v2: Convert tda1997x.c as well (kbuild test robot)

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/media/i2c/adv7511.c  |  2 +-
 drivers/media/i2c/adv7604.c  |  2 +-
 drivers/media/i2c/adv7842.c  |  2 +-
 drivers/media/i2c/tc358743.c |  2 +-
 drivers/media/i2c/tda1997x.c |  4 ++--
 drivers/video/hdmi.c         | 51 ++++++++++++++++++++++++++++++++------------
 include/linux/hdmi.h         |  2 +-
 7 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 55c2ea0720d9..b85b181bbb6c 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -550,7 +550,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
 	buffer[3] = 0;
 	buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
 
-	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
 		return;
 	}
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 668be2bca57a..2e7a28dbad4e 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -2418,7 +2418,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
 		buffer[i + 3] = infoframe_read(sd,
 				       adv76xx_cri[index].payload_addr + i);
 
-	if (hdmi_infoframe_unpack(frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
 			 adv76xx_cri[index].desc);
 		return -ENOENT;
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 4f8fbdd00e35..2cfd03f929b2 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -2563,7 +2563,7 @@ static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infofr
 	for (i = 0; i < len; i++)
 		buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
 
-	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
 		return;
 	}
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 44c41933415a..519bf92508d5 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -444,7 +444,7 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
 
 	i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
 
-	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
 		return;
 	}
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
index d114ac5243ec..195a1fc74ee8 100644
--- a/drivers/media/i2c/tda1997x.c
+++ b/drivers/media/i2c/tda1997x.c
@@ -1253,7 +1253,7 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
 
 	/* read data */
 	len = io_readn(sd, addr, sizeof(buffer), buffer);
-	err = hdmi_infoframe_unpack(&frame, buffer);
+	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
 	if (err) {
 		v4l_err(state->client,
 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
@@ -1928,7 +1928,7 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
 	/* read data */
 	len = io_readn(sd, addr, sizeof(buffer), buffer);
 	v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
-	err = hdmi_infoframe_unpack(&frame, buffer);
+	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
 	if (err) {
 		v4l_err(state->client,
 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 65b915ea4936..b5d491014b0b 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -1005,8 +1005,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
 
 /**
  * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
- * @buffer: source buffer
  * @frame: HDMI AVI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Auxiliary Video (AVI) information frame.
@@ -1016,11 +1017,14 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
-				     const void *buffer)
+				     const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	int ret;
 
+	if (size < HDMI_INFOFRAME_SIZE(AVI))
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
 	    ptr[1] != 2 ||
 	    ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
@@ -1068,8 +1072,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
 
 /**
  * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
- * @buffer: source buffer
  * @frame: HDMI SPD infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Source Product Description (SPD) information frame.
@@ -1079,11 +1084,14 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
-				     const void *buffer)
+				     const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	int ret;
 
+	if (size < HDMI_INFOFRAME_SIZE(SPD))
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
 	    ptr[1] != 1 ||
 	    ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
@@ -1106,8 +1114,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
 
 /**
  * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
- * @buffer: source buffer
  * @frame: HDMI Audio infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Audio information frame.
@@ -1117,11 +1126,14 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
-				       const void *buffer)
+				       const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	int ret;
 
+	if (size < HDMI_INFOFRAME_SIZE(AUDIO))
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
 	    ptr[1] != 1 ||
 	    ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
@@ -1151,8 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
 
 /**
  * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
- * @buffer: source buffer
  * @frame: HDMI Vendor infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Vendor information frame.
@@ -1163,7 +1176,7 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
  */
 static int
 hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
-				 const void *buffer)
+				 const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	size_t length;
@@ -1171,6 +1184,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 	u8 hdmi_video_format;
 	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
 
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
 	    ptr[1] != 1 ||
 	    (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
@@ -1178,6 +1194,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 
 	length = ptr[2];
 
+	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+		return -EINVAL;
+
 	if (hdmi_infoframe_checksum(buffer,
 				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
 		return -EINVAL;
@@ -1224,8 +1243,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
- * @buffer: source buffer
  * @frame: HDMI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary buffer @buffer into a structured
  * @frame of a HDMI infoframe.
@@ -1235,23 +1255,26 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
-			  const void *buffer)
+			  const void *buffer, size_t size)
 {
 	int ret;
 	const u8 *ptr = buffer;
 
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
 	switch (ptr[0]) {
 	case HDMI_INFOFRAME_TYPE_AVI:
-		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
+		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
 		break;
 	case HDMI_INFOFRAME_TYPE_SPD:
-		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
+		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
 		break;
 	case HDMI_INFOFRAME_TYPE_AUDIO:
-		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
+		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
 		break;
 	case HDMI_INFOFRAME_TYPE_VENDOR:
-		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
+		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
 		break;
 	default:
 		ret = -EINVAL;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index d3816170c062..a577d4ae2570 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -333,7 +333,7 @@ union hdmi_infoframe {
 ssize_t
 hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
-			  const void *buffer);
+			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
 			union hdmi_infoframe *frame);
 
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 02/18] video/hdmi: Pass buffer size to infoframe unpack functions
@ 2018-09-20 18:51   ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

To make sure the infoframe unpack functions don't end up examining
stack garbage or oopsing, let's pass in the size of the buffer.

v2: Convert tda1997x.c as well (kbuild test robot)

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/media/i2c/adv7511.c  |  2 +-
 drivers/media/i2c/adv7604.c  |  2 +-
 drivers/media/i2c/adv7842.c  |  2 +-
 drivers/media/i2c/tc358743.c |  2 +-
 drivers/media/i2c/tda1997x.c |  4 ++--
 drivers/video/hdmi.c         | 51 ++++++++++++++++++++++++++++++++------------
 include/linux/hdmi.h         |  2 +-
 7 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 55c2ea0720d9..b85b181bbb6c 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -550,7 +550,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
 	buffer[3] = 0;
 	buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
 
-	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
 		return;
 	}
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 668be2bca57a..2e7a28dbad4e 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -2418,7 +2418,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
 		buffer[i + 3] = infoframe_read(sd,
 				       adv76xx_cri[index].payload_addr + i);
 
-	if (hdmi_infoframe_unpack(frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
 			 adv76xx_cri[index].desc);
 		return -ENOENT;
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 4f8fbdd00e35..2cfd03f929b2 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -2563,7 +2563,7 @@ static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infofr
 	for (i = 0; i < len; i++)
 		buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
 
-	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
 		return;
 	}
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 44c41933415a..519bf92508d5 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -444,7 +444,7 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
 
 	i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
 
-	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
 		v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
 		return;
 	}
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
index d114ac5243ec..195a1fc74ee8 100644
--- a/drivers/media/i2c/tda1997x.c
+++ b/drivers/media/i2c/tda1997x.c
@@ -1253,7 +1253,7 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
 
 	/* read data */
 	len = io_readn(sd, addr, sizeof(buffer), buffer);
-	err = hdmi_infoframe_unpack(&frame, buffer);
+	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
 	if (err) {
 		v4l_err(state->client,
 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
@@ -1928,7 +1928,7 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
 	/* read data */
 	len = io_readn(sd, addr, sizeof(buffer), buffer);
 	v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
-	err = hdmi_infoframe_unpack(&frame, buffer);
+	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
 	if (err) {
 		v4l_err(state->client,
 			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 65b915ea4936..b5d491014b0b 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -1005,8 +1005,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
 
 /**
  * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
- * @buffer: source buffer
  * @frame: HDMI AVI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Auxiliary Video (AVI) information frame.
@@ -1016,11 +1017,14 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
-				     const void *buffer)
+				     const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	int ret;
 
+	if (size < HDMI_INFOFRAME_SIZE(AVI))
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
 	    ptr[1] != 2 ||
 	    ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
@@ -1068,8 +1072,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
 
 /**
  * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
- * @buffer: source buffer
  * @frame: HDMI SPD infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Source Product Description (SPD) information frame.
@@ -1079,11 +1084,14 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
-				     const void *buffer)
+				     const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	int ret;
 
+	if (size < HDMI_INFOFRAME_SIZE(SPD))
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
 	    ptr[1] != 1 ||
 	    ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
@@ -1106,8 +1114,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
 
 /**
  * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
- * @buffer: source buffer
  * @frame: HDMI Audio infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Audio information frame.
@@ -1117,11 +1126,14 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
-				       const void *buffer)
+				       const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	int ret;
 
+	if (size < HDMI_INFOFRAME_SIZE(AUDIO))
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
 	    ptr[1] != 1 ||
 	    ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
@@ -1151,8 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
 
 /**
  * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
- * @buffer: source buffer
  * @frame: HDMI Vendor infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary @buffer into a structured
  * @frame of the HDMI Vendor information frame.
@@ -1163,7 +1176,7 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
  */
 static int
 hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
-				 const void *buffer)
+				 const void *buffer, size_t size)
 {
 	const u8 *ptr = buffer;
 	size_t length;
@@ -1171,6 +1184,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 	u8 hdmi_video_format;
 	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
 
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
 	if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
 	    ptr[1] != 1 ||
 	    (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
@@ -1178,6 +1194,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 
 	length = ptr[2];
 
+	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+		return -EINVAL;
+
 	if (hdmi_infoframe_checksum(buffer,
 				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
 		return -EINVAL;
@@ -1224,8 +1243,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
- * @buffer: source buffer
  * @frame: HDMI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
  *
  * Unpacks the information contained in binary buffer @buffer into a structured
  * @frame of a HDMI infoframe.
@@ -1235,23 +1255,26 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
  * Returns 0 on success or a negative error code on failure.
  */
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
-			  const void *buffer)
+			  const void *buffer, size_t size)
 {
 	int ret;
 	const u8 *ptr = buffer;
 
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
 	switch (ptr[0]) {
 	case HDMI_INFOFRAME_TYPE_AVI:
-		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
+		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
 		break;
 	case HDMI_INFOFRAME_TYPE_SPD:
-		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
+		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
 		break;
 	case HDMI_INFOFRAME_TYPE_AUDIO:
-		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
+		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
 		break;
 	case HDMI_INFOFRAME_TYPE_VENDOR:
-		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
+		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
 		break;
 	default:
 		ret = -EINVAL;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index d3816170c062..a577d4ae2570 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -333,7 +333,7 @@ union hdmi_infoframe {
 ssize_t
 hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
-			  const void *buffer);
+			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
 			union hdmi_infoframe *frame);
 
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions
  2018-09-20 18:51 ` Ville Syrjala
@ 2018-09-20 18:51   ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The log functions don't modify the passed in infoframe so make it const.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 22 +++++++++++-----------
 include/linux/hdmi.h |  2 +-
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index b5d491014b0b..53e7ee2c83fc 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -471,7 +471,7 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 
 static void hdmi_infoframe_log_header(const char *level,
 				      struct device *dev,
-				      struct hdmi_any_infoframe *frame)
+				      const struct hdmi_any_infoframe *frame)
 {
 	hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
 		hdmi_infoframe_type_get_name(frame->type),
@@ -673,10 +673,10 @@ hdmi_content_type_get_name(enum hdmi_content_type content_type)
  */
 static void hdmi_avi_infoframe_log(const char *level,
 				   struct device *dev,
-				   struct hdmi_avi_infoframe *frame)
+				   const struct hdmi_avi_infoframe *frame)
 {
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	hdmi_log("    colorspace: %s\n",
 			hdmi_colorspace_get_name(frame->colorspace));
@@ -750,12 +750,12 @@ static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
  */
 static void hdmi_spd_infoframe_log(const char *level,
 				   struct device *dev,
-				   struct hdmi_spd_infoframe *frame)
+				   const struct hdmi_spd_infoframe *frame)
 {
 	u8 buf[17];
 
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	memset(buf, 0, sizeof(buf));
 
@@ -886,10 +886,10 @@ hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
  */
 static void hdmi_audio_infoframe_log(const char *level,
 				     struct device *dev,
-				     struct hdmi_audio_infoframe *frame)
+				     const struct hdmi_audio_infoframe *frame)
 {
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	if (frame->channels)
 		hdmi_log("    channels: %u\n", frame->channels - 1);
@@ -949,12 +949,12 @@ hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
 static void
 hdmi_vendor_any_infoframe_log(const char *level,
 			      struct device *dev,
-			      union hdmi_vendor_any_infoframe *frame)
+			      const union hdmi_vendor_any_infoframe *frame)
 {
-	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+	const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
 
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	if (frame->any.oui != HDMI_IEEE_OUI) {
 		hdmi_log("    not a HDMI vendor infoframe\n");
@@ -984,7 +984,7 @@ hdmi_vendor_any_infoframe_log(const char *level,
  */
 void hdmi_infoframe_log(const char *level,
 			struct device *dev,
-			union hdmi_infoframe *frame)
+			const union hdmi_infoframe *frame)
 {
 	switch (frame->any.type) {
 	case HDMI_INFOFRAME_TYPE_AVI:
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index a577d4ae2570..bce1abb1fe57 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -335,6 +335,6 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-			union hdmi_infoframe *frame);
+			const union hdmi_infoframe *frame);
 
 #endif /* _DRM_HDMI_H */
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions
@ 2018-09-20 18:51   ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The log functions don't modify the passed in infoframe so make it const.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 22 +++++++++++-----------
 include/linux/hdmi.h |  2 +-
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index b5d491014b0b..53e7ee2c83fc 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -471,7 +471,7 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 
 static void hdmi_infoframe_log_header(const char *level,
 				      struct device *dev,
-				      struct hdmi_any_infoframe *frame)
+				      const struct hdmi_any_infoframe *frame)
 {
 	hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
 		hdmi_infoframe_type_get_name(frame->type),
@@ -673,10 +673,10 @@ hdmi_content_type_get_name(enum hdmi_content_type content_type)
  */
 static void hdmi_avi_infoframe_log(const char *level,
 				   struct device *dev,
-				   struct hdmi_avi_infoframe *frame)
+				   const struct hdmi_avi_infoframe *frame)
 {
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	hdmi_log("    colorspace: %s\n",
 			hdmi_colorspace_get_name(frame->colorspace));
@@ -750,12 +750,12 @@ static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
  */
 static void hdmi_spd_infoframe_log(const char *level,
 				   struct device *dev,
-				   struct hdmi_spd_infoframe *frame)
+				   const struct hdmi_spd_infoframe *frame)
 {
 	u8 buf[17];
 
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	memset(buf, 0, sizeof(buf));
 
@@ -886,10 +886,10 @@ hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
  */
 static void hdmi_audio_infoframe_log(const char *level,
 				     struct device *dev,
-				     struct hdmi_audio_infoframe *frame)
+				     const struct hdmi_audio_infoframe *frame)
 {
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	if (frame->channels)
 		hdmi_log("    channels: %u\n", frame->channels - 1);
@@ -949,12 +949,12 @@ hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
 static void
 hdmi_vendor_any_infoframe_log(const char *level,
 			      struct device *dev,
-			      union hdmi_vendor_any_infoframe *frame)
+			      const union hdmi_vendor_any_infoframe *frame)
 {
-	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+	const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
 
 	hdmi_infoframe_log_header(level, dev,
-				  (struct hdmi_any_infoframe *)frame);
+				  (const struct hdmi_any_infoframe *)frame);
 
 	if (frame->any.oui != HDMI_IEEE_OUI) {
 		hdmi_log("    not a HDMI vendor infoframe\n");
@@ -984,7 +984,7 @@ hdmi_vendor_any_infoframe_log(const char *level,
  */
 void hdmi_infoframe_log(const char *level,
 			struct device *dev,
-			union hdmi_infoframe *frame)
+			const union hdmi_infoframe *frame)
 {
 	switch (frame->any.type) {
 	case HDMI_INFOFRAME_TYPE_AVI:
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index a577d4ae2570..bce1abb1fe57 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -335,6 +335,6 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-			union hdmi_infoframe *frame);
+			const union hdmi_infoframe *frame);
 
 #endif /* _DRM_HDMI_H */
-- 
2.16.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-20 18:51 ` Ville Syrjala
@ 2018-09-20 18:51   ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Let's make the infoframe pack functions usable with a const infoframe
structure. This allows us to precompute the infoframe earlier, and still
pack it later when we're no longer allowed to modify the structure.
So now we end up with a _check()+_pack_only() or _pack() functions
depending on whether you want to precompute the infoframes or not.
The names aren't greate but I was lazy and didn't want to change all the
drivers.

v2: Deal with exynos churn
    Actually export the new funcs

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
 include/linux/hdmi.h |  19 ++-
 2 files changed, 416 insertions(+), 28 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 53e7ee2c83fc..9507f668a569 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_avi_infoframe_init);
 
+static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
+	    frame->version != 2 ||
+	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
+ * hdmi_avi_infoframe_check() - Check and check a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
+{
+	return hdmi_avi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_check);
+
+/**
+ * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
  * @frame: HDMI AVI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_avi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
 	if (size < length)
 		return -ENOSPC;
 
-	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
-		return -EINVAL;
-
 	memset(buffer, 0, size);
 
 	ptr[0] = frame->type;
@@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
+
+/**
+ * hdmi_avi_infoframe_pack() - Check and check a HDMI AVI infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_avi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
 
 /**
@@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 }
 EXPORT_SYMBOL(hdmi_spd_infoframe_init);
 
+static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
+ * hdmi_spd_infoframe_check() - Check and check a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
+{
+	return hdmi_spd_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_check);
+
+/**
+ * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
  * @frame: HDMI SPD infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_spd_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
+
+/**
+ * hdmi_spd_infoframe_pack() - Check and check a HDMI SPD infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_spd_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
 
 /**
@@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_audio_infoframe_init);
 
+static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_audio_infoframe_check() - Check and check a HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+{
+	return hdmi_audio_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+
 /**
- * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
+ * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
  * @frame: HDMI audio infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
-				  void *buffer, size_t size)
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size)
 {
 	unsigned char channels;
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_audio_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
+
+/**
+ * hdmi_audio_infoframe_pack() - Check and check a HDMI Audio infoframe,
+ *                               and write it to binary buffer
+ * @frame: HDMI Audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+				  void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_audio_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
 
 /**
@@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
 	 * value
 	 */
 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+	frame->length = 4;
 
 	return 0;
 }
@@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
 		return 4;
 }
 
+static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->version != 1 ||
+	    frame->oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	/* only one of those can be supplied */
+	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+		return -EINVAL;
+
+	if (frame->length != hdmi_vendor_infoframe_length(frame))
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
+ * hdmi_vendor_infoframe_check() - Check and check a HDMI vendor infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
+{
+	frame->length = hdmi_vendor_infoframe_length(frame);
+
+	return hdmi_vendor_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
+
+/**
+ * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
-				 void *buffer, size_t size)
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
 
-	/* only one of those can be supplied */
-	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
-		return -EINVAL;
-
-	frame->length = hdmi_vendor_infoframe_length(frame);
+	ret = hdmi_vendor_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
+
+/**
+ * hdmi_vendor_infoframe_pack() - Check and check a HDMI Vendor infoframe,
+ *                                and write it to binary buffer
+ * @frame: HDMI Vendor infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+				   void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
 
+static int
+hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
+{
+	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->any.version != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
 /*
- * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
+ * hdmi_vendor_any_infoframe_check() - check and check a vendor infoframe
+ */
+static int
+hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	/* we only know about HDMI vendor infoframes */
+	if (frame->any.oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	return hdmi_vendor_infoframe_check(&frame->hdmi);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
  */
 static ssize_t
-hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
-			   void *buffer, size_t size)
+hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
+				    void *buffer, size_t size)
 {
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
 	/* we only know about HDMI vendor infoframes */
 	if (frame->any.oui != HDMI_IEEE_OUI)
 		return -EINVAL;
 
-	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
+	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack() - check and check a vendor infoframe,
+ *                                              and write it to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
+			       void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
+}
+
+/**
+ * hdmi_infoframe_check() - Check check a HDMI infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+hdmi_infoframe_check(union hdmi_infoframe *frame)
+{
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		return hdmi_avi_infoframe_check(&frame->avi);
+	case HDMI_INFOFRAME_TYPE_SPD:
+		return hdmi_spd_infoframe_check(&frame->spd);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		return hdmi_audio_infoframe_check(&frame->audio);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		return -EINVAL;
+	}
 }
+EXPORT_SYMBOL(hdmi_infoframe_check);
 
 /**
- * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
+ * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
  * error code on failure.
  */
 ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
+hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
+{
+	ssize_t length;
+
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		length = hdmi_avi_infoframe_pack_only(&frame->avi,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_SPD:
+		length = hdmi_spd_infoframe_pack_only(&frame->spd,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		length = hdmi_audio_infoframe_pack_only(&frame->audio,
+							buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
+							     buffer, size);
+		break;
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		length = -EINVAL;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack_only);
+
+/**
+ * hdmi_infoframe_pack() - Check check a HDMI infoframe,
+ *                         and write it to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t
+hdmi_infoframe_pack(union hdmi_infoframe *frame,
+		    void *buffer, size_t size)
 {
 	ssize_t length;
 
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index bce1abb1fe57..c76b50a48e48 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
 int 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);
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
 
 enum hdmi_spd_sdi {
 	HDMI_SPD_SDI_UNKNOWN,
@@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 			    const char *vendor, const char *product);
 ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 				size_t size);
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
 
 enum hdmi_audio_coding_type {
 	HDMI_AUDIO_CODING_TYPE_STREAM,
@@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
 int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
 ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 				  void *buffer, size_t size);
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size);
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
 
 enum hdmi_3d_structure {
 	HDMI_3D_STRUCTURE_INVALID = -1,
@@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
 int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
 ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 				   void *buffer, size_t size);
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size);
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
 
 union hdmi_vendor_any_infoframe {
 	struct {
@@ -330,8 +342,11 @@ union hdmi_infoframe {
 	struct hdmi_audio_infoframe audio;
 };
 
-ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
+ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
+			    size_t size);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
+				 void *buffer, size_t size);
+int hdmi_infoframe_check(union hdmi_infoframe *frame);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions
@ 2018-09-20 18:51   ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Let's make the infoframe pack functions usable with a const infoframe
structure. This allows us to precompute the infoframe earlier, and still
pack it later when we're no longer allowed to modify the structure.
So now we end up with a _check()+_pack_only() or _pack() functions
depending on whether you want to precompute the infoframes or not.
The names aren't greate but I was lazy and didn't want to change all the
drivers.

v2: Deal with exynos churn
    Actually export the new funcs

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
 include/linux/hdmi.h |  19 ++-
 2 files changed, 416 insertions(+), 28 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 53e7ee2c83fc..9507f668a569 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_avi_infoframe_init);
 
+static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
+	    frame->version != 2 ||
+	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
+ * hdmi_avi_infoframe_check() - Check and check a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
+{
+	return hdmi_avi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_check);
+
+/**
+ * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
  * @frame: HDMI AVI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_avi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
 	if (size < length)
 		return -ENOSPC;
 
-	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
-		return -EINVAL;
-
 	memset(buffer, 0, size);
 
 	ptr[0] = frame->type;
@@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
+
+/**
+ * hdmi_avi_infoframe_pack() - Check and check a HDMI AVI infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_avi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
 
 /**
@@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 }
 EXPORT_SYMBOL(hdmi_spd_infoframe_init);
 
+static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
+ * hdmi_spd_infoframe_check() - Check and check a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
+{
+	return hdmi_spd_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_check);
+
+/**
+ * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
  * @frame: HDMI SPD infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_spd_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
+
+/**
+ * hdmi_spd_infoframe_pack() - Check and check a HDMI SPD infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_spd_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
 
 /**
@@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_audio_infoframe_init);
 
+static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_audio_infoframe_check() - Check and check a HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+{
+	return hdmi_audio_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+
 /**
- * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
+ * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
  * @frame: HDMI audio infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
-				  void *buffer, size_t size)
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size)
 {
 	unsigned char channels;
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_audio_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
+
+/**
+ * hdmi_audio_infoframe_pack() - Check and check a HDMI Audio infoframe,
+ *                               and write it to binary buffer
+ * @frame: HDMI Audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+				  void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_audio_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
 
 /**
@@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
 	 * value
 	 */
 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+	frame->length = 4;
 
 	return 0;
 }
@@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
 		return 4;
 }
 
+static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->version != 1 ||
+	    frame->oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	/* only one of those can be supplied */
+	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+		return -EINVAL;
+
+	if (frame->length != hdmi_vendor_infoframe_length(frame))
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
+ * hdmi_vendor_infoframe_check() - Check and check a HDMI vendor infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
+{
+	frame->length = hdmi_vendor_infoframe_length(frame);
+
+	return hdmi_vendor_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
+
+/**
+ * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
-				 void *buffer, size_t size)
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
 
-	/* only one of those can be supplied */
-	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
-		return -EINVAL;
-
-	frame->length = hdmi_vendor_infoframe_length(frame);
+	ret = hdmi_vendor_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
+
+/**
+ * hdmi_vendor_infoframe_pack() - Check and check a HDMI Vendor infoframe,
+ *                                and write it to binary buffer
+ * @frame: HDMI Vendor infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+				   void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
 
+static int
+hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
+{
+	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->any.version != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
 /*
- * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
+ * hdmi_vendor_any_infoframe_check() - check and check a vendor infoframe
+ */
+static int
+hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	/* we only know about HDMI vendor infoframes */
+	if (frame->any.oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	return hdmi_vendor_infoframe_check(&frame->hdmi);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
  */
 static ssize_t
-hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
-			   void *buffer, size_t size)
+hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
+				    void *buffer, size_t size)
 {
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
 	/* we only know about HDMI vendor infoframes */
 	if (frame->any.oui != HDMI_IEEE_OUI)
 		return -EINVAL;
 
-	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
+	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack() - check and check a vendor infoframe,
+ *                                              and write it to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
+			       void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
+}
+
+/**
+ * hdmi_infoframe_check() - Check check a HDMI infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+hdmi_infoframe_check(union hdmi_infoframe *frame)
+{
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		return hdmi_avi_infoframe_check(&frame->avi);
+	case HDMI_INFOFRAME_TYPE_SPD:
+		return hdmi_spd_infoframe_check(&frame->spd);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		return hdmi_audio_infoframe_check(&frame->audio);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		return -EINVAL;
+	}
 }
+EXPORT_SYMBOL(hdmi_infoframe_check);
 
 /**
- * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
+ * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
  * error code on failure.
  */
 ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
+hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
+{
+	ssize_t length;
+
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		length = hdmi_avi_infoframe_pack_only(&frame->avi,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_SPD:
+		length = hdmi_spd_infoframe_pack_only(&frame->spd,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		length = hdmi_audio_infoframe_pack_only(&frame->audio,
+							buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
+							     buffer, size);
+		break;
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		length = -EINVAL;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack_only);
+
+/**
+ * hdmi_infoframe_pack() - Check check a HDMI infoframe,
+ *                         and write it to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t
+hdmi_infoframe_pack(union hdmi_infoframe *frame,
+		    void *buffer, size_t size)
 {
 	ssize_t length;
 
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index bce1abb1fe57..c76b50a48e48 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
 int 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);
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
 
 enum hdmi_spd_sdi {
 	HDMI_SPD_SDI_UNKNOWN,
@@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 			    const char *vendor, const char *product);
 ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 				size_t size);
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
 
 enum hdmi_audio_coding_type {
 	HDMI_AUDIO_CODING_TYPE_STREAM,
@@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
 int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
 ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 				  void *buffer, size_t size);
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size);
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
 
 enum hdmi_3d_structure {
 	HDMI_3D_STRUCTURE_INVALID = -1,
@@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
 int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
 ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 				   void *buffer, size_t size);
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size);
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
 
 union hdmi_vendor_any_infoframe {
 	struct {
@@ -330,8 +342,11 @@ union hdmi_infoframe {
 	struct hdmi_audio_infoframe audio;
 };
 
-ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
+ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
+			    size_t size);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
+				 void *buffer, size_t size);
+int hdmi_infoframe_check(union hdmi_infoframe *frame);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-20 18:51 ` Ville Syrjala
@ 2018-09-20 18:51   ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We'll be wanting to send more than just infoframes over HDMI. So add an
enum for other packet types.

TODO: Maybe just include the infoframe types in the packet type enum
      and get rid of the infoframe type enum?

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 include/linux/hdmi.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index c76b50a48e48..80521d9591a1 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -27,6 +27,21 @@
 #include <linux/types.h>
 #include <linux/device.h>
 
+enum hdmi_packet_type {
+	HDMI_PACKET_TYPE_NULL = 0x00,
+	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
+	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
+	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
+	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
+	HDMI_PACKET_TYPE_ISRC1 = 0x05,
+	HDMI_PACKET_TYPE_ISRC2 = 0x06,
+	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
+	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
+	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
+	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
+	/* + enum hdmi_infoframe_type */
+};
+
 enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
 	HDMI_INFOFRAME_TYPE_AVI = 0x82,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
@ 2018-09-20 18:51   ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We'll be wanting to send more than just infoframes over HDMI. So add an
enum for other packet types.

TODO: Maybe just include the infoframe types in the packet type enum
      and get rid of the infoframe type enum?

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 include/linux/hdmi.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index c76b50a48e48..80521d9591a1 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -27,6 +27,21 @@
 #include <linux/types.h>
 #include <linux/device.h>
 
+enum hdmi_packet_type {
+	HDMI_PACKET_TYPE_NULL = 0x00,
+	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
+	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
+	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
+	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
+	HDMI_PACKET_TYPE_ISRC1 = 0x05,
+	HDMI_PACKET_TYPE_ISRC2 = 0x06,
+	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
+	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
+	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
+	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
+	/* + enum hdmi_infoframe_type */
+};
+
 enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
 	HDMI_INFOFRAME_TYPE_AVI = 0x82,
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe
  2018-09-20 18:51 ` Ville Syrjala
@ 2018-09-20 18:51   ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the MPEG source infoframe.

Blindly typed from the spec, and totally untested.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  27 ++++++
 2 files changed, 256 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 9507f668a569..3d24c7746c51 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
 	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
+	frame->version = 1;
+	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
+
+static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_check() - Check and check a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
+{
+	return hdmi_mpeg_source_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(buffer, 0, size);
+
+	ptr[0] = frame->type;
+	ptr[1] = frame->version;
+	ptr[2] = frame->length;
+	ptr[3] = 0; /* checksum */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	ptr[0] = frame->mpeg_bit_rate >> 0;
+	ptr[1] = frame->mpeg_bit_rate >> 8;
+	ptr[2] = frame->mpeg_bit_rate >> 16;
+	ptr[3] = frame->mpeg_bit_rate >> 24;
+	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack() - Check and check a HDMI MPEG Source infoframe,
+ *                                     and write it to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - Check check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_audio_infoframe_check(&frame->audio);
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
 							     buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
+							      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
 							buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
+							 buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -838,6 +973,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Source Product Description (SPD)";
 	case HDMI_INFOFRAME_TYPE_AUDIO:
 		return "Audio";
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return "MPEG Source";
 	}
 	return "Reserved";
 }
@@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
 	}
 }
 
+static const char *
+hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
+{
+	if (frame < 0 || frame > 3)
+		return "invalid";
+
+	switch (frame) {
+	case HDMI_MPEG_FRAME_UNKNOWN:
+		return "Unknown";
+	case HDMI_MPEG_FRAME_I_PICTURE:
+		return "I Picture";
+	case HDMI_MPEG_FRAME_B_PICTURE:
+		return "B Picture";
+	case HDMI_MPEG_FRAME_P_PICTURE:
+		return "P Picture";
+	}
+	return "Reserved";
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI MPEG Source infoframe
+ */
+static void hdmi_mpeg_source_infoframe_log(const char *level,
+					   struct device *dev,
+					   const struct hdmi_mpeg_source_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    MPEG bit rate: %d Hz\n",
+		 frame->mpeg_bit_rate);
+	hdmi_log("    MPEG frame: %s\n",
+		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
+	hdmi_log("    field repeat: %s\n",
+		 frame->field_repeat ? "Yes" : "No");
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 	return 0;
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
+					     const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	int ret;
+
+	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    ptr[1] != 1 ||
+	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
+		return -EINVAL;
+	}
+
+	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
+		return -EINVAL;
+
+	ret = hdmi_mpeg_source_infoframe_init(frame);
+	if (ret)
+		return ret;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	frame->mpeg_bit_rate =
+		(ptr[0] << 0) | (ptr[1] << 8) |
+		(ptr[2] << 16) | (ptr[3] << 24);
+	frame->mpeg_frame = ptr[4] & 0x3;
+	frame->field_repeat = ptr[4] & 0x10;
+
+	return 0;
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 80521d9591a1..2c9322f7538d 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_AVI = 0x82,
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
+	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -55,6 +56,7 @@ enum hdmi_infoframe_type {
 #define HDMI_AVI_INFOFRAME_SIZE    13
 #define HDMI_SPD_INFOFRAME_SIZE    25
 #define HDMI_AUDIO_INFOFRAME_SIZE  10
+#define HDMI_MPEG_SOURCE_INFOFRAME_SIZE  10
 
 #define HDMI_INFOFRAME_SIZE(type)	\
 	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
@@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
 	struct hdmi_vendor_infoframe hdmi;
 };
 
+enum hdmi_mpeg_frame {
+	HDMI_MPEG_FRAME_UNKNOWN,
+	HDMI_MPEG_FRAME_I_PICTURE,
+	HDMI_MPEG_FRAME_B_PICTURE,
+	HDMI_MPEG_FRAME_P_PICTURE,
+};
+
+struct hdmi_mpeg_source_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned int mpeg_bit_rate;
+	enum hdmi_mpeg_frame mpeg_frame;
+	bool field_repeat;
+};
+
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size);
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size);
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
  * @spd: spd infoframe
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
+ * @mpeg_source: mpeg source infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -355,6 +381,7 @@ union hdmi_infoframe {
 	struct hdmi_spd_infoframe spd;
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
+	struct hdmi_mpeg_source_infoframe mpeg_source;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe
@ 2018-09-20 18:51   ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the MPEG source infoframe.

Blindly typed from the spec, and totally untested.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  27 ++++++
 2 files changed, 256 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 9507f668a569..3d24c7746c51 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
 	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
+	frame->version = 1;
+	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
+
+static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_check() - Check and check a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
+{
+	return hdmi_mpeg_source_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(buffer, 0, size);
+
+	ptr[0] = frame->type;
+	ptr[1] = frame->version;
+	ptr[2] = frame->length;
+	ptr[3] = 0; /* checksum */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	ptr[0] = frame->mpeg_bit_rate >> 0;
+	ptr[1] = frame->mpeg_bit_rate >> 8;
+	ptr[2] = frame->mpeg_bit_rate >> 16;
+	ptr[3] = frame->mpeg_bit_rate >> 24;
+	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack() - Check and check a HDMI MPEG Source infoframe,
+ *                                     and write it to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - Check check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_audio_infoframe_check(&frame->audio);
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
 							     buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
+							      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
 							buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
+							 buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -838,6 +973,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Source Product Description (SPD)";
 	case HDMI_INFOFRAME_TYPE_AUDIO:
 		return "Audio";
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return "MPEG Source";
 	}
 	return "Reserved";
 }
@@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
 	}
 }
 
+static const char *
+hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
+{
+	if (frame < 0 || frame > 3)
+		return "invalid";
+
+	switch (frame) {
+	case HDMI_MPEG_FRAME_UNKNOWN:
+		return "Unknown";
+	case HDMI_MPEG_FRAME_I_PICTURE:
+		return "I Picture";
+	case HDMI_MPEG_FRAME_B_PICTURE:
+		return "B Picture";
+	case HDMI_MPEG_FRAME_P_PICTURE:
+		return "P Picture";
+	}
+	return "Reserved";
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI MPEG Source infoframe
+ */
+static void hdmi_mpeg_source_infoframe_log(const char *level,
+					   struct device *dev,
+					   const struct hdmi_mpeg_source_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    MPEG bit rate: %d Hz\n",
+		 frame->mpeg_bit_rate);
+	hdmi_log("    MPEG frame: %s\n",
+		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
+	hdmi_log("    field repeat: %s\n",
+		 frame->field_repeat ? "Yes" : "No");
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 	return 0;
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
+					     const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	int ret;
+
+	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    ptr[1] != 1 ||
+	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
+		return -EINVAL;
+	}
+
+	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
+		return -EINVAL;
+
+	ret = hdmi_mpeg_source_infoframe_init(frame);
+	if (ret)
+		return ret;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	frame->mpeg_bit_rate =
+		(ptr[0] << 0) | (ptr[1] << 8) |
+		(ptr[2] << 16) | (ptr[3] << 24);
+	frame->mpeg_frame = ptr[4] & 0x3;
+	frame->field_repeat = ptr[4] & 0x10;
+
+	return 0;
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 80521d9591a1..2c9322f7538d 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_AVI = 0x82,
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
+	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -55,6 +56,7 @@ enum hdmi_infoframe_type {
 #define HDMI_AVI_INFOFRAME_SIZE    13
 #define HDMI_SPD_INFOFRAME_SIZE    25
 #define HDMI_AUDIO_INFOFRAME_SIZE  10
+#define HDMI_MPEG_SOURCE_INFOFRAME_SIZE  10
 
 #define HDMI_INFOFRAME_SIZE(type)	\
 	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
@@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
 	struct hdmi_vendor_infoframe hdmi;
 };
 
+enum hdmi_mpeg_frame {
+	HDMI_MPEG_FRAME_UNKNOWN,
+	HDMI_MPEG_FRAME_I_PICTURE,
+	HDMI_MPEG_FRAME_B_PICTURE,
+	HDMI_MPEG_FRAME_P_PICTURE,
+};
+
+struct hdmi_mpeg_source_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned int mpeg_bit_rate;
+	enum hdmi_mpeg_frame mpeg_frame;
+	bool field_repeat;
+};
+
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size);
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size);
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
  * @spd: spd infoframe
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
+ * @mpeg_source: mpeg source infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -355,6 +381,7 @@ union hdmi_infoframe {
 	struct hdmi_spd_infoframe spd;
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
+	struct hdmi_mpeg_source_infoframe mpeg_source;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe
  2018-09-20 18:51 ` Ville Syrjala
@ 2018-09-20 18:51   ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the NTSC VBI infoframe.

I decided against parsing the PES_data_field and just leave
it as an opaque blob, just dumping it out as hex in the log.

Blindly typed from the spec, and totally untested.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  18 +++++
 2 files changed, 226 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 3d24c7746c51..3c320d69fa0a 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
 }
 EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
 
+/**
+ * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ * @pes_data_field: ANSI/SCTE 127 PES_data_field
+ * @length: ANSI/SCTE 127 PES_data_field length
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field,
+				 size_t length)
+{
+	if (length < 1 || length > 27)
+		return -EINVAL;
+
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
+	frame->version = 1;
+	frame->length = length;
+
+	memcpy(frame->pes_data_field, pes_data_field, length);
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
+
+static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    frame->version != 1 ||
+	    frame->length < 1 || frame->length > 27)
+		return -EINVAL;
+
+	if (frame->pes_data_field[0] != 0x99)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	return hdmi_ntsc_vbi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI infoframe to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(buffer, 0, size);
+
+	ptr[0] = frame->type;
+	ptr[1] = frame->version;
+	ptr[2] = frame->length;
+	ptr[3] = 0; /* checksum */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	memcpy(ptr, frame->pes_data_field, frame->length);
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack() - Check and check a HDMI NTSC VBI infoframe,
+ *                                  and write it to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - Check check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
 							      buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
+							   buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
 							 buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
+						      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Audio";
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return "MPEG Source";
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return "NTSC VBI";
 	}
 	return "Reserved";
 }
@@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
 		 frame->field_repeat ? "Yes" : "No");
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_log() - log info of HDMI NTSC VBI infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI NTSC VBI infoframe
+ */
+static void hdmi_ntsc_vbi_infoframe_log(const char *level,
+					struct device *dev,
+					const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
 	return 0;
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_ntsc_vbi_infoframe_unpack(struct hdmi_ntsc_vbi_infoframe *frame,
+					  const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	size_t length;
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    ptr[1] != 1 ||
+	    ptr[2] < 1 || ptr[2] > 27)
+		return -EINVAL;
+
+	length = ptr[2];
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+		return -EINVAL;
+
+	if (hdmi_infoframe_checksum(buffer,
+				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
+		return -EINVAL;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 2c9322f7538d..3821516b336c 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
 	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
+	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
 					     void *buffer, size_t size);
 int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
 
+struct hdmi_ntsc_vbi_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned char pes_data_field[27];
+};
+
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field, size_t length);
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size);
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size);
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
  * @mpeg_source: mpeg source infoframe
+ * @ntsc_vbi: ntsc vbi infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -382,6 +399,7 @@ union hdmi_infoframe {
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
 	struct hdmi_mpeg_source_infoframe mpeg_source;
+	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe
@ 2018-09-20 18:51   ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the NTSC VBI infoframe.

I decided against parsing the PES_data_field and just leave
it as an opaque blob, just dumping it out as hex in the log.

Blindly typed from the spec, and totally untested.

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  18 +++++
 2 files changed, 226 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 3d24c7746c51..3c320d69fa0a 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
 }
 EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
 
+/**
+ * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ * @pes_data_field: ANSI/SCTE 127 PES_data_field
+ * @length: ANSI/SCTE 127 PES_data_field length
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field,
+				 size_t length)
+{
+	if (length < 1 || length > 27)
+		return -EINVAL;
+
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
+	frame->version = 1;
+	frame->length = length;
+
+	memcpy(frame->pes_data_field, pes_data_field, length);
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
+
+static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    frame->version != 1 ||
+	    frame->length < 1 || frame->length > 27)
+		return -EINVAL;
+
+	if (frame->pes_data_field[0] != 0x99)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	return hdmi_ntsc_vbi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI infoframe to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(buffer, 0, size);
+
+	ptr[0] = frame->type;
+	ptr[1] = frame->version;
+	ptr[2] = frame->length;
+	ptr[3] = 0; /* checksum */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	memcpy(ptr, frame->pes_data_field, frame->length);
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack() - Check and check a HDMI NTSC VBI infoframe,
+ *                                  and write it to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. Also
+ * computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - Check check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
 							      buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
+							   buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
 							 buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
+						      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Audio";
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return "MPEG Source";
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return "NTSC VBI";
 	}
 	return "Reserved";
 }
@@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
 		 frame->field_repeat ? "Yes" : "No");
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_log() - log info of HDMI NTSC VBI infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI NTSC VBI infoframe
+ */
+static void hdmi_ntsc_vbi_infoframe_log(const char *level,
+					struct device *dev,
+					const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
 	return 0;
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_ntsc_vbi_infoframe_unpack(struct hdmi_ntsc_vbi_infoframe *frame,
+					  const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	size_t length;
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    ptr[1] != 1 ||
+	    ptr[2] < 1 || ptr[2] > 27)
+		return -EINVAL;
+
+	length = ptr[2];
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+		return -EINVAL;
+
+	if (hdmi_infoframe_checksum(buffer,
+				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
+		return -EINVAL;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 2c9322f7538d..3821516b336c 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
 	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
+	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
 					     void *buffer, size_t size);
 int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
 
+struct hdmi_ntsc_vbi_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned char pes_data_field[27];
+};
+
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field, size_t length);
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size);
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size);
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
  * @mpeg_source: mpeg source infoframe
+ * @ntsc_vbi: ntsc vbi infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -382,6 +399,7 @@ union hdmi_infoframe {
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
 	struct hdmi_mpeg_source_infoframe mpeg_source;
+	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 08/18] drm/i915: Use memmove() for punching the hole into infoframes
  2018-09-20 18:51 ` Ville Syrjala
                   ` (7 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21 13:52   ` Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Replace the hand rolled memmove() with the real thing.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_hdmi.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index a2dab0b6bde6..3b56ab253171 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -457,9 +457,7 @@ static void intel_write_infoframe(struct drm_encoder *encoder,
 		return;
 
 	/* Insert the 'hole' (see big comment above) at position 3 */
-	buffer[0] = buffer[1];
-	buffer[1] = buffer[2];
-	buffer[2] = buffer[3];
+	memmove(&buffer[0], &buffer[1], 3);
 	buffer[3] = 0;
 	len++;
 
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 09/18] drm/i915: Pass intel_encoder to infoframe functions
  2018-09-20 18:51 ` Ville Syrjala
                   ` (8 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21 13:59   ` Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Make life simpler by passing around intel_encoder instead of
drm_encoder.

@r1@
identifier F =~ "infoframe";
identifier I, M;
@@
F(
- struct drm_encoder *I
+ struct intel_encoder *I
  , ...)
{
<...
(
- I->M
+ I->base.M
|
- I
+ &I->base
)
...>
}

@r2@
identifier F =~ "infoframe";
identifier I;
type T, ST;
@@
ST {
...
	T (*F)(
-	       struct drm_encoder *I
+	       struct intel_encoder *encoder
	       , ...);
...
};

@@
identifier r1.F;
expression E;
@@
F(
- E
+ to_intel_encoder(E)
  ,...)

@@
identifier r2.F;
expression E, X;
@@
(
X.F(
-   E
+   to_intel_encoder(E)
    ,...)
|
X->F(
-    E
+    to_intel_encoder(E)
     ,...)
)

@@
expression E;
@@
(
- to_intel_encoder(&E->base)
+ E
|
- to_intel_encoder(&E->base.base)
+ &E->base
)

@@
identifier D, M;
expression E;
@@
 D = enc_to_dig_port(&E->base)
<...
(
- D->base.M
+ E->M
|
- &D->base
+ E
)
...>

@@
identifier D;
expression E;
type T;
@@
- T D = enc_to_dig_port(E);
... when != D

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c  |   6 +-
 drivers/gpu/drm/i915/intel_drv.h  |   6 +-
 drivers/gpu/drm/i915/intel_hdmi.c | 129 +++++++++++++++++++-------------------
 drivers/gpu/drm/i915/intel_psr.c  |   3 +-
 4 files changed, 71 insertions(+), 73 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index b6910c8b4e08..086e3f940586 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2947,7 +2947,7 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
 
 	intel_ddi_enable_pipe_clock(crtc_state);
 
-	intel_dig_port->set_infoframes(&encoder->base,
+	intel_dig_port->set_infoframes(encoder,
 				       crtc_state->has_infoframe,
 				       crtc_state, conn_state);
 }
@@ -3046,7 +3046,7 @@ static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
 	struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
 	struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
 
-	dig_port->set_infoframes(&encoder->base, false,
+	dig_port->set_infoframes(encoder, false,
 				 old_crtc_state, old_conn_state);
 
 	intel_ddi_disable_pipe_clock(old_crtc_state);
@@ -3390,7 +3390,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 		pipe_config->has_hdmi_sink = true;
 		intel_dig_port = enc_to_dig_port(&encoder->base);
 
-		if (intel_dig_port->infoframe_enabled(&encoder->base, pipe_config))
+		if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
 			pipe_config->has_infoframe = true;
 
 		if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index bf1c38728a59..e0f3a79fc75e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1173,15 +1173,15 @@ struct intel_digital_port {
 	enum intel_display_power_domain ddi_io_power_domain;
 	enum tc_port_type tc_type;
 
-	void (*write_infoframe)(struct drm_encoder *encoder,
+	void (*write_infoframe)(struct intel_encoder *encoder,
 				const struct intel_crtc_state *crtc_state,
 				unsigned int type,
 				const void *frame, ssize_t len);
-	void (*set_infoframes)(struct drm_encoder *encoder,
+	void (*set_infoframes)(struct intel_encoder *encoder,
 			       bool enable,
 			       const struct intel_crtc_state *crtc_state,
 			       const struct drm_connector_state *conn_state);
-	bool (*infoframe_enabled)(struct drm_encoder *encoder,
+	bool (*infoframe_enabled)(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config);
 };
 
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 3b56ab253171..454f570275e9 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -148,14 +148,13 @@ hsw_dip_data_reg(struct drm_i915_private *dev_priv,
 	}
 }
 
-static void g4x_write_infoframe(struct drm_encoder *encoder,
+static void g4x_write_infoframe(struct intel_encoder *encoder,
 				const struct intel_crtc_state *crtc_state,
 				unsigned int type,
 				const void *frame, ssize_t len)
 {
 	const u32 *data = frame;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 val = I915_READ(VIDEO_DIP_CTL);
 	int i;
 
@@ -186,31 +185,29 @@ static void g4x_write_infoframe(struct drm_encoder *encoder,
 	POSTING_READ(VIDEO_DIP_CTL);
 }
 
-static bool g4x_infoframe_enabled(struct drm_encoder *encoder,
+static bool g4x_infoframe_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 val = I915_READ(VIDEO_DIP_CTL);
 
 	if ((val & VIDEO_DIP_ENABLE) == 0)
 		return false;
 
-	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
+	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
 		return false;
 
 	return val & (VIDEO_DIP_ENABLE_AVI |
 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
 }
 
-static void ibx_write_infoframe(struct drm_encoder *encoder,
+static void ibx_write_infoframe(struct intel_encoder *encoder,
 				const struct intel_crtc_state *crtc_state,
 				unsigned int type,
 				const void *frame, ssize_t len)
 {
 	const u32 *data = frame;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
 	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
@@ -243,11 +240,10 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
 	POSTING_READ(reg);
 }
 
-static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
+static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
 	i915_reg_t reg = TVIDEO_DIP_CTL(pipe);
 	u32 val = I915_READ(reg);
@@ -255,7 +251,7 @@ static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
 	if ((val & VIDEO_DIP_ENABLE) == 0)
 		return false;
 
-	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
+	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
 		return false;
 
 	return val & (VIDEO_DIP_ENABLE_AVI |
@@ -263,14 +259,13 @@ static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
 }
 
-static void cpt_write_infoframe(struct drm_encoder *encoder,
+static void cpt_write_infoframe(struct intel_encoder *encoder,
 				const struct intel_crtc_state *crtc_state,
 				unsigned int type,
 				const void *frame, ssize_t len)
 {
 	const u32 *data = frame;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
 	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
@@ -306,10 +301,10 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
 	POSTING_READ(reg);
 }
 
-static bool cpt_infoframe_enabled(struct drm_encoder *encoder,
+static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
 	u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
 
@@ -321,14 +316,13 @@ static bool cpt_infoframe_enabled(struct drm_encoder *encoder,
 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
 }
 
-static void vlv_write_infoframe(struct drm_encoder *encoder,
+static void vlv_write_infoframe(struct intel_encoder *encoder,
 				const struct intel_crtc_state *crtc_state,
 				unsigned int type,
 				const void *frame, ssize_t len)
 {
 	const u32 *data = frame;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
 	i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
@@ -361,18 +355,17 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
 	POSTING_READ(reg);
 }
 
-static bool vlv_infoframe_enabled(struct drm_encoder *encoder,
+static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
 	u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
 
 	if ((val & VIDEO_DIP_ENABLE) == 0)
 		return false;
 
-	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
+	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
 		return false;
 
 	return val & (VIDEO_DIP_ENABLE_AVI |
@@ -380,14 +373,13 @@ static bool vlv_infoframe_enabled(struct drm_encoder *encoder,
 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
 }
 
-static void hsw_write_infoframe(struct drm_encoder *encoder,
+static void hsw_write_infoframe(struct intel_encoder *encoder,
 				const struct intel_crtc_state *crtc_state,
 				unsigned int type,
 				const void *frame, ssize_t len)
 {
 	const u32 *data = frame;
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
 	i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
 	int data_size = type == DP_SDP_VSC ?
@@ -415,10 +407,10 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
 	POSTING_READ(ctl_reg);
 }
 
-static bool hsw_infoframe_enabled(struct drm_encoder *encoder,
+static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(pipe_config->cpu_transcoder));
 
 	return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
@@ -443,11 +435,11 @@ static bool hsw_infoframe_enabled(struct drm_encoder *encoder,
  * trick them by giving an offset into the buffer and moving back the header
  * bytes by one.
  */
-static void intel_write_infoframe(struct drm_encoder *encoder,
+static void intel_write_infoframe(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *crtc_state,
 				  union hdmi_infoframe *frame)
 {
-	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
 	u8 buffer[VIDEO_DIP_DATA_SIZE];
 	ssize_t len;
 
@@ -461,14 +453,16 @@ static void intel_write_infoframe(struct drm_encoder *encoder,
 	buffer[3] = 0;
 	len++;
 
-	intel_dig_port->write_infoframe(encoder, crtc_state, frame->any.type, buffer, len);
+	intel_dig_port->write_infoframe(encoder,
+					crtc_state,
+					frame->any.type, buffer, len);
 }
 
-static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
+static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
 					 const struct intel_crtc_state *crtc_state,
 					 const struct drm_connector_state *conn_state)
 {
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
 	const struct drm_display_mode *adjusted_mode =
 		&crtc_state->base.adjusted_mode;
 	struct drm_connector *connector = &intel_hdmi->attached_connector->base;
@@ -500,10 +494,11 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
 					    conn_state);
 
 	/* TODO: handle pixel repetition for YCBCR420 outputs */
-	intel_write_infoframe(encoder, crtc_state, &frame);
+	intel_write_infoframe(encoder, crtc_state,
+			      &frame);
 }
 
-static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder,
+static void intel_hdmi_set_spd_infoframe(struct intel_encoder *encoder,
 					 const struct intel_crtc_state *crtc_state)
 {
 	union hdmi_infoframe frame;
@@ -517,11 +512,12 @@ static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder,
 
 	frame.spd.sdi = HDMI_SPD_SDI_PC;
 
-	intel_write_infoframe(encoder, crtc_state, &frame);
+	intel_write_infoframe(encoder, crtc_state,
+			      &frame);
 }
 
 static void
-intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
+intel_hdmi_set_hdmi_infoframe(struct intel_encoder *encoder,
 			      const struct intel_crtc_state *crtc_state,
 			      const struct drm_connector_state *conn_state)
 {
@@ -534,20 +530,21 @@ intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
 	if (ret < 0)
 		return;
 
-	intel_write_infoframe(encoder, crtc_state, &frame);
+	intel_write_infoframe(encoder, crtc_state,
+			      &frame);
 }
 
-static void g4x_set_infoframes(struct drm_encoder *encoder,
+static void g4x_set_infoframes(struct intel_encoder *encoder,
 			       bool enable,
 			       const struct intel_crtc_state *crtc_state,
 			       const struct drm_connector_state *conn_state)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
 	i915_reg_t reg = VIDEO_DIP_CTL;
 	u32 val = I915_READ(reg);
-	u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
+	u32 port = VIDEO_DIP_PORT(encoder->port);
 
 	assert_hdmi_port_disabled(intel_hdmi);
 
@@ -655,11 +652,11 @@ static bool gcp_default_phase_possible(int pipe_bpp,
 		 mode->crtc_htotal/2 % pixels_per_group == 0);
 }
 
-static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder,
+static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
 					 const struct intel_crtc_state *crtc_state,
 					 const struct drm_connector_state *conn_state)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
 	i915_reg_t reg;
 	u32 val = 0;
@@ -687,18 +684,18 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder,
 	return val != 0;
 }
 
-static void ibx_set_infoframes(struct drm_encoder *encoder,
+static void ibx_set_infoframes(struct intel_encoder *encoder,
 			       bool enable,
 			       const struct intel_crtc_state *crtc_state,
 			       const struct drm_connector_state *conn_state)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
 	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
 	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
-	u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
+	u32 port = VIDEO_DIP_PORT(encoder->port);
 
 	assert_hdmi_port_disabled(intel_hdmi);
 
@@ -740,14 +737,14 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
 	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
 }
 
-static void cpt_set_infoframes(struct drm_encoder *encoder,
+static void cpt_set_infoframes(struct intel_encoder *encoder,
 			       bool enable,
 			       const struct intel_crtc_state *crtc_state,
 			       const struct drm_connector_state *conn_state)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
 	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
 
@@ -783,18 +780,17 @@ static void cpt_set_infoframes(struct drm_encoder *encoder,
 	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
 }
 
-static void vlv_set_infoframes(struct drm_encoder *encoder,
+static void vlv_set_infoframes(struct intel_encoder *encoder,
 			       bool enable,
 			       const struct intel_crtc_state *crtc_state,
 			       const struct drm_connector_state *conn_state)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
 	i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
 	u32 val = I915_READ(reg);
-	u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
+	u32 port = VIDEO_DIP_PORT(encoder->port);
 
 	assert_hdmi_port_disabled(intel_hdmi);
 
@@ -836,12 +832,12 @@ static void vlv_set_infoframes(struct drm_encoder *encoder,
 	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
 }
 
-static void hsw_set_infoframes(struct drm_encoder *encoder,
+static void hsw_set_infoframes(struct intel_encoder *encoder,
 			       bool enable,
 			       const struct intel_crtc_state *crtc_state,
 			       const struct drm_connector_state *conn_state)
 {
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
 	u32 val = I915_READ(reg);
 
@@ -1215,7 +1211,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
 	if (tmp & HDMI_MODE_SELECT_HDMI)
 		pipe_config->has_hdmi_sink = true;
 
-	if (intel_dig_port->infoframe_enabled(&encoder->base, pipe_config))
+	if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
 		pipe_config->has_infoframe = true;
 
 	if (tmp & SDVO_AUDIO_ENABLE)
@@ -1436,7 +1432,8 @@ static void intel_disable_hdmi(struct intel_encoder *encoder,
 		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
 	}
 
-	intel_dig_port->set_infoframes(&encoder->base, false,
+	intel_dig_port->set_infoframes(encoder,
+				       false,
 				       old_crtc_state, old_conn_state);
 
 	intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
@@ -1971,7 +1968,7 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder,
 
 	intel_hdmi_prepare(encoder, pipe_config);
 
-	intel_dig_port->set_infoframes(&encoder->base,
+	intel_dig_port->set_infoframes(encoder,
 				       pipe_config->has_infoframe,
 				       pipe_config, conn_state);
 }
@@ -1989,7 +1986,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder,
 	vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
 				 0x2b247878);
 
-	dport->set_infoframes(&encoder->base,
+	dport->set_infoframes(encoder,
 			      pipe_config->has_infoframe,
 			      pipe_config, conn_state);
 
@@ -2060,7 +2057,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
 	/* Use 800mV-0dB */
 	chv_set_phy_signal_level(encoder, 128, 102, false);
 
-	dport->set_infoframes(&encoder->base,
+	dport->set_infoframes(encoder,
 			      pipe_config->has_infoframe,
 			      pipe_config, conn_state);
 
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index b6838b525502..11fdefaf7728 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -294,7 +294,8 @@ static void intel_psr_setup_vsc(struct intel_dp *intel_dp,
 		psr_vsc.sdp_header.HB3 = 0x8;
 	}
 
-	intel_dig_port->write_infoframe(&intel_dig_port->base.base, crtc_state,
+	intel_dig_port->write_infoframe(&intel_dig_port->base,
+					crtc_state,
 					DP_SDP_VSC, &psr_vsc, sizeof(psr_vsc));
 }
 
-- 
2.16.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 10/18] drm/i915: Add the missing HDMI gamut metadata packet stuff
  2018-09-20 18:51 ` Ville Syrjala
                   ` (9 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-21 14:15   ` [Intel-gfx] " Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We have definitions and low level code for everything except the gamut
metadata HDMI packet. Add the missing bits.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h   |  4 +++-
 drivers/gpu/drm/i915/intel_hdmi.c | 12 ++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 4948b352bf4c..c07fd394ca1d 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -4577,6 +4577,7 @@ enum {
 #define   VIDEO_DIP_ENABLE_SPD		(8 << 21)
 #define   VIDEO_DIP_SELECT_AVI		(0 << 19)
 #define   VIDEO_DIP_SELECT_VENDOR	(1 << 19)
+#define   VIDEO_DIP_SELECT_GAMUT	(2 << 19)
 #define   VIDEO_DIP_SELECT_SPD		(3 << 19)
 #define   VIDEO_DIP_SELECT_MASK		(3 << 19)
 #define   VIDEO_DIP_FREQ_ONCE		(0 << 16)
@@ -7948,10 +7949,11 @@ enum {
 #define _ICL_VIDEO_DIP_PPS_ECC_B	0x613D4
 
 #define HSW_TVIDEO_DIP_CTL(trans)		_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_CTL_A)
+#define HSW_TVIDEO_DIP_GCP(trans)		_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GCP_A)
 #define HSW_TVIDEO_DIP_AVI_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_AVI_DATA_A + (i) * 4)
 #define HSW_TVIDEO_DIP_VS_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VS_DATA_A + (i) * 4)
 #define HSW_TVIDEO_DIP_SPD_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_SPD_DATA_A + (i) * 4)
-#define HSW_TVIDEO_DIP_GCP(trans)		_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GCP_A)
+#define HSW_TVIDEO_DIP_GMP_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GMP_DATA_A + (i) * 4)
 #define HSW_TVIDEO_DIP_VSC_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VSC_DATA_A + (i) * 4)
 #define ICL_VIDEO_DIP_PPS_DATA(trans, i)	_MMIO_TRANS2(trans, _ICL_VIDEO_DIP_PPS_DATA_A + (i) * 4)
 #define ICL_VIDEO_DIP_PPS_ECC(trans, i)		_MMIO_TRANS2(trans, _ICL_VIDEO_DIP_PPS_ECC_A + (i) * 4)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 454f570275e9..c3c2a638d062 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -83,6 +83,8 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
 static u32 g4x_infoframe_index(unsigned int type)
 {
 	switch (type) {
+	case HDMI_PACKET_TYPE_GAMUT_METADATA:
+		return VIDEO_DIP_SELECT_GAMUT;
 	case HDMI_INFOFRAME_TYPE_AVI:
 		return VIDEO_DIP_SELECT_AVI;
 	case HDMI_INFOFRAME_TYPE_SPD:
@@ -98,6 +100,10 @@ static u32 g4x_infoframe_index(unsigned int type)
 static u32 g4x_infoframe_enable(unsigned int type)
 {
 	switch (type) {
+	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
+		return VIDEO_DIP_ENABLE_GCP;
+	case HDMI_PACKET_TYPE_GAMUT_METADATA:
+		return VIDEO_DIP_ENABLE_GAMUT;
 	case HDMI_INFOFRAME_TYPE_AVI:
 		return VIDEO_DIP_ENABLE_AVI;
 	case HDMI_INFOFRAME_TYPE_SPD:
@@ -113,6 +119,10 @@ static u32 g4x_infoframe_enable(unsigned int type)
 static u32 hsw_infoframe_enable(unsigned int type)
 {
 	switch (type) {
+	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
+		return VIDEO_DIP_ENABLE_GCP_HSW;
+	case HDMI_PACKET_TYPE_GAMUT_METADATA:
+		return VIDEO_DIP_ENABLE_GMP_HSW;
 	case DP_SDP_VSC:
 		return VIDEO_DIP_ENABLE_VSC_HSW;
 	case HDMI_INFOFRAME_TYPE_AVI:
@@ -134,6 +144,8 @@ hsw_dip_data_reg(struct drm_i915_private *dev_priv,
 		 int i)
 {
 	switch (type) {
+	case HDMI_PACKET_TYPE_GAMUT_METADATA:
+		return HSW_TVIDEO_DIP_GMP_DATA(cpu_transcoder, i);
 	case DP_SDP_VSC:
 		return HSW_TVIDEO_DIP_VSC_DATA(cpu_transcoder, i);
 	case HDMI_INFOFRAME_TYPE_AVI:
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 11/18] drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
  2018-09-20 18:51 ` Ville Syrjala
                   ` (10 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-24 15:51   ` Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

We want to start tracking which infoframes are enabled, so let's replace
the boolean flag with a bitmask.

We'll abstract the bitmask so that it's not platform dependent. That
will allow us to examine the bitmask later in platform independent code.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c  |  2 +-
 drivers/gpu/drm/i915/intel_drv.h  |  4 +-
 drivers/gpu/drm/i915/intel_hdmi.c | 87 ++++++++++++++++++++++++++++-----------
 3 files changed, 68 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 086e3f940586..098a0e4edf2a 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -3390,7 +3390,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 		pipe_config->has_hdmi_sink = true;
 		intel_dig_port = enc_to_dig_port(&encoder->base);
 
-		if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
+		if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
 			pipe_config->has_infoframe = true;
 
 		if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e0f3a79fc75e..6815c69aac2f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1181,7 +1181,7 @@ struct intel_digital_port {
 			       bool enable,
 			       const struct intel_crtc_state *crtc_state,
 			       const struct drm_connector_state *conn_state);
-	bool (*infoframe_enabled)(struct intel_encoder *encoder,
+	u32 (*infoframes_enabled)(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config);
 };
 
@@ -1856,6 +1856,8 @@ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
 				       bool scrambling);
 void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
 void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
+u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
+				  const struct intel_crtc_state *crtc_state);
 
 
 /* intel_lvds.c */
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index c3c2a638d062..a8fcddb199ae 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -100,10 +100,14 @@ static u32 g4x_infoframe_index(unsigned int type)
 static u32 g4x_infoframe_enable(unsigned int type)
 {
 	switch (type) {
+	case HDMI_PACKET_TYPE_NULL:
+		return VIDEO_DIP_ENABLE; /* slight lie */
 	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
 		return VIDEO_DIP_ENABLE_GCP;
 	case HDMI_PACKET_TYPE_GAMUT_METADATA:
 		return VIDEO_DIP_ENABLE_GAMUT;
+	case DP_SDP_VSC:
+		return 0;
 	case HDMI_INFOFRAME_TYPE_AVI:
 		return VIDEO_DIP_ENABLE_AVI;
 	case HDMI_INFOFRAME_TYPE_SPD:
@@ -119,6 +123,8 @@ static u32 g4x_infoframe_enable(unsigned int type)
 static u32 hsw_infoframe_enable(unsigned int type)
 {
 	switch (type) {
+	case HDMI_PACKET_TYPE_NULL:
+		return 0;
 	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
 		return VIDEO_DIP_ENABLE_GCP_HSW;
 	case HDMI_PACKET_TYPE_GAMUT_METADATA:
@@ -197,19 +203,19 @@ static void g4x_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(VIDEO_DIP_CTL);
 }
 
-static bool g4x_infoframe_enabled(struct intel_encoder *encoder,
+static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	u32 val = I915_READ(VIDEO_DIP_CTL);
 
 	if ((val & VIDEO_DIP_ENABLE) == 0)
-		return false;
+		return 0;
 
 	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
-		return false;
+		return 0;
 
-	return val & (VIDEO_DIP_ENABLE_AVI |
+	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
 }
 
@@ -252,7 +258,7 @@ static void ibx_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(reg);
 }
 
-static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
+static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -261,12 +267,12 @@ static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
 	u32 val = I915_READ(reg);
 
 	if ((val & VIDEO_DIP_ENABLE) == 0)
-		return false;
+		return 0;
 
 	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
-		return false;
+		return 0;
 
-	return val & (VIDEO_DIP_ENABLE_AVI |
+	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
 }
@@ -313,7 +319,7 @@ static void cpt_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(reg);
 }
 
-static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
+static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -321,9 +327,9 @@ static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
 	u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
 
 	if ((val & VIDEO_DIP_ENABLE) == 0)
-		return false;
+		return 0;
 
-	return val & (VIDEO_DIP_ENABLE_AVI |
+	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
 }
@@ -367,7 +373,7 @@ static void vlv_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(reg);
 }
 
-static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
+static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -375,12 +381,12 @@ static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
 	u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
 
 	if ((val & VIDEO_DIP_ENABLE) == 0)
-		return false;
+		return 0;
 
 	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
-		return false;
+		return 0;
 
-	return val & (VIDEO_DIP_ENABLE_AVI |
+	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
 		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
 		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
 }
@@ -419,7 +425,7 @@ static void hsw_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(ctl_reg);
 }
 
-static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
+static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
@@ -430,6 +436,42 @@ static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
 		      VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
 }
 
+static const u8 infoframe_type_to_idx[] = {
+	HDMI_PACKET_TYPE_NULL,
+	HDMI_PACKET_TYPE_GENERAL_CONTROL,
+	HDMI_PACKET_TYPE_GAMUT_METADATA,
+	DP_SDP_VSC,
+	HDMI_INFOFRAME_TYPE_AVI,
+	HDMI_INFOFRAME_TYPE_SPD,
+	HDMI_INFOFRAME_TYPE_VENDOR,
+};
+
+u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
+				  const struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
+	u32 val, ret = 0;
+	int i;
+
+	val = dig_port->infoframes_enabled(encoder, crtc_state);
+
+	/* map from hardware bits to dip idx */
+	for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
+		unsigned int type = infoframe_type_to_idx[i];
+
+		if (HAS_DDI(dev_priv)) {
+			if (val & hsw_infoframe_enable(type))
+				ret |= BIT(i);
+		} else {
+			if (val & g4x_infoframe_enable(type))
+				ret |= BIT(i);
+		}
+	}
+
+	return ret;
+}
+
 /*
  * The data we write to the DIP data buffer registers is 1 byte bigger than the
  * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
@@ -1200,7 +1242,6 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
 				  struct intel_crtc_state *pipe_config)
 {
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
-	struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi);
 	struct drm_device *dev = encoder->base.dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	u32 tmp, flags = 0;
@@ -1223,7 +1264,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
 	if (tmp & HDMI_MODE_SELECT_HDMI)
 		pipe_config->has_hdmi_sink = true;
 
-	if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
+	if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
 		pipe_config->has_infoframe = true;
 
 	if (tmp & SDVO_AUDIO_ENABLE)
@@ -2325,23 +2366,23 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
 		intel_dig_port->write_infoframe = vlv_write_infoframe;
 		intel_dig_port->set_infoframes = vlv_set_infoframes;
-		intel_dig_port->infoframe_enabled = vlv_infoframe_enabled;
+		intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
 	} else if (IS_G4X(dev_priv)) {
 		intel_dig_port->write_infoframe = g4x_write_infoframe;
 		intel_dig_port->set_infoframes = g4x_set_infoframes;
-		intel_dig_port->infoframe_enabled = g4x_infoframe_enabled;
+		intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
 	} else if (HAS_DDI(dev_priv)) {
 		intel_dig_port->write_infoframe = hsw_write_infoframe;
 		intel_dig_port->set_infoframes = hsw_set_infoframes;
-		intel_dig_port->infoframe_enabled = hsw_infoframe_enabled;
+		intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
 	} else if (HAS_PCH_IBX(dev_priv)) {
 		intel_dig_port->write_infoframe = ibx_write_infoframe;
 		intel_dig_port->set_infoframes = ibx_set_infoframes;
-		intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
+		intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
 	} else {
 		intel_dig_port->write_infoframe = cpt_write_infoframe;
 		intel_dig_port->set_infoframes = cpt_set_infoframes;
-		intel_dig_port->infoframe_enabled = cpt_infoframe_enabled;
+		intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
 	}
 }
 
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 12/18] drm/i915: Store mask of enabled infoframes in the crtc state
  2018-09-20 18:51 ` Ville Syrjala
                   ` (11 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-24 15:51   ` [Intel-gfx] " Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Store the mask of enabled infoframes in the crtc state. We'll start
with just the readout for HDMI encoder, and we'll expand this
to compute the bitmask in .compute_config() later. SDVO will also
follow later.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c  | 5 ++++-
 drivers/gpu/drm/i915/intel_drv.h  | 4 ++++
 drivers/gpu/drm/i915/intel_hdmi.c | 5 ++++-
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 098a0e4edf2a..19fef88e680e 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -3390,7 +3390,10 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 		pipe_config->has_hdmi_sink = true;
 		intel_dig_port = enc_to_dig_port(&encoder->base);
 
-		if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
+		pipe_config->infoframes.enable |=
+			intel_hdmi_infoframes_enabled(encoder, pipe_config);
+
+		if (pipe_config->infoframes.enable)
 			pipe_config->has_infoframe = true;
 
 		if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 6815c69aac2f..50c0c049ee15 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -893,6 +893,10 @@ struct intel_crtc_state {
 	u8 active_planes;
 	u8 nv12_planes;
 
+	struct {
+		u32 enable;
+	} infoframes;
+
 	/* HDMI scrambling status */
 	bool hdmi_scrambling;
 
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index a8fcddb199ae..98a44084324c 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1264,7 +1264,10 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
 	if (tmp & HDMI_MODE_SELECT_HDMI)
 		pipe_config->has_hdmi_sink = true;
 
-	if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
+	pipe_config->infoframes.enable |=
+		intel_hdmi_infoframes_enabled(encoder, pipe_config);
+
+	if (pipe_config->infoframes.enable)
 		pipe_config->has_infoframe = true;
 
 	if (tmp & SDVO_AUDIO_ENABLE)
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 13/18] drm/i915: Precompute HDMI infoframes
  2018-09-20 18:51 ` Ville Syrjala
                   ` (12 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-24 15:58   ` Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Store the infoframes in the crtc state and precompute them in
.compute_config(). While precomputing we'll also fill out the
inforames.enable bitmask appropriately.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c  |   1 +
 drivers/gpu/drm/i915/intel_drv.h  |   5 +
 drivers/gpu/drm/i915/intel_hdmi.c | 249 +++++++++++++++++++++++++++-----------
 3 files changed, 187 insertions(+), 68 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 19fef88e680e..5f3bd536d261 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -3391,6 +3391,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 		intel_dig_port = enc_to_dig_port(&encoder->base);
 
 		pipe_config->infoframes.enable |=
+			intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_NULL) |
 			intel_hdmi_infoframes_enabled(encoder, pipe_config);
 
 		if (pipe_config->infoframes.enable)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 50c0c049ee15..357624a6bfe2 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -895,6 +895,10 @@ struct intel_crtc_state {
 
 	struct {
 		u32 enable;
+		u32 gcp;
+		union hdmi_infoframe avi;
+		union hdmi_infoframe spd;
+		union hdmi_infoframe hdmi;
 	} infoframes;
 
 	/* HDMI scrambling status */
@@ -1862,6 +1866,7 @@ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
 void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
 u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *crtc_state);
+u32 intel_hdmi_infoframe_enable(unsigned int type);
 
 
 /* intel_lvds.c */
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 98a44084324c..491001fc0fad 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -446,6 +446,18 @@ static const u8 infoframe_type_to_idx[] = {
 	HDMI_INFOFRAME_TYPE_VENDOR,
 };
 
+u32 intel_hdmi_infoframe_enable(unsigned int type)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
+		if (infoframe_type_to_idx[i] == type)
+			return BIT(i);
+	}
+
+	return 0;
+}
+
 u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *crtc_state)
 {
@@ -491,15 +503,23 @@ u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
  */
 static void intel_write_infoframe(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *crtc_state,
-				  union hdmi_infoframe *frame)
+				  enum hdmi_infoframe_type type,
+				  const union hdmi_infoframe *frame)
 {
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
 	u8 buffer[VIDEO_DIP_DATA_SIZE];
 	ssize_t len;
 
+	if ((crtc_state->infoframes.enable &
+	     intel_hdmi_infoframe_enable(type)) == 0)
+		return;
+
+	if (WARN_ON(frame->any.type != type))
+		return;
+
 	/* see comment above for the reason for this offset */
-	len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1);
-	if (len < 0)
+	len = hdmi_infoframe_pack_only(frame, buffer + 1, sizeof(buffer) - 1);
+	if (WARN_ON(len < 0))
 		return;
 
 	/* Insert the 'hole' (see big comment above) at position 3 */
@@ -507,85 +527,111 @@ static void intel_write_infoframe(struct intel_encoder *encoder,
 	buffer[3] = 0;
 	len++;
 
-	intel_dig_port->write_infoframe(encoder,
-					crtc_state,
-					frame->any.type, buffer, len);
+	intel_dig_port->write_infoframe(encoder, crtc_state, type, buffer, len);
 }
 
-static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
-					 const struct intel_crtc_state *crtc_state,
-					 const struct drm_connector_state *conn_state)
+static bool
+intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder,
+				 struct intel_crtc_state *crtc_state,
+				 struct drm_connector_state *conn_state)
 {
 	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+	struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi;
+	bool is_hdmi2_sink = conn_state->connector->display_info.hdmi.scdc.supported;
 	const struct drm_display_mode *adjusted_mode =
 		&crtc_state->base.adjusted_mode;
-	struct drm_connector *connector = &intel_hdmi->attached_connector->base;
-	bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
-	union hdmi_infoframe frame;
 	int ret;
 
-	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
+	if (!crtc_state->has_infoframe)
+		return true;
+
+	crtc_state->infoframes.enable |=
+		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
+
+	ret = drm_hdmi_avi_infoframe_from_display_mode(frame,
 						       adjusted_mode,
 						       is_hdmi2_sink);
-	if (ret < 0) {
-		DRM_ERROR("couldn't fill AVI infoframe\n");
-		return;
-	}
+	if (ret)
+		return false;
 
 	if (crtc_state->ycbcr420)
-		frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
+		frame->colorspace = HDMI_COLORSPACE_YUV420;
 	else
-		frame.avi.colorspace = HDMI_COLORSPACE_RGB;
+		frame->colorspace = HDMI_COLORSPACE_RGB;
 
-	drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode,
+	drm_hdmi_avi_infoframe_quant_range(frame, adjusted_mode,
 					   crtc_state->limited_color_range ?
 					   HDMI_QUANTIZATION_RANGE_LIMITED :
 					   HDMI_QUANTIZATION_RANGE_FULL,
 					   intel_hdmi->rgb_quant_range_selectable,
 					   is_hdmi2_sink);
 
-	drm_hdmi_avi_infoframe_content_type(&frame.avi,
-					    conn_state);
+	drm_hdmi_avi_infoframe_content_type(frame, conn_state);
 
 	/* TODO: handle pixel repetition for YCBCR420 outputs */
-	intel_write_infoframe(encoder, crtc_state,
-			      &frame);
+
+	ret = hdmi_avi_infoframe_check(frame);
+	if (WARN_ON(ret))
+		return false;
+
+	return true;
 }
 
-static void intel_hdmi_set_spd_infoframe(struct intel_encoder *encoder,
-					 const struct intel_crtc_state *crtc_state)
+static bool
+intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder,
+				 struct intel_crtc_state *crtc_state,
+				 struct drm_connector_state *conn_state)
 {
-	union hdmi_infoframe frame;
+	struct hdmi_spd_infoframe *frame = &crtc_state->infoframes.spd.spd;
 	int ret;
 
-	ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx");
-	if (ret < 0) {
-		DRM_ERROR("couldn't fill SPD infoframe\n");
-		return;
-	}
+	if (!crtc_state->has_infoframe)
+		return true;
 
-	frame.spd.sdi = HDMI_SPD_SDI_PC;
+	crtc_state->infoframes.enable |=
+		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD);
 
-	intel_write_infoframe(encoder, crtc_state,
-			      &frame);
+	ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx");
+	if (WARN_ON(ret))
+		return false;
+
+	frame->sdi = HDMI_SPD_SDI_PC;
+
+	ret = hdmi_spd_infoframe_check(frame);
+	if (WARN_ON(ret))
+		return false;
+
+	return true;
 }
 
-static void
-intel_hdmi_set_hdmi_infoframe(struct intel_encoder *encoder,
-			      const struct intel_crtc_state *crtc_state,
-			      const struct drm_connector_state *conn_state)
-{
-	union hdmi_infoframe frame;
+static bool
+intel_hdmi_compute_hdmi_infoframe(struct intel_encoder *encoder,
+				  struct intel_crtc_state *crtc_state,
+				  struct drm_connector_state *conn_state)
+{
+	struct hdmi_vendor_infoframe *frame =
+		&crtc_state->infoframes.hdmi.vendor.hdmi;
+	const struct drm_display_info *info =
+		&conn_state->connector->display_info;
 	int ret;
 
-	ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
+	if (!crtc_state->has_infoframe || !info->has_hdmi_infoframe)
+		return true;
+
+	crtc_state->infoframes.enable |=
+		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_VENDOR);
+
+	ret = drm_hdmi_vendor_infoframe_from_display_mode(frame,
 							  conn_state->connector,
 							  &crtc_state->base.adjusted_mode);
-	if (ret < 0)
-		return;
+	if (WARN_ON(ret))
+		return false;
 
-	intel_write_infoframe(encoder, crtc_state,
-			      &frame);
+	ret = hdmi_vendor_infoframe_check(frame);
+	if (WARN_ON(ret))
+		return false;
+
+	return true;
 }
 
 static void g4x_set_infoframes(struct intel_encoder *encoder,
@@ -645,9 +691,15 @@ static void g4x_set_infoframes(struct intel_encoder *encoder,
 	I915_WRITE(reg, val);
 	POSTING_READ(reg);
 
-	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
-	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
-	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_AVI,
+			      &crtc_state->infoframes.avi);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_SPD,
+			      &crtc_state->infoframes.spd);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_VENDOR,
+			      &crtc_state->infoframes.hdmi);
 }
 
 static bool hdmi_sink_is_deep_color(const struct drm_connector_state *conn_state)
@@ -713,7 +765,10 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
 	i915_reg_t reg;
-	u32 val = 0;
+
+	if ((crtc_state->infoframes.enable &
+	     intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
+		return false;
 
 	if (HAS_DDI(dev_priv))
 		reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
@@ -724,18 +779,31 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
 	else
 		return false;
 
+	I915_WRITE(reg, crtc_state->infoframes.gcp);
+
+	return true;
+}
+
+static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder,
+					     struct intel_crtc_state *crtc_state,
+					     struct drm_connector_state *conn_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+	if (IS_G4X(dev_priv) || !crtc_state->has_infoframe)
+		return;
+
+	crtc_state->infoframes.enable |=
+		intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL);
+
 	/* Indicate color depth whenever the sink supports deep color */
 	if (hdmi_sink_is_deep_color(conn_state))
-		val |= GCP_COLOR_INDICATION;
+		crtc_state->infoframes.gcp |= GCP_COLOR_INDICATION;
 
 	/* Enable default_phase whenever the display mode is suitably aligned */
 	if (gcp_default_phase_possible(crtc_state->pipe_bpp,
 				       &crtc_state->base.adjusted_mode))
-		val |= GCP_DEFAULT_PHASE_ENABLE;
-
-	I915_WRITE(reg, val);
-
-	return val != 0;
+		crtc_state->infoframes.gcp |= GCP_DEFAULT_PHASE_ENABLE;
 }
 
 static void ibx_set_infoframes(struct intel_encoder *encoder,
@@ -786,9 +854,15 @@ static void ibx_set_infoframes(struct intel_encoder *encoder,
 	I915_WRITE(reg, val);
 	POSTING_READ(reg);
 
-	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
-	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
-	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_AVI,
+			      &crtc_state->infoframes.avi);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_SPD,
+			      &crtc_state->infoframes.spd);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_VENDOR,
+			      &crtc_state->infoframes.hdmi);
 }
 
 static void cpt_set_infoframes(struct intel_encoder *encoder,
@@ -829,9 +903,15 @@ static void cpt_set_infoframes(struct intel_encoder *encoder,
 	I915_WRITE(reg, val);
 	POSTING_READ(reg);
 
-	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
-	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
-	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_AVI,
+			      &crtc_state->infoframes.avi);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_SPD,
+			      &crtc_state->infoframes.spd);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_VENDOR,
+			      &crtc_state->infoframes.hdmi);
 }
 
 static void vlv_set_infoframes(struct intel_encoder *encoder,
@@ -881,9 +961,15 @@ static void vlv_set_infoframes(struct intel_encoder *encoder,
 	I915_WRITE(reg, val);
 	POSTING_READ(reg);
 
-	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
-	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
-	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_AVI,
+			      &crtc_state->infoframes.avi);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_SPD,
+			      &crtc_state->infoframes.spd);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_VENDOR,
+			      &crtc_state->infoframes.hdmi);
 }
 
 static void hsw_set_infoframes(struct intel_encoder *encoder,
@@ -914,9 +1000,15 @@ static void hsw_set_infoframes(struct intel_encoder *encoder,
 	I915_WRITE(reg, val);
 	POSTING_READ(reg);
 
-	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
-	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
-	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_AVI,
+			      &crtc_state->infoframes.avi);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_SPD,
+			      &crtc_state->infoframes.spd);
+	intel_write_infoframe(encoder, crtc_state,
+			      HDMI_INFOFRAME_TYPE_VENDOR,
+			      &crtc_state->infoframes.hdmi);
 }
 
 void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
@@ -1851,6 +1943,27 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
 		}
 	}
 
+	if (pipe_config->has_hdmi_sink)
+		pipe_config->infoframes.enable |=
+			intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_NULL);
+
+	intel_hdmi_compute_gcp_infoframe(encoder, pipe_config, conn_state);
+
+	if (!intel_hdmi_compute_avi_infoframe(encoder, pipe_config, conn_state)) {
+		DRM_DEBUG_KMS("bad AVI infoframe\n");
+		return false;
+	}
+
+	if (!intel_hdmi_compute_spd_infoframe(encoder, pipe_config, conn_state)) {
+		DRM_DEBUG_KMS("bad SPD infoframe\n");
+		return false;
+	}
+
+	if (!intel_hdmi_compute_hdmi_infoframe(encoder, pipe_config, conn_state)) {
+		DRM_DEBUG_KMS("bad HDMI infoframe\n");
+		return false;
+	}
+
 	return true;
 }
 
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 14/18] drm/i915: Read out HDMI infoframes
  2018-09-20 18:51 ` Ville Syrjala
                   ` (13 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-24 16:08   ` Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add code to read the infoframes from the video DIP and unpack them into
the crtc state.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c  |  17 ++++
 drivers/gpu/drm/i915/intel_drv.h  |  10 ++
 drivers/gpu/drm/i915/intel_hdmi.c | 203 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 230 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 5f3bd536d261..a56289f78326 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -3459,6 +3459,23 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 			bxt_ddi_phy_get_lane_lat_optim_mask(encoder);
 
 	intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
+
+	intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
+
+	if (!intel_read_infoframe(encoder, pipe_config,
+				  HDMI_INFOFRAME_TYPE_AVI,
+				  &pipe_config->infoframes.avi))
+		DRM_ERROR("failed to read AVI infoframe\n");
+
+	if (!intel_read_infoframe(encoder, pipe_config,
+				  HDMI_INFOFRAME_TYPE_SPD,
+				  &pipe_config->infoframes.spd))
+		DRM_ERROR("failed to read SPD infoframe:\n");
+
+	if (!intel_read_infoframe(encoder, pipe_config,
+				  HDMI_INFOFRAME_TYPE_VENDOR,
+				  &pipe_config->infoframes.hdmi))
+		DRM_ERROR("failed to read HDMI infoframe\n");
 }
 
 static enum intel_output_type
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 357624a6bfe2..75ec99b85232 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1185,6 +1185,10 @@ struct intel_digital_port {
 				const struct intel_crtc_state *crtc_state,
 				unsigned int type,
 				const void *frame, ssize_t len);
+	ssize_t (*read_infoframe)(struct intel_encoder *encoder,
+				  const struct intel_crtc_state *crtc_state,
+				  unsigned int type,
+				  void *frame, ssize_t len);
 	void (*set_infoframes)(struct intel_encoder *encoder,
 			       bool enable,
 			       const struct intel_crtc_state *crtc_state,
@@ -1867,6 +1871,12 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
 u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *crtc_state);
 u32 intel_hdmi_infoframe_enable(unsigned int type);
+void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
+				   struct intel_crtc_state *crtc_state);
+bool intel_read_infoframe(struct intel_encoder *encoder,
+			  const struct intel_crtc_state *crtc_state,
+			  enum hdmi_infoframe_type type,
+			  union hdmi_infoframe *frame);
 
 
 /* intel_lvds.c */
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 491001fc0fad..27cb6ec32e94 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -203,6 +203,31 @@ static void g4x_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(VIDEO_DIP_CTL);
 }
 
+static ssize_t g4x_read_infoframe(struct intel_encoder *encoder,
+				  const struct intel_crtc_state *crtc_state,
+				  unsigned int type,
+				  void *frame, ssize_t len)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	u32 val, *data = frame;
+	int i;
+
+	val = I915_READ(VIDEO_DIP_CTL);
+
+	if ((val & g4x_infoframe_enable(type)) == 0)
+		return 0;
+
+	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+	val |= g4x_infoframe_index(type);
+
+	I915_WRITE(VIDEO_DIP_CTL, val);
+
+	for (i = 0; i < len; i += 4)
+		*data++ = I915_READ(VIDEO_DIP_DATA);
+
+	return len;
+}
+
 static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
@@ -258,6 +283,32 @@ static void ibx_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(reg);
 }
 
+static ssize_t ibx_read_infoframe(struct intel_encoder *encoder,
+				  const struct intel_crtc_state *crtc_state,
+				  unsigned int type,
+				  void *frame, ssize_t len)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+	u32 val, *data = frame;
+	int i;
+
+	val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
+
+	if ((val & g4x_infoframe_enable(type)) == 0)
+		return 0;
+
+	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+	val |= g4x_infoframe_index(type);
+
+	I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
+
+	for (i = 0; i < len; i += 4)
+		*data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
+
+	return len;
+}
+
 static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
@@ -319,6 +370,32 @@ static void cpt_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(reg);
 }
 
+static ssize_t cpt_read_infoframe(struct intel_encoder *encoder,
+				  const struct intel_crtc_state *crtc_state,
+				  unsigned int type,
+				  void *frame, ssize_t len)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+	u32 val, *data = frame;
+	int i;
+
+	val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
+
+	if ((val & g4x_infoframe_enable(type)) == 0)
+		return 0;
+
+	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+	val |= g4x_infoframe_index(type);
+
+	I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
+
+	for (i = 0; i < len; i += 4)
+		*data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
+
+	return len;
+}
+
 static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
@@ -373,6 +450,32 @@ static void vlv_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(reg);
 }
 
+static ssize_t vlv_read_infoframe(struct intel_encoder *encoder,
+				  const struct intel_crtc_state *crtc_state,
+				  unsigned int type,
+				  void *frame, ssize_t len)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+	u32 val, *data = frame;
+	int i;
+
+	val = I915_READ(VLV_TVIDEO_DIP_CTL(crtc->pipe));
+
+	if ((val & g4x_infoframe_enable(type)) == 0)
+		return 0;
+
+	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+	val |= g4x_infoframe_index(type);
+
+	I915_WRITE(VLV_TVIDEO_DIP_CTL(crtc->pipe), val);
+
+	for (i = 0; i < len; i += 4)
+		*data++ = I915_READ(VLV_TVIDEO_DIP_DATA(crtc->pipe));
+
+	return len;
+}
+
 static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
@@ -425,6 +528,28 @@ static void hsw_write_infoframe(struct intel_encoder *encoder,
 	POSTING_READ(ctl_reg);
 }
 
+static ssize_t hsw_read_infoframe(struct intel_encoder *encoder,
+				  const struct intel_crtc_state *crtc_state,
+				  unsigned int type,
+				  void *frame, ssize_t len)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
+	u32 val, *data = frame;
+	int i;
+
+	val = I915_READ(HSW_TVIDEO_DIP_CTL(cpu_transcoder));
+
+	if ((val & hsw_infoframe_enable(type)) == 0)
+		return 0;
+
+	for (i = 0; i < len; i += 4)
+		*data++ = I915_READ(hsw_dip_data_reg(dev_priv, cpu_transcoder,
+						     type, i >> 2));
+
+	return len;
+}
+
 static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
 				  const struct intel_crtc_state *pipe_config)
 {
@@ -530,6 +655,39 @@ static void intel_write_infoframe(struct intel_encoder *encoder,
 	intel_dig_port->write_infoframe(encoder, crtc_state, type, buffer, len);
 }
 
+bool intel_read_infoframe(struct intel_encoder *encoder,
+			  const struct intel_crtc_state *crtc_state,
+			  enum hdmi_infoframe_type type,
+			  union hdmi_infoframe *frame)
+{
+	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
+	u8 buffer[VIDEO_DIP_DATA_SIZE];
+	ssize_t len;
+	int ret;
+
+	if ((crtc_state->infoframes.enable &
+	     intel_hdmi_infoframe_enable(type)) == 0)
+		return true;
+
+	len = intel_dig_port->read_infoframe(encoder, crtc_state,
+					     type, buffer, sizeof(buffer));
+	if (len == 0)
+		return true;
+
+	/* Fill the 'hole' (see big comment above) at position 3 */
+	memmove(&buffer[1], &buffer[0], 3);
+
+	/* see comment above for the reason for this offset */
+	ret = hdmi_infoframe_unpack(frame, buffer + 1, sizeof(buffer) - 1);
+	if (ret)
+		return false;
+
+	if (frame->any.type != type)
+		return false;
+
+	return true;
+}
+
 static bool
 intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder,
 				 struct intel_crtc_state *crtc_state,
@@ -784,6 +942,29 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
 	return true;
 }
 
+void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
+				   struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+	i915_reg_t reg;
+
+	if ((crtc_state->infoframes.enable &
+	     intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
+		return;
+
+	if (HAS_DDI(dev_priv))
+		reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
+	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+		reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
+	else if (HAS_PCH_SPLIT(dev_priv))
+		reg = TVIDEO_DIP_GCP(crtc->pipe);
+	else
+		return;
+
+	crtc_state->infoframes.gcp = I915_READ(reg);
+}
+
 static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder,
 					     struct intel_crtc_state *crtc_state,
 					     struct drm_connector_state *conn_state)
@@ -1382,6 +1563,23 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
 	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
 
 	pipe_config->lane_count = 4;
+
+	intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
+
+	if (!intel_read_infoframe(encoder, pipe_config,
+				  HDMI_INFOFRAME_TYPE_AVI,
+				  &pipe_config->infoframes.avi))
+		DRM_ERROR("failed to read AVI infoframe\n");
+
+	if (!intel_read_infoframe(encoder, pipe_config,
+				  HDMI_INFOFRAME_TYPE_SPD,
+				  &pipe_config->infoframes.spd))
+		DRM_ERROR("failed to read SPD infoframe:\n");
+
+	if (!intel_read_infoframe(encoder, pipe_config,
+				  HDMI_INFOFRAME_TYPE_VENDOR,
+				  &pipe_config->infoframes.hdmi))
+		DRM_ERROR("failed to read HDMI infoframe\n");
 }
 
 static void intel_enable_hdmi_audio(struct intel_encoder *encoder,
@@ -2481,22 +2679,27 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
 
 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
 		intel_dig_port->write_infoframe = vlv_write_infoframe;
+		intel_dig_port->read_infoframe = vlv_read_infoframe;
 		intel_dig_port->set_infoframes = vlv_set_infoframes;
 		intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
 	} else if (IS_G4X(dev_priv)) {
 		intel_dig_port->write_infoframe = g4x_write_infoframe;
+		intel_dig_port->read_infoframe = g4x_read_infoframe;
 		intel_dig_port->set_infoframes = g4x_set_infoframes;
 		intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
 	} else if (HAS_DDI(dev_priv)) {
 		intel_dig_port->write_infoframe = hsw_write_infoframe;
+		intel_dig_port->read_infoframe = hsw_read_infoframe;
 		intel_dig_port->set_infoframes = hsw_set_infoframes;
 		intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
 	} else if (HAS_PCH_IBX(dev_priv)) {
 		intel_dig_port->write_infoframe = ibx_write_infoframe;
+		intel_dig_port->read_infoframe = ibx_read_infoframe;
 		intel_dig_port->set_infoframes = ibx_set_infoframes;
 		intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
 	} else {
 		intel_dig_port->write_infoframe = cpt_write_infoframe;
+		intel_dig_port->read_infoframe = cpt_read_infoframe;
 		intel_dig_port->set_infoframes = cpt_set_infoframes;
 		intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
 	}
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 15/18] drm/i915/sdvo: Precompute HDMI infoframes
  2018-09-20 18:51 ` Ville Syrjala
                   ` (14 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

As with regular HDMI encoders, let's precompute the infoframes
(actually just AVI infoframe for the time being) with SDVO HDMI
encoders.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_sdvo.c | 58 +++++++++++++++++++++++++++++----------
 1 file changed, 43 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 701372e512a8..d8c78aebaf01 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -981,33 +981,57 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
 				    &tx_rate, 1);
 }
 
-static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
-					 const struct intel_crtc_state *pipe_config)
+static bool intel_sdvo_compute_avi_infoframe(struct intel_sdvo *intel_sdvo,
+					     struct intel_crtc_state *crtc_state,
+					     struct drm_connector_state *conn_state)
 {
-	uint8_t sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
-	union hdmi_infoframe frame;
+	struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi;
 	int ret;
-	ssize_t len;
 
-	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
-						       &pipe_config->base.adjusted_mode,
+	if (!crtc_state->has_hdmi_sink)
+		return true;
+
+	crtc_state->infoframes.enable |=
+		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
+
+	ret = drm_hdmi_avi_infoframe_from_display_mode(frame,
+						       &crtc_state->base.adjusted_mode,
 						       false);
-	if (ret < 0) {
-		DRM_ERROR("couldn't fill AVI infoframe\n");
+	if (WARN_ON(ret))
 		return false;
-	}
 
 	if (intel_sdvo->rgb_quant_range_selectable) {
-		if (pipe_config->limited_color_range)
-			frame.avi.quantization_range =
+		if (crtc_state->limited_color_range)
+			frame->quantization_range =
 				HDMI_QUANTIZATION_RANGE_LIMITED;
 		else
-			frame.avi.quantization_range =
+			frame->quantization_range =
 				HDMI_QUANTIZATION_RANGE_FULL;
 	}
 
-	len = hdmi_infoframe_pack(&frame, sdvo_data, sizeof(sdvo_data));
-	if (len < 0)
+	ret = hdmi_avi_infoframe_check(frame);
+	if (WARN_ON(ret))
+		return false;
+
+	return true;
+}
+
+static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
+					 const struct intel_crtc_state *crtc_state)
+{
+	u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
+	const union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
+	ssize_t len;
+
+	if ((crtc_state->infoframes.enable &
+	     intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI)) == 0)
+		return true;
+
+	if (WARN_ON(frame->any.type != HDMI_INFOFRAME_TYPE_AVI))
+		return false;
+
+	len = hdmi_infoframe_pack_only(frame, sdvo_data, sizeof(sdvo_data));
+	if (WARN_ON(len < 0))
 		return false;
 
 	return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
@@ -1194,6 +1218,10 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
 	if (intel_sdvo_connector->is_hdmi)
 		adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio;
 
+	if (!intel_sdvo_compute_avi_infoframe(intel_sdvo,
+					      pipe_config, conn_state))
+		return false;
+
 	return true;
 }
 
-- 
2.16.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 16/18] drm/i915/sdvo: Read out HDMI infoframes
  2018-09-20 18:51 ` Ville Syrjala
                   ` (15 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-24 16:10   ` [Intel-gfx] " Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Read the HDMI infoframes from the hbuf and unpack them into
the crtc state.

Well, actually just AVI infoframe for now but let's write the
infoframe readout code in a more generic fashion in case we
expand this later.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_sdvo.c | 92 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 89 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index d8c78aebaf01..4d787c86df6d 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -981,6 +981,58 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
 				    &tx_rate, 1);
 }
 
+static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
+					 unsigned int if_index,
+					 u8 *data, unsigned int length)
+{
+	u8 set_buf_index[2] = { if_index, 0 };
+	u8 hbuf_size, tx_rate, av_split;
+	int i;
+
+	if (!intel_sdvo_get_value(intel_sdvo,
+				  SDVO_CMD_GET_HBUF_AV_SPLIT,
+				  &av_split, 1))
+		return -ENXIO;
+
+	if (av_split < if_index)
+		return 0;
+
+	if (!intel_sdvo_get_value(intel_sdvo,
+				  SDVO_CMD_GET_HBUF_TXRATE,
+				  &tx_rate, 1))
+		return -ENXIO;
+
+	if (tx_rate == SDVO_HBUF_TX_DISABLED)
+		return 0;
+
+	if (!intel_sdvo_set_value(intel_sdvo,
+				  SDVO_CMD_SET_HBUF_INDEX,
+				  set_buf_index, 2))
+		return -ENXIO;
+
+	if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
+				  &hbuf_size, 1))
+		return -ENXIO;
+
+	/* Buffer size is 0 based, hooray! */
+	hbuf_size++;
+
+	DRM_DEBUG_KMS("reading sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
+		      if_index, length, hbuf_size);
+
+	hbuf_size = min_t(unsigned int, length, hbuf_size);
+
+	for (i = 0; i < hbuf_size; i += 8) {
+		if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HBUF_DATA, NULL, 0))
+			return -ENXIO;
+		if (!intel_sdvo_read_response(intel_sdvo, &data[i],
+					      min_t(unsigned int, 8, hbuf_size - i)))
+			return -ENXIO;
+	}
+
+	return hbuf_size;
+}
+
 static bool intel_sdvo_compute_avi_infoframe(struct intel_sdvo *intel_sdvo,
 					     struct intel_crtc_state *crtc_state,
 					     struct drm_connector_state *conn_state)
@@ -1039,6 +1091,37 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
 					  sdvo_data, sizeof(sdvo_data));
 }
 
+static bool intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
+					 struct intel_crtc_state *crtc_state)
+{
+	u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
+	union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
+	ssize_t len;
+	int ret;
+
+	if (!crtc_state->has_hdmi_sink)
+		return true;
+
+	len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
+					sdvo_data, sizeof(sdvo_data));
+	if (len < 0)
+		return false;
+	else if (len == 0)
+		return true;
+
+	crtc_state->infoframes.enable |=
+		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
+
+	ret = hdmi_infoframe_unpack(frame, sdvo_data, sizeof(sdvo_data));
+	if (ret)
+		return false;
+
+	if (frame->any.type != HDMI_INFOFRAME_TYPE_AVI)
+		return false;
+
+	return true;
+}
+
 static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
 				     const struct drm_connector_state *conn_state)
 {
@@ -1535,6 +1618,10 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
 		}
 	}
 
+	WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
+	     "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
+	     pipe_config->pixel_multiplier, encoder_pixel_multiplier);
+
 	if (sdvox & HDMI_COLOR_RANGE_16_235)
 		pipe_config->limited_color_range = true;
 
@@ -1547,9 +1634,8 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
 			pipe_config->has_hdmi_sink = true;
 	}
 
-	WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
-	     "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
-	     pipe_config->pixel_multiplier, encoder_pixel_multiplier);
+	if (!intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config))
+		DRM_ERROR("failed to read AVI infoframe\n");
 }
 
 static void intel_disable_sdvo(struct intel_encoder *encoder,
-- 
2.16.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 17/18] drm/i915: Check infoframe state in intel_pipe_config_compare()
  2018-09-20 18:51 ` Ville Syrjala
                   ` (16 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-24 16:12   ` Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Check the infoframes and infoframe enable state when comparing two
crtc states.

We'll use the infoframe logging functions from video/hdmi.c to
show the infoframes as part of the state dump.

TODO: Try to better integrate the infoframe dumps with
      drm state dumps

v2: drm_printk() is no more

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 49 +++++++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index fbcc56caffb6..3dce49e36a05 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11380,6 +11380,37 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n,
 	return false;
 }
 
+static bool
+intel_compare_infoframe(const union hdmi_infoframe *a,
+			const union hdmi_infoframe *b)
+{
+	return memcmp(a, b, sizeof(*a)) == 0;
+}
+
+static void
+pipe_config_infoframe_err(struct drm_i915_private *dev_priv,
+			  bool adjust, const char *name,
+			  const union hdmi_infoframe *a,
+			  const union hdmi_infoframe *b)
+{
+	if (adjust) {
+		if ((drm_debug & DRM_UT_KMS) == 0)
+			return;
+
+		drm_dbg(DRM_UT_KMS, "mismatch in %s infoframe", name);
+		drm_dbg(DRM_UT_KMS, "expected:");
+		hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, a);
+		drm_dbg(DRM_UT_KMS, "found");
+		hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, b);
+	} else {
+		drm_err("mismatch in %s infoframe", name);
+		drm_err("expected:");
+		hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, a);
+		drm_err("found");
+		hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, b);
+	}
+}
+
 static void __printf(3, 4)
 pipe_config_err(bool adjust, const char *name, const char *format, ...)
 {
@@ -11541,7 +11572,17 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
 	} \
 } while (0)
 
-#define PIPE_CONF_QUIRK(quirk)	\
+#define PIPE_CONF_CHECK_INFOFRAME(name) do { \
+	if (!intel_compare_infoframe(&current_config->infoframes.name, \
+				     &pipe_config->infoframes.name)) { \
+		pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \
+					  &current_config->infoframes.name, \
+					  &pipe_config->infoframes.name); \
+		ret = false; \
+	} \
+} while (0)
+
+#define PIPE_CONF_QUIRK(quirk) \
 	((current_config->quirks | pipe_config->quirks) & (quirk))
 
 	PIPE_CONF_CHECK_I(cpu_transcoder);
@@ -11670,6 +11711,12 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
 
 	PIPE_CONF_CHECK_I(min_voltage_level);
 
+	PIPE_CONF_CHECK_X(infoframes.enable);
+	PIPE_CONF_CHECK_X(infoframes.gcp);
+	PIPE_CONF_CHECK_INFOFRAME(avi);
+	PIPE_CONF_CHECK_INFOFRAME(spd);
+	PIPE_CONF_CHECK_INFOFRAME(hdmi);
+
 #undef PIPE_CONF_CHECK_X
 #undef PIPE_CONF_CHECK_I
 #undef PIPE_CONF_CHECK_BOOL
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH 18/18] drm/i915: Include infoframes in the crtc state dump
  2018-09-20 18:51 ` Ville Syrjala
                   ` (17 preceding siblings ...)
  (?)
@ 2018-09-20 18:51 ` Ville Syrjala
  2018-09-24 16:14   ` [Intel-gfx] " Daniel Vetter
  -1 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjala @ 2018-09-20 18:51 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Dump out the infoframes in the normal crtc state dump.

TODO: Try to better integrate the infoframe dumps with
      drm state dumps

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 3dce49e36a05..27ac33a2a4d3 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10924,6 +10924,16 @@ intel_dump_m_n_config(struct intel_crtc_state *pipe_config, char *id,
 		      m_n->link_m, m_n->link_n, m_n->tu);
 }
 
+static void
+intel_dump_infoframe(struct drm_i915_private *dev_priv,
+		     const union hdmi_infoframe *frame)
+{
+	if ((drm_debug & DRM_UT_KMS) == 0)
+		return;
+
+	hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, frame);
+}
+
 #define OUTPUT_TYPE(x) [INTEL_OUTPUT_ ## x] = #x
 
 static const char * const output_type_str[] = {
@@ -11013,6 +11023,22 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
 	DRM_DEBUG_KMS("audio: %i, infoframes: %i\n",
 		      pipe_config->has_audio, pipe_config->has_infoframe);
 
+	DRM_DEBUG_KMS("infoframes enabled: 0x%x\n",
+		      pipe_config->infoframes.enable);
+
+	if (pipe_config->infoframes.enable &
+	    intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL))
+		DRM_DEBUG_KMS("GCP: 0x%x\n", pipe_config->infoframes.gcp);
+	if (pipe_config->infoframes.enable &
+	    intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI))
+		intel_dump_infoframe(dev_priv, &pipe_config->infoframes.avi);
+	if (pipe_config->infoframes.enable &
+	    intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD))
+		intel_dump_infoframe(dev_priv, &pipe_config->infoframes.spd);
+	if (pipe_config->infoframes.enable &
+	    intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_VENDOR))
+		intel_dump_infoframe(dev_priv, &pipe_config->infoframes.hdmi);
+
 	DRM_DEBUG_KMS("requested mode:\n");
 	drm_mode_debug_printmodeline(&pipe_config->base.mode);
 	DRM_DEBUG_KMS("adjusted mode:\n");
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Infoframe precompute/check
  2018-09-20 18:51 ` Ville Syrjala
                   ` (18 preceding siblings ...)
  (?)
@ 2018-09-20 19:02 ` Patchwork
  -1 siblings, 0 replies; 95+ messages in thread
From: Patchwork @ 2018-09-20 19:02 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Infoframe precompute/check
URL   : https://patchwork.freedesktop.org/series/49983/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
a017fc23cf36 video/hdmi: Constify 'buffer' to the unpack functions
0a03b408d82f video/hdmi: Pass buffer size to infoframe unpack functions
5e5b56d27f18 video/hdmi: Constify infoframe passed to the log functions
d0b178dc443b video/hdmi: Constify infoframe passed to the pack functions
0986996f110b video/hdmi: Add an enum for HDMI packet types
72b90dd1fe07 video/hdmi: Handle the MPEG Source infoframe
-:351: CHECK:BOOL_MEMBER: Avoid using bool structure members because of possible alignment issues - see: https://lkml.org/lkml/2017/11/21/384
#351: FILE: include/linux/hdmi.h:355:
+	bool field_repeat;

total: 0 errors, 0 warnings, 1 checks, 340 lines checked
41d4768fd109 video/hdmi: Handle the NTSC VBI infoframe
c2cb612d54fa drm/i915: Use memmove() for punching the hole into infoframes
367a7d97dd45 drm/i915: Pass intel_encoder to infoframe functions
cbdd05631044 drm/i915: Add the missing HDMI gamut metadata packet stuff
-:35: WARNING:LONG_LINE: line over 100 characters
#35: FILE: drivers/gpu/drm/i915/i915_reg.h:7956:
+#define HSW_TVIDEO_DIP_GMP_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GMP_DATA_A + (i) * 4)

total: 0 errors, 1 warnings, 0 checks, 55 lines checked
a5c2fe997d55 drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
570e42f6d35c drm/i915: Store mask of enabled infoframes in the crtc state
05deffb2dac6 drm/i915: Precompute HDMI infoframes
4a85a46081d1 drm/i915: Read out HDMI infoframes
183a843e443c drm/i915/sdvo: Precompute HDMI infoframes
a12eb68ce310 drm/i915/sdvo: Read out HDMI infoframes
e102b1bf70d2 drm/i915: Check infoframe state in intel_pipe_config_compare()
-:70: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'name' - possible side-effects?
#70: FILE: drivers/gpu/drm/i915/intel_display.c:11575:
+#define PIPE_CONF_CHECK_INFOFRAME(name) do { \
+	if (!intel_compare_infoframe(&current_config->infoframes.name, \
+				     &pipe_config->infoframes.name)) { \
+		pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \
+					  &current_config->infoframes.name, \
+					  &pipe_config->infoframes.name); \
+		ret = false; \
+	} \
+} while (0)

total: 0 errors, 0 warnings, 1 checks, 67 lines checked
cbbbc6773054 drm/i915: Include infoframes in the crtc state dump

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* ✗ Fi.CI.SPARSE: warning for drm/i915: Infoframe precompute/check
  2018-09-20 18:51 ` Ville Syrjala
                   ` (19 preceding siblings ...)
  (?)
@ 2018-09-20 19:12 ` Patchwork
  -1 siblings, 0 replies; 95+ messages in thread
From: Patchwork @ 2018-09-20 19:12 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Infoframe precompute/check
URL   : https://patchwork.freedesktop.org/series/49983/
State : warning

== Summary ==

$ dim sparse origin/drm-tip
Commit: video/hdmi: Constify 'buffer' to the unpack functions
Okay!

Commit: video/hdmi: Pass buffer size to infoframe unpack functions
Okay!

Commit: video/hdmi: Constify infoframe passed to the log functions
Okay!

Commit: video/hdmi: Constify infoframe passed to the pack functions
Okay!

Commit: video/hdmi: Add an enum for HDMI packet types
Okay!

Commit: video/hdmi: Handle the MPEG Source infoframe
Okay!

Commit: video/hdmi: Handle the NTSC VBI infoframe
Okay!

Commit: drm/i915: Use memmove() for punching the hole into infoframes
Okay!

Commit: drm/i915: Pass intel_encoder to infoframe functions
Okay!

Commit: drm/i915: Add the missing HDMI gamut metadata packet stuff
Okay!

Commit: drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
Okay!

Commit: drm/i915: Store mask of enabled infoframes in the crtc state
Okay!

Commit: drm/i915: Precompute HDMI infoframes
Okay!

Commit: drm/i915: Read out HDMI infoframes
Okay!

Commit: drm/i915/sdvo: Precompute HDMI infoframes
Okay!

Commit: drm/i915/sdvo: Read out HDMI infoframes
+drivers/gpu/drm/i915/intel_sdvo.c:1023:21: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/intel_sdvo.c:1023:21: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/intel_sdvo.c:1029:47: warning: expression using sizeof(void)

Commit: drm/i915: Check infoframe state in intel_pipe_config_compare()
Okay!

Commit: drm/i915: Include infoframes in the crtc state dump
Okay!

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* ✓ Fi.CI.BAT: success for drm/i915: Infoframe precompute/check
  2018-09-20 18:51 ` Ville Syrjala
                   ` (20 preceding siblings ...)
  (?)
@ 2018-09-20 19:26 ` Patchwork
  -1 siblings, 0 replies; 95+ messages in thread
From: Patchwork @ 2018-09-20 19:26 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Infoframe precompute/check
URL   : https://patchwork.freedesktop.org/series/49983/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_4852 -> Patchwork_10242 =

== Summary - SUCCESS ==

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/49983/revisions/1/mbox/

== Known issues ==

  Here are the changes found in Patchwork_10242 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@drv_selftest@live_coherency:
      fi-gdg-551:         PASS -> DMESG-FAIL (fdo#107164)

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
      fi-byt-clapper:     PASS -> FAIL (fdo#103191, fdo#107362)

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-c:
      fi-skl-6260u:       PASS -> INCOMPLETE (fdo#104108)

    igt@kms_psr@primary_page_flip:
      fi-icl-u:           PASS -> FAIL (fdo#107336)

    
    ==== Possible fixes ====

    igt@kms_frontbuffer_tracking@basic:
      fi-byt-clapper:     FAIL (fdo#103167) -> PASS

    igt@kms_pipe_crc_basic@hang-read-crc-pipe-c:
      fi-skl-6700hq:      DMESG-WARN (fdo#105998) -> PASS +1

    igt@kms_pipe_crc_basic@nonblocking-crc-pipe-a-frame-sequence:
      fi-byt-clapper:     FAIL (fdo#103191, fdo#107362) -> PASS

    igt@kms_psr@primary_page_flip:
      fi-whl-u:           FAIL (fdo#107336) -> PASS

    
  fdo#103167 https://bugs.freedesktop.org/show_bug.cgi?id=103167
  fdo#103191 https://bugs.freedesktop.org/show_bug.cgi?id=103191
  fdo#104108 https://bugs.freedesktop.org/show_bug.cgi?id=104108
  fdo#105998 https://bugs.freedesktop.org/show_bug.cgi?id=105998
  fdo#107164 https://bugs.freedesktop.org/show_bug.cgi?id=107164
  fdo#107336 https://bugs.freedesktop.org/show_bug.cgi?id=107336
  fdo#107362 https://bugs.freedesktop.org/show_bug.cgi?id=107362


== Participating hosts (52 -> 47) ==

  Missing    (5): fi-ctg-p8600 fi-ilk-m540 fi-byt-squawks fi-bsw-cyan fi-hsw-4200u 


== Build changes ==

    * Linux: CI_DRM_4852 -> Patchwork_10242

  CI_DRM_4852: c7249769bf8b7da87c0f3d8e343a7c342f0f4c16 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4647: ae8187922d8de2bc739519da3bd40cf5f03f5e4f @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10242: cbbbc677305468fbab0b7943eebc62584250f296 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

cbbbc6773054 drm/i915: Include infoframes in the crtc state dump
e102b1bf70d2 drm/i915: Check infoframe state in intel_pipe_config_compare()
a12eb68ce310 drm/i915/sdvo: Read out HDMI infoframes
183a843e443c drm/i915/sdvo: Precompute HDMI infoframes
4a85a46081d1 drm/i915: Read out HDMI infoframes
05deffb2dac6 drm/i915: Precompute HDMI infoframes
570e42f6d35c drm/i915: Store mask of enabled infoframes in the crtc state
a5c2fe997d55 drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
cbdd05631044 drm/i915: Add the missing HDMI gamut metadata packet stuff
367a7d97dd45 drm/i915: Pass intel_encoder to infoframe functions
c2cb612d54fa drm/i915: Use memmove() for punching the hole into infoframes
41d4768fd109 video/hdmi: Handle the NTSC VBI infoframe
72b90dd1fe07 video/hdmi: Handle the MPEG Source infoframe
0986996f110b video/hdmi: Add an enum for HDMI packet types
d0b178dc443b video/hdmi: Constify infoframe passed to the pack functions
5e5b56d27f18 video/hdmi: Constify infoframe passed to the log functions
0a03b408d82f video/hdmi: Pass buffer size to infoframe unpack functions
a017fc23cf36 video/hdmi: Constify 'buffer' to the unpack functions

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10242/issues.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* ✓ Fi.CI.IGT: success for drm/i915: Infoframe precompute/check
  2018-09-20 18:51 ` Ville Syrjala
                   ` (21 preceding siblings ...)
  (?)
@ 2018-09-20 22:30 ` Patchwork
  -1 siblings, 0 replies; 95+ messages in thread
From: Patchwork @ 2018-09-20 22:30 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Infoframe precompute/check
URL   : https://patchwork.freedesktop.org/series/49983/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_4852_full -> Patchwork_10242_full =

== Summary - SUCCESS ==

  No regressions found.

  

== Known issues ==

  Here are the changes found in Patchwork_10242_full that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@gem_eio@in-flight-1us:
      shard-glk:          PASS -> FAIL (fdo#107799)

    igt@gem_userptr_blits@sync-unmap-after-close:
      shard-snb:          SKIP -> INCOMPLETE (fdo#105411)

    igt@kms_available_modes_crc@available_mode_test_crc:
      shard-snb:          NOTRUN -> FAIL (fdo#106641)

    igt@kms_busy@extended-modeset-hang-newfb-render-c:
      shard-apl:          NOTRUN -> DMESG-WARN (fdo#107956)

    
    ==== Possible fixes ====

    igt@gem_ctx_isolation@vcs0-s3:
      shard-apl:          INCOMPLETE (fdo#103927) -> PASS

    igt@gem_render_copy_redux@normal:
      shard-kbl:          INCOMPLETE (fdo#103665, fdo#106650) -> PASS

    igt@kms_chv_cursor_fail@pipe-b-128x128-left-edge:
      shard-kbl:          FAIL (fdo#104671) -> PASS

    igt@kms_cursor_crc@cursor-256x256-suspend:
      shard-kbl:          FAIL (fdo#103191, fdo#103232) -> PASS
      shard-apl:          FAIL (fdo#103191, fdo#103232) -> PASS

    igt@kms_flip_tiling@flip-to-yf-tiled:
      shard-apl:          DMESG-WARN (fdo#105602, fdo#103558) -> PASS +3
      shard-kbl:          DMESG-WARN (fdo#105602, fdo#103558) -> PASS

    igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-pwrite:
      shard-glk:          FAIL (fdo#103167) -> PASS

    igt@kms_setmode@basic:
      shard-apl:          FAIL (fdo#99912) -> PASS
      shard-kbl:          FAIL (fdo#99912) -> PASS

    igt@perf@blocking:
      shard-hsw:          FAIL (fdo#102252) -> PASS

    
  fdo#102252 https://bugs.freedesktop.org/show_bug.cgi?id=102252
  fdo#103167 https://bugs.freedesktop.org/show_bug.cgi?id=103167
  fdo#103191 https://bugs.freedesktop.org/show_bug.cgi?id=103191
  fdo#103232 https://bugs.freedesktop.org/show_bug.cgi?id=103232
  fdo#103558 https://bugs.freedesktop.org/show_bug.cgi?id=103558
  fdo#103665 https://bugs.freedesktop.org/show_bug.cgi?id=103665
  fdo#103927 https://bugs.freedesktop.org/show_bug.cgi?id=103927
  fdo#104671 https://bugs.freedesktop.org/show_bug.cgi?id=104671
  fdo#105411 https://bugs.freedesktop.org/show_bug.cgi?id=105411
  fdo#105602 https://bugs.freedesktop.org/show_bug.cgi?id=105602
  fdo#106641 https://bugs.freedesktop.org/show_bug.cgi?id=106641
  fdo#106650 https://bugs.freedesktop.org/show_bug.cgi?id=106650
  fdo#107799 https://bugs.freedesktop.org/show_bug.cgi?id=107799
  fdo#107956 https://bugs.freedesktop.org/show_bug.cgi?id=107956
  fdo#99912 https://bugs.freedesktop.org/show_bug.cgi?id=99912


== Participating hosts (5 -> 5) ==

  No changes in participating hosts


== Build changes ==

    * Linux: CI_DRM_4852 -> Patchwork_10242

  CI_DRM_4852: c7249769bf8b7da87c0f3d8e343a7c342f0f4c16 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4647: ae8187922d8de2bc739519da3bd40cf5f03f5e4f @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10242: cbbbc677305468fbab0b7943eebc62584250f296 @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10242/shards.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21  8:03     ` Hans Verkuil
  -1 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:03 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The unpack functions just read from the passed in buffer,
> so make it const.
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Thanks!

	Hans

> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 23 ++++++++++++-----------
>  include/linux/hdmi.h |  3 ++-
>  2 files changed, 14 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 38716eb50408..65b915ea4936 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -31,7 +31,7 @@
>  
>  #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
>  
> -static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
> +static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
>  {
>  	u8 csum = 0;
>  	size_t i;
> @@ -1016,9 +1016,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
> -				     void *buffer)
> +				     const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	int ret;
>  
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
> @@ -1079,9 +1079,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
> -				     void *buffer)
> +				     const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	int ret;
>  
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
> @@ -1117,9 +1117,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
> -				       void *buffer)
> +				       const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	int ret;
>  
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
> @@ -1163,9 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
>   */
>  static int
>  hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
> -				 void *buffer)
> +				 const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	size_t length;
>  	int ret;
>  	u8 hdmi_video_format;
> @@ -1234,10 +1234,11 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>   *
>   * Returns 0 on success or a negative error code on failure.
>   */
> -int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
> +int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> +			  const void *buffer)
>  {
>  	int ret;
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  
>  	switch (ptr[0]) {
>  	case HDMI_INFOFRAME_TYPE_AVI:
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index d271ff23984f..d3816170c062 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -332,7 +332,8 @@ union hdmi_infoframe {
>  
>  ssize_t
>  hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> -int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
> +int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> +			  const void *buffer);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
>  			union hdmi_infoframe *frame);
>  
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions
@ 2018-09-21  8:03     ` Hans Verkuil
  0 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:03 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The unpack functions just read from the passed in buffer,
> so make it const.
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Thanks!

	Hans

> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 23 ++++++++++++-----------
>  include/linux/hdmi.h |  3 ++-
>  2 files changed, 14 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 38716eb50408..65b915ea4936 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -31,7 +31,7 @@
>  
>  #define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
>  
> -static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
> +static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
>  {
>  	u8 csum = 0;
>  	size_t i;
> @@ -1016,9 +1016,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
> -				     void *buffer)
> +				     const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	int ret;
>  
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
> @@ -1079,9 +1079,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
> -				     void *buffer)
> +				     const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	int ret;
>  
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
> @@ -1117,9 +1117,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
> -				       void *buffer)
> +				       const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	int ret;
>  
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
> @@ -1163,9 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
>   */
>  static int
>  hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
> -				 void *buffer)
> +				 const void *buffer)
>  {
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  	size_t length;
>  	int ret;
>  	u8 hdmi_video_format;
> @@ -1234,10 +1234,11 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>   *
>   * Returns 0 on success or a negative error code on failure.
>   */
> -int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
> +int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> +			  const void *buffer)
>  {
>  	int ret;
> -	u8 *ptr = buffer;
> +	const u8 *ptr = buffer;
>  
>  	switch (ptr[0]) {
>  	case HDMI_INFOFRAME_TYPE_AVI:
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index d271ff23984f..d3816170c062 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -332,7 +332,8 @@ union hdmi_infoframe {
>  
>  ssize_t
>  hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> -int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
> +int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> +			  const void *buffer);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
>  			union hdmi_infoframe *frame);
>  
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 02/18] video/hdmi: Pass buffer size to infoframe unpack functions
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21  8:06     ` Hans Verkuil
  -1 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:06 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> To make sure the infoframe unpack functions don't end up examining
> stack garbage or oopsing, let's pass in the size of the buffer.
> 
> v2: Convert tda1997x.c as well (kbuild test robot)
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Thanks,

	Hans

> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/media/i2c/adv7511.c  |  2 +-
>  drivers/media/i2c/adv7604.c  |  2 +-
>  drivers/media/i2c/adv7842.c  |  2 +-
>  drivers/media/i2c/tc358743.c |  2 +-
>  drivers/media/i2c/tda1997x.c |  4 ++--
>  drivers/video/hdmi.c         | 51 ++++++++++++++++++++++++++++++++------------
>  include/linux/hdmi.h         |  2 +-
>  7 files changed, 44 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
> index 55c2ea0720d9..b85b181bbb6c 100644
> --- a/drivers/media/i2c/adv7511.c
> +++ b/drivers/media/i2c/adv7511.c
> @@ -550,7 +550,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
>  	buffer[3] = 0;
>  	buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
>  
> -	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
>  		return;
>  	}
> diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
> index 668be2bca57a..2e7a28dbad4e 100644
> --- a/drivers/media/i2c/adv7604.c
> +++ b/drivers/media/i2c/adv7604.c
> @@ -2418,7 +2418,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
>  		buffer[i + 3] = infoframe_read(sd,
>  				       adv76xx_cri[index].payload_addr + i);
>  
> -	if (hdmi_infoframe_unpack(frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
>  			 adv76xx_cri[index].desc);
>  		return -ENOENT;
> diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
> index 4f8fbdd00e35..2cfd03f929b2 100644
> --- a/drivers/media/i2c/adv7842.c
> +++ b/drivers/media/i2c/adv7842.c
> @@ -2563,7 +2563,7 @@ static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infofr
>  	for (i = 0; i < len; i++)
>  		buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
>  
> -	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
>  		return;
>  	}
> diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
> index 44c41933415a..519bf92508d5 100644
> --- a/drivers/media/i2c/tc358743.c
> +++ b/drivers/media/i2c/tc358743.c
> @@ -444,7 +444,7 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
>  
>  	i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
>  
> -	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
>  		return;
>  	}
> diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
> index d114ac5243ec..195a1fc74ee8 100644
> --- a/drivers/media/i2c/tda1997x.c
> +++ b/drivers/media/i2c/tda1997x.c
> @@ -1253,7 +1253,7 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
>  
>  	/* read data */
>  	len = io_readn(sd, addr, sizeof(buffer), buffer);
> -	err = hdmi_infoframe_unpack(&frame, buffer);
> +	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
>  	if (err) {
>  		v4l_err(state->client,
>  			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
> @@ -1928,7 +1928,7 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
>  	/* read data */
>  	len = io_readn(sd, addr, sizeof(buffer), buffer);
>  	v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
> -	err = hdmi_infoframe_unpack(&frame, buffer);
> +	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
>  	if (err) {
>  		v4l_err(state->client,
>  			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 65b915ea4936..b5d491014b0b 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -1005,8 +1005,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
>  
>  /**
>   * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
> - * @buffer: source buffer
>   * @frame: HDMI AVI infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Auxiliary Video (AVI) information frame.
> @@ -1016,11 +1017,14 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
> -				     const void *buffer)
> +				     const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	int ret;
>  
> +	if (size < HDMI_INFOFRAME_SIZE(AVI))
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
>  	    ptr[1] != 2 ||
>  	    ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
> @@ -1068,8 +1072,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
>  
>  /**
>   * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
> - * @buffer: source buffer
>   * @frame: HDMI SPD infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Source Product Description (SPD) information frame.
> @@ -1079,11 +1084,14 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
> -				     const void *buffer)
> +				     const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	int ret;
>  
> +	if (size < HDMI_INFOFRAME_SIZE(SPD))
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
>  	    ptr[1] != 1 ||
>  	    ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
> @@ -1106,8 +1114,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
>  
>  /**
>   * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
> - * @buffer: source buffer
>   * @frame: HDMI Audio infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Audio information frame.
> @@ -1117,11 +1126,14 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
> -				       const void *buffer)
> +				       const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	int ret;
>  
> +	if (size < HDMI_INFOFRAME_SIZE(AUDIO))
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
>  	    ptr[1] != 1 ||
>  	    ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
> @@ -1151,8 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
>  
>  /**
>   * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
> - * @buffer: source buffer
>   * @frame: HDMI Vendor infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Vendor information frame.
> @@ -1163,7 +1176,7 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
>   */
>  static int
>  hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
> -				 const void *buffer)
> +				 const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	size_t length;
> @@ -1171,6 +1184,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  	u8 hdmi_video_format;
>  	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
>  
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
>  	    ptr[1] != 1 ||
>  	    (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
> @@ -1178,6 +1194,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  
>  	length = ptr[2];
>  
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
> +		return -EINVAL;
> +
>  	if (hdmi_infoframe_checksum(buffer,
>  				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
>  		return -EINVAL;
> @@ -1224,8 +1243,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  
>  /**
>   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
> - * @buffer: source buffer
>   * @frame: HDMI infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary buffer @buffer into a structured
>   * @frame of a HDMI infoframe.
> @@ -1235,23 +1255,26 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> -			  const void *buffer)
> +			  const void *buffer, size_t size)
>  {
>  	int ret;
>  	const u8 *ptr = buffer;
>  
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> +		return -EINVAL;
> +
>  	switch (ptr[0]) {
>  	case HDMI_INFOFRAME_TYPE_AVI:
> -		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
> +		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
>  		break;
>  	case HDMI_INFOFRAME_TYPE_SPD:
> -		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
> +		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
>  		break;
>  	case HDMI_INFOFRAME_TYPE_AUDIO:
> -		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
> +		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
>  		break;
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
> -		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
> +		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
>  		break;
>  	default:
>  		ret = -EINVAL;
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index d3816170c062..a577d4ae2570 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -333,7 +333,7 @@ union hdmi_infoframe {
>  ssize_t
>  hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> -			  const void *buffer);
> +			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
>  			union hdmi_infoframe *frame);
>  
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 02/18] video/hdmi: Pass buffer size to infoframe unpack functions
@ 2018-09-21  8:06     ` Hans Verkuil
  0 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:06 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> To make sure the infoframe unpack functions don't end up examining
> stack garbage or oopsing, let's pass in the size of the buffer.
> 
> v2: Convert tda1997x.c as well (kbuild test robot)
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Thanks,

	Hans

> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/media/i2c/adv7511.c  |  2 +-
>  drivers/media/i2c/adv7604.c  |  2 +-
>  drivers/media/i2c/adv7842.c  |  2 +-
>  drivers/media/i2c/tc358743.c |  2 +-
>  drivers/media/i2c/tda1997x.c |  4 ++--
>  drivers/video/hdmi.c         | 51 ++++++++++++++++++++++++++++++++------------
>  include/linux/hdmi.h         |  2 +-
>  7 files changed, 44 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
> index 55c2ea0720d9..b85b181bbb6c 100644
> --- a/drivers/media/i2c/adv7511.c
> +++ b/drivers/media/i2c/adv7511.c
> @@ -550,7 +550,7 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
>  	buffer[3] = 0;
>  	buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
>  
> -	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
>  		return;
>  	}
> diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
> index 668be2bca57a..2e7a28dbad4e 100644
> --- a/drivers/media/i2c/adv7604.c
> +++ b/drivers/media/i2c/adv7604.c
> @@ -2418,7 +2418,7 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
>  		buffer[i + 3] = infoframe_read(sd,
>  				       adv76xx_cri[index].payload_addr + i);
>  
> -	if (hdmi_infoframe_unpack(frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
>  			 adv76xx_cri[index].desc);
>  		return -ENOENT;
> diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
> index 4f8fbdd00e35..2cfd03f929b2 100644
> --- a/drivers/media/i2c/adv7842.c
> +++ b/drivers/media/i2c/adv7842.c
> @@ -2563,7 +2563,7 @@ static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infofr
>  	for (i = 0; i < len; i++)
>  		buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
>  
> -	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
>  		return;
>  	}
> diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
> index 44c41933415a..519bf92508d5 100644
> --- a/drivers/media/i2c/tc358743.c
> +++ b/drivers/media/i2c/tc358743.c
> @@ -444,7 +444,7 @@ static void print_avi_infoframe(struct v4l2_subdev *sd)
>  
>  	i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI));
>  
> -	if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
> +	if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) {
>  		v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__);
>  		return;
>  	}
> diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
> index d114ac5243ec..195a1fc74ee8 100644
> --- a/drivers/media/i2c/tda1997x.c
> +++ b/drivers/media/i2c/tda1997x.c
> @@ -1253,7 +1253,7 @@ tda1997x_parse_infoframe(struct tda1997x_state *state, u16 addr)
>  
>  	/* read data */
>  	len = io_readn(sd, addr, sizeof(buffer), buffer);
> -	err = hdmi_infoframe_unpack(&frame, buffer);
> +	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
>  	if (err) {
>  		v4l_err(state->client,
>  			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
> @@ -1928,7 +1928,7 @@ static int tda1997x_log_infoframe(struct v4l2_subdev *sd, int addr)
>  	/* read data */
>  	len = io_readn(sd, addr, sizeof(buffer), buffer);
>  	v4l2_dbg(1, debug, sd, "infoframe: addr=%d len=%d\n", addr, len);
> -	err = hdmi_infoframe_unpack(&frame, buffer);
> +	err = hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer));
>  	if (err) {
>  		v4l_err(state->client,
>  			"failed parsing %d byte infoframe: 0x%04x/0x%02x\n",
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 65b915ea4936..b5d491014b0b 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -1005,8 +1005,9 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
>  
>  /**
>   * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
> - * @buffer: source buffer
>   * @frame: HDMI AVI infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Auxiliary Video (AVI) information frame.
> @@ -1016,11 +1017,14 @@ EXPORT_SYMBOL(hdmi_infoframe_log);
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
> -				     const void *buffer)
> +				     const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	int ret;
>  
> +	if (size < HDMI_INFOFRAME_SIZE(AVI))
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
>  	    ptr[1] != 2 ||
>  	    ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
> @@ -1068,8 +1072,9 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
>  
>  /**
>   * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
> - * @buffer: source buffer
>   * @frame: HDMI SPD infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Source Product Description (SPD) information frame.
> @@ -1079,11 +1084,14 @@ static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
> -				     const void *buffer)
> +				     const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	int ret;
>  
> +	if (size < HDMI_INFOFRAME_SIZE(SPD))
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
>  	    ptr[1] != 1 ||
>  	    ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
> @@ -1106,8 +1114,9 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
>  
>  /**
>   * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
> - * @buffer: source buffer
>   * @frame: HDMI Audio infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Audio information frame.
> @@ -1117,11 +1126,14 @@ static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
> -				       const void *buffer)
> +				       const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	int ret;
>  
> +	if (size < HDMI_INFOFRAME_SIZE(AUDIO))
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
>  	    ptr[1] != 1 ||
>  	    ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
> @@ -1151,8 +1163,9 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
>  
>  /**
>   * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
> - * @buffer: source buffer
>   * @frame: HDMI Vendor infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary @buffer into a structured
>   * @frame of the HDMI Vendor information frame.
> @@ -1163,7 +1176,7 @@ static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
>   */
>  static int
>  hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
> -				 const void *buffer)
> +				 const void *buffer, size_t size)
>  {
>  	const u8 *ptr = buffer;
>  	size_t length;
> @@ -1171,6 +1184,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  	u8 hdmi_video_format;
>  	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
>  
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> +		return -EINVAL;
> +
>  	if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
>  	    ptr[1] != 1 ||
>  	    (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
> @@ -1178,6 +1194,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  
>  	length = ptr[2];
>  
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
> +		return -EINVAL;
> +
>  	if (hdmi_infoframe_checksum(buffer,
>  				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
>  		return -EINVAL;
> @@ -1224,8 +1243,9 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  
>  /**
>   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
> - * @buffer: source buffer
>   * @frame: HDMI infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
>   *
>   * Unpacks the information contained in binary buffer @buffer into a structured
>   * @frame of a HDMI infoframe.
> @@ -1235,23 +1255,26 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>   * Returns 0 on success or a negative error code on failure.
>   */
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> -			  const void *buffer)
> +			  const void *buffer, size_t size)
>  {
>  	int ret;
>  	const u8 *ptr = buffer;
>  
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> +		return -EINVAL;
> +
>  	switch (ptr[0]) {
>  	case HDMI_INFOFRAME_TYPE_AVI:
> -		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
> +		ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
>  		break;
>  	case HDMI_INFOFRAME_TYPE_SPD:
> -		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
> +		ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
>  		break;
>  	case HDMI_INFOFRAME_TYPE_AUDIO:
> -		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
> +		ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
>  		break;
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
> -		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
> +		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
>  		break;
>  	default:
>  		ret = -EINVAL;
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index d3816170c062..a577d4ae2570 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -333,7 +333,7 @@ union hdmi_infoframe {
>  ssize_t
>  hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> -			  const void *buffer);
> +			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
>  			union hdmi_infoframe *frame);
>  
> 

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21  8:06     ` Hans Verkuil
  -1 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:06 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The log functions don't modify the passed in infoframe so make it const.
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Thanks,

	Hans


> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 22 +++++++++++-----------
>  include/linux/hdmi.h |  2 +-
>  2 files changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index b5d491014b0b..53e7ee2c83fc 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -471,7 +471,7 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
>  
>  static void hdmi_infoframe_log_header(const char *level,
>  				      struct device *dev,
> -				      struct hdmi_any_infoframe *frame)
> +				      const struct hdmi_any_infoframe *frame)
>  {
>  	hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
>  		hdmi_infoframe_type_get_name(frame->type),
> @@ -673,10 +673,10 @@ hdmi_content_type_get_name(enum hdmi_content_type content_type)
>   */
>  static void hdmi_avi_infoframe_log(const char *level,
>  				   struct device *dev,
> -				   struct hdmi_avi_infoframe *frame)
> +				   const struct hdmi_avi_infoframe *frame)
>  {
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	hdmi_log("    colorspace: %s\n",
>  			hdmi_colorspace_get_name(frame->colorspace));
> @@ -750,12 +750,12 @@ static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
>   */
>  static void hdmi_spd_infoframe_log(const char *level,
>  				   struct device *dev,
> -				   struct hdmi_spd_infoframe *frame)
> +				   const struct hdmi_spd_infoframe *frame)
>  {
>  	u8 buf[17];
>  
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	memset(buf, 0, sizeof(buf));
>  
> @@ -886,10 +886,10 @@ hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
>   */
>  static void hdmi_audio_infoframe_log(const char *level,
>  				     struct device *dev,
> -				     struct hdmi_audio_infoframe *frame)
> +				     const struct hdmi_audio_infoframe *frame)
>  {
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	if (frame->channels)
>  		hdmi_log("    channels: %u\n", frame->channels - 1);
> @@ -949,12 +949,12 @@ hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
>  static void
>  hdmi_vendor_any_infoframe_log(const char *level,
>  			      struct device *dev,
> -			      union hdmi_vendor_any_infoframe *frame)
> +			      const union hdmi_vendor_any_infoframe *frame)
>  {
> -	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
> +	const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
>  
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	if (frame->any.oui != HDMI_IEEE_OUI) {
>  		hdmi_log("    not a HDMI vendor infoframe\n");
> @@ -984,7 +984,7 @@ hdmi_vendor_any_infoframe_log(const char *level,
>   */
>  void hdmi_infoframe_log(const char *level,
>  			struct device *dev,
> -			union hdmi_infoframe *frame)
> +			const union hdmi_infoframe *frame)
>  {
>  	switch (frame->any.type) {
>  	case HDMI_INFOFRAME_TYPE_AVI:
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index a577d4ae2570..bce1abb1fe57 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -335,6 +335,6 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
> -			union hdmi_infoframe *frame);
> +			const union hdmi_infoframe *frame);
>  
>  #endif /* _DRM_HDMI_H */
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions
@ 2018-09-21  8:06     ` Hans Verkuil
  0 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:06 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The log functions don't modify the passed in infoframe so make it const.
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Thanks,

	Hans


> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 22 +++++++++++-----------
>  include/linux/hdmi.h |  2 +-
>  2 files changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index b5d491014b0b..53e7ee2c83fc 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -471,7 +471,7 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
>  
>  static void hdmi_infoframe_log_header(const char *level,
>  				      struct device *dev,
> -				      struct hdmi_any_infoframe *frame)
> +				      const struct hdmi_any_infoframe *frame)
>  {
>  	hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
>  		hdmi_infoframe_type_get_name(frame->type),
> @@ -673,10 +673,10 @@ hdmi_content_type_get_name(enum hdmi_content_type content_type)
>   */
>  static void hdmi_avi_infoframe_log(const char *level,
>  				   struct device *dev,
> -				   struct hdmi_avi_infoframe *frame)
> +				   const struct hdmi_avi_infoframe *frame)
>  {
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	hdmi_log("    colorspace: %s\n",
>  			hdmi_colorspace_get_name(frame->colorspace));
> @@ -750,12 +750,12 @@ static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
>   */
>  static void hdmi_spd_infoframe_log(const char *level,
>  				   struct device *dev,
> -				   struct hdmi_spd_infoframe *frame)
> +				   const struct hdmi_spd_infoframe *frame)
>  {
>  	u8 buf[17];
>  
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	memset(buf, 0, sizeof(buf));
>  
> @@ -886,10 +886,10 @@ hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
>   */
>  static void hdmi_audio_infoframe_log(const char *level,
>  				     struct device *dev,
> -				     struct hdmi_audio_infoframe *frame)
> +				     const struct hdmi_audio_infoframe *frame)
>  {
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	if (frame->channels)
>  		hdmi_log("    channels: %u\n", frame->channels - 1);
> @@ -949,12 +949,12 @@ hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
>  static void
>  hdmi_vendor_any_infoframe_log(const char *level,
>  			      struct device *dev,
> -			      union hdmi_vendor_any_infoframe *frame)
> +			      const union hdmi_vendor_any_infoframe *frame)
>  {
> -	struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
> +	const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
>  
>  	hdmi_infoframe_log_header(level, dev,
> -				  (struct hdmi_any_infoframe *)frame);
> +				  (const struct hdmi_any_infoframe *)frame);
>  
>  	if (frame->any.oui != HDMI_IEEE_OUI) {
>  		hdmi_log("    not a HDMI vendor infoframe\n");
> @@ -984,7 +984,7 @@ hdmi_vendor_any_infoframe_log(const char *level,
>   */
>  void hdmi_infoframe_log(const char *level,
>  			struct device *dev,
> -			union hdmi_infoframe *frame)
> +			const union hdmi_infoframe *frame)
>  {
>  	switch (frame->any.type) {
>  	case HDMI_INFOFRAME_TYPE_AVI:
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index a577d4ae2570..bce1abb1fe57 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -335,6 +335,6 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
> -			union hdmi_infoframe *frame);
> +			const union hdmi_infoframe *frame);
>  
>  #endif /* _DRM_HDMI_H */
> 

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21  8:24     ` Hans Verkuil
  -1 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:24 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Let's make the infoframe pack functions usable with a const infoframe
> structure. This allows us to precompute the infoframe earlier, and still
> pack it later when we're no longer allowed to modify the structure.
> So now we end up with a _check()+_pack_only() or _pack() functions
> depending on whether you want to precompute the infoframes or not.
> The names aren't greate but I was lazy and didn't want to change all the

greate -> great

> drivers.
> 
> v2: Deal with exynos churn
>     Actually export the new funcs
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
>  include/linux/hdmi.h |  19 ++-
>  2 files changed, 416 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 53e7ee2c83fc..9507f668a569 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>  
> +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
> +	    frame->version != 2 ||
> +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
> + * hdmi_avi_infoframe_check() - Check and check a HDMI AVI infoframe

"Check and check"? This is repeated elsewhere as well (clearly copy-and-paste).

> + * @frame: HDMI AVI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
> +{
> +	return hdmi_avi_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
> +
> +/**
> + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
>   * @frame: HDMI AVI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
>  	if (size < length)
>  		return -ENOSPC;
>  
> -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> -		return -EINVAL;
> -
>  	memset(buffer, 0, size);
>  
>  	ptr[0] = frame->type;
> @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
> +
> +/**
> + * hdmi_avi_infoframe_pack() - Check and check a HDMI AVI infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI AVI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information

which packs -> which it packs

Ditto elsewhere.

> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also

Also -> This function also

Ditto elsewhere.

> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
>  
>  /**
> @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  }
>  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>  
> +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
> + * hdmi_spd_infoframe_check() - Check and check a HDMI SPD infoframe
> + * @frame: HDMI SPD infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
> +{
> +	return hdmi_spd_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
> +
> +/**
> + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
>   * @frame: HDMI SPD infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
> +
> +/**
> + * hdmi_spd_infoframe_pack() - Check and check a HDMI SPD infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI SPD infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
>  
>  /**
> @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>  
> +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_audio_infoframe_check() - Check and check a HDMI audio infoframe
> + * @frame: HDMI audio infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
> +{
> +	return hdmi_audio_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
> +
>  /**
> - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
> + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
>   * @frame: HDMI audio infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> -				  void *buffer, size_t size)
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size)
>  {
>  	unsigned char channels;
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
> +
> +/**
> + * hdmi_audio_infoframe_pack() - Check and check a HDMI Audio infoframe,
> + *                               and write it to binary buffer
> + * @frame: HDMI Audio infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> +				  void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
>  
>  /**
> @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
>  	 * value
>  	 */
>  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
> +	frame->length = 4;
>  
>  	return 0;
>  }
> @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>  		return 4;
>  }
>  
> +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->version != 1 ||
> +	    frame->oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	/* only one of those can be supplied */
> +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> +		return -EINVAL;
> +
> +	if (frame->length != hdmi_vendor_infoframe_length(frame))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
> + * hdmi_vendor_infoframe_check() - Check and check a HDMI vendor infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
> +{
> +	frame->length = hdmi_vendor_infoframe_length(frame);
> +
> +	return hdmi_vendor_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
> +
> +/**
> + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> -				 void *buffer, size_t size)
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
>  
> -	/* only one of those can be supplied */
> -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> -		return -EINVAL;
> -
> -	frame->length = hdmi_vendor_infoframe_length(frame);
> +	ret = hdmi_vendor_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
> +
> +/**
> + * hdmi_vendor_infoframe_pack() - Check and check a HDMI Vendor infoframe,
> + *                                and write it to binary buffer
> + * @frame: HDMI Vendor infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> +				   void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
>  
> +static int
> +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
> +{
> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->any.version != 1)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
> - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
> + * hdmi_vendor_any_infoframe_check() - check and check a vendor infoframe
> + */
> +static int
> +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	/* we only know about HDMI vendor infoframes */
> +	if (frame->any.oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	return hdmi_vendor_infoframe_check(&frame->hdmi);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
>   */
>  static ssize_t
> -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> -			   void *buffer, size_t size)
> +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
> +				    void *buffer, size_t size)
>  {
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
>  	/* we only know about HDMI vendor infoframes */
>  	if (frame->any.oui != HDMI_IEEE_OUI)
>  		return -EINVAL;
>  
> -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
> +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack() - check and check a vendor infoframe,
> + *                                              and write it to binary buffer
> + */
> +static ssize_t
> +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> +			       void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> +}
> +
> +/**
> + * hdmi_infoframe_check() - Check check a HDMI infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int
> +hdmi_infoframe_check(union hdmi_infoframe *frame)
> +{
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		return hdmi_avi_infoframe_check(&frame->avi);
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		return hdmi_spd_infoframe_check(&frame->spd);
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		return hdmi_audio_infoframe_check(&frame->audio);
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		return -EINVAL;
> +	}
>  }
> +EXPORT_SYMBOL(hdmi_infoframe_check);
>  
>  /**
> - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
> + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>   * error code on failure.
>   */
>  ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
> +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
> +{
> +	ssize_t length;
> +
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
> +							buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> +							     buffer, size);
> +		break;
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		length = -EINVAL;
> +	}
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
> +
> +/**
> + * hdmi_infoframe_pack() - Check check a HDMI infoframe,

Check check?

> + *                         and write it to binary buffer
> + * @frame: HDMI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t
> +hdmi_infoframe_pack(union hdmi_infoframe *frame,
> +		    void *buffer, size_t size)
>  {
>  	ssize_t length;
>  
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index bce1abb1fe57..c76b50a48e48 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
>  int 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);
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
>  
>  enum hdmi_spd_sdi {
>  	HDMI_SPD_SDI_UNKNOWN,
> @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  			    const char *vendor, const char *product);
>  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  				size_t size);
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
>  
>  enum hdmi_audio_coding_type {
>  	HDMI_AUDIO_CODING_TYPE_STREAM,
> @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
>  int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
>  ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  				  void *buffer, size_t size);
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size);
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
>  
>  enum hdmi_3d_structure {
>  	HDMI_3D_STRUCTURE_INVALID = -1,
> @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
>  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
>  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  				   void *buffer, size_t size);
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size);
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
>  
>  union hdmi_vendor_any_infoframe {
>  	struct {
> @@ -330,8 +342,11 @@ union hdmi_infoframe {
>  	struct hdmi_audio_infoframe audio;
>  };
>  
> -ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> +			    size_t size);
> +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
> +				 void *buffer, size_t size);
> +int hdmi_infoframe_check(union hdmi_infoframe *frame);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
> 

Regards,

	Hans

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions
@ 2018-09-21  8:24     ` Hans Verkuil
  0 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:24 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Let's make the infoframe pack functions usable with a const infoframe
> structure. This allows us to precompute the infoframe earlier, and still
> pack it later when we're no longer allowed to modify the structure.
> So now we end up with a _check()+_pack_only() or _pack() functions
> depending on whether you want to precompute the infoframes or not.
> The names aren't greate but I was lazy and didn't want to change all the

greate -> great

> drivers.
> 
> v2: Deal with exynos churn
>     Actually export the new funcs
> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
>  include/linux/hdmi.h |  19 ++-
>  2 files changed, 416 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 53e7ee2c83fc..9507f668a569 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>  
> +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
> +	    frame->version != 2 ||
> +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
> + * hdmi_avi_infoframe_check() - Check and check a HDMI AVI infoframe

"Check and check"? This is repeated elsewhere as well (clearly copy-and-paste).

> + * @frame: HDMI AVI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
> +{
> +	return hdmi_avi_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
> +
> +/**
> + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
>   * @frame: HDMI AVI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
>  	if (size < length)
>  		return -ENOSPC;
>  
> -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> -		return -EINVAL;
> -
>  	memset(buffer, 0, size);
>  
>  	ptr[0] = frame->type;
> @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
> +
> +/**
> + * hdmi_avi_infoframe_pack() - Check and check a HDMI AVI infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI AVI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information

which packs -> which it packs

Ditto elsewhere.

> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also

Also -> This function also

Ditto elsewhere.

> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
>  
>  /**
> @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  }
>  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>  
> +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
> + * hdmi_spd_infoframe_check() - Check and check a HDMI SPD infoframe
> + * @frame: HDMI SPD infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
> +{
> +	return hdmi_spd_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
> +
> +/**
> + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
>   * @frame: HDMI SPD infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
> +
> +/**
> + * hdmi_spd_infoframe_pack() - Check and check a HDMI SPD infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI SPD infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
>  
>  /**
> @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>  
> +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_audio_infoframe_check() - Check and check a HDMI audio infoframe
> + * @frame: HDMI audio infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
> +{
> +	return hdmi_audio_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
> +
>  /**
> - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
> + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
>   * @frame: HDMI audio infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> -				  void *buffer, size_t size)
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size)
>  {
>  	unsigned char channels;
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
> +
> +/**
> + * hdmi_audio_infoframe_pack() - Check and check a HDMI Audio infoframe,
> + *                               and write it to binary buffer
> + * @frame: HDMI Audio infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> +				  void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
>  
>  /**
> @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
>  	 * value
>  	 */
>  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
> +	frame->length = 4;
>  
>  	return 0;
>  }
> @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>  		return 4;
>  }
>  
> +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->version != 1 ||
> +	    frame->oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	/* only one of those can be supplied */
> +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> +		return -EINVAL;
> +
> +	if (frame->length != hdmi_vendor_infoframe_length(frame))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
> + * hdmi_vendor_infoframe_check() - Check and check a HDMI vendor infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
> +{
> +	frame->length = hdmi_vendor_infoframe_length(frame);
> +
> +	return hdmi_vendor_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
> +
> +/**
> + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> -				 void *buffer, size_t size)
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
>  
> -	/* only one of those can be supplied */
> -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> -		return -EINVAL;
> -
> -	frame->length = hdmi_vendor_infoframe_length(frame);
> +	ret = hdmi_vendor_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
> +
> +/**
> + * hdmi_vendor_infoframe_pack() - Check and check a HDMI Vendor infoframe,
> + *                                and write it to binary buffer
> + * @frame: HDMI Vendor infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> +				   void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
>  
> +static int
> +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
> +{
> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->any.version != 1)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
> - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
> + * hdmi_vendor_any_infoframe_check() - check and check a vendor infoframe
> + */
> +static int
> +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	/* we only know about HDMI vendor infoframes */
> +	if (frame->any.oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	return hdmi_vendor_infoframe_check(&frame->hdmi);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
>   */
>  static ssize_t
> -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> -			   void *buffer, size_t size)
> +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
> +				    void *buffer, size_t size)
>  {
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
>  	/* we only know about HDMI vendor infoframes */
>  	if (frame->any.oui != HDMI_IEEE_OUI)
>  		return -EINVAL;
>  
> -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
> +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack() - check and check a vendor infoframe,
> + *                                              and write it to binary buffer
> + */
> +static ssize_t
> +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> +			       void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> +}
> +
> +/**
> + * hdmi_infoframe_check() - Check check a HDMI infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int
> +hdmi_infoframe_check(union hdmi_infoframe *frame)
> +{
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		return hdmi_avi_infoframe_check(&frame->avi);
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		return hdmi_spd_infoframe_check(&frame->spd);
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		return hdmi_audio_infoframe_check(&frame->audio);
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		return -EINVAL;
> +	}
>  }
> +EXPORT_SYMBOL(hdmi_infoframe_check);
>  
>  /**
> - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
> + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>   * error code on failure.
>   */
>  ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
> +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
> +{
> +	ssize_t length;
> +
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
> +							buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> +							     buffer, size);
> +		break;
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		length = -EINVAL;
> +	}
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
> +
> +/**
> + * hdmi_infoframe_pack() - Check check a HDMI infoframe,

Check check?

> + *                         and write it to binary buffer
> + * @frame: HDMI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t
> +hdmi_infoframe_pack(union hdmi_infoframe *frame,
> +		    void *buffer, size_t size)
>  {
>  	ssize_t length;
>  
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index bce1abb1fe57..c76b50a48e48 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
>  int 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);
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
>  
>  enum hdmi_spd_sdi {
>  	HDMI_SPD_SDI_UNKNOWN,
> @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  			    const char *vendor, const char *product);
>  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  				size_t size);
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
>  
>  enum hdmi_audio_coding_type {
>  	HDMI_AUDIO_CODING_TYPE_STREAM,
> @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
>  int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
>  ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  				  void *buffer, size_t size);
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size);
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
>  
>  enum hdmi_3d_structure {
>  	HDMI_3D_STRUCTURE_INVALID = -1,
> @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
>  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
>  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  				   void *buffer, size_t size);
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size);
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
>  
>  union hdmi_vendor_any_infoframe {
>  	struct {
> @@ -330,8 +342,11 @@ union hdmi_infoframe {
>  	struct hdmi_audio_infoframe audio;
>  };
>  
> -ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> +			    size_t size);
> +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
> +				 void *buffer, size_t size);
> +int hdmi_infoframe_check(union hdmi_infoframe *frame);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
> 

Regards,

	Hans
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21  8:28     ` Hans Verkuil
  -1 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:28 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Add the code to deal with the MPEG source infoframe.
> 
> Blindly typed from the spec, and totally untested.

I'm not sure this patch should be added at all. The CTA-861-G spec (section 6.7)
says that the implementation of this infoframe is not recommended due to unresolved
issues.

I don't think I've ever seen it either.

It obviously doesn't hurt to have this code, but I prefer to wait until there
are devices that actively set/use this infoframe.

Regards,

	Hans

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/hdmi.h |  27 ++++++
>  2 files changed, 256 insertions(+)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 9507f668a569..3d24c7746c51 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>  	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
>  }
>  
> +/**
> + * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	memset(frame, 0, sizeof(*frame));
> +
> +	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
> +	frame->version = 1;
> +	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
> +
> +static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_mpeg_source_infoframe_check() - Check and check a HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	return hdmi_mpeg_source_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
> +
> +/**
> + * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Packs the information contained in the @frame structure into a binary
> + * representation that can be written into the corresponding controller
> + * registers. Also computes the checksum as required by section 5.3.5 of
> + * the HDMI 1.4 specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> +					     void *buffer, size_t size)
> +{
> +	u8 *ptr = buffer;
> +	size_t length;
> +	int ret;
> +
> +	ret = hdmi_mpeg_source_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> +
> +	if (size < length)
> +		return -ENOSPC;
> +
> +	memset(buffer, 0, size);
> +
> +	ptr[0] = frame->type;
> +	ptr[1] = frame->version;
> +	ptr[2] = frame->length;
> +	ptr[3] = 0; /* checksum */
> +
> +	/* start infoframe payload */
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	ptr[0] = frame->mpeg_bit_rate >> 0;
> +	ptr[1] = frame->mpeg_bit_rate >> 8;
> +	ptr[2] = frame->mpeg_bit_rate >> 16;
> +	ptr[3] = frame->mpeg_bit_rate >> 24;
> +	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
> +
> +	hdmi_infoframe_set_checksum(buffer, length);
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
> +
> +/**
> + * hdmi_mpeg_source_infoframe_pack() - Check and check a HDMI MPEG Source infoframe,
> + *                                     and write it to binary buffer
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> +					void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_mpeg_source_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
> +
>  /**
>   * hdmi_infoframe_check() - Check check a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
>  		return hdmi_audio_infoframe_check(&frame->audio);
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
>  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		return -EINVAL;
> @@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
>  		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
>  							     buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
> +							      buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
>  		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
>  							buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
> +							 buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -838,6 +973,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
>  		return "Source Product Description (SPD)";
>  	case HDMI_INFOFRAME_TYPE_AUDIO:
>  		return "Audio";
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		return "MPEG Source";
>  	}
>  	return "Reserved";
>  }
> @@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
>  	}
>  }
>  
> +static const char *
> +hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
> +{
> +	if (frame < 0 || frame > 3)
> +		return "invalid";
> +
> +	switch (frame) {
> +	case HDMI_MPEG_FRAME_UNKNOWN:
> +		return "Unknown";
> +	case HDMI_MPEG_FRAME_I_PICTURE:
> +		return "I Picture";
> +	case HDMI_MPEG_FRAME_B_PICTURE:
> +		return "B Picture";
> +	case HDMI_MPEG_FRAME_P_PICTURE:
> +		return "P Picture";
> +	}
> +	return "Reserved";
> +}
> +
> +/**
> + * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
> + * @level: logging level
> + * @dev: device
> + * @frame: HDMI MPEG Source infoframe
> + */
> +static void hdmi_mpeg_source_infoframe_log(const char *level,
> +					   struct device *dev,
> +					   const struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	hdmi_infoframe_log_header(level, dev,
> +				  (const struct hdmi_any_infoframe *)frame);
> +
> +	hdmi_log("    MPEG bit rate: %d Hz\n",
> +		 frame->mpeg_bit_rate);
> +	hdmi_log("    MPEG frame: %s\n",
> +		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
> +	hdmi_log("    field repeat: %s\n",
> +		 frame->field_repeat ? "Yes" : "No");
> +}
> +
>  /**
>   * hdmi_infoframe_log() - log info of HDMI infoframe
>   * @level: logging level
> @@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
>  		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
> +		break;
>  	}
>  }
>  EXPORT_SYMBOL(hdmi_infoframe_log);
> @@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  	return 0;
>  }
>  
> +/**
> + * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
> + *
> + * Unpacks the information contained in binary @buffer into a structured
> + * @frame of the HDMI MPEG Source information frame.
> + * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
> +					     const void *buffer, size_t size)
> +{
> +	const u8 *ptr = buffer;
> +	int ret;
> +
> +	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
> +		return -EINVAL;
> +
> +	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> +	    ptr[1] != 1 ||
> +	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
> +		return -EINVAL;
> +	}
> +
> +	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
> +		return -EINVAL;
> +
> +	ret = hdmi_mpeg_source_infoframe_init(frame);
> +	if (ret)
> +		return ret;
> +
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	frame->mpeg_bit_rate =
> +		(ptr[0] << 0) | (ptr[1] << 8) |
> +		(ptr[2] << 16) | (ptr[3] << 24);
> +	frame->mpeg_frame = ptr[4] & 0x3;
> +	frame->field_repeat = ptr[4] & 0x10;
> +
> +	return 0;
> +}
> +
>  /**
>   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
>  		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  		break;
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index 80521d9591a1..2c9322f7538d 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
>  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
>  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
> +	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
>  };
>  
>  #define HDMI_IEEE_OUI 0x000c03
> @@ -55,6 +56,7 @@ enum hdmi_infoframe_type {
>  #define HDMI_AVI_INFOFRAME_SIZE    13
>  #define HDMI_SPD_INFOFRAME_SIZE    25
>  #define HDMI_AUDIO_INFOFRAME_SIZE  10
> +#define HDMI_MPEG_SOURCE_INFOFRAME_SIZE  10
>  
>  #define HDMI_INFOFRAME_SIZE(type)	\
>  	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
> @@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
>  	struct hdmi_vendor_infoframe hdmi;
>  };
>  
> +enum hdmi_mpeg_frame {
> +	HDMI_MPEG_FRAME_UNKNOWN,
> +	HDMI_MPEG_FRAME_I_PICTURE,
> +	HDMI_MPEG_FRAME_B_PICTURE,
> +	HDMI_MPEG_FRAME_P_PICTURE,
> +};
> +
> +struct hdmi_mpeg_source_infoframe {
> +	enum hdmi_infoframe_type type;
> +	unsigned char version;
> +	unsigned char length;
> +	unsigned int mpeg_bit_rate;
> +	enum hdmi_mpeg_frame mpeg_frame;
> +	bool field_repeat;
> +};
> +
> +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
> +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> +					void *buffer, size_t size);
> +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> +					     void *buffer, size_t size);
> +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> +
>  /**
>   * union hdmi_infoframe - overall union of all abstract infoframe representations
>   * @any: generic infoframe
> @@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
>   * @spd: spd infoframe
>   * @vendor: union of all vendor infoframes
>   * @audio: audio infoframe
> + * @mpeg_source: mpeg source infoframe
>   *
>   * This is used by the generic pack function. This works since all infoframes
>   * have the same header which also indicates which type of infoframe should be
> @@ -355,6 +381,7 @@ union hdmi_infoframe {
>  	struct hdmi_spd_infoframe spd;
>  	union hdmi_vendor_any_infoframe vendor;
>  	struct hdmi_audio_infoframe audio;
> +	struct hdmi_mpeg_source_infoframe mpeg_source;
>  };
>  
>  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe
@ 2018-09-21  8:28     ` Hans Verkuil
  0 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:28 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Add the code to deal with the MPEG source infoframe.
> 
> Blindly typed from the spec, and totally untested.

I'm not sure this patch should be added at all. The CTA-861-G spec (section 6.7)
says that the implementation of this infoframe is not recommended due to unresolved
issues.

I don't think I've ever seen it either.

It obviously doesn't hurt to have this code, but I prefer to wait until there
are devices that actively set/use this infoframe.

Regards,

	Hans

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/hdmi.h |  27 ++++++
>  2 files changed, 256 insertions(+)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 9507f668a569..3d24c7746c51 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>  	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
>  }
>  
> +/**
> + * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	memset(frame, 0, sizeof(*frame));
> +
> +	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
> +	frame->version = 1;
> +	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
> +
> +static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_mpeg_source_infoframe_check() - Check and check a HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	return hdmi_mpeg_source_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
> +
> +/**
> + * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Packs the information contained in the @frame structure into a binary
> + * representation that can be written into the corresponding controller
> + * registers. Also computes the checksum as required by section 5.3.5 of
> + * the HDMI 1.4 specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> +					     void *buffer, size_t size)
> +{
> +	u8 *ptr = buffer;
> +	size_t length;
> +	int ret;
> +
> +	ret = hdmi_mpeg_source_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> +
> +	if (size < length)
> +		return -ENOSPC;
> +
> +	memset(buffer, 0, size);
> +
> +	ptr[0] = frame->type;
> +	ptr[1] = frame->version;
> +	ptr[2] = frame->length;
> +	ptr[3] = 0; /* checksum */
> +
> +	/* start infoframe payload */
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	ptr[0] = frame->mpeg_bit_rate >> 0;
> +	ptr[1] = frame->mpeg_bit_rate >> 8;
> +	ptr[2] = frame->mpeg_bit_rate >> 16;
> +	ptr[3] = frame->mpeg_bit_rate >> 24;
> +	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
> +
> +	hdmi_infoframe_set_checksum(buffer, length);
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
> +
> +/**
> + * hdmi_mpeg_source_infoframe_pack() - Check and check a HDMI MPEG Source infoframe,
> + *                                     and write it to binary buffer
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> +					void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_mpeg_source_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
> +}
> +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
> +
>  /**
>   * hdmi_infoframe_check() - Check check a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
>  		return hdmi_audio_infoframe_check(&frame->audio);
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
>  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		return -EINVAL;
> @@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
>  		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
>  							     buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
> +							      buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
>  		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
>  							buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
> +							 buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -838,6 +973,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
>  		return "Source Product Description (SPD)";
>  	case HDMI_INFOFRAME_TYPE_AUDIO:
>  		return "Audio";
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		return "MPEG Source";
>  	}
>  	return "Reserved";
>  }
> @@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
>  	}
>  }
>  
> +static const char *
> +hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
> +{
> +	if (frame < 0 || frame > 3)
> +		return "invalid";
> +
> +	switch (frame) {
> +	case HDMI_MPEG_FRAME_UNKNOWN:
> +		return "Unknown";
> +	case HDMI_MPEG_FRAME_I_PICTURE:
> +		return "I Picture";
> +	case HDMI_MPEG_FRAME_B_PICTURE:
> +		return "B Picture";
> +	case HDMI_MPEG_FRAME_P_PICTURE:
> +		return "P Picture";
> +	}
> +	return "Reserved";
> +}
> +
> +/**
> + * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
> + * @level: logging level
> + * @dev: device
> + * @frame: HDMI MPEG Source infoframe
> + */
> +static void hdmi_mpeg_source_infoframe_log(const char *level,
> +					   struct device *dev,
> +					   const struct hdmi_mpeg_source_infoframe *frame)
> +{
> +	hdmi_infoframe_log_header(level, dev,
> +				  (const struct hdmi_any_infoframe *)frame);
> +
> +	hdmi_log("    MPEG bit rate: %d Hz\n",
> +		 frame->mpeg_bit_rate);
> +	hdmi_log("    MPEG frame: %s\n",
> +		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
> +	hdmi_log("    field repeat: %s\n",
> +		 frame->field_repeat ? "Yes" : "No");
> +}
> +
>  /**
>   * hdmi_infoframe_log() - log info of HDMI infoframe
>   * @level: logging level
> @@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
>  		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
> +		break;
>  	}
>  }
>  EXPORT_SYMBOL(hdmi_infoframe_log);
> @@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
>  	return 0;
>  }
>  
> +/**
> + * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
> + *
> + * Unpacks the information contained in binary @buffer into a structured
> + * @frame of the HDMI MPEG Source information frame.
> + * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
> +					     const void *buffer, size_t size)
> +{
> +	const u8 *ptr = buffer;
> +	int ret;
> +
> +	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
> +		return -EINVAL;
> +
> +	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> +	    ptr[1] != 1 ||
> +	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
> +		return -EINVAL;
> +	}
> +
> +	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
> +		return -EINVAL;
> +
> +	ret = hdmi_mpeg_source_infoframe_init(frame);
> +	if (ret)
> +		return ret;
> +
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	frame->mpeg_bit_rate =
> +		(ptr[0] << 0) | (ptr[1] << 8) |
> +		(ptr[2] << 16) | (ptr[3] << 24);
> +	frame->mpeg_frame = ptr[4] & 0x3;
> +	frame->field_repeat = ptr[4] & 0x10;
> +
> +	return 0;
> +}
> +
>  /**
>   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  	case HDMI_INFOFRAME_TYPE_VENDOR:
>  		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> +		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  		break;
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index 80521d9591a1..2c9322f7538d 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
>  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
>  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
> +	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
>  };
>  
>  #define HDMI_IEEE_OUI 0x000c03
> @@ -55,6 +56,7 @@ enum hdmi_infoframe_type {
>  #define HDMI_AVI_INFOFRAME_SIZE    13
>  #define HDMI_SPD_INFOFRAME_SIZE    25
>  #define HDMI_AUDIO_INFOFRAME_SIZE  10
> +#define HDMI_MPEG_SOURCE_INFOFRAME_SIZE  10
>  
>  #define HDMI_INFOFRAME_SIZE(type)	\
>  	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
> @@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
>  	struct hdmi_vendor_infoframe hdmi;
>  };
>  
> +enum hdmi_mpeg_frame {
> +	HDMI_MPEG_FRAME_UNKNOWN,
> +	HDMI_MPEG_FRAME_I_PICTURE,
> +	HDMI_MPEG_FRAME_B_PICTURE,
> +	HDMI_MPEG_FRAME_P_PICTURE,
> +};
> +
> +struct hdmi_mpeg_source_infoframe {
> +	enum hdmi_infoframe_type type;
> +	unsigned char version;
> +	unsigned char length;
> +	unsigned int mpeg_bit_rate;
> +	enum hdmi_mpeg_frame mpeg_frame;
> +	bool field_repeat;
> +};
> +
> +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
> +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> +					void *buffer, size_t size);
> +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> +					     void *buffer, size_t size);
> +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> +
>  /**
>   * union hdmi_infoframe - overall union of all abstract infoframe representations
>   * @any: generic infoframe
> @@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
>   * @spd: spd infoframe
>   * @vendor: union of all vendor infoframes
>   * @audio: audio infoframe
> + * @mpeg_source: mpeg source infoframe
>   *
>   * This is used by the generic pack function. This works since all infoframes
>   * have the same header which also indicates which type of infoframe should be
> @@ -355,6 +381,7 @@ union hdmi_infoframe {
>  	struct hdmi_spd_infoframe spd;
>  	union hdmi_vendor_any_infoframe vendor;
>  	struct hdmi_audio_infoframe audio;
> +	struct hdmi_mpeg_source_infoframe mpeg_source;
>  };
>  
>  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21  8:30     ` Hans Verkuil
  -1 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:30 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Add the code to deal with the NTSC VBI infoframe.
> 
> I decided against parsing the PES_data_field and just leave
> it as an opaque blob, just dumping it out as hex in the log.
> 
> Blindly typed from the spec, and totally untested.

Do we have any driver that uses this? I would prefer to wait until someone
actually need this.

Regards,

	Hans

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/hdmi.h |  18 +++++
>  2 files changed, 226 insertions(+)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 3d24c7746c51..3c320d69fa0a 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
>  }
>  EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
>  
> +/**
> + * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
> + * @frame: HDMI NTSC VBI infoframe
> + * @pes_data_field: ANSI/SCTE 127 PES_data_field
> + * @length: ANSI/SCTE 127 PES_data_field length
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> +				 const void *pes_data_field,
> +				 size_t length)
> +{
> +	if (length < 1 || length > 27)
> +		return -EINVAL;
> +
> +	memset(frame, 0, sizeof(*frame));
> +
> +	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
> +	frame->version = 1;
> +	frame->length = length;
> +
> +	memcpy(frame->pes_data_field, pes_data_field, length);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
> +
> +static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> +	    frame->version != 1 ||
> +	    frame->length < 1 || frame->length > 27)
> +		return -EINVAL;
> +
> +	if (frame->pes_data_field[0] != 0x99)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
> + * @frame: HDMI NTSC VBI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
> +{
> +	return hdmi_ntsc_vbi_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
> +
> +/**
> + * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI infoframe to binary buffer
> + * @frame: HDMI NTSC VBI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Packs the information contained in the @frame structure into a binary
> + * representation that can be written into the corresponding controller
> + * registers. Also computes the checksum as required by section 5.3.5 of
> + * the HDMI 1.4 specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> +					  void *buffer, size_t size)
> +{
> +	u8 *ptr = buffer;
> +	size_t length;
> +	int ret;
> +
> +	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> +
> +	if (size < length)
> +		return -ENOSPC;
> +
> +	memset(buffer, 0, size);
> +
> +	ptr[0] = frame->type;
> +	ptr[1] = frame->version;
> +	ptr[2] = frame->length;
> +	ptr[3] = 0; /* checksum */
> +
> +	/* start infoframe payload */
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	memcpy(ptr, frame->pes_data_field, frame->length);
> +
> +	hdmi_infoframe_set_checksum(buffer, length);
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
> +
> +/**
> + * hdmi_ntsc_vbi_infoframe_pack() - Check and check a HDMI NTSC VBI infoframe,
> + *                                  and write it to binary buffer
> + * @frame: HDMI NTSC VBI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> +				     void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_ntsc_vbi_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
> +
>  /**
>   * hdmi_infoframe_check() - Check check a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
>  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		return -EINVAL;
> @@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
>  		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
>  							      buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
> +							   buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
>  		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
>  							 buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
> +						      buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
>  		return "Audio";
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		return "MPEG Source";
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		return "NTSC VBI";
>  	}
>  	return "Reserved";
>  }
> @@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
>  		 frame->field_repeat ? "Yes" : "No");
>  }
>  
> +/**
> + * hdmi_ntsc_vbi_infoframe_log() - log info of HDMI NTSC VBI infoframe
> + * @level: logging level
> + * @dev: device
> + * @frame: HDMI NTSC VBI infoframe
> + */
> +static void hdmi_ntsc_vbi_infoframe_log(const char *level,
> +					struct device *dev,
> +					const struct hdmi_ntsc_vbi_infoframe *frame)
> +{
> +	hdmi_infoframe_log_header(level, dev,
> +				  (const struct hdmi_any_infoframe *)frame);
> +
> +	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
> +}
> +
>  /**
>   * hdmi_infoframe_log() - log info of HDMI infoframe
>   * @level: logging level
> @@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
> +		break;
>  	}
>  }
>  EXPORT_SYMBOL(hdmi_infoframe_log);
> @@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
>  	return 0;
>  }
>  
> +/**
> + * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
> + *
> + * Unpacks the information contained in binary @buffer into a structured
> + * @frame of the HDMI MPEG Source information frame.
> + * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +static int hdmi_ntsc_vbi_infoframe_unpack(struct hdmi_ntsc_vbi_infoframe *frame,
> +					  const void *buffer, size_t size)
> +{
> +	const u8 *ptr = buffer;
> +	size_t length;
> +
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> +		return -EINVAL;
> +
> +	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> +	    ptr[1] != 1 ||
> +	    ptr[2] < 1 || ptr[2] > 27)
> +		return -EINVAL;
> +
> +	length = ptr[2];
> +
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
> +		return -EINVAL;
> +
> +	if (hdmi_infoframe_checksum(buffer,
> +				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
> +		return -EINVAL;
> +
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
> +}
> +
>  /**
>   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  		break;
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index 2c9322f7538d..3821516b336c 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
>  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
>  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
>  	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
> +	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
>  };
>  
>  #define HDMI_IEEE_OUI 0x000c03
> @@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
>  					     void *buffer, size_t size);
>  int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
>  
> +struct hdmi_ntsc_vbi_infoframe {
> +	enum hdmi_infoframe_type type;
> +	unsigned char version;
> +	unsigned char length;
> +	unsigned char pes_data_field[27];
> +};
> +
> +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> +				 const void *pes_data_field, size_t length);
> +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> +				     void *buffer, size_t size);
> +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> +					  void *buffer, size_t size);
> +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
> +
>  /**
>   * union hdmi_infoframe - overall union of all abstract infoframe representations
>   * @any: generic infoframe
> @@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
>   * @vendor: union of all vendor infoframes
>   * @audio: audio infoframe
>   * @mpeg_source: mpeg source infoframe
> + * @ntsc_vbi: ntsc vbi infoframe
>   *
>   * This is used by the generic pack function. This works since all infoframes
>   * have the same header which also indicates which type of infoframe should be
> @@ -382,6 +399,7 @@ union hdmi_infoframe {
>  	union hdmi_vendor_any_infoframe vendor;
>  	struct hdmi_audio_infoframe audio;
>  	struct hdmi_mpeg_source_infoframe mpeg_source;
> +	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
>  };
>  
>  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe
@ 2018-09-21  8:30     ` Hans Verkuil
  0 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:30 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Add the code to deal with the NTSC VBI infoframe.
> 
> I decided against parsing the PES_data_field and just leave
> it as an opaque blob, just dumping it out as hex in the log.
> 
> Blindly typed from the spec, and totally untested.

Do we have any driver that uses this? I would prefer to wait until someone
actually need this.

Regards,

	Hans

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/hdmi.h |  18 +++++
>  2 files changed, 226 insertions(+)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 3d24c7746c51..3c320d69fa0a 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
>  }
>  EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
>  
> +/**
> + * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
> + * @frame: HDMI NTSC VBI infoframe
> + * @pes_data_field: ANSI/SCTE 127 PES_data_field
> + * @length: ANSI/SCTE 127 PES_data_field length
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> +				 const void *pes_data_field,
> +				 size_t length)
> +{
> +	if (length < 1 || length > 27)
> +		return -EINVAL;
> +
> +	memset(frame, 0, sizeof(*frame));
> +
> +	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
> +	frame->version = 1;
> +	frame->length = length;
> +
> +	memcpy(frame->pes_data_field, pes_data_field, length);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
> +
> +static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> +	    frame->version != 1 ||
> +	    frame->length < 1 || frame->length > 27)
> +		return -EINVAL;
> +
> +	if (frame->pes_data_field[0] != 0x99)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
> + * @frame: HDMI NTSC VBI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
> +{
> +	return hdmi_ntsc_vbi_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
> +
> +/**
> + * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI infoframe to binary buffer
> + * @frame: HDMI NTSC VBI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Packs the information contained in the @frame structure into a binary
> + * representation that can be written into the corresponding controller
> + * registers. Also computes the checksum as required by section 5.3.5 of
> + * the HDMI 1.4 specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> +					  void *buffer, size_t size)
> +{
> +	u8 *ptr = buffer;
> +	size_t length;
> +	int ret;
> +
> +	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> +
> +	if (size < length)
> +		return -ENOSPC;
> +
> +	memset(buffer, 0, size);
> +
> +	ptr[0] = frame->type;
> +	ptr[1] = frame->version;
> +	ptr[2] = frame->length;
> +	ptr[3] = 0; /* checksum */
> +
> +	/* start infoframe payload */
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	memcpy(ptr, frame->pes_data_field, frame->length);
> +
> +	hdmi_infoframe_set_checksum(buffer, length);
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
> +
> +/**
> + * hdmi_ntsc_vbi_infoframe_pack() - Check and check a HDMI NTSC VBI infoframe,
> + *                                  and write it to binary buffer
> + * @frame: HDMI NTSC VBI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. Also
> + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> +				     void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_ntsc_vbi_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
> +}
> +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
> +
>  /**
>   * hdmi_infoframe_check() - Check check a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
>  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		return -EINVAL;
> @@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
>  		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
>  							      buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
> +							   buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
>  		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
>  							 buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
> +						      buffer, size);
> +		break;
>  	default:
>  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>  		length = -EINVAL;
> @@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
>  		return "Audio";
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		return "MPEG Source";
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		return "NTSC VBI";
>  	}
>  	return "Reserved";
>  }
> @@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
>  		 frame->field_repeat ? "Yes" : "No");
>  }
>  
> +/**
> + * hdmi_ntsc_vbi_infoframe_log() - log info of HDMI NTSC VBI infoframe
> + * @level: logging level
> + * @dev: device
> + * @frame: HDMI NTSC VBI infoframe
> + */
> +static void hdmi_ntsc_vbi_infoframe_log(const char *level,
> +					struct device *dev,
> +					const struct hdmi_ntsc_vbi_infoframe *frame)
> +{
> +	hdmi_infoframe_log_header(level, dev,
> +				  (const struct hdmi_any_infoframe *)frame);
> +
> +	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
> +}
> +
>  /**
>   * hdmi_infoframe_log() - log info of HDMI infoframe
>   * @level: logging level
> @@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
> +		break;
>  	}
>  }
>  EXPORT_SYMBOL(hdmi_infoframe_log);
> @@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
>  	return 0;
>  }
>  
> +/**
> + * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> + * @frame: HDMI MPEG Source infoframe
> + * @buffer: source buffer
> + * @size: size of buffer
> + *
> + * Unpacks the information contained in binary @buffer into a structured
> + * @frame of the HDMI MPEG Source information frame.
> + * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +static int hdmi_ntsc_vbi_infoframe_unpack(struct hdmi_ntsc_vbi_infoframe *frame,
> +					  const void *buffer, size_t size)
> +{
> +	const u8 *ptr = buffer;
> +	size_t length;
> +
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> +		return -EINVAL;
> +
> +	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> +	    ptr[1] != 1 ||
> +	    ptr[2] < 1 || ptr[2] > 27)
> +		return -EINVAL;
> +
> +	length = ptr[2];
> +
> +	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
> +		return -EINVAL;
> +
> +	if (hdmi_infoframe_checksum(buffer,
> +				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
> +		return -EINVAL;
> +
> +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> +
> +	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
> +}
> +
>  /**
>   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
>   * @frame: HDMI infoframe
> @@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
>  		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
>  		break;
> +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> +		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  		break;
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index 2c9322f7538d..3821516b336c 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
>  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
>  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
>  	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
> +	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
>  };
>  
>  #define HDMI_IEEE_OUI 0x000c03
> @@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
>  					     void *buffer, size_t size);
>  int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
>  
> +struct hdmi_ntsc_vbi_infoframe {
> +	enum hdmi_infoframe_type type;
> +	unsigned char version;
> +	unsigned char length;
> +	unsigned char pes_data_field[27];
> +};
> +
> +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> +				 const void *pes_data_field, size_t length);
> +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> +				     void *buffer, size_t size);
> +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> +					  void *buffer, size_t size);
> +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
> +
>  /**
>   * union hdmi_infoframe - overall union of all abstract infoframe representations
>   * @any: generic infoframe
> @@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
>   * @vendor: union of all vendor infoframes
>   * @audio: audio infoframe
>   * @mpeg_source: mpeg source infoframe
> + * @ntsc_vbi: ntsc vbi infoframe
>   *
>   * This is used by the generic pack function. This works since all infoframes
>   * have the same header which also indicates which type of infoframe should be
> @@ -382,6 +399,7 @@ union hdmi_infoframe {
>  	union hdmi_vendor_any_infoframe vendor;
>  	struct hdmi_audio_infoframe audio;
>  	struct hdmi_mpeg_source_infoframe mpeg_source;
> +	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
>  };
>  
>  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> 

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21  8:41     ` Hans Verkuil
  -1 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:41 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> We'll be wanting to send more than just infoframes over HDMI. So add an
> enum for other packet types.
> 
> TODO: Maybe just include the infoframe types in the packet type enum
>       and get rid of the infoframe type enum?

I think that's better, IMHO. With a comment that the types starting with
0x81 are defined in CTA-861-G.

It's really the same byte that is being checked, so having two enums is
a bit misleading. The main difference is really which standard defines
the packet types.

Regards,

	Hans

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  include/linux/hdmi.h | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index c76b50a48e48..80521d9591a1 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -27,6 +27,21 @@
>  #include <linux/types.h>
>  #include <linux/device.h>
>  
> +enum hdmi_packet_type {
> +	HDMI_PACKET_TYPE_NULL = 0x00,
> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> +	/* + enum hdmi_infoframe_type */
> +};
> +
>  enum hdmi_infoframe_type {
>  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
@ 2018-09-21  8:41     ` Hans Verkuil
  0 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21  8:41 UTC (permalink / raw)
  To: Ville Syrjala, dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

On 09/20/18 20:51, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> We'll be wanting to send more than just infoframes over HDMI. So add an
> enum for other packet types.
> 
> TODO: Maybe just include the infoframe types in the packet type enum
>       and get rid of the infoframe type enum?

I think that's better, IMHO. With a comment that the types starting with
0x81 are defined in CTA-861-G.

It's really the same byte that is being checked, so having two enums is
a bit misleading. The main difference is really which standard defines
the packet types.

Regards,

	Hans

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  include/linux/hdmi.h | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index c76b50a48e48..80521d9591a1 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -27,6 +27,21 @@
>  #include <linux/types.h>
>  #include <linux/device.h>
>  
> +enum hdmi_packet_type {
> +	HDMI_PACKET_TYPE_NULL = 0x00,
> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> +	/* + enum hdmi_infoframe_type */
> +};
> +
>  enum hdmi_infoframe_type {
>  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> 

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 08/18] drm/i915: Use memmove() for punching the hole into infoframes
  2018-09-20 18:51 ` [PATCH 08/18] drm/i915: Use memmove() for punching the hole into infoframes Ville Syrjala
@ 2018-09-21 13:52   ` Daniel Vetter
  0 siblings, 0 replies; 95+ messages in thread
From: Daniel Vetter @ 2018-09-21 13:52 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:35PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Replace the hand rolled memmove() with the real thing.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/intel_hdmi.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index a2dab0b6bde6..3b56ab253171 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -457,9 +457,7 @@ static void intel_write_infoframe(struct drm_encoder *encoder,
>  		return;
>  
>  	/* Insert the 'hole' (see big comment above) at position 3 */
> -	buffer[0] = buffer[1];
> -	buffer[1] = buffer[2];
> -	buffer[2] = buffer[3];
> +	memmove(&buffer[0], &buffer[1], 3);
>  	buffer[3] = 0;
>  	len++;
>  
> -- 
> 2.16.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe
  2018-09-21  8:28     ` Hans Verkuil
@ 2018-09-21 13:53       ` Ville Syrjälä
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 13:53 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 10:28:09AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Add the code to deal with the MPEG source infoframe.
> > 
> > Blindly typed from the spec, and totally untested.
> 
> I'm not sure this patch should be added at all. The CTA-861-G spec (section 6.7)
> says that the implementation of this infoframe is not recommended due to unresolved
> issues.
> 
> I don't think I've ever seen it either.
> 
> It obviously doesn't hurt to have this code, but I prefer to wait until there
> are devices that actively set/use this infoframe.

Sure. I'm totally fine with leaving it out. Just figured I'd send it out
in case anyone has some use for it.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/hdmi.h |  27 ++++++
> >  2 files changed, 256 insertions(+)
> > 
> > diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> > index 9507f668a569..3d24c7746c51 100644
> > --- a/drivers/video/hdmi.c
> > +++ b/drivers/video/hdmi.c
> > @@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> >  	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> >  }
> >  
> > +/**
> > + * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	memset(frame, 0, sizeof(*frame));
> > +
> > +	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
> > +	frame->version = 1;
> > +	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
> > +
> > +static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> > +	    frame->version != 1 ||
> > +	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_check() - Check and check a HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	return hdmi_mpeg_source_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Packs the information contained in the @frame structure into a binary
> > + * representation that can be written into the corresponding controller
> > + * registers. Also computes the checksum as required by section 5.3.5 of
> > + * the HDMI 1.4 specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> > +					     void *buffer, size_t size)
> > +{
> > +	u8 *ptr = buffer;
> > +	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_mpeg_source_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> > +
> > +	if (size < length)
> > +		return -ENOSPC;
> > +
> > +	memset(buffer, 0, size);
> > +
> > +	ptr[0] = frame->type;
> > +	ptr[1] = frame->version;
> > +	ptr[2] = frame->length;
> > +	ptr[3] = 0; /* checksum */
> > +
> > +	/* start infoframe payload */
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	ptr[0] = frame->mpeg_bit_rate >> 0;
> > +	ptr[1] = frame->mpeg_bit_rate >> 8;
> > +	ptr[2] = frame->mpeg_bit_rate >> 16;
> > +	ptr[3] = frame->mpeg_bit_rate >> 24;
> > +	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
> > +
> > +	hdmi_infoframe_set_checksum(buffer, length);
> > +
> > +	return length;
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_pack() - Check and check a HDMI MPEG Source infoframe,
> > + *                                     and write it to binary buffer
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> > +					void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_mpeg_source_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
> > +
> >  /**
> >   * hdmi_infoframe_check() - Check check a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
> >  		return hdmi_audio_infoframe_check(&frame->audio);
> >  	case HDMI_INFOFRAME_TYPE_VENDOR:
> >  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		return -EINVAL;
> > @@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
> >  		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> >  							     buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
> > +							      buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
> >  		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
> >  							buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
> > +							 buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -838,6 +973,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
> >  		return "Source Product Description (SPD)";
> >  	case HDMI_INFOFRAME_TYPE_AUDIO:
> >  		return "Audio";
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		return "MPEG Source";
> >  	}
> >  	return "Reserved";
> >  }
> > @@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
> >  	}
> >  }
> >  
> > +static const char *
> > +hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
> > +{
> > +	if (frame < 0 || frame > 3)
> > +		return "invalid";
> > +
> > +	switch (frame) {
> > +	case HDMI_MPEG_FRAME_UNKNOWN:
> > +		return "Unknown";
> > +	case HDMI_MPEG_FRAME_I_PICTURE:
> > +		return "I Picture";
> > +	case HDMI_MPEG_FRAME_B_PICTURE:
> > +		return "B Picture";
> > +	case HDMI_MPEG_FRAME_P_PICTURE:
> > +		return "P Picture";
> > +	}
> > +	return "Reserved";
> > +}
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
> > + * @level: logging level
> > + * @dev: device
> > + * @frame: HDMI MPEG Source infoframe
> > + */
> > +static void hdmi_mpeg_source_infoframe_log(const char *level,
> > +					   struct device *dev,
> > +					   const struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	hdmi_infoframe_log_header(level, dev,
> > +				  (const struct hdmi_any_infoframe *)frame);
> > +
> > +	hdmi_log("    MPEG bit rate: %d Hz\n",
> > +		 frame->mpeg_bit_rate);
> > +	hdmi_log("    MPEG frame: %s\n",
> > +		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
> > +	hdmi_log("    field repeat: %s\n",
> > +		 frame->field_repeat ? "Yes" : "No");
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_log() - log info of HDMI infoframe
> >   * @level: logging level
> > @@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
> >  	case HDMI_INFOFRAME_TYPE_VENDOR:
> >  		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
> > +		break;
> >  	}
> >  }
> >  EXPORT_SYMBOL(hdmi_infoframe_log);
> > @@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
> >  	return 0;
> >  }
> >  
> > +/**
> > + * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: source buffer
> > + * @size: size of buffer
> > + *
> > + * Unpacks the information contained in binary @buffer into a structured
> > + * @frame of the HDMI MPEG Source information frame.
> > + * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
> > +					     const void *buffer, size_t size)
> > +{
> > +	const u8 *ptr = buffer;
> > +	int ret;
> > +
> > +	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
> > +		return -EINVAL;
> > +
> > +	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> > +	    ptr[1] != 1 ||
> > +	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
> > +		return -EINVAL;
> > +
> > +	ret = hdmi_mpeg_source_infoframe_init(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	frame->mpeg_bit_rate =
> > +		(ptr[0] << 0) | (ptr[1] << 8) |
> > +		(ptr[2] << 16) | (ptr[3] << 24);
> > +	frame->mpeg_frame = ptr[4] & 0x3;
> > +	frame->field_repeat = ptr[4] & 0x10;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> >  	case HDMI_INFOFRAME_TYPE_VENDOR:
> >  		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
> > +		break;
> >  	default:
> >  		ret = -EINVAL;
> >  		break;
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index 80521d9591a1..2c9322f7538d 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
> >  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> >  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
> >  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
> > +	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
> >  };
> >  
> >  #define HDMI_IEEE_OUI 0x000c03
> > @@ -55,6 +56,7 @@ enum hdmi_infoframe_type {
> >  #define HDMI_AVI_INFOFRAME_SIZE    13
> >  #define HDMI_SPD_INFOFRAME_SIZE    25
> >  #define HDMI_AUDIO_INFOFRAME_SIZE  10
> > +#define HDMI_MPEG_SOURCE_INFOFRAME_SIZE  10
> >  
> >  #define HDMI_INFOFRAME_SIZE(type)	\
> >  	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
> > @@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
> >  	struct hdmi_vendor_infoframe hdmi;
> >  };
> >  
> > +enum hdmi_mpeg_frame {
> > +	HDMI_MPEG_FRAME_UNKNOWN,
> > +	HDMI_MPEG_FRAME_I_PICTURE,
> > +	HDMI_MPEG_FRAME_B_PICTURE,
> > +	HDMI_MPEG_FRAME_P_PICTURE,
> > +};
> > +
> > +struct hdmi_mpeg_source_infoframe {
> > +	enum hdmi_infoframe_type type;
> > +	unsigned char version;
> > +	unsigned char length;
> > +	unsigned int mpeg_bit_rate;
> > +	enum hdmi_mpeg_frame mpeg_frame;
> > +	bool field_repeat;
> > +};
> > +
> > +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
> > +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> > +					void *buffer, size_t size);
> > +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> > +					     void *buffer, size_t size);
> > +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> > +
> >  /**
> >   * union hdmi_infoframe - overall union of all abstract infoframe representations
> >   * @any: generic infoframe
> > @@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
> >   * @spd: spd infoframe
> >   * @vendor: union of all vendor infoframes
> >   * @audio: audio infoframe
> > + * @mpeg_source: mpeg source infoframe
> >   *
> >   * This is used by the generic pack function. This works since all infoframes
> >   * have the same header which also indicates which type of infoframe should be
> > @@ -355,6 +381,7 @@ union hdmi_infoframe {
> >  	struct hdmi_spd_infoframe spd;
> >  	union hdmi_vendor_any_infoframe vendor;
> >  	struct hdmi_audio_infoframe audio;
> > +	struct hdmi_mpeg_source_infoframe mpeg_source;
> >  };
> >  
> >  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> > 

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe
@ 2018-09-21 13:53       ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 13:53 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, dri-devel, linux-media

On Fri, Sep 21, 2018 at 10:28:09AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Add the code to deal with the MPEG source infoframe.
> > 
> > Blindly typed from the spec, and totally untested.
> 
> I'm not sure this patch should be added at all. The CTA-861-G spec (section 6.7)
> says that the implementation of this infoframe is not recommended due to unresolved
> issues.
> 
> I don't think I've ever seen it either.
> 
> It obviously doesn't hurt to have this code, but I prefer to wait until there
> are devices that actively set/use this infoframe.

Sure. I'm totally fine with leaving it out. Just figured I'd send it out
in case anyone has some use for it.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/hdmi.h |  27 ++++++
> >  2 files changed, 256 insertions(+)
> > 
> > diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> > index 9507f668a569..3d24c7746c51 100644
> > --- a/drivers/video/hdmi.c
> > +++ b/drivers/video/hdmi.c
> > @@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> >  	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> >  }
> >  
> > +/**
> > + * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	memset(frame, 0, sizeof(*frame));
> > +
> > +	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
> > +	frame->version = 1;
> > +	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
> > +
> > +static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> > +	    frame->version != 1 ||
> > +	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_check() - Check and check a HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	return hdmi_mpeg_source_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Packs the information contained in the @frame structure into a binary
> > + * representation that can be written into the corresponding controller
> > + * registers. Also computes the checksum as required by section 5.3.5 of
> > + * the HDMI 1.4 specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> > +					     void *buffer, size_t size)
> > +{
> > +	u8 *ptr = buffer;
> > +	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_mpeg_source_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> > +
> > +	if (size < length)
> > +		return -ENOSPC;
> > +
> > +	memset(buffer, 0, size);
> > +
> > +	ptr[0] = frame->type;
> > +	ptr[1] = frame->version;
> > +	ptr[2] = frame->length;
> > +	ptr[3] = 0; /* checksum */
> > +
> > +	/* start infoframe payload */
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	ptr[0] = frame->mpeg_bit_rate >> 0;
> > +	ptr[1] = frame->mpeg_bit_rate >> 8;
> > +	ptr[2] = frame->mpeg_bit_rate >> 16;
> > +	ptr[3] = frame->mpeg_bit_rate >> 24;
> > +	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
> > +
> > +	hdmi_infoframe_set_checksum(buffer, length);
> > +
> > +	return length;
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_pack() - Check and check a HDMI MPEG Source infoframe,
> > + *                                     and write it to binary buffer
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> > +					void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_mpeg_source_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
> > +}
> > +EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
> > +
> >  /**
> >   * hdmi_infoframe_check() - Check check a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
> >  		return hdmi_audio_infoframe_check(&frame->audio);
> >  	case HDMI_INFOFRAME_TYPE_VENDOR:
> >  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		return -EINVAL;
> > @@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
> >  		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> >  							     buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
> > +							      buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
> >  		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
> >  							buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
> > +							 buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -838,6 +973,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
> >  		return "Source Product Description (SPD)";
> >  	case HDMI_INFOFRAME_TYPE_AUDIO:
> >  		return "Audio";
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		return "MPEG Source";
> >  	}
> >  	return "Reserved";
> >  }
> > @@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
> >  	}
> >  }
> >  
> > +static const char *
> > +hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
> > +{
> > +	if (frame < 0 || frame > 3)
> > +		return "invalid";
> > +
> > +	switch (frame) {
> > +	case HDMI_MPEG_FRAME_UNKNOWN:
> > +		return "Unknown";
> > +	case HDMI_MPEG_FRAME_I_PICTURE:
> > +		return "I Picture";
> > +	case HDMI_MPEG_FRAME_B_PICTURE:
> > +		return "B Picture";
> > +	case HDMI_MPEG_FRAME_P_PICTURE:
> > +		return "P Picture";
> > +	}
> > +	return "Reserved";
> > +}
> > +
> > +/**
> > + * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
> > + * @level: logging level
> > + * @dev: device
> > + * @frame: HDMI MPEG Source infoframe
> > + */
> > +static void hdmi_mpeg_source_infoframe_log(const char *level,
> > +					   struct device *dev,
> > +					   const struct hdmi_mpeg_source_infoframe *frame)
> > +{
> > +	hdmi_infoframe_log_header(level, dev,
> > +				  (const struct hdmi_any_infoframe *)frame);
> > +
> > +	hdmi_log("    MPEG bit rate: %d Hz\n",
> > +		 frame->mpeg_bit_rate);
> > +	hdmi_log("    MPEG frame: %s\n",
> > +		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
> > +	hdmi_log("    field repeat: %s\n",
> > +		 frame->field_repeat ? "Yes" : "No");
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_log() - log info of HDMI infoframe
> >   * @level: logging level
> > @@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
> >  	case HDMI_INFOFRAME_TYPE_VENDOR:
> >  		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
> > +		break;
> >  	}
> >  }
> >  EXPORT_SYMBOL(hdmi_infoframe_log);
> > @@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
> >  	return 0;
> >  }
> >  
> > +/**
> > + * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: source buffer
> > + * @size: size of buffer
> > + *
> > + * Unpacks the information contained in binary @buffer into a structured
> > + * @frame of the HDMI MPEG Source information frame.
> > + * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
> > +					     const void *buffer, size_t size)
> > +{
> > +	const u8 *ptr = buffer;
> > +	int ret;
> > +
> > +	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
> > +		return -EINVAL;
> > +
> > +	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
> > +	    ptr[1] != 1 ||
> > +	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
> > +		return -EINVAL;
> > +
> > +	ret = hdmi_mpeg_source_infoframe_init(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	frame->mpeg_bit_rate =
> > +		(ptr[0] << 0) | (ptr[1] << 8) |
> > +		(ptr[2] << 16) | (ptr[3] << 24);
> > +	frame->mpeg_frame = ptr[4] & 0x3;
> > +	frame->field_repeat = ptr[4] & 0x10;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> >  	case HDMI_INFOFRAME_TYPE_VENDOR:
> >  		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> > +		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
> > +		break;
> >  	default:
> >  		ret = -EINVAL;
> >  		break;
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index 80521d9591a1..2c9322f7538d 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
> >  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> >  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
> >  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
> > +	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
> >  };
> >  
> >  #define HDMI_IEEE_OUI 0x000c03
> > @@ -55,6 +56,7 @@ enum hdmi_infoframe_type {
> >  #define HDMI_AVI_INFOFRAME_SIZE    13
> >  #define HDMI_SPD_INFOFRAME_SIZE    25
> >  #define HDMI_AUDIO_INFOFRAME_SIZE  10
> > +#define HDMI_MPEG_SOURCE_INFOFRAME_SIZE  10
> >  
> >  #define HDMI_INFOFRAME_SIZE(type)	\
> >  	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
> > @@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
> >  	struct hdmi_vendor_infoframe hdmi;
> >  };
> >  
> > +enum hdmi_mpeg_frame {
> > +	HDMI_MPEG_FRAME_UNKNOWN,
> > +	HDMI_MPEG_FRAME_I_PICTURE,
> > +	HDMI_MPEG_FRAME_B_PICTURE,
> > +	HDMI_MPEG_FRAME_P_PICTURE,
> > +};
> > +
> > +struct hdmi_mpeg_source_infoframe {
> > +	enum hdmi_infoframe_type type;
> > +	unsigned char version;
> > +	unsigned char length;
> > +	unsigned int mpeg_bit_rate;
> > +	enum hdmi_mpeg_frame mpeg_frame;
> > +	bool field_repeat;
> > +};
> > +
> > +int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
> > +ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
> > +					void *buffer, size_t size);
> > +ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
> > +					     void *buffer, size_t size);
> > +int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> > +
> >  /**
> >   * union hdmi_infoframe - overall union of all abstract infoframe representations
> >   * @any: generic infoframe
> > @@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
> >   * @spd: spd infoframe
> >   * @vendor: union of all vendor infoframes
> >   * @audio: audio infoframe
> > + * @mpeg_source: mpeg source infoframe
> >   *
> >   * This is used by the generic pack function. This works since all infoframes
> >   * have the same header which also indicates which type of infoframe should be
> > @@ -355,6 +381,7 @@ union hdmi_infoframe {
> >  	struct hdmi_spd_infoframe spd;
> >  	union hdmi_vendor_any_infoframe vendor;
> >  	struct hdmi_audio_infoframe audio;
> > +	struct hdmi_mpeg_source_infoframe mpeg_source;
> >  };
> >  
> >  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> > 

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe
  2018-09-21  8:30     ` Hans Verkuil
@ 2018-09-21 13:54       ` Ville Syrjälä
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 13:54 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 10:30:16AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Add the code to deal with the NTSC VBI infoframe.
> > 
> > I decided against parsing the PES_data_field and just leave
> > it as an opaque blob, just dumping it out as hex in the log.
> > 
> > Blindly typed from the spec, and totally untested.
> 
> Do we have any driver that uses this? I would prefer to wait until someone
> actually need this.

No users that I know of. So totally fine with me to leave it out.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/hdmi.h |  18 +++++
> >  2 files changed, 226 insertions(+)
> > 
> > diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> > index 3d24c7746c51..3c320d69fa0a 100644
> > --- a/drivers/video/hdmi.c
> > +++ b/drivers/video/hdmi.c
> > @@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
> >  }
> >  EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
> >  
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
> > + * @frame: HDMI NTSC VBI infoframe
> > + * @pes_data_field: ANSI/SCTE 127 PES_data_field
> > + * @length: ANSI/SCTE 127 PES_data_field length
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				 const void *pes_data_field,
> > +				 size_t length)
> > +{
> > +	if (length < 1 || length > 27)
> > +		return -EINVAL;
> > +
> > +	memset(frame, 0, sizeof(*frame));
> > +
> > +	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
> > +	frame->version = 1;
> > +	frame->length = length;
> > +
> > +	memcpy(frame->pes_data_field, pes_data_field, length);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
> > +
> > +static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> > +	    frame->version != 1 ||
> > +	    frame->length < 1 || frame->length > 27)
> > +		return -EINVAL;
> > +
> > +	if (frame->pes_data_field[0] != 0x99)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
> > + * @frame: HDMI NTSC VBI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
> > +{
> > +	return hdmi_ntsc_vbi_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
> > +
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI infoframe to binary buffer
> > + * @frame: HDMI NTSC VBI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Packs the information contained in the @frame structure into a binary
> > + * representation that can be written into the corresponding controller
> > + * registers. Also computes the checksum as required by section 5.3.5 of
> > + * the HDMI 1.4 specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> > +					  void *buffer, size_t size)
> > +{
> > +	u8 *ptr = buffer;
> > +	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> > +
> > +	if (size < length)
> > +		return -ENOSPC;
> > +
> > +	memset(buffer, 0, size);
> > +
> > +	ptr[0] = frame->type;
> > +	ptr[1] = frame->version;
> > +	ptr[2] = frame->length;
> > +	ptr[3] = 0; /* checksum */
> > +
> > +	/* start infoframe payload */
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	memcpy(ptr, frame->pes_data_field, frame->length);
> > +
> > +	hdmi_infoframe_set_checksum(buffer, length);
> > +
> > +	return length;
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_pack() - Check and check a HDMI NTSC VBI infoframe,
> > + *                                  and write it to binary buffer
> > + * @frame: HDMI NTSC VBI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				     void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_ntsc_vbi_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
> > +
> >  /**
> >   * hdmi_infoframe_check() - Check check a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
> >  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		return -EINVAL;
> > @@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
> >  		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
> >  							      buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
> > +							   buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
> >  		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
> >  							 buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
> > +						      buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
> >  		return "Audio";
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		return "MPEG Source";
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		return "NTSC VBI";
> >  	}
> >  	return "Reserved";
> >  }
> > @@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
> >  		 frame->field_repeat ? "Yes" : "No");
> >  }
> >  
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_log() - log info of HDMI NTSC VBI infoframe
> > + * @level: logging level
> > + * @dev: device
> > + * @frame: HDMI NTSC VBI infoframe
> > + */
> > +static void hdmi_ntsc_vbi_infoframe_log(const char *level,
> > +					struct device *dev,
> > +					const struct hdmi_ntsc_vbi_infoframe *frame)
> > +{
> > +	hdmi_infoframe_log_header(level, dev,
> > +				  (const struct hdmi_any_infoframe *)frame);
> > +
> > +	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_log() - log info of HDMI infoframe
> >   * @level: logging level
> > @@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
> > +		break;
> >  	}
> >  }
> >  EXPORT_SYMBOL(hdmi_infoframe_log);
> > @@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
> >  	return 0;
> >  }
> >  
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: source buffer
> > + * @size: size of buffer
> > + *
> > + * Unpacks the information contained in binary @buffer into a structured
> > + * @frame of the HDMI MPEG Source information frame.
> > + * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +static int hdmi_ntsc_vbi_infoframe_unpack(struct hdmi_ntsc_vbi_infoframe *frame,
> > +					  const void *buffer, size_t size)
> > +{
> > +	const u8 *ptr = buffer;
> > +	size_t length;
> > +
> > +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> > +		return -EINVAL;
> > +
> > +	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> > +	    ptr[1] != 1 ||
> > +	    ptr[2] < 1 || ptr[2] > 27)
> > +		return -EINVAL;
> > +
> > +	length = ptr[2];
> > +
> > +	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
> > +		return -EINVAL;
> > +
> > +	if (hdmi_infoframe_checksum(buffer,
> > +				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
> > +		return -EINVAL;
> > +
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
> > +		break;
> >  	default:
> >  		ret = -EINVAL;
> >  		break;
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index 2c9322f7538d..3821516b336c 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
> >  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
> >  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
> >  	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
> > +	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
> >  };
> >  
> >  #define HDMI_IEEE_OUI 0x000c03
> > @@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
> >  					     void *buffer, size_t size);
> >  int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> >  
> > +struct hdmi_ntsc_vbi_infoframe {
> > +	enum hdmi_infoframe_type type;
> > +	unsigned char version;
> > +	unsigned char length;
> > +	unsigned char pes_data_field[27];
> > +};
> > +
> > +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				 const void *pes_data_field, size_t length);
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				     void *buffer, size_t size);
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> > +					  void *buffer, size_t size);
> > +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
> > +
> >  /**
> >   * union hdmi_infoframe - overall union of all abstract infoframe representations
> >   * @any: generic infoframe
> > @@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> >   * @vendor: union of all vendor infoframes
> >   * @audio: audio infoframe
> >   * @mpeg_source: mpeg source infoframe
> > + * @ntsc_vbi: ntsc vbi infoframe
> >   *
> >   * This is used by the generic pack function. This works since all infoframes
> >   * have the same header which also indicates which type of infoframe should be
> > @@ -382,6 +399,7 @@ union hdmi_infoframe {
> >  	union hdmi_vendor_any_infoframe vendor;
> >  	struct hdmi_audio_infoframe audio;
> >  	struct hdmi_mpeg_source_infoframe mpeg_source;
> > +	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
> >  };
> >  
> >  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> > 

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe
@ 2018-09-21 13:54       ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 13:54 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: intel-gfx, Hans Verkuil, dri-devel, linux-media

On Fri, Sep 21, 2018 at 10:30:16AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Add the code to deal with the NTSC VBI infoframe.
> > 
> > I decided against parsing the PES_data_field and just leave
> > it as an opaque blob, just dumping it out as hex in the log.
> > 
> > Blindly typed from the spec, and totally untested.
> 
> Do we have any driver that uses this? I would prefer to wait until someone
> actually need this.

No users that I know of. So totally fine with me to leave it out.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  include/linux/hdmi.h |  18 +++++
> >  2 files changed, 226 insertions(+)
> > 
> > diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> > index 3d24c7746c51..3c320d69fa0a 100644
> > --- a/drivers/video/hdmi.c
> > +++ b/drivers/video/hdmi.c
> > @@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
> >  }
> >  EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
> >  
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
> > + * @frame: HDMI NTSC VBI infoframe
> > + * @pes_data_field: ANSI/SCTE 127 PES_data_field
> > + * @length: ANSI/SCTE 127 PES_data_field length
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				 const void *pes_data_field,
> > +				 size_t length)
> > +{
> > +	if (length < 1 || length > 27)
> > +		return -EINVAL;
> > +
> > +	memset(frame, 0, sizeof(*frame));
> > +
> > +	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
> > +	frame->version = 1;
> > +	frame->length = length;
> > +
> > +	memcpy(frame->pes_data_field, pes_data_field, length);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
> > +
> > +static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> > +	    frame->version != 1 ||
> > +	    frame->length < 1 || frame->length > 27)
> > +		return -EINVAL;
> > +
> > +	if (frame->pes_data_field[0] != 0x99)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
> > + * @frame: HDMI NTSC VBI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
> > +{
> > +	return hdmi_ntsc_vbi_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
> > +
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI infoframe to binary buffer
> > + * @frame: HDMI NTSC VBI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Packs the information contained in the @frame structure into a binary
> > + * representation that can be written into the corresponding controller
> > + * registers. Also computes the checksum as required by section 5.3.5 of
> > + * the HDMI 1.4 specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> > +					  void *buffer, size_t size)
> > +{
> > +	u8 *ptr = buffer;
> > +	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> > +
> > +	if (size < length)
> > +		return -ENOSPC;
> > +
> > +	memset(buffer, 0, size);
> > +
> > +	ptr[0] = frame->type;
> > +	ptr[1] = frame->version;
> > +	ptr[2] = frame->length;
> > +	ptr[3] = 0; /* checksum */
> > +
> > +	/* start infoframe payload */
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	memcpy(ptr, frame->pes_data_field, frame->length);
> > +
> > +	hdmi_infoframe_set_checksum(buffer, length);
> > +
> > +	return length;
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_pack() - Check and check a HDMI NTSC VBI infoframe,
> > + *                                  and write it to binary buffer
> > + * @frame: HDMI NTSC VBI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				     void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_ntsc_vbi_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
> > +}
> > +EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
> > +
> >  /**
> >   * hdmi_infoframe_check() - Check check a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
> >  		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		return -EINVAL;
> > @@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
> >  		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
> >  							      buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
> > +							   buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
> >  		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
> >  							 buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
> > +						      buffer, size);
> > +		break;
> >  	default:
> >  		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> >  		length = -EINVAL;
> > @@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
> >  		return "Audio";
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		return "MPEG Source";
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		return "NTSC VBI";
> >  	}
> >  	return "Reserved";
> >  }
> > @@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
> >  		 frame->field_repeat ? "Yes" : "No");
> >  }
> >  
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_log() - log info of HDMI NTSC VBI infoframe
> > + * @level: logging level
> > + * @dev: device
> > + * @frame: HDMI NTSC VBI infoframe
> > + */
> > +static void hdmi_ntsc_vbi_infoframe_log(const char *level,
> > +					struct device *dev,
> > +					const struct hdmi_ntsc_vbi_infoframe *frame)
> > +{
> > +	hdmi_infoframe_log_header(level, dev,
> > +				  (const struct hdmi_any_infoframe *)frame);
> > +
> > +	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_log() - log info of HDMI infoframe
> >   * @level: logging level
> > @@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
> > +		break;
> >  	}
> >  }
> >  EXPORT_SYMBOL(hdmi_infoframe_log);
> > @@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
> >  	return 0;
> >  }
> >  
> > +/**
> > + * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
> > + * @frame: HDMI MPEG Source infoframe
> > + * @buffer: source buffer
> > + * @size: size of buffer
> > + *
> > + * Unpacks the information contained in binary @buffer into a structured
> > + * @frame of the HDMI MPEG Source information frame.
> > + * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +static int hdmi_ntsc_vbi_infoframe_unpack(struct hdmi_ntsc_vbi_infoframe *frame,
> > +					  const void *buffer, size_t size)
> > +{
> > +	const u8 *ptr = buffer;
> > +	size_t length;
> > +
> > +	if (size < HDMI_INFOFRAME_HEADER_SIZE)
> > +		return -EINVAL;
> > +
> > +	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
> > +	    ptr[1] != 1 ||
> > +	    ptr[2] < 1 || ptr[2] > 27)
> > +		return -EINVAL;
> > +
> > +	length = ptr[2];
> > +
> > +	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
> > +		return -EINVAL;
> > +
> > +	if (hdmi_infoframe_checksum(buffer,
> > +				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
> > +		return -EINVAL;
> > +
> > +	ptr += HDMI_INFOFRAME_HEADER_SIZE;
> > +
> > +	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
> > +}
> > +
> >  /**
> >   * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
> >   * @frame: HDMI infoframe
> > @@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> >  	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
> >  		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
> >  		break;
> > +	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
> > +		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
> > +		break;
> >  	default:
> >  		ret = -EINVAL;
> >  		break;
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index 2c9322f7538d..3821516b336c 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
> >  	HDMI_INFOFRAME_TYPE_SPD = 0x83,
> >  	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
> >  	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
> > +	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
> >  };
> >  
> >  #define HDMI_IEEE_OUI 0x000c03
> > @@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
> >  					     void *buffer, size_t size);
> >  int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> >  
> > +struct hdmi_ntsc_vbi_infoframe {
> > +	enum hdmi_infoframe_type type;
> > +	unsigned char version;
> > +	unsigned char length;
> > +	unsigned char pes_data_field[27];
> > +};
> > +
> > +int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				 const void *pes_data_field, size_t length);
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
> > +				     void *buffer, size_t size);
> > +ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
> > +					  void *buffer, size_t size);
> > +int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
> > +
> >  /**
> >   * union hdmi_infoframe - overall union of all abstract infoframe representations
> >   * @any: generic infoframe
> > @@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
> >   * @vendor: union of all vendor infoframes
> >   * @audio: audio infoframe
> >   * @mpeg_source: mpeg source infoframe
> > + * @ntsc_vbi: ntsc vbi infoframe
> >   *
> >   * This is used by the generic pack function. This works since all infoframes
> >   * have the same header which also indicates which type of infoframe should be
> > @@ -382,6 +399,7 @@ union hdmi_infoframe {
> >  	union hdmi_vendor_any_infoframe vendor;
> >  	struct hdmi_audio_infoframe audio;
> >  	struct hdmi_mpeg_source_infoframe mpeg_source;
> > +	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
> >  };
> >  
> >  ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> > 

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 09/18] drm/i915: Pass intel_encoder to infoframe functions
  2018-09-20 18:51 ` [PATCH 09/18] drm/i915: Pass intel_encoder to infoframe functions Ville Syrjala
@ 2018-09-21 13:59   ` Daniel Vetter
  2018-09-21 15:03     ` Ville Syrjälä
  0 siblings, 1 reply; 95+ messages in thread
From: Daniel Vetter @ 2018-09-21 13:59 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:36PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Make life simpler by passing around intel_encoder instead of
> drm_encoder.
> 
> @r1@
> identifier F =~ "infoframe";
> identifier I, M;
> @@
> F(
> - struct drm_encoder *I
> + struct intel_encoder *I
>   , ...)
> {
> <...
> (
> - I->M
> + I->base.M
> |
> - I
> + &I->base
> )
> ...>
> }
> 
> @r2@
> identifier F =~ "infoframe";
> identifier I;
> type T, ST;
> @@
> ST {
> ...
> 	T (*F)(
> -	       struct drm_encoder *I
> +	       struct intel_encoder *encoder
> 	       , ...);
> ...
> };
> 
> @@
> identifier r1.F;
> expression E;
> @@
> F(
> - E
> + to_intel_encoder(E)
>   ,...)
> 
> @@
> identifier r2.F;
> expression E, X;
> @@
> (
> X.F(
> -   E
> +   to_intel_encoder(E)
>     ,...)
> |
> X->F(
> -    E
> +    to_intel_encoder(E)
>      ,...)
> )
> 
> @@
> expression E;
> @@
> (
> - to_intel_encoder(&E->base)
> + E
> |
> - to_intel_encoder(&E->base.base)
> + &E->base
> )
> 
> @@
> identifier D, M;
> expression E;
> @@
>  D = enc_to_dig_port(&E->base)
> <...
> (
> - D->base.M
> + E->M
> |
> - &D->base
> + E
> )
> ...>
> 
> @@
> identifier D;
> expression E;
> type T;
> @@
> - T D = enc_to_dig_port(E);
> ... when != D

Someone knows a lot more cocci than I do, impressive. How do you figure
this stuff out? Read the source?

Also seems to have some manual fixups below, so I just looked at the diff.
That looks fine.

Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

I'll trust the compiler more here :-)

Cheers, Daniel


> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c  |   6 +-
>  drivers/gpu/drm/i915/intel_drv.h  |   6 +-
>  drivers/gpu/drm/i915/intel_hdmi.c | 129 +++++++++++++++++++-------------------
>  drivers/gpu/drm/i915/intel_psr.c  |   3 +-
>  4 files changed, 71 insertions(+), 73 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index b6910c8b4e08..086e3f940586 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -2947,7 +2947,7 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
>  
>  	intel_ddi_enable_pipe_clock(crtc_state);
>  
> -	intel_dig_port->set_infoframes(&encoder->base,
> +	intel_dig_port->set_infoframes(encoder,
>  				       crtc_state->has_infoframe,
>  				       crtc_state, conn_state);
>  }
> @@ -3046,7 +3046,7 @@ static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
>  	struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
>  	struct intel_hdmi *intel_hdmi = &dig_port->hdmi;
>  
> -	dig_port->set_infoframes(&encoder->base, false,
> +	dig_port->set_infoframes(encoder, false,
>  				 old_crtc_state, old_conn_state);
>  
>  	intel_ddi_disable_pipe_clock(old_crtc_state);
> @@ -3390,7 +3390,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
>  		pipe_config->has_hdmi_sink = true;
>  		intel_dig_port = enc_to_dig_port(&encoder->base);
>  
> -		if (intel_dig_port->infoframe_enabled(&encoder->base, pipe_config))
> +		if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
>  			pipe_config->has_infoframe = true;
>  
>  		if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index bf1c38728a59..e0f3a79fc75e 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1173,15 +1173,15 @@ struct intel_digital_port {
>  	enum intel_display_power_domain ddi_io_power_domain;
>  	enum tc_port_type tc_type;
>  
> -	void (*write_infoframe)(struct drm_encoder *encoder,
> +	void (*write_infoframe)(struct intel_encoder *encoder,
>  				const struct intel_crtc_state *crtc_state,
>  				unsigned int type,
>  				const void *frame, ssize_t len);
> -	void (*set_infoframes)(struct drm_encoder *encoder,
> +	void (*set_infoframes)(struct intel_encoder *encoder,
>  			       bool enable,
>  			       const struct intel_crtc_state *crtc_state,
>  			       const struct drm_connector_state *conn_state);
> -	bool (*infoframe_enabled)(struct drm_encoder *encoder,
> +	bool (*infoframe_enabled)(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config);
>  };
>  
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index 3b56ab253171..454f570275e9 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -148,14 +148,13 @@ hsw_dip_data_reg(struct drm_i915_private *dev_priv,
>  	}
>  }
>  
> -static void g4x_write_infoframe(struct drm_encoder *encoder,
> +static void g4x_write_infoframe(struct intel_encoder *encoder,
>  				const struct intel_crtc_state *crtc_state,
>  				unsigned int type,
>  				const void *frame, ssize_t len)
>  {
>  	const u32 *data = frame;
> -	struct drm_device *dev = encoder->dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	u32 val = I915_READ(VIDEO_DIP_CTL);
>  	int i;
>  
> @@ -186,31 +185,29 @@ static void g4x_write_infoframe(struct drm_encoder *encoder,
>  	POSTING_READ(VIDEO_DIP_CTL);
>  }
>  
> -static bool g4x_infoframe_enabled(struct drm_encoder *encoder,
> +static bool g4x_infoframe_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> -	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	u32 val = I915_READ(VIDEO_DIP_CTL);
>  
>  	if ((val & VIDEO_DIP_ENABLE) == 0)
>  		return false;
>  
> -	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
> +	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
>  		return false;
>  
>  	return val & (VIDEO_DIP_ENABLE_AVI |
>  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
>  }
>  
> -static void ibx_write_infoframe(struct drm_encoder *encoder,
> +static void ibx_write_infoframe(struct intel_encoder *encoder,
>  				const struct intel_crtc_state *crtc_state,
>  				unsigned int type,
>  				const void *frame, ssize_t len)
>  {
>  	const u32 *data = frame;
> -	struct drm_device *dev = encoder->dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
>  	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
>  	u32 val = I915_READ(reg);
> @@ -243,11 +240,10 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
>  	POSTING_READ(reg);
>  }
>  
> -static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
> +static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> -	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
>  	i915_reg_t reg = TVIDEO_DIP_CTL(pipe);
>  	u32 val = I915_READ(reg);
> @@ -255,7 +251,7 @@ static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
>  	if ((val & VIDEO_DIP_ENABLE) == 0)
>  		return false;
>  
> -	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
> +	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
>  		return false;
>  
>  	return val & (VIDEO_DIP_ENABLE_AVI |
> @@ -263,14 +259,13 @@ static bool ibx_infoframe_enabled(struct drm_encoder *encoder,
>  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
>  }
>  
> -static void cpt_write_infoframe(struct drm_encoder *encoder,
> +static void cpt_write_infoframe(struct intel_encoder *encoder,
>  				const struct intel_crtc_state *crtc_state,
>  				unsigned int type,
>  				const void *frame, ssize_t len)
>  {
>  	const u32 *data = frame;
> -	struct drm_device *dev = encoder->dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
>  	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
>  	u32 val = I915_READ(reg);
> @@ -306,10 +301,10 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
>  	POSTING_READ(reg);
>  }
>  
> -static bool cpt_infoframe_enabled(struct drm_encoder *encoder,
> +static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
>  	u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
>  
> @@ -321,14 +316,13 @@ static bool cpt_infoframe_enabled(struct drm_encoder *encoder,
>  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
>  }
>  
> -static void vlv_write_infoframe(struct drm_encoder *encoder,
> +static void vlv_write_infoframe(struct intel_encoder *encoder,
>  				const struct intel_crtc_state *crtc_state,
>  				unsigned int type,
>  				const void *frame, ssize_t len)
>  {
>  	const u32 *data = frame;
> -	struct drm_device *dev = encoder->dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
>  	i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
>  	u32 val = I915_READ(reg);
> @@ -361,18 +355,17 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
>  	POSTING_READ(reg);
>  }
>  
> -static bool vlv_infoframe_enabled(struct drm_encoder *encoder,
> +static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> -	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	enum pipe pipe = to_intel_crtc(pipe_config->base.crtc)->pipe;
>  	u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
>  
>  	if ((val & VIDEO_DIP_ENABLE) == 0)
>  		return false;
>  
> -	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->base.port))
> +	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
>  		return false;
>  
>  	return val & (VIDEO_DIP_ENABLE_AVI |
> @@ -380,14 +373,13 @@ static bool vlv_infoframe_enabled(struct drm_encoder *encoder,
>  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
>  }
>  
> -static void hsw_write_infoframe(struct drm_encoder *encoder,
> +static void hsw_write_infoframe(struct intel_encoder *encoder,
>  				const struct intel_crtc_state *crtc_state,
>  				unsigned int type,
>  				const void *frame, ssize_t len)
>  {
>  	const u32 *data = frame;
> -	struct drm_device *dev = encoder->dev;
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
>  	i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
>  	int data_size = type == DP_SDP_VSC ?
> @@ -415,10 +407,10 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
>  	POSTING_READ(ctl_reg);
>  }
>  
> -static bool hsw_infoframe_enabled(struct drm_encoder *encoder,
> +static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(pipe_config->cpu_transcoder));
>  
>  	return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW |
> @@ -443,11 +435,11 @@ static bool hsw_infoframe_enabled(struct drm_encoder *encoder,
>   * trick them by giving an offset into the buffer and moving back the header
>   * bytes by one.
>   */
> -static void intel_write_infoframe(struct drm_encoder *encoder,
> +static void intel_write_infoframe(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *crtc_state,
>  				  union hdmi_infoframe *frame)
>  {
> -	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
> +	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
>  	u8 buffer[VIDEO_DIP_DATA_SIZE];
>  	ssize_t len;
>  
> @@ -461,14 +453,16 @@ static void intel_write_infoframe(struct drm_encoder *encoder,
>  	buffer[3] = 0;
>  	len++;
>  
> -	intel_dig_port->write_infoframe(encoder, crtc_state, frame->any.type, buffer, len);
> +	intel_dig_port->write_infoframe(encoder,
> +					crtc_state,
> +					frame->any.type, buffer, len);
>  }
>  
> -static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
> +static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
>  					 const struct intel_crtc_state *crtc_state,
>  					 const struct drm_connector_state *conn_state)
>  {
> -	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
> +	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
>  	const struct drm_display_mode *adjusted_mode =
>  		&crtc_state->base.adjusted_mode;
>  	struct drm_connector *connector = &intel_hdmi->attached_connector->base;
> @@ -500,10 +494,11 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
>  					    conn_state);
>  
>  	/* TODO: handle pixel repetition for YCBCR420 outputs */
> -	intel_write_infoframe(encoder, crtc_state, &frame);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      &frame);
>  }
>  
> -static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder,
> +static void intel_hdmi_set_spd_infoframe(struct intel_encoder *encoder,
>  					 const struct intel_crtc_state *crtc_state)
>  {
>  	union hdmi_infoframe frame;
> @@ -517,11 +512,12 @@ static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder,
>  
>  	frame.spd.sdi = HDMI_SPD_SDI_PC;
>  
> -	intel_write_infoframe(encoder, crtc_state, &frame);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      &frame);
>  }
>  
>  static void
> -intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
> +intel_hdmi_set_hdmi_infoframe(struct intel_encoder *encoder,
>  			      const struct intel_crtc_state *crtc_state,
>  			      const struct drm_connector_state *conn_state)
>  {
> @@ -534,20 +530,21 @@ intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
>  	if (ret < 0)
>  		return;
>  
> -	intel_write_infoframe(encoder, crtc_state, &frame);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      &frame);
>  }
>  
> -static void g4x_set_infoframes(struct drm_encoder *encoder,
> +static void g4x_set_infoframes(struct intel_encoder *encoder,
>  			       bool enable,
>  			       const struct intel_crtc_state *crtc_state,
>  			       const struct drm_connector_state *conn_state)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> -	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
>  	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
>  	i915_reg_t reg = VIDEO_DIP_CTL;
>  	u32 val = I915_READ(reg);
> -	u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
> +	u32 port = VIDEO_DIP_PORT(encoder->port);
>  
>  	assert_hdmi_port_disabled(intel_hdmi);
>  
> @@ -655,11 +652,11 @@ static bool gcp_default_phase_possible(int pipe_bpp,
>  		 mode->crtc_htotal/2 % pixels_per_group == 0);
>  }
>  
> -static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder,
> +static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
>  					 const struct intel_crtc_state *crtc_state,
>  					 const struct drm_connector_state *conn_state)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
>  	i915_reg_t reg;
>  	u32 val = 0;
> @@ -687,18 +684,18 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder,
>  	return val != 0;
>  }
>  
> -static void ibx_set_infoframes(struct drm_encoder *encoder,
> +static void ibx_set_infoframes(struct intel_encoder *encoder,
>  			       bool enable,
>  			       const struct intel_crtc_state *crtc_state,
>  			       const struct drm_connector_state *conn_state)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
> -	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
> +	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
>  	struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
>  	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
>  	u32 val = I915_READ(reg);
> -	u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
> +	u32 port = VIDEO_DIP_PORT(encoder->port);
>  
>  	assert_hdmi_port_disabled(intel_hdmi);
>  
> @@ -740,14 +737,14 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
>  	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
>  }
>  
> -static void cpt_set_infoframes(struct drm_encoder *encoder,
> +static void cpt_set_infoframes(struct intel_encoder *encoder,
>  			       bool enable,
>  			       const struct intel_crtc_state *crtc_state,
>  			       const struct drm_connector_state *conn_state)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
> -	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
> +	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
>  	i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
>  	u32 val = I915_READ(reg);
>  
> @@ -783,18 +780,17 @@ static void cpt_set_infoframes(struct drm_encoder *encoder,
>  	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
>  }
>  
> -static void vlv_set_infoframes(struct drm_encoder *encoder,
> +static void vlv_set_infoframes(struct intel_encoder *encoder,
>  			       bool enable,
>  			       const struct intel_crtc_state *crtc_state,
>  			       const struct drm_connector_state *conn_state)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> -	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
> -	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
> +	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
>  	i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
>  	u32 val = I915_READ(reg);
> -	u32 port = VIDEO_DIP_PORT(intel_dig_port->base.port);
> +	u32 port = VIDEO_DIP_PORT(encoder->port);
>  
>  	assert_hdmi_port_disabled(intel_hdmi);
>  
> @@ -836,12 +832,12 @@ static void vlv_set_infoframes(struct drm_encoder *encoder,
>  	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
>  }
>  
> -static void hsw_set_infoframes(struct drm_encoder *encoder,
> +static void hsw_set_infoframes(struct intel_encoder *encoder,
>  			       bool enable,
>  			       const struct intel_crtc_state *crtc_state,
>  			       const struct drm_connector_state *conn_state)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
>  	u32 val = I915_READ(reg);
>  
> @@ -1215,7 +1211,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
>  	if (tmp & HDMI_MODE_SELECT_HDMI)
>  		pipe_config->has_hdmi_sink = true;
>  
> -	if (intel_dig_port->infoframe_enabled(&encoder->base, pipe_config))
> +	if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
>  		pipe_config->has_infoframe = true;
>  
>  	if (tmp & SDVO_AUDIO_ENABLE)
> @@ -1436,7 +1432,8 @@ static void intel_disable_hdmi(struct intel_encoder *encoder,
>  		intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true);
>  	}
>  
> -	intel_dig_port->set_infoframes(&encoder->base, false,
> +	intel_dig_port->set_infoframes(encoder,
> +				       false,
>  				       old_crtc_state, old_conn_state);
>  
>  	intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
> @@ -1971,7 +1968,7 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder,
>  
>  	intel_hdmi_prepare(encoder, pipe_config);
>  
> -	intel_dig_port->set_infoframes(&encoder->base,
> +	intel_dig_port->set_infoframes(encoder,
>  				       pipe_config->has_infoframe,
>  				       pipe_config, conn_state);
>  }
> @@ -1989,7 +1986,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder,
>  	vlv_set_phy_signal_level(encoder, 0x2b245f5f, 0x00002000, 0x5578b83a,
>  				 0x2b247878);
>  
> -	dport->set_infoframes(&encoder->base,
> +	dport->set_infoframes(encoder,
>  			      pipe_config->has_infoframe,
>  			      pipe_config, conn_state);
>  
> @@ -2060,7 +2057,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
>  	/* Use 800mV-0dB */
>  	chv_set_phy_signal_level(encoder, 128, 102, false);
>  
> -	dport->set_infoframes(&encoder->base,
> +	dport->set_infoframes(encoder,
>  			      pipe_config->has_infoframe,
>  			      pipe_config, conn_state);
>  
> diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
> index b6838b525502..11fdefaf7728 100644
> --- a/drivers/gpu/drm/i915/intel_psr.c
> +++ b/drivers/gpu/drm/i915/intel_psr.c
> @@ -294,7 +294,8 @@ static void intel_psr_setup_vsc(struct intel_dp *intel_dp,
>  		psr_vsc.sdp_header.HB3 = 0x8;
>  	}
>  
> -	intel_dig_port->write_infoframe(&intel_dig_port->base.base, crtc_state,
> +	intel_dig_port->write_infoframe(&intel_dig_port->base,
> +					crtc_state,
>  					DP_SDP_VSC, &psr_vsc, sizeof(psr_vsc));
>  }
>  
> -- 
> 2.16.4
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-21  8:41     ` Hans Verkuil
@ 2018-09-21 14:01       ` Ville Syrjälä
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 14:01 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 10:41:46AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > We'll be wanting to send more than just infoframes over HDMI. So add an
> > enum for other packet types.
> > 
> > TODO: Maybe just include the infoframe types in the packet type enum
> >       and get rid of the infoframe type enum?
> 
> I think that's better, IMHO. With a comment that the types starting with
> 0x81 are defined in CTA-861-G.
> 
> It's really the same byte that is being checked, so having two enums is
> a bit misleading. The main difference is really which standard defines
> the packet types.

Right. The only slight annoyance is that we'll get a bunch of warnings
from the compiler if we don't handle all the enum valus in the switch
statements. If we want to avoid that I guess I could limit this
to just the null, gcp and gamut metadata packets initially and try to
write some actual code for them. Those three are the only ones we
care about in i915 at the moment.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  include/linux/hdmi.h | 15 +++++++++++++++
> >  1 file changed, 15 insertions(+)
> > 
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index c76b50a48e48..80521d9591a1 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -27,6 +27,21 @@
> >  #include <linux/types.h>
> >  #include <linux/device.h>
> >  
> > +enum hdmi_packet_type {
> > +	HDMI_PACKET_TYPE_NULL = 0x00,
> > +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> > +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> > +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> > +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
> > +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> > +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> > +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> > +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> > +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> > +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> > +	/* + enum hdmi_infoframe_type */
> > +};
> > +
> >  enum hdmi_infoframe_type {
> >  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
> >  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> > 

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
@ 2018-09-21 14:01       ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 14:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: intel-gfx, Hans Verkuil, dri-devel, linux-media

On Fri, Sep 21, 2018 at 10:41:46AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > We'll be wanting to send more than just infoframes over HDMI. So add an
> > enum for other packet types.
> > 
> > TODO: Maybe just include the infoframe types in the packet type enum
> >       and get rid of the infoframe type enum?
> 
> I think that's better, IMHO. With a comment that the types starting with
> 0x81 are defined in CTA-861-G.
> 
> It's really the same byte that is being checked, so having two enums is
> a bit misleading. The main difference is really which standard defines
> the packet types.

Right. The only slight annoyance is that we'll get a bunch of warnings
from the compiler if we don't handle all the enum valus in the switch
statements. If we want to avoid that I guess I could limit this
to just the null, gcp and gamut metadata packets initially and try to
write some actual code for them. Those three are the only ones we
care about in i915 at the moment.

> 
> Regards,
> 
> 	Hans
> 
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  include/linux/hdmi.h | 15 +++++++++++++++
> >  1 file changed, 15 insertions(+)
> > 
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index c76b50a48e48..80521d9591a1 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -27,6 +27,21 @@
> >  #include <linux/types.h>
> >  #include <linux/device.h>
> >  
> > +enum hdmi_packet_type {
> > +	HDMI_PACKET_TYPE_NULL = 0x00,
> > +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> > +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> > +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> > +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
> > +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> > +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> > +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> > +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> > +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> > +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> > +	/* + enum hdmi_infoframe_type */
> > +};
> > +
> >  enum hdmi_infoframe_type {
> >  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
> >  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> > 

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-21 14:01       ` Ville Syrjälä
@ 2018-09-21 14:12         ` Hans Verkuil
  -1 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21 14:12 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 09/21/18 16:01, Ville Syrjälä wrote:
> On Fri, Sep 21, 2018 at 10:41:46AM +0200, Hans Verkuil wrote:
>> On 09/20/18 20:51, Ville Syrjala wrote:
>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>
>>> We'll be wanting to send more than just infoframes over HDMI. So add an
>>> enum for other packet types.
>>>
>>> TODO: Maybe just include the infoframe types in the packet type enum
>>>       and get rid of the infoframe type enum?
>>
>> I think that's better, IMHO. With a comment that the types starting with
>> 0x81 are defined in CTA-861-G.
>>
>> It's really the same byte that is being checked, so having two enums is
>> a bit misleading. The main difference is really which standard defines
>> the packet types.
> 
> Right. The only slight annoyance is that we'll get a bunch of warnings
> from the compiler if we don't handle all the enum valus in the switch
> statements. If we want to avoid that I guess I could limit this
> to just the null, gcp and gamut metadata packets initially and try to
> write some actual code for them. Those three are the only ones we
> care about in i915 at the moment.

Note that I don't have a terribly strong opinion on this, so if using
one enum instead of two causes more problems than it is worth, then
that's fine with me as well.

But you asked, and given a choice with all other things being equal,
then one enum has my preference.

Regards,

	Hans

> 
>>
>> Regards,
>>
>> 	Hans
>>
>>>
>>> Cc: Thierry Reding <thierry.reding@gmail.com>
>>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
>>> Cc: linux-media@vger.kernel.org
>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>> ---
>>>  include/linux/hdmi.h | 15 +++++++++++++++
>>>  1 file changed, 15 insertions(+)
>>>
>>> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
>>> index c76b50a48e48..80521d9591a1 100644
>>> --- a/include/linux/hdmi.h
>>> +++ b/include/linux/hdmi.h
>>> @@ -27,6 +27,21 @@
>>>  #include <linux/types.h>
>>>  #include <linux/device.h>
>>>  
>>> +enum hdmi_packet_type {
>>> +	HDMI_PACKET_TYPE_NULL = 0x00,
>>> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
>>> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
>>> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
>>> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
>>> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
>>> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
>>> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
>>> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
>>> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
>>> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
>>> +	/* + enum hdmi_infoframe_type */
>>> +};
>>> +
>>>  enum hdmi_infoframe_type {
>>>  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
>>>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
>>>
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
@ 2018-09-21 14:12         ` Hans Verkuil
  0 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-09-21 14:12 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, dri-devel, linux-media

On 09/21/18 16:01, Ville Syrjälä wrote:
> On Fri, Sep 21, 2018 at 10:41:46AM +0200, Hans Verkuil wrote:
>> On 09/20/18 20:51, Ville Syrjala wrote:
>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>
>>> We'll be wanting to send more than just infoframes over HDMI. So add an
>>> enum for other packet types.
>>>
>>> TODO: Maybe just include the infoframe types in the packet type enum
>>>       and get rid of the infoframe type enum?
>>
>> I think that's better, IMHO. With a comment that the types starting with
>> 0x81 are defined in CTA-861-G.
>>
>> It's really the same byte that is being checked, so having two enums is
>> a bit misleading. The main difference is really which standard defines
>> the packet types.
> 
> Right. The only slight annoyance is that we'll get a bunch of warnings
> from the compiler if we don't handle all the enum valus in the switch
> statements. If we want to avoid that I guess I could limit this
> to just the null, gcp and gamut metadata packets initially and try to
> write some actual code for them. Those three are the only ones we
> care about in i915 at the moment.

Note that I don't have a terribly strong opinion on this, so if using
one enum instead of two causes more problems than it is worth, then
that's fine with me as well.

But you asked, and given a choice with all other things being equal,
then one enum has my preference.

Regards,

	Hans

> 
>>
>> Regards,
>>
>> 	Hans
>>
>>>
>>> Cc: Thierry Reding <thierry.reding@gmail.com>
>>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
>>> Cc: linux-media@vger.kernel.org
>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>> ---
>>>  include/linux/hdmi.h | 15 +++++++++++++++
>>>  1 file changed, 15 insertions(+)
>>>
>>> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
>>> index c76b50a48e48..80521d9591a1 100644
>>> --- a/include/linux/hdmi.h
>>> +++ b/include/linux/hdmi.h
>>> @@ -27,6 +27,21 @@
>>>  #include <linux/types.h>
>>>  #include <linux/device.h>
>>>  
>>> +enum hdmi_packet_type {
>>> +	HDMI_PACKET_TYPE_NULL = 0x00,
>>> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
>>> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
>>> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
>>> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
>>> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
>>> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
>>> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
>>> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
>>> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
>>> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
>>> +	/* + enum hdmi_infoframe_type */
>>> +};
>>> +
>>>  enum hdmi_infoframe_type {
>>>  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
>>>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
>>>
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Intel-gfx] [PATCH 10/18] drm/i915: Add the missing HDMI gamut metadata packet stuff
  2018-09-20 18:51 ` [PATCH 10/18] drm/i915: Add the missing HDMI gamut metadata packet stuff Ville Syrjala
@ 2018-09-21 14:15   ` Daniel Vetter
  0 siblings, 0 replies; 95+ messages in thread
From: Daniel Vetter @ 2018-09-21 14:15 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:37PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> We have definitions and low level code for everything except the gamut
> metadata HDMI packet. Add the missing bits.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Online Bspec seems to have dropped pre-cpt/snb stuff, but I found some old copies
still :-)

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_reg.h   |  4 +++-
>  drivers/gpu/drm/i915/intel_hdmi.c | 12 ++++++++++++
>  2 files changed, 15 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 4948b352bf4c..c07fd394ca1d 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -4577,6 +4577,7 @@ enum {
>  #define   VIDEO_DIP_ENABLE_SPD		(8 << 21)
>  #define   VIDEO_DIP_SELECT_AVI		(0 << 19)
>  #define   VIDEO_DIP_SELECT_VENDOR	(1 << 19)
> +#define   VIDEO_DIP_SELECT_GAMUT	(2 << 19)
>  #define   VIDEO_DIP_SELECT_SPD		(3 << 19)
>  #define   VIDEO_DIP_SELECT_MASK		(3 << 19)
>  #define   VIDEO_DIP_FREQ_ONCE		(0 << 16)
> @@ -7948,10 +7949,11 @@ enum {
>  #define _ICL_VIDEO_DIP_PPS_ECC_B	0x613D4
>  
>  #define HSW_TVIDEO_DIP_CTL(trans)		_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_CTL_A)
> +#define HSW_TVIDEO_DIP_GCP(trans)		_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GCP_A)
>  #define HSW_TVIDEO_DIP_AVI_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_AVI_DATA_A + (i) * 4)
>  #define HSW_TVIDEO_DIP_VS_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VS_DATA_A + (i) * 4)
>  #define HSW_TVIDEO_DIP_SPD_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_SPD_DATA_A + (i) * 4)
> -#define HSW_TVIDEO_DIP_GCP(trans)		_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GCP_A)
> +#define HSW_TVIDEO_DIP_GMP_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GMP_DATA_A + (i) * 4)
>  #define HSW_TVIDEO_DIP_VSC_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VSC_DATA_A + (i) * 4)
>  #define ICL_VIDEO_DIP_PPS_DATA(trans, i)	_MMIO_TRANS2(trans, _ICL_VIDEO_DIP_PPS_DATA_A + (i) * 4)
>  #define ICL_VIDEO_DIP_PPS_ECC(trans, i)		_MMIO_TRANS2(trans, _ICL_VIDEO_DIP_PPS_ECC_A + (i) * 4)
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index 454f570275e9..c3c2a638d062 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -83,6 +83,8 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
>  static u32 g4x_infoframe_index(unsigned int type)
>  {
>  	switch (type) {
> +	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> +		return VIDEO_DIP_SELECT_GAMUT;
>  	case HDMI_INFOFRAME_TYPE_AVI:
>  		return VIDEO_DIP_SELECT_AVI;
>  	case HDMI_INFOFRAME_TYPE_SPD:
> @@ -98,6 +100,10 @@ static u32 g4x_infoframe_index(unsigned int type)
>  static u32 g4x_infoframe_enable(unsigned int type)
>  {
>  	switch (type) {
> +	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
> +		return VIDEO_DIP_ENABLE_GCP;
> +	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> +		return VIDEO_DIP_ENABLE_GAMUT;
>  	case HDMI_INFOFRAME_TYPE_AVI:
>  		return VIDEO_DIP_ENABLE_AVI;
>  	case HDMI_INFOFRAME_TYPE_SPD:
> @@ -113,6 +119,10 @@ static u32 g4x_infoframe_enable(unsigned int type)
>  static u32 hsw_infoframe_enable(unsigned int type)
>  {
>  	switch (type) {
> +	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
> +		return VIDEO_DIP_ENABLE_GCP_HSW;
> +	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> +		return VIDEO_DIP_ENABLE_GMP_HSW;
>  	case DP_SDP_VSC:
>  		return VIDEO_DIP_ENABLE_VSC_HSW;
>  	case HDMI_INFOFRAME_TYPE_AVI:
> @@ -134,6 +144,8 @@ hsw_dip_data_reg(struct drm_i915_private *dev_priv,
>  		 int i)
>  {
>  	switch (type) {
> +	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> +		return HSW_TVIDEO_DIP_GMP_DATA(cpu_transcoder, i);
>  	case DP_SDP_VSC:
>  		return HSW_TVIDEO_DIP_VSC_DATA(cpu_transcoder, i);
>  	case HDMI_INFOFRAME_TYPE_AVI:
> -- 
> 2.16.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-21  8:24     ` Hans Verkuil
@ 2018-09-21 14:30       ` Ville Syrjälä
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 14:30 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 10:24:25AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Let's make the infoframe pack functions usable with a const infoframe
> > structure. This allows us to precompute the infoframe earlier, and still
> > pack it later when we're no longer allowed to modify the structure.
> > So now we end up with a _check()+_pack_only() or _pack() functions
> > depending on whether you want to precompute the infoframes or not.
> > The names aren't greate but I was lazy and didn't want to change all the
> 
> greate -> great

Thanks for reading through it. Fixed up all the crap you spotted.

> 
> > drivers.
> > 
> > v2: Deal with exynos churn
> >     Actually export the new funcs
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
> >  include/linux/hdmi.h |  19 ++-
> >  2 files changed, 416 insertions(+), 28 deletions(-)
> > 
> > diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> > index 53e7ee2c83fc..9507f668a569 100644
> > --- a/drivers/video/hdmi.c
> > +++ b/drivers/video/hdmi.c
> > @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
> >  }
> >  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
> >  
> > +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
> > +	    frame->version != 2 ||
> > +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> > - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
> > + * hdmi_avi_infoframe_check() - Check and check a HDMI AVI infoframe
> 
> "Check and check"? This is repeated elsewhere as well (clearly copy-and-paste).
> 
> > + * @frame: HDMI AVI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
> > +{
> > +	return hdmi_avi_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
> > +
> > +/**
> > + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
> >   * @frame: HDMI AVI infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> > -				size_t size)
> > +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> > +				     void *buffer, size_t size)
> >  {
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_avi_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> >  	if (size < length)
> >  		return -ENOSPC;
> >  
> > -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> > -		return -EINVAL;
> > -
> >  	memset(buffer, 0, size);
> >  
> >  	ptr[0] = frame->type;
> > @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_avi_infoframe_pack() - Check and check a HDMI AVI infoframe,
> > + *                             and write it to binary buffer
> > + * @frame: HDMI AVI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> 
> which packs -> which it packs
> 
> Ditto elsewhere.
> 
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> 
> Also -> This function also
> 
> Ditto elsewhere.
> 
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
> > +				void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_avi_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
> >  
> >  /**
> > @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
> >  }
> >  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
> >  
> > +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
> > +	    frame->version != 1 ||
> > +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> > - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
> > + * hdmi_spd_infoframe_check() - Check and check a HDMI SPD infoframe
> > + * @frame: HDMI SPD infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
> > +{
> > +	return hdmi_spd_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
> > +
> > +/**
> > + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
> >   * @frame: HDMI SPD infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> > -				size_t size)
> > +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> > +				     void *buffer, size_t size)
> >  {
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_spd_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> > @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_spd_infoframe_pack() - Check and check a HDMI SPD infoframe,
> > + *                             and write it to binary buffer
> > + * @frame: HDMI SPD infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
> > +				void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_spd_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
> >  
> >  /**
> > @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
> >  }
> >  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
> >  
> > +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
> > +	    frame->version != 1 ||
> > +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * hdmi_audio_infoframe_check() - Check and check a HDMI audio infoframe
> > + * @frame: HDMI audio infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
> > +{
> > +	return hdmi_audio_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
> > +
> >  /**
> > - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
> > + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
> >   * @frame: HDMI audio infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> > -				  void *buffer, size_t size)
> > +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> > +				       void *buffer, size_t size)
> >  {
> >  	unsigned char channels;
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_audio_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> > @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_audio_infoframe_pack() - Check and check a HDMI Audio infoframe,
> > + *                               and write it to binary buffer
> > + * @frame: HDMI Audio infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> > +				  void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_audio_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
> >  
> >  /**
> > @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
> >  	 * value
> >  	 */
> >  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
> > +	frame->length = 4;
> >  
> >  	return 0;
> >  }
> > @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
> >  		return 4;
> >  }
> >  
> > +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
> > +	    frame->version != 1 ||
> > +	    frame->oui != HDMI_IEEE_OUI)
> > +		return -EINVAL;
> > +
> > +	/* only one of those can be supplied */
> > +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> > +		return -EINVAL;
> > +
> > +	if (frame->length != hdmi_vendor_infoframe_length(frame))
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> > - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
> > + * hdmi_vendor_infoframe_check() - Check and check a HDMI vendor infoframe
> > + * @frame: HDMI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
> > +{
> > +	frame->length = hdmi_vendor_infoframe_length(frame);
> > +
> > +	return hdmi_vendor_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
> > +
> > +/**
> > + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
> >   * @frame: HDMI infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> > -				 void *buffer, size_t size)
> > +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> > +					void *buffer, size_t size)
> >  {
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> >  
> > -	/* only one of those can be supplied */
> > -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> > -		return -EINVAL;
> > -
> > -	frame->length = hdmi_vendor_infoframe_length(frame);
> > +	ret = hdmi_vendor_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> > @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_vendor_infoframe_pack() - Check and check a HDMI Vendor infoframe,
> > + *                                and write it to binary buffer
> > + * @frame: HDMI Vendor infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> > +				   void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
> >  
> > +static int
> > +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
> > +{
> > +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
> > +	    frame->any.version != 1)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /*
> > - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
> > + * hdmi_vendor_any_infoframe_check() - check and check a vendor infoframe
> > + */
> > +static int
> > +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* we only know about HDMI vendor infoframes */
> > +	if (frame->any.oui != HDMI_IEEE_OUI)
> > +		return -EINVAL;
> > +
> > +	return hdmi_vendor_infoframe_check(&frame->hdmi);
> > +}
> > +
> > +/*
> > + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
> >   */
> >  static ssize_t
> > -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> > -			   void *buffer, size_t size)
> > +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
> > +				    void *buffer, size_t size)
> >  {
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> >  	/* we only know about HDMI vendor infoframes */
> >  	if (frame->any.oui != HDMI_IEEE_OUI)
> >  		return -EINVAL;
> >  
> > -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
> > +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
> > +}
> > +
> > +/*
> > + * hdmi_vendor_any_infoframe_pack() - check and check a vendor infoframe,
> > + *                                              and write it to binary buffer
> > + */
> > +static ssize_t
> > +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> > +			       void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_any_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> > +}
> > +
> > +/**
> > + * hdmi_infoframe_check() - Check check a HDMI infoframe
> > + * @frame: HDMI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int
> > +hdmi_infoframe_check(union hdmi_infoframe *frame)
> > +{
> > +	switch (frame->any.type) {
> > +	case HDMI_INFOFRAME_TYPE_AVI:
> > +		return hdmi_avi_infoframe_check(&frame->avi);
> > +	case HDMI_INFOFRAME_TYPE_SPD:
> > +		return hdmi_spd_infoframe_check(&frame->spd);
> > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > +		return hdmi_audio_infoframe_check(&frame->audio);
> > +	case HDMI_INFOFRAME_TYPE_VENDOR:
> > +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> > +	default:
> > +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> > +		return -EINVAL;
> > +	}
> >  }
> > +EXPORT_SYMBOL(hdmi_infoframe_check);
> >  
> >  /**
> > - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
> > + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
> >   * @frame: HDMI infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> >   * error code on failure.
> >   */
> >  ssize_t
> > -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
> > +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
> > +{
> > +	ssize_t length;
> > +
> > +	switch (frame->any.type) {
> > +	case HDMI_INFOFRAME_TYPE_AVI:
> > +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
> > +						      buffer, size);
> > +		break;
> > +	case HDMI_INFOFRAME_TYPE_SPD:
> > +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
> > +						      buffer, size);
> > +		break;
> > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
> > +							buffer, size);
> > +		break;
> > +	case HDMI_INFOFRAME_TYPE_VENDOR:
> > +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> > +							     buffer, size);
> > +		break;
> > +	default:
> > +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> > +		length = -EINVAL;
> > +	}
> > +
> > +	return length;
> > +}
> > +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_infoframe_pack() - Check check a HDMI infoframe,
> 
> Check check?
> 
> > + *                         and write it to binary buffer
> > + * @frame: HDMI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t
> > +hdmi_infoframe_pack(union hdmi_infoframe *frame,
> > +		    void *buffer, size_t size)
> >  {
> >  	ssize_t length;
> >  
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index bce1abb1fe57..c76b50a48e48 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
> >  int 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);
> > +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> > +				     void *buffer, size_t size);
> > +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
> >  
> >  enum hdmi_spd_sdi {
> >  	HDMI_SPD_SDI_UNKNOWN,
> > @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
> >  			    const char *vendor, const char *product);
> >  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> >  				size_t size);
> > +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> > +				     void *buffer, size_t size);
> > +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
> >  
> >  enum hdmi_audio_coding_type {
> >  	HDMI_AUDIO_CODING_TYPE_STREAM,
> > @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
> >  int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
> >  ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> >  				  void *buffer, size_t size);
> > +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> > +				       void *buffer, size_t size);
> > +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
> >  
> >  enum hdmi_3d_structure {
> >  	HDMI_3D_STRUCTURE_INVALID = -1,
> > @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
> >  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
> >  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> >  				   void *buffer, size_t size);
> > +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> > +					void *buffer, size_t size);
> > +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
> >  
> >  union hdmi_vendor_any_infoframe {
> >  	struct {
> > @@ -330,8 +342,11 @@ union hdmi_infoframe {
> >  	struct hdmi_audio_infoframe audio;
> >  };
> >  
> > -ssize_t
> > -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> > +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> > +			    size_t size);
> > +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
> > +				 void *buffer, size_t size);
> > +int hdmi_infoframe_check(union hdmi_infoframe *frame);
> >  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> >  			  const void *buffer, size_t size);
> >  void hdmi_infoframe_log(const char *level, struct device *dev,
> > 
> 
> Regards,
> 
> 	Hans

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions
@ 2018-09-21 14:30       ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 14:30 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: intel-gfx, Hans Verkuil, dri-devel, linux-media

On Fri, Sep 21, 2018 at 10:24:25AM +0200, Hans Verkuil wrote:
> On 09/20/18 20:51, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Let's make the infoframe pack functions usable with a const infoframe
> > structure. This allows us to precompute the infoframe earlier, and still
> > pack it later when we're no longer allowed to modify the structure.
> > So now we end up with a _check()+_pack_only() or _pack() functions
> > depending on whether you want to precompute the infoframes or not.
> > The names aren't greate but I was lazy and didn't want to change all the
> 
> greate -> great

Thanks for reading through it. Fixed up all the crap you spotted.

> 
> > drivers.
> > 
> > v2: Deal with exynos churn
> >     Actually export the new funcs
> > 
> > Cc: Thierry Reding <thierry.reding@gmail.com>
> > Cc: Hans Verkuil <hans.verkuil@cisco.com>
> > Cc: linux-media@vger.kernel.org
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
> >  include/linux/hdmi.h |  19 ++-
> >  2 files changed, 416 insertions(+), 28 deletions(-)
> > 
> > diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> > index 53e7ee2c83fc..9507f668a569 100644
> > --- a/drivers/video/hdmi.c
> > +++ b/drivers/video/hdmi.c
> > @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
> >  }
> >  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
> >  
> > +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
> > +	    frame->version != 2 ||
> > +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> > - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
> > + * hdmi_avi_infoframe_check() - Check and check a HDMI AVI infoframe
> 
> "Check and check"? This is repeated elsewhere as well (clearly copy-and-paste).
> 
> > + * @frame: HDMI AVI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
> > +{
> > +	return hdmi_avi_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
> > +
> > +/**
> > + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
> >   * @frame: HDMI AVI infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> > -				size_t size)
> > +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> > +				     void *buffer, size_t size)
> >  {
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_avi_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> >  	if (size < length)
> >  		return -ENOSPC;
> >  
> > -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> > -		return -EINVAL;
> > -
> >  	memset(buffer, 0, size);
> >  
> >  	ptr[0] = frame->type;
> > @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_avi_infoframe_pack() - Check and check a HDMI AVI infoframe,
> > + *                             and write it to binary buffer
> > + * @frame: HDMI AVI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> 
> which packs -> which it packs
> 
> Ditto elsewhere.
> 
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> 
> Also -> This function also
> 
> Ditto elsewhere.
> 
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
> > +				void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_avi_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
> >  
> >  /**
> > @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
> >  }
> >  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
> >  
> > +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
> > +	    frame->version != 1 ||
> > +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> > - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
> > + * hdmi_spd_infoframe_check() - Check and check a HDMI SPD infoframe
> > + * @frame: HDMI SPD infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
> > +{
> > +	return hdmi_spd_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
> > +
> > +/**
> > + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
> >   * @frame: HDMI SPD infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> > -				size_t size)
> > +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> > +				     void *buffer, size_t size)
> >  {
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_spd_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> > @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_spd_infoframe_pack() - Check and check a HDMI SPD infoframe,
> > + *                             and write it to binary buffer
> > + * @frame: HDMI SPD infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
> > +				void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_spd_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
> >  
> >  /**
> > @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
> >  }
> >  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
> >  
> > +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
> > +	    frame->version != 1 ||
> > +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * hdmi_audio_infoframe_check() - Check and check a HDMI audio infoframe
> > + * @frame: HDMI audio infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
> > +{
> > +	return hdmi_audio_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
> > +
> >  /**
> > - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
> > + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
> >   * @frame: HDMI audio infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> > -				  void *buffer, size_t size)
> > +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> > +				       void *buffer, size_t size)
> >  {
> >  	unsigned char channels;
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> > +
> > +	ret = hdmi_audio_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> > @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_audio_infoframe_pack() - Check and check a HDMI Audio infoframe,
> > + *                               and write it to binary buffer
> > + * @frame: HDMI Audio infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> > +				  void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_audio_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
> >  
> >  /**
> > @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
> >  	 * value
> >  	 */
> >  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
> > +	frame->length = 4;
> >  
> >  	return 0;
> >  }
> > @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
> >  		return 4;
> >  }
> >  
> > +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
> > +{
> > +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
> > +	    frame->version != 1 ||
> > +	    frame->oui != HDMI_IEEE_OUI)
> > +		return -EINVAL;
> > +
> > +	/* only one of those can be supplied */
> > +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> > +		return -EINVAL;
> > +
> > +	if (frame->length != hdmi_vendor_infoframe_length(frame))
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /**
> > - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
> > + * hdmi_vendor_infoframe_check() - Check and check a HDMI vendor infoframe
> > + * @frame: HDMI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
> > +{
> > +	frame->length = hdmi_vendor_infoframe_length(frame);
> > +
> > +	return hdmi_vendor_infoframe_check_only(frame);
> > +}
> > +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
> > +
> > +/**
> > + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
> >   * @frame: HDMI infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
> >   * Returns the number of bytes packed into the binary buffer or a negative
> >   * error code on failure.
> >   */
> > -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> > -				 void *buffer, size_t size)
> > +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> > +					void *buffer, size_t size)
> >  {
> >  	u8 *ptr = buffer;
> >  	size_t length;
> > +	int ret;
> >  
> > -	/* only one of those can be supplied */
> > -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> > -		return -EINVAL;
> > -
> > -	frame->length = hdmi_vendor_infoframe_length(frame);
> > +	ret = hdmi_vendor_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> >  
> >  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
> >  
> > @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> >  
> >  	return length;
> >  }
> > +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_vendor_infoframe_pack() - Check and check a HDMI Vendor infoframe,
> > + *                                and write it to binary buffer
> > + * @frame: HDMI Vendor infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> > +				   void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
> > +}
> >  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
> >  
> > +static int
> > +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
> > +{
> > +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
> > +	    frame->any.version != 1)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> >  /*
> > - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
> > + * hdmi_vendor_any_infoframe_check() - check and check a vendor infoframe
> > + */
> > +static int
> > +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* we only know about HDMI vendor infoframes */
> > +	if (frame->any.oui != HDMI_IEEE_OUI)
> > +		return -EINVAL;
> > +
> > +	return hdmi_vendor_infoframe_check(&frame->hdmi);
> > +}
> > +
> > +/*
> > + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
> >   */
> >  static ssize_t
> > -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> > -			   void *buffer, size_t size)
> > +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
> > +				    void *buffer, size_t size)
> >  {
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> > +	if (ret)
> > +		return ret;
> > +
> >  	/* we only know about HDMI vendor infoframes */
> >  	if (frame->any.oui != HDMI_IEEE_OUI)
> >  		return -EINVAL;
> >  
> > -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
> > +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
> > +}
> > +
> > +/*
> > + * hdmi_vendor_any_infoframe_pack() - check and check a vendor infoframe,
> > + *                                              and write it to binary buffer
> > + */
> > +static ssize_t
> > +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> > +			       void *buffer, size_t size)
> > +{
> > +	int ret;
> > +
> > +	ret = hdmi_vendor_any_infoframe_check(frame);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> > +}
> > +
> > +/**
> > + * hdmi_infoframe_check() - Check check a HDMI infoframe
> > + * @frame: HDMI infoframe
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields.
> > + *
> > + * Returns 0 on success or a negative error code on failure.
> > + */
> > +int
> > +hdmi_infoframe_check(union hdmi_infoframe *frame)
> > +{
> > +	switch (frame->any.type) {
> > +	case HDMI_INFOFRAME_TYPE_AVI:
> > +		return hdmi_avi_infoframe_check(&frame->avi);
> > +	case HDMI_INFOFRAME_TYPE_SPD:
> > +		return hdmi_spd_infoframe_check(&frame->spd);
> > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > +		return hdmi_audio_infoframe_check(&frame->audio);
> > +	case HDMI_INFOFRAME_TYPE_VENDOR:
> > +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> > +	default:
> > +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> > +		return -EINVAL;
> > +	}
> >  }
> > +EXPORT_SYMBOL(hdmi_infoframe_check);
> >  
> >  /**
> > - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
> > + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
> >   * @frame: HDMI infoframe
> >   * @buffer: destination buffer
> >   * @size: size of buffer
> > @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> >   * error code on failure.
> >   */
> >  ssize_t
> > -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
> > +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
> > +{
> > +	ssize_t length;
> > +
> > +	switch (frame->any.type) {
> > +	case HDMI_INFOFRAME_TYPE_AVI:
> > +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
> > +						      buffer, size);
> > +		break;
> > +	case HDMI_INFOFRAME_TYPE_SPD:
> > +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
> > +						      buffer, size);
> > +		break;
> > +	case HDMI_INFOFRAME_TYPE_AUDIO:
> > +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
> > +							buffer, size);
> > +		break;
> > +	case HDMI_INFOFRAME_TYPE_VENDOR:
> > +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> > +							     buffer, size);
> > +		break;
> > +	default:
> > +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> > +		length = -EINVAL;
> > +	}
> > +
> > +	return length;
> > +}
> > +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
> > +
> > +/**
> > + * hdmi_infoframe_pack() - Check check a HDMI infoframe,
> 
> Check check?
> 
> > + *                         and write it to binary buffer
> > + * @frame: HDMI infoframe
> > + * @buffer: destination buffer
> > + * @size: size of buffer
> > + *
> > + * Validates that the infoframe is consistent and updates derived fields
> > + * (eg. length) based on other fields, after which packs the information
> > + * contained in the @frame structure into a binary representation that
> > + * can be written into the corresponding controller registers. Also
> > + * computes the checksum as required by section 5.3.5 of the HDMI 1.4
> > + * specification.
> > + *
> > + * Returns the number of bytes packed into the binary buffer or a negative
> > + * error code on failure.
> > + */
> > +ssize_t
> > +hdmi_infoframe_pack(union hdmi_infoframe *frame,
> > +		    void *buffer, size_t size)
> >  {
> >  	ssize_t length;
> >  
> > diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> > index bce1abb1fe57..c76b50a48e48 100644
> > --- a/include/linux/hdmi.h
> > +++ b/include/linux/hdmi.h
> > @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
> >  int 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);
> > +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> > +				     void *buffer, size_t size);
> > +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
> >  
> >  enum hdmi_spd_sdi {
> >  	HDMI_SPD_SDI_UNKNOWN,
> > @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
> >  			    const char *vendor, const char *product);
> >  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> >  				size_t size);
> > +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> > +				     void *buffer, size_t size);
> > +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
> >  
> >  enum hdmi_audio_coding_type {
> >  	HDMI_AUDIO_CODING_TYPE_STREAM,
> > @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
> >  int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
> >  ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> >  				  void *buffer, size_t size);
> > +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> > +				       void *buffer, size_t size);
> > +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
> >  
> >  enum hdmi_3d_structure {
> >  	HDMI_3D_STRUCTURE_INVALID = -1,
> > @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
> >  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
> >  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> >  				   void *buffer, size_t size);
> > +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> > +					void *buffer, size_t size);
> > +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
> >  
> >  union hdmi_vendor_any_infoframe {
> >  	struct {
> > @@ -330,8 +342,11 @@ union hdmi_infoframe {
> >  	struct hdmi_audio_infoframe audio;
> >  };
> >  
> > -ssize_t
> > -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> > +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> > +			    size_t size);
> > +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
> > +				 void *buffer, size_t size);
> > +int hdmi_infoframe_check(union hdmi_infoframe *frame);
> >  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
> >  			  const void *buffer, size_t size);
> >  void hdmi_infoframe_log(const char *level, struct device *dev,
> > 
> 
> Regards,
> 
> 	Hans

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH v3 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21 14:33     ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-21 14:33 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Let's make the infoframe pack functions usable with a const infoframe
structure. This allows us to precompute the infoframe earlier, and still
pack it later when we're no longer allowed to modify the structure.
So now we end up with a _check()+_pack_only() or _pack() functions
depending on whether you want to precompute the infoframes or not.
The names aren't great but I was lazy and didn't want to change all the
drivers.

v2: Deal with exynos churn
    Actually export the new funcs
v3: Fix various documentation fails (Hans)

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
 include/linux/hdmi.h |  19 ++-
 2 files changed, 416 insertions(+), 28 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 53e7ee2c83fc..08d94ab00467 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_avi_infoframe_init);
 
+static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
+	    frame->version != 2 ||
+	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
+ * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
+{
+	return hdmi_avi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_check);
+
+/**
+ * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
  * @frame: HDMI AVI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_avi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
 	if (size < length)
 		return -ENOSPC;
 
-	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
-		return -EINVAL;
-
 	memset(buffer, 0, size);
 
 	ptr[0] = frame->type;
@@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
+
+/**
+ * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_avi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
 
 /**
@@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 }
 EXPORT_SYMBOL(hdmi_spd_infoframe_init);
 
+static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
+ * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
+{
+	return hdmi_spd_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_check);
+
+/**
+ * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
  * @frame: HDMI SPD infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_spd_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
+
+/**
+ * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_spd_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
 
 /**
@@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_audio_infoframe_init);
 
+static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+{
+	return hdmi_audio_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+
 /**
- * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
+ * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
  * @frame: HDMI audio infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
-				  void *buffer, size_t size)
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size)
 {
 	unsigned char channels;
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_audio_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
+
+/**
+ * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
+ *                               and write it to binary buffer
+ * @frame: HDMI Audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+				  void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_audio_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
 
 /**
@@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
 	 * value
 	 */
 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+	frame->length = 4;
 
 	return 0;
 }
@@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
 		return 4;
 }
 
+static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->version != 1 ||
+	    frame->oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	/* only one of those can be supplied */
+	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+		return -EINVAL;
+
+	if (frame->length != hdmi_vendor_infoframe_length(frame))
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
+ * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
+{
+	frame->length = hdmi_vendor_infoframe_length(frame);
+
+	return hdmi_vendor_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
+
+/**
+ * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
-				 void *buffer, size_t size)
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
 
-	/* only one of those can be supplied */
-	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
-		return -EINVAL;
-
-	frame->length = hdmi_vendor_infoframe_length(frame);
+	ret = hdmi_vendor_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
+
+/**
+ * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
+ *                                and write it to binary buffer
+ * @frame: HDMI Vendor infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+				   void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
 
+static int
+hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
+{
+	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->any.version != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
 /*
- * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
+ * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
+ */
+static int
+hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	/* we only know about HDMI vendor infoframes */
+	if (frame->any.oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	return hdmi_vendor_infoframe_check(&frame->hdmi);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
  */
 static ssize_t
-hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
-			   void *buffer, size_t size)
+hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
+				    void *buffer, size_t size)
 {
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
 	/* we only know about HDMI vendor infoframes */
 	if (frame->any.oui != HDMI_IEEE_OUI)
 		return -EINVAL;
 
-	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
+	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
+ *                                    and write it to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
+			       void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
+}
+
+/**
+ * hdmi_infoframe_check() - check a HDMI infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+hdmi_infoframe_check(union hdmi_infoframe *frame)
+{
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		return hdmi_avi_infoframe_check(&frame->avi);
+	case HDMI_INFOFRAME_TYPE_SPD:
+		return hdmi_spd_infoframe_check(&frame->spd);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		return hdmi_audio_infoframe_check(&frame->audio);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		return -EINVAL;
+	}
 }
+EXPORT_SYMBOL(hdmi_infoframe_check);
 
 /**
- * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
+ * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
  * error code on failure.
  */
 ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
+hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
+{
+	ssize_t length;
+
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		length = hdmi_avi_infoframe_pack_only(&frame->avi,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_SPD:
+		length = hdmi_spd_infoframe_pack_only(&frame->spd,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		length = hdmi_audio_infoframe_pack_only(&frame->audio,
+							buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
+							     buffer, size);
+		break;
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		length = -EINVAL;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack_only);
+
+/**
+ * hdmi_infoframe_pack() - check a HDMI infoframe,
+ *                         and write it to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t
+hdmi_infoframe_pack(union hdmi_infoframe *frame,
+		    void *buffer, size_t size)
 {
 	ssize_t length;
 
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index bce1abb1fe57..c76b50a48e48 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
 int 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);
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
 
 enum hdmi_spd_sdi {
 	HDMI_SPD_SDI_UNKNOWN,
@@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 			    const char *vendor, const char *product);
 ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 				size_t size);
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
 
 enum hdmi_audio_coding_type {
 	HDMI_AUDIO_CODING_TYPE_STREAM,
@@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
 int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
 ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 				  void *buffer, size_t size);
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size);
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
 
 enum hdmi_3d_structure {
 	HDMI_3D_STRUCTURE_INVALID = -1,
@@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
 int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
 ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 				   void *buffer, size_t size);
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size);
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
 
 union hdmi_vendor_any_infoframe {
 	struct {
@@ -330,8 +342,11 @@ union hdmi_infoframe {
 	struct hdmi_audio_infoframe audio;
 };
 
-ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
+ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
+			    size_t size);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
+				 void *buffer, size_t size);
+int hdmi_infoframe_check(union hdmi_infoframe *frame);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v3 04/18] video/hdmi: Constify infoframe passed to the pack functions
@ 2018-09-21 14:33     ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-21 14:33 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Let's make the infoframe pack functions usable with a const infoframe
structure. This allows us to precompute the infoframe earlier, and still
pack it later when we're no longer allowed to modify the structure.
So now we end up with a _check()+_pack_only() or _pack() functions
depending on whether you want to precompute the infoframes or not.
The names aren't great but I was lazy and didn't want to change all the
drivers.

v2: Deal with exynos churn
    Actually export the new funcs
v3: Fix various documentation fails (Hans)

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
 include/linux/hdmi.h |  19 ++-
 2 files changed, 416 insertions(+), 28 deletions(-)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 53e7ee2c83fc..08d94ab00467 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_avi_infoframe_init);
 
+static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
+	    frame->version != 2 ||
+	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
+ * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
+{
+	return hdmi_avi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_check);
+
+/**
+ * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
  * @frame: HDMI AVI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_avi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
 	if (size < length)
 		return -ENOSPC;
 
-	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
-		return -EINVAL;
-
 	memset(buffer, 0, size);
 
 	ptr[0] = frame->type;
@@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
+
+/**
+ * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_avi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
 
 /**
@@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 }
 EXPORT_SYMBOL(hdmi_spd_infoframe_init);
 
+static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
+ * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
+{
+	return hdmi_spd_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_check);
+
+/**
+ * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
  * @frame: HDMI SPD infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
-				size_t size)
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_spd_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
+
+/**
+ * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
+ *                             and write it to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
+				void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_spd_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
 
 /**
@@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
 }
 EXPORT_SYMBOL(hdmi_audio_infoframe_init);
 
+static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+{
+	return hdmi_audio_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+
 /**
- * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
+ * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
  * @frame: HDMI audio infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
-				  void *buffer, size_t size)
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size)
 {
 	unsigned char channels;
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
+
+	ret = hdmi_audio_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
+
+/**
+ * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
+ *                               and write it to binary buffer
+ * @frame: HDMI Audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+				  void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_audio_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
 
 /**
@@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
 	 * value
 	 */
 	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+	frame->length = 4;
 
 	return 0;
 }
@@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
 		return 4;
 }
 
+static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->version != 1 ||
+	    frame->oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	/* only one of those can be supplied */
+	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+		return -EINVAL;
+
+	if (frame->length != hdmi_vendor_infoframe_length(frame))
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
- * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
+ * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
+{
+	frame->length = hdmi_vendor_infoframe_length(frame);
+
+	return hdmi_vendor_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
+
+/**
+ * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
  * Returns the number of bytes packed into the binary buffer or a negative
  * error code on failure.
  */
-ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
-				 void *buffer, size_t size)
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size)
 {
 	u8 *ptr = buffer;
 	size_t length;
+	int ret;
 
-	/* only one of those can be supplied */
-	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
-		return -EINVAL;
-
-	frame->length = hdmi_vendor_infoframe_length(frame);
+	ret = hdmi_vendor_infoframe_check_only(frame);
+	if (ret)
+		return ret;
 
 	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
 
@@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 
 	return length;
 }
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
+
+/**
+ * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
+ *                                and write it to binary buffer
+ * @frame: HDMI Vendor infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+				   void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
+}
 EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
 
+static int
+hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
+{
+	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+	    frame->any.version != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
 /*
- * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
+ * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
+ */
+static int
+hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	/* we only know about HDMI vendor infoframes */
+	if (frame->any.oui != HDMI_IEEE_OUI)
+		return -EINVAL;
+
+	return hdmi_vendor_infoframe_check(&frame->hdmi);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
  */
 static ssize_t
-hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
-			   void *buffer, size_t size)
+hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
+				    void *buffer, size_t size)
 {
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
 	/* we only know about HDMI vendor infoframes */
 	if (frame->any.oui != HDMI_IEEE_OUI)
 		return -EINVAL;
 
-	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
+	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
+ *                                    and write it to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
+			       void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_vendor_any_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
+}
+
+/**
+ * hdmi_infoframe_check() - check a HDMI infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+hdmi_infoframe_check(union hdmi_infoframe *frame)
+{
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		return hdmi_avi_infoframe_check(&frame->avi);
+	case HDMI_INFOFRAME_TYPE_SPD:
+		return hdmi_spd_infoframe_check(&frame->spd);
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		return hdmi_audio_infoframe_check(&frame->audio);
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		return -EINVAL;
+	}
 }
+EXPORT_SYMBOL(hdmi_infoframe_check);
 
 /**
- * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
+ * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
  * @frame: HDMI infoframe
  * @buffer: destination buffer
  * @size: size of buffer
@@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
  * error code on failure.
  */
 ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
+hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
+{
+	ssize_t length;
+
+	switch (frame->any.type) {
+	case HDMI_INFOFRAME_TYPE_AVI:
+		length = hdmi_avi_infoframe_pack_only(&frame->avi,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_SPD:
+		length = hdmi_spd_infoframe_pack_only(&frame->spd,
+						      buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_AUDIO:
+		length = hdmi_audio_infoframe_pack_only(&frame->audio,
+							buffer, size);
+		break;
+	case HDMI_INFOFRAME_TYPE_VENDOR:
+		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
+							     buffer, size);
+		break;
+	default:
+		WARN(1, "Bad infoframe type %d\n", frame->any.type);
+		length = -EINVAL;
+	}
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack_only);
+
+/**
+ * hdmi_infoframe_pack() - check a HDMI infoframe,
+ *                         and write it to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t
+hdmi_infoframe_pack(union hdmi_infoframe *frame,
+		    void *buffer, size_t size)
 {
 	ssize_t length;
 
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index bce1abb1fe57..c76b50a48e48 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
 int 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);
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
 
 enum hdmi_spd_sdi {
 	HDMI_SPD_SDI_UNKNOWN,
@@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
 			    const char *vendor, const char *product);
 ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
 				size_t size);
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+				     void *buffer, size_t size);
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
 
 enum hdmi_audio_coding_type {
 	HDMI_AUDIO_CODING_TYPE_STREAM,
@@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
 int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
 ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
 				  void *buffer, size_t size);
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+				       void *buffer, size_t size);
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
 
 enum hdmi_3d_structure {
 	HDMI_3D_STRUCTURE_INVALID = -1,
@@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
 int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
 ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
 				   void *buffer, size_t size);
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+					void *buffer, size_t size);
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
 
 union hdmi_vendor_any_infoframe {
 	struct {
@@ -330,8 +342,11 @@ union hdmi_infoframe {
 	struct hdmi_audio_infoframe audio;
 };
 
-ssize_t
-hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
+ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
+			    size_t size);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
+				 void *buffer, size_t size);
+int hdmi_infoframe_check(union hdmi_infoframe *frame);
 int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 			  const void *buffer, size_t size);
 void hdmi_infoframe_log(const char *level, struct device *dev,
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* ✗ Fi.CI.BAT: failure for drm/i915: Infoframe precompute/check (rev2)
  2018-09-20 18:51 ` Ville Syrjala
                   ` (22 preceding siblings ...)
  (?)
@ 2018-09-21 14:40 ` Patchwork
  -1 siblings, 0 replies; 95+ messages in thread
From: Patchwork @ 2018-09-21 14:40 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Infoframe precompute/check (rev2)
URL   : https://patchwork.freedesktop.org/series/49983/
State : failure

== Summary ==

Applying: video/hdmi: Constify 'buffer' to the unpack functions
Applying: video/hdmi: Pass buffer size to infoframe unpack functions
Applying: video/hdmi: Constify infoframe passed to the log functions
Applying: video/hdmi: Constify infoframe passed to the pack functions
Applying: video/hdmi: Add an enum for HDMI packet types
Applying: video/hdmi: Handle the MPEG Source infoframe
Using index info to reconstruct a base tree...
M	drivers/video/hdmi.c
Falling back to patching base and 3-way merge...
Auto-merging drivers/video/hdmi.c
CONFLICT (content): Merge conflict in drivers/video/hdmi.c
error: Failed to merge in the changes.
Patch failed at 0006 video/hdmi: Handle the MPEG Source infoframe
Use 'git am --show-current-patch' to see the failed patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 09/18] drm/i915: Pass intel_encoder to infoframe functions
  2018-09-21 13:59   ` Daniel Vetter
@ 2018-09-21 15:03     ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 15:03 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Fri, Sep 21, 2018 at 03:59:06PM +0200, Daniel Vetter wrote:
> On Thu, Sep 20, 2018 at 09:51:36PM +0300, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Make life simpler by passing around intel_encoder instead of
> > drm_encoder.
> > 
> > @r1@
> > identifier F =~ "infoframe";
> > identifier I, M;
> > @@
> > F(
> > - struct drm_encoder *I
> > + struct intel_encoder *I
> >   , ...)
> > {
> > <...
> > (
> > - I->M
> > + I->base.M
> > |
> > - I
> > + &I->base
> > )
> > ...>
> > }
> > 
> > @r2@
> > identifier F =~ "infoframe";
> > identifier I;
> > type T, ST;
> > @@
> > ST {
> > ...
> > 	T (*F)(
> > -	       struct drm_encoder *I
> > +	       struct intel_encoder *encoder
> > 	       , ...);
> > ...
> > };
> > 
> > @@
> > identifier r1.F;
> > expression E;
> > @@
> > F(
> > - E
> > + to_intel_encoder(E)
> >   ,...)
> > 
> > @@
> > identifier r2.F;
> > expression E, X;
> > @@
> > (
> > X.F(
> > -   E
> > +   to_intel_encoder(E)
> >     ,...)
> > |
> > X->F(
> > -    E
> > +    to_intel_encoder(E)
> >      ,...)
> > )
> > 
> > @@
> > expression E;
> > @@
> > (
> > - to_intel_encoder(&E->base)
> > + E
> > |
> > - to_intel_encoder(&E->base.base)
> > + &E->base
> > )
> > 
> > @@
> > identifier D, M;
> > expression E;
> > @@
> >  D = enc_to_dig_port(&E->base)
> > <...
> > (
> > - D->base.M
> > + E->M
> > |
> > - &D->base
> > + E
> > )
> > ...>
> > 
> > @@
> > identifier D;
> > expression E;
> > type T;
> > @@
> > - T D = enc_to_dig_port(E);
> > ... when != D
> 
> Someone knows a lot more cocci than I do, impressive. How do you figure
> this stuff out? Read the source?

A combination of reading the docs, looking at other cocci scripts,
cursing, and lost hair. And every time I repeat the process
because I've forgotten what I learned last time around.

> 
> Also seems to have some manual fixups below, so I just looked at the diff.
> That looks fine.

I might have accidentally tweaked things when I rebased this. Should
have re-run the cocci script actually. Would be nice if git rebase
did that for you automagically.

I just re-ran spatch and that highlighted five occurances of the
following manual change I had made "accidentally" while rebasing:

++<<<<<<< HEAD
+      struct drm_device *dev = encoder->base.dev;
+      struct drm_i915_private *dev_priv = to_i915(dev);
++=======
+      struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
++>>>>>>> 8cdf27dd7e50... drm/i915: Pass intel_encoder to infoframe functions

Nothing else had been tweaked apparently.

> 
> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Thanks.

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-21 14:12         ` Hans Verkuil
@ 2018-09-21 15:07           ` Ville Syrjälä
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 15:07 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: dri-devel, intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 04:12:36PM +0200, Hans Verkuil wrote:
> On 09/21/18 16:01, Ville Syrjälä wrote:
> > On Fri, Sep 21, 2018 at 10:41:46AM +0200, Hans Verkuil wrote:
> >> On 09/20/18 20:51, Ville Syrjala wrote:
> >>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>
> >>> We'll be wanting to send more than just infoframes over HDMI. So add an
> >>> enum for other packet types.
> >>>
> >>> TODO: Maybe just include the infoframe types in the packet type enum
> >>>       and get rid of the infoframe type enum?
> >>
> >> I think that's better, IMHO. With a comment that the types starting with
> >> 0x81 are defined in CTA-861-G.
> >>
> >> It's really the same byte that is being checked, so having two enums is
> >> a bit misleading. The main difference is really which standard defines
> >> the packet types.
> > 
> > Right. The only slight annoyance is that we'll get a bunch of warnings
> > from the compiler if we don't handle all the enum valus in the switch
> > statements. If we want to avoid that I guess I could limit this
> > to just the null, gcp and gamut metadata packets initially and try to
> > write some actual code for them. Those three are the only ones we
> > care about in i915 at the moment.
> 
> Note that I don't have a terribly strong opinion on this, so if using
> one enum instead of two causes more problems than it is worth, then
> that's fine with me as well.
> 
> But you asked, and given a choice with all other things being equal,
> then one enum has my preference.

I do agree that it would seem nicer.

But I'm a bit busy with other things at the moment so I might want
to leave it like this for now and revisit the topic in the
hopefully-not-too-distant future.

> 
> Regards,
> 
> 	Hans
> 
> > 
> >>
> >> Regards,
> >>
> >> 	Hans
> >>
> >>>
> >>> Cc: Thierry Reding <thierry.reding@gmail.com>
> >>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> >>> Cc: linux-media@vger.kernel.org
> >>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>> ---
> >>>  include/linux/hdmi.h | 15 +++++++++++++++
> >>>  1 file changed, 15 insertions(+)
> >>>
> >>> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> >>> index c76b50a48e48..80521d9591a1 100644
> >>> --- a/include/linux/hdmi.h
> >>> +++ b/include/linux/hdmi.h
> >>> @@ -27,6 +27,21 @@
> >>>  #include <linux/types.h>
> >>>  #include <linux/device.h>
> >>>  
> >>> +enum hdmi_packet_type {
> >>> +	HDMI_PACKET_TYPE_NULL = 0x00,
> >>> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> >>> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> >>> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> >>> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
> >>> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> >>> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> >>> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> >>> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> >>> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> >>> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> >>> +	/* + enum hdmi_infoframe_type */
> >>> +};
> >>> +
> >>>  enum hdmi_infoframe_type {
> >>>  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
> >>>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> >>>
> > 

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
@ 2018-09-21 15:07           ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-21 15:07 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, dri-devel, linux-media

On Fri, Sep 21, 2018 at 04:12:36PM +0200, Hans Verkuil wrote:
> On 09/21/18 16:01, Ville Syrjälä wrote:
> > On Fri, Sep 21, 2018 at 10:41:46AM +0200, Hans Verkuil wrote:
> >> On 09/20/18 20:51, Ville Syrjala wrote:
> >>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>
> >>> We'll be wanting to send more than just infoframes over HDMI. So add an
> >>> enum for other packet types.
> >>>
> >>> TODO: Maybe just include the infoframe types in the packet type enum
> >>>       and get rid of the infoframe type enum?
> >>
> >> I think that's better, IMHO. With a comment that the types starting with
> >> 0x81 are defined in CTA-861-G.
> >>
> >> It's really the same byte that is being checked, so having two enums is
> >> a bit misleading. The main difference is really which standard defines
> >> the packet types.
> > 
> > Right. The only slight annoyance is that we'll get a bunch of warnings
> > from the compiler if we don't handle all the enum valus in the switch
> > statements. If we want to avoid that I guess I could limit this
> > to just the null, gcp and gamut metadata packets initially and try to
> > write some actual code for them. Those three are the only ones we
> > care about in i915 at the moment.
> 
> Note that I don't have a terribly strong opinion on this, so if using
> one enum instead of two causes more problems than it is worth, then
> that's fine with me as well.
> 
> But you asked, and given a choice with all other things being equal,
> then one enum has my preference.

I do agree that it would seem nicer.

But I'm a bit busy with other things at the moment so I might want
to leave it like this for now and revisit the topic in the
hopefully-not-too-distant future.

> 
> Regards,
> 
> 	Hans
> 
> > 
> >>
> >> Regards,
> >>
> >> 	Hans
> >>
> >>>
> >>> Cc: Thierry Reding <thierry.reding@gmail.com>
> >>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> >>> Cc: linux-media@vger.kernel.org
> >>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>> ---
> >>>  include/linux/hdmi.h | 15 +++++++++++++++
> >>>  1 file changed, 15 insertions(+)
> >>>
> >>> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> >>> index c76b50a48e48..80521d9591a1 100644
> >>> --- a/include/linux/hdmi.h
> >>> +++ b/include/linux/hdmi.h
> >>> @@ -27,6 +27,21 @@
> >>>  #include <linux/types.h>
> >>>  #include <linux/device.h>
> >>>  
> >>> +enum hdmi_packet_type {
> >>> +	HDMI_PACKET_TYPE_NULL = 0x00,
> >>> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> >>> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> >>> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> >>> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
> >>> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> >>> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> >>> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> >>> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> >>> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> >>> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> >>> +	/* + enum hdmi_infoframe_type */
> >>> +};
> >>> +
> >>>  enum hdmi_infoframe_type {
> >>>  	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
> >>>  	HDMI_INFOFRAME_TYPE_AVI = 0x82,
> >>>
> > 

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* [PATCH v2 06/18] video/hdmi: Handle the MPEG Source infoframe
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21 15:09     ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-21 15:09 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the MPEG source infoframe.

Blindly typed from the spec, and totally untested.

v2: Rebase

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  27 ++++++
 2 files changed, 256 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 08d94ab00467..6f39b9ae56b9 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
 	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
+	frame->version = 1;
+	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
+
+static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_check() - check a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
+{
+	return hdmi_mpeg_source_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(buffer, 0, size);
+
+	ptr[0] = frame->type;
+	ptr[1] = frame->version;
+	ptr[2] = frame->length;
+	ptr[3] = 0; /* checksum */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	ptr[0] = frame->mpeg_bit_rate >> 0;
+	ptr[1] = frame->mpeg_bit_rate >> 8;
+	ptr[2] = frame->mpeg_bit_rate >> 16;
+	ptr[3] = frame->mpeg_bit_rate >> 24;
+	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack() - check a HDMI MPEG Source infoframe,
+ *                                     and write it to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_audio_infoframe_check(&frame->audio);
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
 							     buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
+							      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
 							buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
+							 buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -838,6 +973,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Source Product Description (SPD)";
 	case HDMI_INFOFRAME_TYPE_AUDIO:
 		return "Audio";
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return "MPEG Source";
 	}
 	return "Reserved";
 }
@@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
 	}
 }
 
+static const char *
+hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
+{
+	if (frame < 0 || frame > 3)
+		return "invalid";
+
+	switch (frame) {
+	case HDMI_MPEG_FRAME_UNKNOWN:
+		return "Unknown";
+	case HDMI_MPEG_FRAME_I_PICTURE:
+		return "I Picture";
+	case HDMI_MPEG_FRAME_B_PICTURE:
+		return "B Picture";
+	case HDMI_MPEG_FRAME_P_PICTURE:
+		return "P Picture";
+	}
+	return "Reserved";
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI MPEG Source infoframe
+ */
+static void hdmi_mpeg_source_infoframe_log(const char *level,
+					   struct device *dev,
+					   const struct hdmi_mpeg_source_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    MPEG bit rate: %d Hz\n",
+		 frame->mpeg_bit_rate);
+	hdmi_log("    MPEG frame: %s\n",
+		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
+	hdmi_log("    field repeat: %s\n",
+		 frame->field_repeat ? "Yes" : "No");
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 	return 0;
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
+					     const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	int ret;
+
+	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    ptr[1] != 1 ||
+	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
+		return -EINVAL;
+	}
+
+	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
+		return -EINVAL;
+
+	ret = hdmi_mpeg_source_infoframe_init(frame);
+	if (ret)
+		return ret;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	frame->mpeg_bit_rate =
+		(ptr[0] << 0) | (ptr[1] << 8) |
+		(ptr[2] << 16) | (ptr[3] << 24);
+	frame->mpeg_frame = ptr[4] & 0x3;
+	frame->field_repeat = ptr[4] & 0x10;
+
+	return 0;
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 80521d9591a1..2c9322f7538d 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_AVI = 0x82,
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
+	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -55,6 +56,7 @@ enum hdmi_infoframe_type {
 #define HDMI_AVI_INFOFRAME_SIZE    13
 #define HDMI_SPD_INFOFRAME_SIZE    25
 #define HDMI_AUDIO_INFOFRAME_SIZE  10
+#define HDMI_MPEG_SOURCE_INFOFRAME_SIZE  10
 
 #define HDMI_INFOFRAME_SIZE(type)	\
 	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
@@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
 	struct hdmi_vendor_infoframe hdmi;
 };
 
+enum hdmi_mpeg_frame {
+	HDMI_MPEG_FRAME_UNKNOWN,
+	HDMI_MPEG_FRAME_I_PICTURE,
+	HDMI_MPEG_FRAME_B_PICTURE,
+	HDMI_MPEG_FRAME_P_PICTURE,
+};
+
+struct hdmi_mpeg_source_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned int mpeg_bit_rate;
+	enum hdmi_mpeg_frame mpeg_frame;
+	bool field_repeat;
+};
+
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size);
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size);
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
  * @spd: spd infoframe
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
+ * @mpeg_source: mpeg source infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -355,6 +381,7 @@ union hdmi_infoframe {
 	struct hdmi_spd_infoframe spd;
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
+	struct hdmi_mpeg_source_infoframe mpeg_source;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v2 06/18] video/hdmi: Handle the MPEG Source infoframe
@ 2018-09-21 15:09     ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-21 15:09 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the MPEG source infoframe.

Blindly typed from the spec, and totally untested.

v2: Rebase

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  27 ++++++
 2 files changed, 256 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 08d94ab00467..6f39b9ae56b9 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -706,6 +706,131 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
 	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_init() - initialize an HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_MPEG_SOURCE;
+	frame->version = 1;
+	frame->length = HDMI_MPEG_SOURCE_INFOFRAME_SIZE;
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_init);
+
+static int hdmi_mpeg_source_infoframe_check_only(const struct hdmi_mpeg_source_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    frame->version != 1 ||
+	    frame->length != HDMI_MPEG_SOURCE_INFOFRAME_SIZE)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_check() - check a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame)
+{
+	return hdmi_mpeg_source_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_check);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack_only() - write HDMI MPEG Source infoframe to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(buffer, 0, size);
+
+	ptr[0] = frame->type;
+	ptr[1] = frame->version;
+	ptr[2] = frame->length;
+	ptr[3] = 0; /* checksum */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	ptr[0] = frame->mpeg_bit_rate >> 0;
+	ptr[1] = frame->mpeg_bit_rate >> 8;
+	ptr[2] = frame->mpeg_bit_rate >> 16;
+	ptr[3] = frame->mpeg_bit_rate >> 24;
+	ptr[4] = (frame->field_repeat << 4) | frame->mpeg_frame;
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack_only);
+
+/**
+ * hdmi_mpeg_source_infoframe_pack() - check a HDMI MPEG Source infoframe,
+ *                                     and write it to binary buffer
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_mpeg_source_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_mpeg_source_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -727,6 +852,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_audio_infoframe_check(&frame->audio);
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -770,6 +897,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
 							     buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
+							      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -816,6 +947,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
 							buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
+							 buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -838,6 +973,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Source Product Description (SPD)";
 	case HDMI_INFOFRAME_TYPE_AUDIO:
 		return "Audio";
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		return "MPEG Source";
 	}
 	return "Reserved";
 }
@@ -1349,6 +1486,46 @@ hdmi_vendor_any_infoframe_log(const char *level,
 	}
 }
 
+static const char *
+hdmi_mpeg_frame_get_name(enum hdmi_mpeg_frame frame)
+{
+	if (frame < 0 || frame > 3)
+		return "invalid";
+
+	switch (frame) {
+	case HDMI_MPEG_FRAME_UNKNOWN:
+		return "Unknown";
+	case HDMI_MPEG_FRAME_I_PICTURE:
+		return "I Picture";
+	case HDMI_MPEG_FRAME_B_PICTURE:
+		return "B Picture";
+	case HDMI_MPEG_FRAME_P_PICTURE:
+		return "P Picture";
+	}
+	return "Reserved";
+}
+
+/**
+ * hdmi_mpeg_source_infoframe_log() - log info of HDMI MPEG Source infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI MPEG Source infoframe
+ */
+static void hdmi_mpeg_source_infoframe_log(const char *level,
+					   struct device *dev,
+					   const struct hdmi_mpeg_source_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    MPEG bit rate: %d Hz\n",
+		 frame->mpeg_bit_rate);
+	hdmi_log("    MPEG frame: %s\n",
+		 hdmi_mpeg_frame_get_name(frame->mpeg_frame));
+	hdmi_log("    field repeat: %s\n",
+		 frame->field_repeat ? "Yes" : "No");
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1372,6 +1549,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1614,6 +1794,52 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
 	return 0;
 }
 
+/**
+ * hdmi_mpeg_source_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *frame,
+					     const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	int ret;
+
+	if (size < HDMI_INFOFRAME_SIZE(MPEG_SOURCE))
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_MPEG_SOURCE ||
+	    ptr[1] != 1 ||
+	    ptr[2] != HDMI_MPEG_SOURCE_INFOFRAME_SIZE) {
+		return -EINVAL;
+	}
+
+	if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(MPEG_SOURCE)) != 0)
+		return -EINVAL;
+
+	ret = hdmi_mpeg_source_infoframe_init(frame);
+	if (ret)
+		return ret;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	frame->mpeg_bit_rate =
+		(ptr[0] << 0) | (ptr[1] << 8) |
+		(ptr[2] << 16) | (ptr[3] << 24);
+	frame->mpeg_frame = ptr[4] & 0x3;
+	frame->field_repeat = ptr[4] & 0x10;
+
+	return 0;
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1649,6 +1875,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_VENDOR:
 		ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
+		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 80521d9591a1..2c9322f7538d 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -47,6 +47,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_AVI = 0x82,
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
+	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -55,6 +56,7 @@ enum hdmi_infoframe_type {
 #define HDMI_AVI_INFOFRAME_SIZE    13
 #define HDMI_SPD_INFOFRAME_SIZE    25
 #define HDMI_AUDIO_INFOFRAME_SIZE  10
+#define HDMI_MPEG_SOURCE_INFOFRAME_SIZE  10
 
 #define HDMI_INFOFRAME_SIZE(type)	\
 	(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
@@ -337,6 +339,29 @@ union hdmi_vendor_any_infoframe {
 	struct hdmi_vendor_infoframe hdmi;
 };
 
+enum hdmi_mpeg_frame {
+	HDMI_MPEG_FRAME_UNKNOWN,
+	HDMI_MPEG_FRAME_I_PICTURE,
+	HDMI_MPEG_FRAME_B_PICTURE,
+	HDMI_MPEG_FRAME_P_PICTURE,
+};
+
+struct hdmi_mpeg_source_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned int mpeg_bit_rate;
+	enum hdmi_mpeg_frame mpeg_frame;
+	bool field_repeat;
+};
+
+int hdmi_mpeg_source_infoframe_init(struct hdmi_mpeg_source_infoframe *frame);
+ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame,
+					void *buffer, size_t size);
+ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infoframe *frame,
+					     void *buffer, size_t size);
+int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -344,6 +369,7 @@ union hdmi_vendor_any_infoframe {
  * @spd: spd infoframe
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
+ * @mpeg_source: mpeg source infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -355,6 +381,7 @@ union hdmi_infoframe {
 	struct hdmi_spd_infoframe spd;
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
+	struct hdmi_mpeg_source_infoframe mpeg_source;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v2 07/18] video/hdmi: Handle the NTSC VBI infoframe
  2018-09-20 18:51   ` Ville Syrjala
@ 2018-09-21 15:10     ` Ville Syrjala
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-21 15:10 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the NTSC VBI infoframe.

I decided against parsing the PES_data_field and just leave
it as an opaque blob, just dumping it out as hex in the log.

Blindly typed from the spec, and totally untested.

v2: Rebase

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  18 +++++
 2 files changed, 226 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 6f39b9ae56b9..b14202fc5854 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
 }
 EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
 
+/**
+ * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ * @pes_data_field: ANSI/SCTE 127 PES_data_field
+ * @length: ANSI/SCTE 127 PES_data_field length
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field,
+				 size_t length)
+{
+	if (length < 1 || length > 27)
+		return -EINVAL;
+
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
+	frame->version = 1;
+	frame->length = length;
+
+	memcpy(frame->pes_data_field, pes_data_field, length);
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
+
+static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    frame->version != 1 ||
+	    frame->length < 1 || frame->length > 27)
+		return -EINVAL;
+
+	if (frame->pes_data_field[0] != 0x99)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	return hdmi_ntsc_vbi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI infoframe to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(buffer, 0, size);
+
+	ptr[0] = frame->type;
+	ptr[1] = frame->version;
+	ptr[2] = frame->length;
+	ptr[3] = 0; /* checksum */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	memcpy(ptr, frame->pes_data_field, frame->length);
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack() - check a HDMI NTSC VBI infoframe,
+ *                                  and write it to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
 							      buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
+							   buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
 							 buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
+						      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Audio";
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return "MPEG Source";
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return "NTSC VBI";
 	}
 	return "Reserved";
 }
@@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
 		 frame->field_repeat ? "Yes" : "No");
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_log() - log info of HDMI NTSC VBI infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI NTSC VBI infoframe
+ */
+static void hdmi_ntsc_vbi_infoframe_log(const char *level,
+					struct device *dev,
+					const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
 	return 0;
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_ntsc_vbi_infoframe_unpack(struct hdmi_ntsc_vbi_infoframe *frame,
+					  const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	size_t length;
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    ptr[1] != 1 ||
+	    ptr[2] < 1 || ptr[2] > 27)
+		return -EINVAL;
+
+	length = ptr[2];
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+		return -EINVAL;
+
+	if (hdmi_infoframe_checksum(buffer,
+				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
+		return -EINVAL;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 2c9322f7538d..3821516b336c 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
 	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
+	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
 					     void *buffer, size_t size);
 int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
 
+struct hdmi_ntsc_vbi_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned char pes_data_field[27];
+};
+
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field, size_t length);
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size);
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size);
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
  * @mpeg_source: mpeg source infoframe
+ * @ntsc_vbi: ntsc vbi infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -382,6 +399,7 @@ union hdmi_infoframe {
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
 	struct hdmi_mpeg_source_infoframe mpeg_source;
+	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* [PATCH v2 07/18] video/hdmi: Handle the NTSC VBI infoframe
@ 2018-09-21 15:10     ` Ville Syrjala
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjala @ 2018-09-21 15:10 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Add the code to deal with the NTSC VBI infoframe.

I decided against parsing the PES_data_field and just leave
it as an opaque blob, just dumping it out as hex in the log.

Blindly typed from the spec, and totally untested.

v2: Rebase

Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/video/hdmi.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/hdmi.h |  18 +++++
 2 files changed, 226 insertions(+)

diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 6f39b9ae56b9..b14202fc5854 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -831,6 +831,139 @@ ssize_t hdmi_mpeg_source_infoframe_pack(struct hdmi_mpeg_source_infoframe *frame
 }
 EXPORT_SYMBOL(hdmi_mpeg_source_infoframe_pack);
 
+/**
+ * hdmi_ntsc_vbi_infoframe_init() - initialize an HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ * @pes_data_field: ANSI/SCTE 127 PES_data_field
+ * @length: ANSI/SCTE 127 PES_data_field length
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field,
+				 size_t length)
+{
+	if (length < 1 || length > 27)
+		return -EINVAL;
+
+	memset(frame, 0, sizeof(*frame));
+
+	frame->type = HDMI_INFOFRAME_TYPE_NTSC_VBI;
+	frame->version = 1;
+	frame->length = length;
+
+	memcpy(frame->pes_data_field, pes_data_field, length);
+
+	return 0;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_init);
+
+static int hdmi_ntsc_vbi_infoframe_check_only(const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	if (frame->type != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    frame->version != 1 ||
+	    frame->length < 1 || frame->length > 27)
+		return -EINVAL;
+
+	if (frame->pes_data_field[0] != 0x99)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * hdmi_ntsc_vbi_infoframe_check() - Check and check a HDMI NTSC VBI infoframe
+ * @frame: HDMI NTSC VBI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	return hdmi_ntsc_vbi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_check);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack_only() - write HDMI NTSC VBI infoframe to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size)
+{
+	u8 *ptr = buffer;
+	size_t length;
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check_only(frame);
+	if (ret)
+		return ret;
+
+	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(buffer, 0, size);
+
+	ptr[0] = frame->type;
+	ptr[1] = frame->version;
+	ptr[2] = frame->length;
+	ptr[3] = 0; /* checksum */
+
+	/* start infoframe payload */
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	memcpy(ptr, frame->pes_data_field, frame->length);
+
+	hdmi_infoframe_set_checksum(buffer, length);
+
+	return length;
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack_only);
+
+/**
+ * hdmi_ntsc_vbi_infoframe_pack() - check a HDMI NTSC VBI infoframe,
+ *                                  and write it to binary buffer
+ * @frame: HDMI NTSC VBI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size)
+{
+	int ret;
+
+	ret = hdmi_ntsc_vbi_infoframe_check(frame);
+	if (ret)
+		return ret;
+
+	return hdmi_ntsc_vbi_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_ntsc_vbi_infoframe_pack);
+
 /**
  * hdmi_infoframe_check() - check a HDMI infoframe
  * @frame: HDMI infoframe
@@ -854,6 +987,8 @@ hdmi_infoframe_check(union hdmi_infoframe *frame)
 		return hdmi_vendor_any_infoframe_check(&frame->vendor);
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		return -EINVAL;
@@ -901,6 +1036,10 @@ hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t
 		length = hdmi_mpeg_source_infoframe_pack_only(&frame->mpeg_source,
 							      buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack_only(&frame->ntsc_vbi,
+							   buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -951,6 +1090,10 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame,
 		length = hdmi_mpeg_source_infoframe_pack(&frame->mpeg_source,
 							 buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		length = hdmi_ntsc_vbi_infoframe_pack(&frame->ntsc_vbi,
+						      buffer, size);
+		break;
 	default:
 		WARN(1, "Bad infoframe type %d\n", frame->any.type);
 		length = -EINVAL;
@@ -975,6 +1118,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
 		return "Audio";
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		return "MPEG Source";
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		return "NTSC VBI";
 	}
 	return "Reserved";
 }
@@ -1526,6 +1671,22 @@ static void hdmi_mpeg_source_infoframe_log(const char *level,
 		 frame->field_repeat ? "Yes" : "No");
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_log() - log info of HDMI NTSC VBI infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI NTSC VBI infoframe
+ */
+static void hdmi_ntsc_vbi_infoframe_log(const char *level,
+					struct device *dev,
+					const struct hdmi_ntsc_vbi_infoframe *frame)
+{
+	hdmi_infoframe_log_header(level, dev,
+				  (const struct hdmi_any_infoframe *)frame);
+
+	hdmi_log("    %*ph\n", frame->length, frame->pes_data_field);
+}
+
 /**
  * hdmi_infoframe_log() - log info of HDMI infoframe
  * @level: logging level
@@ -1552,6 +1713,9 @@ void hdmi_infoframe_log(const char *level,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		hdmi_mpeg_source_infoframe_log(level, dev, &frame->mpeg_source);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		hdmi_ntsc_vbi_infoframe_log(level, dev, &frame->ntsc_vbi);
+		break;
 	}
 }
 EXPORT_SYMBOL(hdmi_infoframe_log);
@@ -1840,6 +2004,47 @@ static int hdmi_mpeg_source_infoframe_unpack(struct hdmi_mpeg_source_infoframe *
 	return 0;
 }
 
+/**
+ * hdmi_ntsc_vbi_infoframe_unpack() - unpack binary buffer to a HDMI MPEG Source infoframe
+ * @frame: HDMI MPEG Source infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI MPEG Source information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_ntsc_vbi_infoframe_unpack(struct hdmi_ntsc_vbi_infoframe *frame,
+					  const void *buffer, size_t size)
+{
+	const u8 *ptr = buffer;
+	size_t length;
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE)
+		return -EINVAL;
+
+	if (ptr[0] != HDMI_INFOFRAME_TYPE_NTSC_VBI ||
+	    ptr[1] != 1 ||
+	    ptr[2] < 1 || ptr[2] > 27)
+		return -EINVAL;
+
+	length = ptr[2];
+
+	if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+		return -EINVAL;
+
+	if (hdmi_infoframe_checksum(buffer,
+				    HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
+		return -EINVAL;
+
+	ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+	return hdmi_ntsc_vbi_infoframe_init(frame, ptr, length);
+}
+
 /**
  * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
  * @frame: HDMI infoframe
@@ -1878,6 +2083,9 @@ int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
 	case HDMI_INFOFRAME_TYPE_MPEG_SOURCE:
 		ret = hdmi_mpeg_source_infoframe_unpack(&frame->mpeg_source, buffer, size);
 		break;
+	case HDMI_INFOFRAME_TYPE_NTSC_VBI:
+		ret = hdmi_ntsc_vbi_infoframe_unpack(&frame->ntsc_vbi, buffer, size);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index 2c9322f7538d..3821516b336c 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -48,6 +48,7 @@ enum hdmi_infoframe_type {
 	HDMI_INFOFRAME_TYPE_SPD = 0x83,
 	HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
 	HDMI_INFOFRAME_TYPE_MPEG_SOURCE = 0x85,
+	HDMI_INFOFRAME_TYPE_NTSC_VBI = 0x86,
 };
 
 #define HDMI_IEEE_OUI 0x000c03
@@ -362,6 +363,21 @@ ssize_t hdmi_mpeg_source_infoframe_pack_only(const struct hdmi_mpeg_source_infof
 					     void *buffer, size_t size);
 int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
 
+struct hdmi_ntsc_vbi_infoframe {
+	enum hdmi_infoframe_type type;
+	unsigned char version;
+	unsigned char length;
+	unsigned char pes_data_field[27];
+};
+
+int hdmi_ntsc_vbi_infoframe_init(struct hdmi_ntsc_vbi_infoframe *frame,
+				 const void *pes_data_field, size_t length);
+ssize_t hdmi_ntsc_vbi_infoframe_pack(struct hdmi_ntsc_vbi_infoframe *frame,
+				     void *buffer, size_t size);
+ssize_t hdmi_ntsc_vbi_infoframe_pack_only(const struct hdmi_ntsc_vbi_infoframe *frame,
+					  void *buffer, size_t size);
+int hdmi_ntsc_vbi_infoframe_check(struct hdmi_ntsc_vbi_infoframe *frame);
+
 /**
  * union hdmi_infoframe - overall union of all abstract infoframe representations
  * @any: generic infoframe
@@ -370,6 +386,7 @@ int hdmi_mpeg_source_infoframe_check(struct hdmi_mpeg_source_infoframe *frame);
  * @vendor: union of all vendor infoframes
  * @audio: audio infoframe
  * @mpeg_source: mpeg source infoframe
+ * @ntsc_vbi: ntsc vbi infoframe
  *
  * This is used by the generic pack function. This works since all infoframes
  * have the same header which also indicates which type of infoframe should be
@@ -382,6 +399,7 @@ union hdmi_infoframe {
 	union hdmi_vendor_any_infoframe vendor;
 	struct hdmi_audio_infoframe audio;
 	struct hdmi_mpeg_source_infoframe mpeg_source;
+	struct hdmi_ntsc_vbi_infoframe ntsc_vbi;
 };
 
 ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
-- 
2.16.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 95+ messages in thread

* ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Infoframe precompute/check (rev4)
  2018-09-20 18:51 ` Ville Syrjala
                   ` (23 preceding siblings ...)
  (?)
@ 2018-09-21 15:25 ` Patchwork
  -1 siblings, 0 replies; 95+ messages in thread
From: Patchwork @ 2018-09-21 15:25 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Infoframe precompute/check (rev4)
URL   : https://patchwork.freedesktop.org/series/49983/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
bd2b9221d985 video/hdmi: Constify 'buffer' to the unpack functions
865f880ff261 video/hdmi: Pass buffer size to infoframe unpack functions
2b2f89f9122e video/hdmi: Constify infoframe passed to the log functions
44007fc474cd video/hdmi: Constify infoframe passed to the pack functions
869ca9812ed0 video/hdmi: Add an enum for HDMI packet types
0ec089a8d890 video/hdmi: Handle the MPEG Source infoframe
-:353: CHECK:BOOL_MEMBER: Avoid using bool structure members because of possible alignment issues - see: https://lkml.org/lkml/2017/11/21/384
#353: FILE: include/linux/hdmi.h:355:
+	bool field_repeat;

total: 0 errors, 0 warnings, 1 checks, 340 lines checked
6f188967d1cb video/hdmi: Handle the NTSC VBI infoframe
d8151ddb397c drm/i915: Use memmove() for punching the hole into infoframes
052da5736c71 drm/i915: Pass intel_encoder to infoframe functions
14810ca2d1e7 drm/i915: Add the missing HDMI gamut metadata packet stuff
-:36: WARNING:LONG_LINE: line over 100 characters
#36: FILE: drivers/gpu/drm/i915/i915_reg.h:7956:
+#define HSW_TVIDEO_DIP_GMP_DATA(trans, i)	_MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GMP_DATA_A + (i) * 4)

total: 0 errors, 1 warnings, 0 checks, 55 lines checked
bc1216d6c2e5 drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
fe8d386ab1bc drm/i915: Store mask of enabled infoframes in the crtc state
551baa38db82 drm/i915: Precompute HDMI infoframes
125c7a3847d1 drm/i915: Read out HDMI infoframes
f224f3b22927 drm/i915/sdvo: Precompute HDMI infoframes
26c55f850c3d drm/i915/sdvo: Read out HDMI infoframes
c97506450a5c drm/i915: Check infoframe state in intel_pipe_config_compare()
-:70: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'name' - possible side-effects?
#70: FILE: drivers/gpu/drm/i915/intel_display.c:11575:
+#define PIPE_CONF_CHECK_INFOFRAME(name) do { \
+	if (!intel_compare_infoframe(&current_config->infoframes.name, \
+				     &pipe_config->infoframes.name)) { \
+		pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \
+					  &current_config->infoframes.name, \
+					  &pipe_config->infoframes.name); \
+		ret = false; \
+	} \
+} while (0)

total: 0 errors, 0 warnings, 1 checks, 67 lines checked
8fdf44951d06 drm/i915: Include infoframes in the crtc state dump

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* ✗ Fi.CI.SPARSE: warning for drm/i915: Infoframe precompute/check (rev4)
  2018-09-20 18:51 ` Ville Syrjala
                   ` (24 preceding siblings ...)
  (?)
@ 2018-09-21 15:35 ` Patchwork
  -1 siblings, 0 replies; 95+ messages in thread
From: Patchwork @ 2018-09-21 15:35 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Infoframe precompute/check (rev4)
URL   : https://patchwork.freedesktop.org/series/49983/
State : warning

== Summary ==

$ dim sparse origin/drm-tip
Commit: video/hdmi: Constify 'buffer' to the unpack functions
Okay!

Commit: video/hdmi: Pass buffer size to infoframe unpack functions
Okay!

Commit: video/hdmi: Constify infoframe passed to the log functions
Okay!

Commit: video/hdmi: Constify infoframe passed to the pack functions
Okay!

Commit: video/hdmi: Add an enum for HDMI packet types
Okay!

Commit: video/hdmi: Handle the MPEG Source infoframe
Okay!

Commit: video/hdmi: Handle the NTSC VBI infoframe
Okay!

Commit: drm/i915: Use memmove() for punching the hole into infoframes
Okay!

Commit: drm/i915: Pass intel_encoder to infoframe functions
Okay!

Commit: drm/i915: Add the missing HDMI gamut metadata packet stuff
Okay!

Commit: drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
Okay!

Commit: drm/i915: Store mask of enabled infoframes in the crtc state
Okay!

Commit: drm/i915: Precompute HDMI infoframes
Okay!

Commit: drm/i915: Read out HDMI infoframes
Okay!

Commit: drm/i915/sdvo: Precompute HDMI infoframes
Okay!

Commit: drm/i915/sdvo: Read out HDMI infoframes
+drivers/gpu/drm/i915/intel_sdvo.c:1023:21: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/intel_sdvo.c:1023:21: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/intel_sdvo.c:1029:47: warning: expression using sizeof(void)

Commit: drm/i915: Check infoframe state in intel_pipe_config_compare()
Okay!

Commit: drm/i915: Include infoframes in the crtc state dump
Okay!

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* ✓ Fi.CI.BAT: success for drm/i915: Infoframe precompute/check (rev4)
  2018-09-20 18:51 ` Ville Syrjala
                   ` (25 preceding siblings ...)
  (?)
@ 2018-09-21 15:46 ` Patchwork
  -1 siblings, 0 replies; 95+ messages in thread
From: Patchwork @ 2018-09-21 15:46 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Infoframe precompute/check (rev4)
URL   : https://patchwork.freedesktop.org/series/49983/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_4860 -> Patchwork_10252 =

== Summary - SUCCESS ==

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/49983/revisions/4/mbox/

== Known issues ==

  Here are the changes found in Patchwork_10252 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@gem_exec_suspend@basic-s4-devices:
      fi-kbl-7500u:       PASS -> DMESG-WARN (fdo#107139, fdo#105128)

    igt@kms_pipe_crc_basic@nonblocking-crc-pipe-a-frame-sequence:
      fi-byt-clapper:     PASS -> FAIL (fdo#103191, fdo#107362)

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
      fi-bdw-samus:       NOTRUN -> INCOMPLETE (fdo#107773)

    
    ==== Possible fixes ====

    igt@gem_exec_suspend@basic-s3:
      fi-bdw-samus:       INCOMPLETE (fdo#107773) -> PASS
      fi-blb-e6850:       INCOMPLETE (fdo#107718) -> PASS

    igt@gem_mmap_gtt@basic-short:
      fi-glk-dsi:         INCOMPLETE (k.org#198133, fdo#103359) -> PASS

    igt@kms_frontbuffer_tracking@basic:
      fi-byt-clapper:     FAIL (fdo#103167) -> PASS

    igt@kms_psr@primary_page_flip:
      fi-kbl-r:           FAIL (fdo#107336) -> PASS

    
  fdo#103167 https://bugs.freedesktop.org/show_bug.cgi?id=103167
  fdo#103191 https://bugs.freedesktop.org/show_bug.cgi?id=103191
  fdo#103359 https://bugs.freedesktop.org/show_bug.cgi?id=103359
  fdo#105128 https://bugs.freedesktop.org/show_bug.cgi?id=105128
  fdo#107139 https://bugs.freedesktop.org/show_bug.cgi?id=107139
  fdo#107336 https://bugs.freedesktop.org/show_bug.cgi?id=107336
  fdo#107362 https://bugs.freedesktop.org/show_bug.cgi?id=107362
  fdo#107718 https://bugs.freedesktop.org/show_bug.cgi?id=107718
  fdo#107773 https://bugs.freedesktop.org/show_bug.cgi?id=107773
  k.org#198133 https://bugzilla.kernel.org/show_bug.cgi?id=198133


== Participating hosts (52 -> 46) ==

  Missing    (6): fi-ilk-m540 fi-hsw-4200u fi-byt-squawks fi-bsw-cyan fi-ctg-p8600 fi-snb-2600 


== Build changes ==

    * Linux: CI_DRM_4860 -> Patchwork_10252

  CI_DRM_4860: 31c6d083d8c6fe280e3daabf22521335762759b9 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4649: 19b0c74d20d9b53d4c82be14af0909a3b6846010 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10252: 8fdf44951d066dbaae95f155e24f16f7ddfb505d @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

8fdf44951d06 drm/i915: Include infoframes in the crtc state dump
c97506450a5c drm/i915: Check infoframe state in intel_pipe_config_compare()
26c55f850c3d drm/i915/sdvo: Read out HDMI infoframes
f224f3b22927 drm/i915/sdvo: Precompute HDMI infoframes
125c7a3847d1 drm/i915: Read out HDMI infoframes
551baa38db82 drm/i915: Precompute HDMI infoframes
fe8d386ab1bc drm/i915: Store mask of enabled infoframes in the crtc state
bc1216d6c2e5 drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
14810ca2d1e7 drm/i915: Add the missing HDMI gamut metadata packet stuff
052da5736c71 drm/i915: Pass intel_encoder to infoframe functions
d8151ddb397c drm/i915: Use memmove() for punching the hole into infoframes
6f188967d1cb video/hdmi: Handle the NTSC VBI infoframe
0ec089a8d890 video/hdmi: Handle the MPEG Source infoframe
869ca9812ed0 video/hdmi: Add an enum for HDMI packet types
44007fc474cd video/hdmi: Constify infoframe passed to the pack functions
2b2f89f9122e video/hdmi: Constify infoframe passed to the log functions
865f880ff261 video/hdmi: Pass buffer size to infoframe unpack functions
bd2b9221d985 video/hdmi: Constify 'buffer' to the unpack functions

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10252/issues.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* ✓ Fi.CI.IGT: success for drm/i915: Infoframe precompute/check (rev4)
  2018-09-20 18:51 ` Ville Syrjala
                   ` (26 preceding siblings ...)
  (?)
@ 2018-09-21 17:04 ` Patchwork
  -1 siblings, 0 replies; 95+ messages in thread
From: Patchwork @ 2018-09-21 17:04 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Infoframe precompute/check (rev4)
URL   : https://patchwork.freedesktop.org/series/49983/
State : success

== Summary ==

= CI Bug Log - changes from CI_DRM_4860_full -> Patchwork_10252_full =

== Summary - SUCCESS ==

  No regressions found.

  

== Known issues ==

  Here are the changes found in Patchwork_10252_full that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@drv_selftest@mock_breadcrumbs:
      shard-glk:          PASS -> INCOMPLETE (k.org#198133, fdo#103359)

    igt@gem_exec_big:
      shard-hsw:          PASS -> TIMEOUT (fdo#107937)

    igt@gem_exec_schedule@pi-ringfull-vebox:
      shard-glk:          NOTRUN -> FAIL (fdo#103158)

    igt@kms_busy@extended-modeset-hang-newfb-with-reset-render-b:
      shard-glk:          NOTRUN -> DMESG-WARN (fdo#107956) +1

    igt@kms_cursor_crc@cursor-64x64-suspend:
      shard-apl:          PASS -> INCOMPLETE (fdo#103927)

    igt@kms_cursor_legacy@2x-nonblocking-modeset-vs-cursor-atomic:
      shard-glk:          NOTRUN -> FAIL (fdo#105454, fdo#106509)

    igt@kms_setmode@basic:
      shard-apl:          PASS -> FAIL (fdo#99912)
      shard-kbl:          PASS -> FAIL (fdo#99912)

    igt@kms_universal_plane@universal-plane-gen9-features-pipe-a:
      shard-kbl:          PASS -> DMESG-WARN (fdo#105602, fdo#103558) +10

    
    ==== Possible fixes ====

    igt@kms_busy@extended-modeset-hang-newfb-with-reset-render-c:
      shard-hsw:          DMESG-WARN (fdo#107956) -> PASS

    igt@kms_cursor_crc@cursor-256x256-suspend:
      shard-kbl:          INCOMPLETE (fdo#103665) -> PASS

    igt@kms_cursor_legacy@cursora-vs-flipa-toggle:
      shard-glk:          DMESG-WARN (fdo#106538, fdo#105763) -> PASS

    igt@kms_flip@2x-flip-vs-expired-vblank-interruptible:
      shard-glk:          FAIL (fdo#105363) -> PASS

    
  fdo#103158 https://bugs.freedesktop.org/show_bug.cgi?id=103158
  fdo#103359 https://bugs.freedesktop.org/show_bug.cgi?id=103359
  fdo#103558 https://bugs.freedesktop.org/show_bug.cgi?id=103558
  fdo#103665 https://bugs.freedesktop.org/show_bug.cgi?id=103665
  fdo#103927 https://bugs.freedesktop.org/show_bug.cgi?id=103927
  fdo#105363 https://bugs.freedesktop.org/show_bug.cgi?id=105363
  fdo#105454 https://bugs.freedesktop.org/show_bug.cgi?id=105454
  fdo#105602 https://bugs.freedesktop.org/show_bug.cgi?id=105602
  fdo#105763 https://bugs.freedesktop.org/show_bug.cgi?id=105763
  fdo#106509 https://bugs.freedesktop.org/show_bug.cgi?id=106509
  fdo#106538 https://bugs.freedesktop.org/show_bug.cgi?id=106538
  fdo#107937 https://bugs.freedesktop.org/show_bug.cgi?id=107937
  fdo#107956 https://bugs.freedesktop.org/show_bug.cgi?id=107956
  fdo#99912 https://bugs.freedesktop.org/show_bug.cgi?id=99912
  k.org#198133 https://bugzilla.kernel.org/show_bug.cgi?id=198133


== Participating hosts (5 -> 5) ==

  No changes in participating hosts


== Build changes ==

    * Linux: CI_DRM_4860 -> Patchwork_10252

  CI_DRM_4860: 31c6d083d8c6fe280e3daabf22521335762759b9 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4649: 19b0c74d20d9b53d4c82be14af0909a3b6846010 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_10252: 8fdf44951d066dbaae95f155e24f16f7ddfb505d @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_10252/shards.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 11/18] drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
  2018-09-20 18:51 ` [PATCH 11/18] drm/i915: Return the mask of enabled infoframes from ->inforame_enabled() Ville Syrjala
@ 2018-09-24 15:51   ` Daniel Vetter
  2018-09-24 16:36     ` [Intel-gfx] " Ville Syrjälä
  0 siblings, 1 reply; 95+ messages in thread
From: Daniel Vetter @ 2018-09-24 15:51 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:38PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> We want to start tracking which infoframes are enabled, so let's replace
> the boolean flag with a bitmask.
> 
> We'll abstract the bitmask so that it's not platform dependent. That
> will allow us to examine the bitmask later in platform independent code.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c  |  2 +-
>  drivers/gpu/drm/i915/intel_drv.h  |  4 +-
>  drivers/gpu/drm/i915/intel_hdmi.c | 87 ++++++++++++++++++++++++++++-----------
>  3 files changed, 68 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 086e3f940586..098a0e4edf2a 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -3390,7 +3390,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
>  		pipe_config->has_hdmi_sink = true;
>  		intel_dig_port = enc_to_dig_port(&encoder->base);
>  
> -		if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
> +		if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
>  			pipe_config->has_infoframe = true;
>  
>  		if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e0f3a79fc75e..6815c69aac2f 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1181,7 +1181,7 @@ struct intel_digital_port {
>  			       bool enable,
>  			       const struct intel_crtc_state *crtc_state,
>  			       const struct drm_connector_state *conn_state);
> -	bool (*infoframe_enabled)(struct intel_encoder *encoder,
> +	u32 (*infoframes_enabled)(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config);
>  };
>  
> @@ -1856,6 +1856,8 @@ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
>  				       bool scrambling);
>  void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
>  void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
> +u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state);
>  
>  
>  /* intel_lvds.c */
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index c3c2a638d062..a8fcddb199ae 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -100,10 +100,14 @@ static u32 g4x_infoframe_index(unsigned int type)
>  static u32 g4x_infoframe_enable(unsigned int type)
>  {
>  	switch (type) {
> +	case HDMI_PACKET_TYPE_NULL:
> +		return VIDEO_DIP_ENABLE; /* slight lie */

Not exactly sure why we're tracking this one here, but not for hsw.
Shouldn't we include that one if the DDI port is in hdmi mode? Would be
more consistent I think.

Aside from that lgtm, has my

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

once we figured the TYPE_NULL thing out.
-Daniel

>  	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
>  		return VIDEO_DIP_ENABLE_GCP;
>  	case HDMI_PACKET_TYPE_GAMUT_METADATA:
>  		return VIDEO_DIP_ENABLE_GAMUT;
> +	case DP_SDP_VSC:
> +		return 0;
>  	case HDMI_INFOFRAME_TYPE_AVI:
>  		return VIDEO_DIP_ENABLE_AVI;
>  	case HDMI_INFOFRAME_TYPE_SPD:
> @@ -119,6 +123,8 @@ static u32 g4x_infoframe_enable(unsigned int type)
>  static u32 hsw_infoframe_enable(unsigned int type)
>  {
>  	switch (type) {
> +	case HDMI_PACKET_TYPE_NULL:
> +		return 0;
>  	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
>  		return VIDEO_DIP_ENABLE_GCP_HSW;
>  	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> @@ -197,19 +203,19 @@ static void g4x_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(VIDEO_DIP_CTL);
>  }
>  
> -static bool g4x_infoframe_enabled(struct intel_encoder *encoder,
> +static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	u32 val = I915_READ(VIDEO_DIP_CTL);
>  
>  	if ((val & VIDEO_DIP_ENABLE) == 0)
> -		return false;
> +		return 0;
>  
>  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> -		return false;
> +		return 0;
>  
> -	return val & (VIDEO_DIP_ENABLE_AVI |
> +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
>  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
>  }
>  
> @@ -252,7 +258,7 @@ static void ibx_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(reg);
>  }
>  
> -static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
> +static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> @@ -261,12 +267,12 @@ static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
>  	u32 val = I915_READ(reg);
>  
>  	if ((val & VIDEO_DIP_ENABLE) == 0)
> -		return false;
> +		return 0;
>  
>  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> -		return false;
> +		return 0;
>  
> -	return val & (VIDEO_DIP_ENABLE_AVI |
> +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
>  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
>  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
>  }
> @@ -313,7 +319,7 @@ static void cpt_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(reg);
>  }
>  
> -static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
> +static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> @@ -321,9 +327,9 @@ static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
>  	u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
>  
>  	if ((val & VIDEO_DIP_ENABLE) == 0)
> -		return false;
> +		return 0;
>  
> -	return val & (VIDEO_DIP_ENABLE_AVI |
> +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
>  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
>  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
>  }
> @@ -367,7 +373,7 @@ static void vlv_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(reg);
>  }
>  
> -static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
> +static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> @@ -375,12 +381,12 @@ static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
>  	u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
>  
>  	if ((val & VIDEO_DIP_ENABLE) == 0)
> -		return false;
> +		return 0;
>  
>  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> -		return false;
> +		return 0;
>  
> -	return val & (VIDEO_DIP_ENABLE_AVI |
> +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
>  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
>  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
>  }
> @@ -419,7 +425,7 @@ static void hsw_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(ctl_reg);
>  }
>  
> -static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
> +static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> @@ -430,6 +436,42 @@ static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
>  		      VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
>  }
>  
> +static const u8 infoframe_type_to_idx[] = {
> +	HDMI_PACKET_TYPE_NULL,
> +	HDMI_PACKET_TYPE_GENERAL_CONTROL,
> +	HDMI_PACKET_TYPE_GAMUT_METADATA,
> +	DP_SDP_VSC,
> +	HDMI_INFOFRAME_TYPE_AVI,
> +	HDMI_INFOFRAME_TYPE_SPD,
> +	HDMI_INFOFRAME_TYPE_VENDOR,
> +};
> +
> +u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
> +	u32 val, ret = 0;
> +	int i;
> +
> +	val = dig_port->infoframes_enabled(encoder, crtc_state);
> +
> +	/* map from hardware bits to dip idx */
> +	for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
> +		unsigned int type = infoframe_type_to_idx[i];
> +
> +		if (HAS_DDI(dev_priv)) {
> +			if (val & hsw_infoframe_enable(type))
> +				ret |= BIT(i);
> +		} else {
> +			if (val & g4x_infoframe_enable(type))
> +				ret |= BIT(i);
> +		}
> +	}
> +
> +	return ret;
> +}
> +
>  /*
>   * The data we write to the DIP data buffer registers is 1 byte bigger than the
>   * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
> @@ -1200,7 +1242,6 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
>  				  struct intel_crtc_state *pipe_config)
>  {
>  	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> -	struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi);
>  	struct drm_device *dev = encoder->base.dev;
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	u32 tmp, flags = 0;
> @@ -1223,7 +1264,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
>  	if (tmp & HDMI_MODE_SELECT_HDMI)
>  		pipe_config->has_hdmi_sink = true;
>  
> -	if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
> +	if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
>  		pipe_config->has_infoframe = true;
>  
>  	if (tmp & SDVO_AUDIO_ENABLE)
> @@ -2325,23 +2366,23 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
>  	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
>  		intel_dig_port->write_infoframe = vlv_write_infoframe;
>  		intel_dig_port->set_infoframes = vlv_set_infoframes;
> -		intel_dig_port->infoframe_enabled = vlv_infoframe_enabled;
> +		intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
>  	} else if (IS_G4X(dev_priv)) {
>  		intel_dig_port->write_infoframe = g4x_write_infoframe;
>  		intel_dig_port->set_infoframes = g4x_set_infoframes;
> -		intel_dig_port->infoframe_enabled = g4x_infoframe_enabled;
> +		intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
>  	} else if (HAS_DDI(dev_priv)) {
>  		intel_dig_port->write_infoframe = hsw_write_infoframe;
>  		intel_dig_port->set_infoframes = hsw_set_infoframes;
> -		intel_dig_port->infoframe_enabled = hsw_infoframe_enabled;
> +		intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
>  	} else if (HAS_PCH_IBX(dev_priv)) {
>  		intel_dig_port->write_infoframe = ibx_write_infoframe;
>  		intel_dig_port->set_infoframes = ibx_set_infoframes;
> -		intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
> +		intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
>  	} else {
>  		intel_dig_port->write_infoframe = cpt_write_infoframe;
>  		intel_dig_port->set_infoframes = cpt_set_infoframes;
> -		intel_dig_port->infoframe_enabled = cpt_infoframe_enabled;
> +		intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
>  	}
>  }
>  
> -- 
> 2.16.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Intel-gfx] [PATCH 12/18] drm/i915: Store mask of enabled infoframes in the crtc state
  2018-09-20 18:51 ` [PATCH 12/18] drm/i915: Store mask of enabled infoframes in the crtc state Ville Syrjala
@ 2018-09-24 15:51   ` Daniel Vetter
  0 siblings, 0 replies; 95+ messages in thread
From: Daniel Vetter @ 2018-09-24 15:51 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:39PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Store the mask of enabled infoframes in the crtc state. We'll start
> with just the readout for HDMI encoder, and we'll expand this
> to compute the bitmask in .compute_config() later. SDVO will also
> follow later.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/intel_ddi.c  | 5 ++++-
>  drivers/gpu/drm/i915/intel_drv.h  | 4 ++++
>  drivers/gpu/drm/i915/intel_hdmi.c | 5 ++++-
>  3 files changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 098a0e4edf2a..19fef88e680e 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -3390,7 +3390,10 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
>  		pipe_config->has_hdmi_sink = true;
>  		intel_dig_port = enc_to_dig_port(&encoder->base);
>  
> -		if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
> +		pipe_config->infoframes.enable |=
> +			intel_hdmi_infoframes_enabled(encoder, pipe_config);
> +
> +		if (pipe_config->infoframes.enable)
>  			pipe_config->has_infoframe = true;
>  
>  		if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 6815c69aac2f..50c0c049ee15 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -893,6 +893,10 @@ struct intel_crtc_state {
>  	u8 active_planes;
>  	u8 nv12_planes;
>  
> +	struct {
> +		u32 enable;
> +	} infoframes;
> +
>  	/* HDMI scrambling status */
>  	bool hdmi_scrambling;
>  
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index a8fcddb199ae..98a44084324c 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -1264,7 +1264,10 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
>  	if (tmp & HDMI_MODE_SELECT_HDMI)
>  		pipe_config->has_hdmi_sink = true;
>  
> -	if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
> +	pipe_config->infoframes.enable |=
> +		intel_hdmi_infoframes_enabled(encoder, pipe_config);
> +
> +	if (pipe_config->infoframes.enable)
>  		pipe_config->has_infoframe = true;
>  
>  	if (tmp & SDVO_AUDIO_ENABLE)
> -- 
> 2.16.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 13/18] drm/i915: Precompute HDMI infoframes
  2018-09-20 18:51 ` [PATCH 13/18] drm/i915: Precompute HDMI infoframes Ville Syrjala
@ 2018-09-24 15:58   ` Daniel Vetter
  2018-09-24 16:42     ` Ville Syrjälä
  0 siblings, 1 reply; 95+ messages in thread
From: Daniel Vetter @ 2018-09-24 15:58 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:40PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Store the infoframes in the crtc state and precompute them in
> .compute_config(). While precomputing we'll also fill out the
> inforames.enable bitmask appropriately.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c  |   1 +
>  drivers/gpu/drm/i915/intel_drv.h  |   5 +
>  drivers/gpu/drm/i915/intel_hdmi.c | 249 +++++++++++++++++++++++++++-----------
>  3 files changed, 187 insertions(+), 68 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 19fef88e680e..5f3bd536d261 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -3391,6 +3391,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
>  		intel_dig_port = enc_to_dig_port(&encoder->base);
>  
>  		pipe_config->infoframes.enable |=
> +			intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_NULL) |

Misplaced hunk? Assuming I'm reading this correctly, this will give you a
0. Not exactly sure what's going on here ... I guess I'm not following why
we care about TYPE_NULL, and why we have to reconstruct it here?

I thought TYPE_NULL is equivalent to state->has_hdmi_sink? Comment
(unfortunately not yet kerneldoc) even explains that ...

Maybe just nuke all the TYPE_NULL tracking here, perhaps with the g4x
(except for g4x itself, because it's shared there) decoder to also take
DIP_ENABLE into account for has_hdmi_sink.

Or update the comment in intel_crtc_state.

Otherwise lgtm, thought admittedly I did clean over the details a bit,
trusting CI and gcc to catch the small stuff :-)

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> with the TYPE_NULL
story somehow figured out.
-Daniel


>  			intel_hdmi_infoframes_enabled(encoder, pipe_config);
>  
>  		if (pipe_config->infoframes.enable)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 50c0c049ee15..357624a6bfe2 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -895,6 +895,10 @@ struct intel_crtc_state {
>  
>  	struct {
>  		u32 enable;
> +		u32 gcp;
> +		union hdmi_infoframe avi;
> +		union hdmi_infoframe spd;
> +		union hdmi_infoframe hdmi;
>  	} infoframes;
>  
>  	/* HDMI scrambling status */
> @@ -1862,6 +1866,7 @@ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
>  void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
>  u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *crtc_state);
> +u32 intel_hdmi_infoframe_enable(unsigned int type);
>  
>  
>  /* intel_lvds.c */
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index 98a44084324c..491001fc0fad 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -446,6 +446,18 @@ static const u8 infoframe_type_to_idx[] = {
>  	HDMI_INFOFRAME_TYPE_VENDOR,
>  };
>  
> +u32 intel_hdmi_infoframe_enable(unsigned int type)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
> +		if (infoframe_type_to_idx[i] == type)
> +			return BIT(i);
> +	}
> +
> +	return 0;
> +}
> +
>  u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *crtc_state)
>  {
> @@ -491,15 +503,23 @@ u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
>   */
>  static void intel_write_infoframe(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *crtc_state,
> -				  union hdmi_infoframe *frame)
> +				  enum hdmi_infoframe_type type,
> +				  const union hdmi_infoframe *frame)
>  {
>  	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
>  	u8 buffer[VIDEO_DIP_DATA_SIZE];
>  	ssize_t len;
>  
> +	if ((crtc_state->infoframes.enable &
> +	     intel_hdmi_infoframe_enable(type)) == 0)
> +		return;
> +
> +	if (WARN_ON(frame->any.type != type))
> +		return;
> +
>  	/* see comment above for the reason for this offset */
> -	len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1);
> -	if (len < 0)
> +	len = hdmi_infoframe_pack_only(frame, buffer + 1, sizeof(buffer) - 1);
> +	if (WARN_ON(len < 0))
>  		return;
>  
>  	/* Insert the 'hole' (see big comment above) at position 3 */
> @@ -507,85 +527,111 @@ static void intel_write_infoframe(struct intel_encoder *encoder,
>  	buffer[3] = 0;
>  	len++;
>  
> -	intel_dig_port->write_infoframe(encoder,
> -					crtc_state,
> -					frame->any.type, buffer, len);
> +	intel_dig_port->write_infoframe(encoder, crtc_state, type, buffer, len);
>  }
>  
> -static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
> -					 const struct intel_crtc_state *crtc_state,
> -					 const struct drm_connector_state *conn_state)
> +static bool
> +intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder,
> +				 struct intel_crtc_state *crtc_state,
> +				 struct drm_connector_state *conn_state)
>  {
>  	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> +	struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi;
> +	bool is_hdmi2_sink = conn_state->connector->display_info.hdmi.scdc.supported;
>  	const struct drm_display_mode *adjusted_mode =
>  		&crtc_state->base.adjusted_mode;
> -	struct drm_connector *connector = &intel_hdmi->attached_connector->base;
> -	bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
> -	union hdmi_infoframe frame;
>  	int ret;
>  
> -	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
> +	if (!crtc_state->has_infoframe)
> +		return true;
> +
> +	crtc_state->infoframes.enable |=
> +		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
> +
> +	ret = drm_hdmi_avi_infoframe_from_display_mode(frame,
>  						       adjusted_mode,
>  						       is_hdmi2_sink);
> -	if (ret < 0) {
> -		DRM_ERROR("couldn't fill AVI infoframe\n");
> -		return;
> -	}
> +	if (ret)
> +		return false;
>  
>  	if (crtc_state->ycbcr420)
> -		frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
> +		frame->colorspace = HDMI_COLORSPACE_YUV420;
>  	else
> -		frame.avi.colorspace = HDMI_COLORSPACE_RGB;
> +		frame->colorspace = HDMI_COLORSPACE_RGB;
>  
> -	drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode,
> +	drm_hdmi_avi_infoframe_quant_range(frame, adjusted_mode,
>  					   crtc_state->limited_color_range ?
>  					   HDMI_QUANTIZATION_RANGE_LIMITED :
>  					   HDMI_QUANTIZATION_RANGE_FULL,
>  					   intel_hdmi->rgb_quant_range_selectable,
>  					   is_hdmi2_sink);
>  
> -	drm_hdmi_avi_infoframe_content_type(&frame.avi,
> -					    conn_state);
> +	drm_hdmi_avi_infoframe_content_type(frame, conn_state);
>  
>  	/* TODO: handle pixel repetition for YCBCR420 outputs */
> -	intel_write_infoframe(encoder, crtc_state,
> -			      &frame);
> +
> +	ret = hdmi_avi_infoframe_check(frame);
> +	if (WARN_ON(ret))
> +		return false;
> +
> +	return true;
>  }
>  
> -static void intel_hdmi_set_spd_infoframe(struct intel_encoder *encoder,
> -					 const struct intel_crtc_state *crtc_state)
> +static bool
> +intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder,
> +				 struct intel_crtc_state *crtc_state,
> +				 struct drm_connector_state *conn_state)
>  {
> -	union hdmi_infoframe frame;
> +	struct hdmi_spd_infoframe *frame = &crtc_state->infoframes.spd.spd;
>  	int ret;
>  
> -	ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx");
> -	if (ret < 0) {
> -		DRM_ERROR("couldn't fill SPD infoframe\n");
> -		return;
> -	}
> +	if (!crtc_state->has_infoframe)
> +		return true;
>  
> -	frame.spd.sdi = HDMI_SPD_SDI_PC;
> +	crtc_state->infoframes.enable |=
> +		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD);
>  
> -	intel_write_infoframe(encoder, crtc_state,
> -			      &frame);
> +	ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx");
> +	if (WARN_ON(ret))
> +		return false;
> +
> +	frame->sdi = HDMI_SPD_SDI_PC;
> +
> +	ret = hdmi_spd_infoframe_check(frame);
> +	if (WARN_ON(ret))
> +		return false;
> +
> +	return true;
>  }
>  
> -static void
> -intel_hdmi_set_hdmi_infoframe(struct intel_encoder *encoder,
> -			      const struct intel_crtc_state *crtc_state,
> -			      const struct drm_connector_state *conn_state)
> -{
> -	union hdmi_infoframe frame;
> +static bool
> +intel_hdmi_compute_hdmi_infoframe(struct intel_encoder *encoder,
> +				  struct intel_crtc_state *crtc_state,
> +				  struct drm_connector_state *conn_state)
> +{
> +	struct hdmi_vendor_infoframe *frame =
> +		&crtc_state->infoframes.hdmi.vendor.hdmi;
> +	const struct drm_display_info *info =
> +		&conn_state->connector->display_info;
>  	int ret;
>  
> -	ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
> +	if (!crtc_state->has_infoframe || !info->has_hdmi_infoframe)
> +		return true;
> +
> +	crtc_state->infoframes.enable |=
> +		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_VENDOR);
> +
> +	ret = drm_hdmi_vendor_infoframe_from_display_mode(frame,
>  							  conn_state->connector,
>  							  &crtc_state->base.adjusted_mode);
> -	if (ret < 0)
> -		return;
> +	if (WARN_ON(ret))
> +		return false;
>  
> -	intel_write_infoframe(encoder, crtc_state,
> -			      &frame);
> +	ret = hdmi_vendor_infoframe_check(frame);
> +	if (WARN_ON(ret))
> +		return false;
> +
> +	return true;
>  }
>  
>  static void g4x_set_infoframes(struct intel_encoder *encoder,
> @@ -645,9 +691,15 @@ static void g4x_set_infoframes(struct intel_encoder *encoder,
>  	I915_WRITE(reg, val);
>  	POSTING_READ(reg);
>  
> -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_AVI,
> +			      &crtc_state->infoframes.avi);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_SPD,
> +			      &crtc_state->infoframes.spd);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_VENDOR,
> +			      &crtc_state->infoframes.hdmi);
>  }
>  
>  static bool hdmi_sink_is_deep_color(const struct drm_connector_state *conn_state)
> @@ -713,7 +765,10 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
>  	i915_reg_t reg;
> -	u32 val = 0;
> +
> +	if ((crtc_state->infoframes.enable &
> +	     intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
> +		return false;
>  
>  	if (HAS_DDI(dev_priv))
>  		reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
> @@ -724,18 +779,31 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
>  	else
>  		return false;
>  
> +	I915_WRITE(reg, crtc_state->infoframes.gcp);
> +
> +	return true;
> +}
> +
> +static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder,
> +					     struct intel_crtc_state *crtc_state,
> +					     struct drm_connector_state *conn_state)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +
> +	if (IS_G4X(dev_priv) || !crtc_state->has_infoframe)
> +		return;
> +
> +	crtc_state->infoframes.enable |=
> +		intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL);
> +
>  	/* Indicate color depth whenever the sink supports deep color */
>  	if (hdmi_sink_is_deep_color(conn_state))
> -		val |= GCP_COLOR_INDICATION;
> +		crtc_state->infoframes.gcp |= GCP_COLOR_INDICATION;
>  
>  	/* Enable default_phase whenever the display mode is suitably aligned */
>  	if (gcp_default_phase_possible(crtc_state->pipe_bpp,
>  				       &crtc_state->base.adjusted_mode))
> -		val |= GCP_DEFAULT_PHASE_ENABLE;
> -
> -	I915_WRITE(reg, val);
> -
> -	return val != 0;
> +		crtc_state->infoframes.gcp |= GCP_DEFAULT_PHASE_ENABLE;
>  }
>  
>  static void ibx_set_infoframes(struct intel_encoder *encoder,
> @@ -786,9 +854,15 @@ static void ibx_set_infoframes(struct intel_encoder *encoder,
>  	I915_WRITE(reg, val);
>  	POSTING_READ(reg);
>  
> -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_AVI,
> +			      &crtc_state->infoframes.avi);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_SPD,
> +			      &crtc_state->infoframes.spd);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_VENDOR,
> +			      &crtc_state->infoframes.hdmi);
>  }
>  
>  static void cpt_set_infoframes(struct intel_encoder *encoder,
> @@ -829,9 +903,15 @@ static void cpt_set_infoframes(struct intel_encoder *encoder,
>  	I915_WRITE(reg, val);
>  	POSTING_READ(reg);
>  
> -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_AVI,
> +			      &crtc_state->infoframes.avi);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_SPD,
> +			      &crtc_state->infoframes.spd);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_VENDOR,
> +			      &crtc_state->infoframes.hdmi);
>  }
>  
>  static void vlv_set_infoframes(struct intel_encoder *encoder,
> @@ -881,9 +961,15 @@ static void vlv_set_infoframes(struct intel_encoder *encoder,
>  	I915_WRITE(reg, val);
>  	POSTING_READ(reg);
>  
> -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_AVI,
> +			      &crtc_state->infoframes.avi);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_SPD,
> +			      &crtc_state->infoframes.spd);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_VENDOR,
> +			      &crtc_state->infoframes.hdmi);
>  }
>  
>  static void hsw_set_infoframes(struct intel_encoder *encoder,
> @@ -914,9 +1000,15 @@ static void hsw_set_infoframes(struct intel_encoder *encoder,
>  	I915_WRITE(reg, val);
>  	POSTING_READ(reg);
>  
> -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_AVI,
> +			      &crtc_state->infoframes.avi);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_SPD,
> +			      &crtc_state->infoframes.spd);
> +	intel_write_infoframe(encoder, crtc_state,
> +			      HDMI_INFOFRAME_TYPE_VENDOR,
> +			      &crtc_state->infoframes.hdmi);
>  }
>  
>  void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
> @@ -1851,6 +1943,27 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
>  		}
>  	}
>  
> +	if (pipe_config->has_hdmi_sink)
> +		pipe_config->infoframes.enable |=
> +			intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_NULL);
> +
> +	intel_hdmi_compute_gcp_infoframe(encoder, pipe_config, conn_state);
> +
> +	if (!intel_hdmi_compute_avi_infoframe(encoder, pipe_config, conn_state)) {
> +		DRM_DEBUG_KMS("bad AVI infoframe\n");
> +		return false;
> +	}
> +
> +	if (!intel_hdmi_compute_spd_infoframe(encoder, pipe_config, conn_state)) {
> +		DRM_DEBUG_KMS("bad SPD infoframe\n");
> +		return false;
> +	}
> +
> +	if (!intel_hdmi_compute_hdmi_infoframe(encoder, pipe_config, conn_state)) {
> +		DRM_DEBUG_KMS("bad HDMI infoframe\n");
> +		return false;
> +	}
> +
>  	return true;
>  }
>  
> -- 
> 2.16.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 14/18] drm/i915: Read out HDMI infoframes
  2018-09-20 18:51 ` [PATCH 14/18] drm/i915: Read out " Ville Syrjala
@ 2018-09-24 16:08   ` Daniel Vetter
  2018-09-24 16:52     ` Ville Syrjälä
  0 siblings, 1 reply; 95+ messages in thread
From: Daniel Vetter @ 2018-09-24 16:08 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:41PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Add code to read the infoframes from the video DIP and unpack them into
> the crtc state.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c  |  17 ++++
>  drivers/gpu/drm/i915/intel_drv.h  |  10 ++
>  drivers/gpu/drm/i915/intel_hdmi.c | 203 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 230 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 5f3bd536d261..a56289f78326 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -3459,6 +3459,23 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
>  			bxt_ddi_phy_get_lane_lat_optim_mask(encoder);
>  
>  	intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
> +
> +	intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
> +
> +	if (!intel_read_infoframe(encoder, pipe_config,
> +				  HDMI_INFOFRAME_TYPE_AVI,
> +				  &pipe_config->infoframes.avi))
> +		DRM_ERROR("failed to read AVI infoframe\n");
> +
> +	if (!intel_read_infoframe(encoder, pipe_config,
> +				  HDMI_INFOFRAME_TYPE_SPD,
> +				  &pipe_config->infoframes.spd))
> +		DRM_ERROR("failed to read SPD infoframe:\n");
> +
> +	if (!intel_read_infoframe(encoder, pipe_config,
> +				  HDMI_INFOFRAME_TYPE_VENDOR,
> +				  &pipe_config->infoframes.hdmi))
> +		DRM_ERROR("failed to read HDMI infoframe\n");
>  }
>  
>  static enum intel_output_type
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 357624a6bfe2..75ec99b85232 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1185,6 +1185,10 @@ struct intel_digital_port {
>  				const struct intel_crtc_state *crtc_state,
>  				unsigned int type,
>  				const void *frame, ssize_t len);
> +	ssize_t (*read_infoframe)(struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state,
> +				  unsigned int type,
> +				  void *frame, ssize_t len);
>  	void (*set_infoframes)(struct intel_encoder *encoder,
>  			       bool enable,
>  			       const struct intel_crtc_state *crtc_state,
> @@ -1867,6 +1871,12 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
>  u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *crtc_state);
>  u32 intel_hdmi_infoframe_enable(unsigned int type);
> +void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
> +				   struct intel_crtc_state *crtc_state);
> +bool intel_read_infoframe(struct intel_encoder *encoder,
> +			  const struct intel_crtc_state *crtc_state,
> +			  enum hdmi_infoframe_type type,
> +			  union hdmi_infoframe *frame);
>  
>  
>  /* intel_lvds.c */
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index 491001fc0fad..27cb6ec32e94 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -203,6 +203,31 @@ static void g4x_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(VIDEO_DIP_CTL);
>  }
>  
> +static ssize_t g4x_read_infoframe(struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state,
> +				  unsigned int type,
> +				  void *frame, ssize_t len)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	u32 val, *data = frame;
> +	int i;
> +
> +	val = I915_READ(VIDEO_DIP_CTL);
> +
> +	if ((val & g4x_infoframe_enable(type)) == 0)
> +		return 0;
> +
> +	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
> +	val |= g4x_infoframe_index(type);
> +
> +	I915_WRITE(VIDEO_DIP_CTL, val);
> +
> +	for (i = 0; i < len; i += 4)
> +		*data++ = I915_READ(VIDEO_DIP_DATA);
> +
> +	return len;
> +}
> +
>  static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> @@ -258,6 +283,32 @@ static void ibx_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(reg);
>  }
>  
> +static ssize_t ibx_read_infoframe(struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state,
> +				  unsigned int type,
> +				  void *frame, ssize_t len)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> +	u32 val, *data = frame;
> +	int i;
> +
> +	val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
> +
> +	if ((val & g4x_infoframe_enable(type)) == 0)
> +		return 0;
> +
> +	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
> +	val |= g4x_infoframe_index(type);
> +
> +	I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
> +
> +	for (i = 0; i < len; i += 4)
> +		*data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
> +
> +	return len;
> +}
> +
>  static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> @@ -319,6 +370,32 @@ static void cpt_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(reg);
>  }
>  
> +static ssize_t cpt_read_infoframe(struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state,
> +				  unsigned int type,
> +				  void *frame, ssize_t len)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> +	u32 val, *data = frame;
> +	int i;
> +
> +	val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
> +
> +	if ((val & g4x_infoframe_enable(type)) == 0)
> +		return 0;
> +
> +	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
> +	val |= g4x_infoframe_index(type);
> +
> +	I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
> +
> +	for (i = 0; i < len; i += 4)
> +		*data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
> +
> +	return len;
> +}
> +
>  static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> @@ -373,6 +450,32 @@ static void vlv_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(reg);
>  }
>  
> +static ssize_t vlv_read_infoframe(struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state,
> +				  unsigned int type,
> +				  void *frame, ssize_t len)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> +	u32 val, *data = frame;
> +	int i;
> +
> +	val = I915_READ(VLV_TVIDEO_DIP_CTL(crtc->pipe));
> +
> +	if ((val & g4x_infoframe_enable(type)) == 0)
> +		return 0;
> +
> +	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
> +	val |= g4x_infoframe_index(type);
> +
> +	I915_WRITE(VLV_TVIDEO_DIP_CTL(crtc->pipe), val);
> +
> +	for (i = 0; i < len; i += 4)
> +		*data++ = I915_READ(VLV_TVIDEO_DIP_DATA(crtc->pipe));
> +
> +	return len;
> +}
> +
>  static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> @@ -425,6 +528,28 @@ static void hsw_write_infoframe(struct intel_encoder *encoder,
>  	POSTING_READ(ctl_reg);
>  }
>  
> +static ssize_t hsw_read_infoframe(struct intel_encoder *encoder,
> +				  const struct intel_crtc_state *crtc_state,
> +				  unsigned int type,
> +				  void *frame, ssize_t len)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
> +	u32 val, *data = frame;
> +	int i;
> +
> +	val = I915_READ(HSW_TVIDEO_DIP_CTL(cpu_transcoder));
> +
> +	if ((val & hsw_infoframe_enable(type)) == 0)
> +		return 0;
> +
> +	for (i = 0; i < len; i += 4)
> +		*data++ = I915_READ(hsw_dip_data_reg(dev_priv, cpu_transcoder,
> +						     type, i >> 2));
> +
> +	return len;
> +}
> +
>  static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
>  				  const struct intel_crtc_state *pipe_config)
>  {
> @@ -530,6 +655,39 @@ static void intel_write_infoframe(struct intel_encoder *encoder,
>  	intel_dig_port->write_infoframe(encoder, crtc_state, type, buffer, len);
>  }
>  
> +bool intel_read_infoframe(struct intel_encoder *encoder,
> +			  const struct intel_crtc_state *crtc_state,
> +			  enum hdmi_infoframe_type type,
> +			  union hdmi_infoframe *frame)

Bit a bikeshed: I'd drop the boolean here and pull the debug output in.
That way you can give a bit better hint about what's going wrong. And less
duplicated code. You can still print the type.

> +{
> +	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
> +	u8 buffer[VIDEO_DIP_DATA_SIZE];
> +	ssize_t len;
> +	int ret;
> +
> +	if ((crtc_state->infoframes.enable &
> +	     intel_hdmi_infoframe_enable(type)) == 0)
> +		return true;

Afaiui you only need this because g4x doesn't check the pipe (well, port)
association. But then all the tests once again check this by confirming
that the infoframe they should read out is enabled. I'd drop the check in
the various hw-specific readout functions (it's duplicated). That should
still work with g4x here, as long as you filter at this level here.

With or without the bikesheds:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> +
> +	len = intel_dig_port->read_infoframe(encoder, crtc_state,
> +					     type, buffer, sizeof(buffer));
> +	if (len == 0)
> +		return true;
> +
> +	/* Fill the 'hole' (see big comment above) at position 3 */
> +	memmove(&buffer[1], &buffer[0], 3);
> +
> +	/* see comment above for the reason for this offset */
> +	ret = hdmi_infoframe_unpack(frame, buffer + 1, sizeof(buffer) - 1);
> +	if (ret)
> +		return false;
> +
> +	if (frame->any.type != type)
> +		return false;
> +
> +	return true;
> +}
> +
>  static bool
>  intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder,
>  				 struct intel_crtc_state *crtc_state,
> @@ -784,6 +942,29 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
>  	return true;
>  }
>  
> +void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
> +				   struct intel_crtc_state *crtc_state)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> +	i915_reg_t reg;
> +
> +	if ((crtc_state->infoframes.enable &
> +	     intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
> +		return;
> +
> +	if (HAS_DDI(dev_priv))
> +		reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
> +	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> +		reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
> +	else if (HAS_PCH_SPLIT(dev_priv))
> +		reg = TVIDEO_DIP_GCP(crtc->pipe);
> +	else
> +		return;
> +
> +	crtc_state->infoframes.gcp = I915_READ(reg);
> +}
> +
>  static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder,
>  					     struct intel_crtc_state *crtc_state,
>  					     struct drm_connector_state *conn_state)
> @@ -1382,6 +1563,23 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
>  	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
>  
>  	pipe_config->lane_count = 4;
> +
> +	intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
> +
> +	if (!intel_read_infoframe(encoder, pipe_config,
> +				  HDMI_INFOFRAME_TYPE_AVI,
> +				  &pipe_config->infoframes.avi))
> +		DRM_ERROR("failed to read AVI infoframe\n");
> +
> +	if (!intel_read_infoframe(encoder, pipe_config,
> +				  HDMI_INFOFRAME_TYPE_SPD,
> +				  &pipe_config->infoframes.spd))
> +		DRM_ERROR("failed to read SPD infoframe:\n");
> +
> +	if (!intel_read_infoframe(encoder, pipe_config,
> +				  HDMI_INFOFRAME_TYPE_VENDOR,
> +				  &pipe_config->infoframes.hdmi))
> +		DRM_ERROR("failed to read HDMI infoframe\n");
>  }
>  
>  static void intel_enable_hdmi_audio(struct intel_encoder *encoder,
> @@ -2481,22 +2679,27 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
>  
>  	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
>  		intel_dig_port->write_infoframe = vlv_write_infoframe;
> +		intel_dig_port->read_infoframe = vlv_read_infoframe;
>  		intel_dig_port->set_infoframes = vlv_set_infoframes;
>  		intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
>  	} else if (IS_G4X(dev_priv)) {
>  		intel_dig_port->write_infoframe = g4x_write_infoframe;
> +		intel_dig_port->read_infoframe = g4x_read_infoframe;
>  		intel_dig_port->set_infoframes = g4x_set_infoframes;
>  		intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
>  	} else if (HAS_DDI(dev_priv)) {
>  		intel_dig_port->write_infoframe = hsw_write_infoframe;
> +		intel_dig_port->read_infoframe = hsw_read_infoframe;
>  		intel_dig_port->set_infoframes = hsw_set_infoframes;
>  		intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
>  	} else if (HAS_PCH_IBX(dev_priv)) {
>  		intel_dig_port->write_infoframe = ibx_write_infoframe;
> +		intel_dig_port->read_infoframe = ibx_read_infoframe;
>  		intel_dig_port->set_infoframes = ibx_set_infoframes;
>  		intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
>  	} else {
>  		intel_dig_port->write_infoframe = cpt_write_infoframe;
> +		intel_dig_port->read_infoframe = cpt_read_infoframe;
>  		intel_dig_port->set_infoframes = cpt_set_infoframes;
>  		intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
>  	}
> -- 
> 2.16.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Intel-gfx] [PATCH 16/18] drm/i915/sdvo: Read out HDMI infoframes
  2018-09-20 18:51 ` [PATCH 16/18] drm/i915/sdvo: Read out " Ville Syrjala
@ 2018-09-24 16:10   ` Daniel Vetter
  2018-09-24 17:13     ` Ville Syrjälä
  0 siblings, 1 reply; 95+ messages in thread
From: Daniel Vetter @ 2018-09-24 16:10 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:43PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Read the HDMI infoframes from the hbuf and unpack them into
> the crtc state.
> 
> Well, actually just AVI infoframe for now but let's write the
> infoframe readout code in a more generic fashion in case we
> expand this later.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Hm, caring about sdvo seems a bit overkill. And afaik we don't have any
sdvo (much less hdmi) in CI. I'm leaning towards just adding a
PIPE_CONFIG_QUIRK_INFOFRAMES for sdvo, and short-circuiting the checks if
that's set. Except if you can somehow convince CI folks to add an sdvo
hdmi card to CI :-)

> ---
>  drivers/gpu/drm/i915/intel_sdvo.c | 92 +++++++++++++++++++++++++++++++++++++--
>  1 file changed, 89 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> index d8c78aebaf01..4d787c86df6d 100644
> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> @@ -981,6 +981,58 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
>  				    &tx_rate, 1);
>  }
>  
> +static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
> +					 unsigned int if_index,
> +					 u8 *data, unsigned int length)
> +{
> +	u8 set_buf_index[2] = { if_index, 0 };
> +	u8 hbuf_size, tx_rate, av_split;
> +	int i;
> +
> +	if (!intel_sdvo_get_value(intel_sdvo,
> +				  SDVO_CMD_GET_HBUF_AV_SPLIT,
> +				  &av_split, 1))
> +		return -ENXIO;
> +
> +	if (av_split < if_index)
> +		return 0;
> +
> +	if (!intel_sdvo_get_value(intel_sdvo,
> +				  SDVO_CMD_GET_HBUF_TXRATE,
> +				  &tx_rate, 1))
> +		return -ENXIO;
> +
> +	if (tx_rate == SDVO_HBUF_TX_DISABLED)
> +		return 0;
> +
> +	if (!intel_sdvo_set_value(intel_sdvo,
> +				  SDVO_CMD_SET_HBUF_INDEX,
> +				  set_buf_index, 2))
> +		return -ENXIO;
> +
> +	if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
> +				  &hbuf_size, 1))
> +		return -ENXIO;
> +
> +	/* Buffer size is 0 based, hooray! */
> +	hbuf_size++;
> +
> +	DRM_DEBUG_KMS("reading sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
> +		      if_index, length, hbuf_size);
> +
> +	hbuf_size = min_t(unsigned int, length, hbuf_size);
> +
> +	for (i = 0; i < hbuf_size; i += 8) {
> +		if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HBUF_DATA, NULL, 0))
> +			return -ENXIO;
> +		if (!intel_sdvo_read_response(intel_sdvo, &data[i],
> +					      min_t(unsigned int, 8, hbuf_size - i)))
> +			return -ENXIO;
> +	}
> +
> +	return hbuf_size;
> +}
> +
>  static bool intel_sdvo_compute_avi_infoframe(struct intel_sdvo *intel_sdvo,
>  					     struct intel_crtc_state *crtc_state,
>  					     struct drm_connector_state *conn_state)
> @@ -1039,6 +1091,37 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
>  					  sdvo_data, sizeof(sdvo_data));
>  }
>  
> +static bool intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
> +					 struct intel_crtc_state *crtc_state)
> +{
> +	u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
> +	union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
> +	ssize_t len;
> +	int ret;
> +
> +	if (!crtc_state->has_hdmi_sink)
> +		return true;
> +
> +	len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
> +					sdvo_data, sizeof(sdvo_data));
> +	if (len < 0)
> +		return false;
> +	else if (len == 0)
> +		return true;
> +
> +	crtc_state->infoframes.enable |=
> +		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
> +
> +	ret = hdmi_infoframe_unpack(frame, sdvo_data, sizeof(sdvo_data));
> +	if (ret)
> +		return false;
> +
> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_AVI)
> +		return false;
> +
> +	return true;
> +}
> +
>  static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
>  				     const struct drm_connector_state *conn_state)
>  {
> @@ -1535,6 +1618,10 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
>  		}
>  	}
>  
> +	WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
> +	     "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
> +	     pipe_config->pixel_multiplier, encoder_pixel_multiplier);
> +
>  	if (sdvox & HDMI_COLOR_RANGE_16_235)
>  		pipe_config->limited_color_range = true;
>  
> @@ -1547,9 +1634,8 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
>  			pipe_config->has_hdmi_sink = true;
>  	}
>  
> -	WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
> -	     "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
> -	     pipe_config->pixel_multiplier, encoder_pixel_multiplier);
> +	if (!intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config))
> +		DRM_ERROR("failed to read AVI infoframe\n");
>  }
>  
>  static void intel_disable_sdvo(struct intel_encoder *encoder,
> -- 
> 2.16.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 17/18] drm/i915: Check infoframe state in intel_pipe_config_compare()
  2018-09-20 18:51 ` [PATCH 17/18] drm/i915: Check infoframe state in intel_pipe_config_compare() Ville Syrjala
@ 2018-09-24 16:12   ` Daniel Vetter
  2018-10-01 20:35     ` [Intel-gfx] " Ville Syrjälä
  0 siblings, 1 reply; 95+ messages in thread
From: Daniel Vetter @ 2018-09-24 16:12 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:44PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Check the infoframes and infoframe enable state when comparing two
> crtc states.
> 
> We'll use the infoframe logging functions from video/hdmi.c to
> show the infoframes as part of the state dump.
> 
> TODO: Try to better integrate the infoframe dumps with
>       drm state dumps
> 
> v2: drm_printk() is no more
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---

Might need adapting to PIPE_CONFIG_QUIRK_INFOFRAME, but aside from that

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

>  drivers/gpu/drm/i915/intel_display.c | 49 +++++++++++++++++++++++++++++++++++-
>  1 file changed, 48 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index fbcc56caffb6..3dce49e36a05 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -11380,6 +11380,37 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n,
>  	return false;
>  }
>  
> +static bool
> +intel_compare_infoframe(const union hdmi_infoframe *a,
> +			const union hdmi_infoframe *b)
> +{
> +	return memcmp(a, b, sizeof(*a)) == 0;
> +}
> +
> +static void
> +pipe_config_infoframe_err(struct drm_i915_private *dev_priv,
> +			  bool adjust, const char *name,
> +			  const union hdmi_infoframe *a,
> +			  const union hdmi_infoframe *b)
> +{
> +	if (adjust) {
> +		if ((drm_debug & DRM_UT_KMS) == 0)
> +			return;
> +
> +		drm_dbg(DRM_UT_KMS, "mismatch in %s infoframe", name);
> +		drm_dbg(DRM_UT_KMS, "expected:");
> +		hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, a);
> +		drm_dbg(DRM_UT_KMS, "found");
> +		hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, b);
> +	} else {
> +		drm_err("mismatch in %s infoframe", name);
> +		drm_err("expected:");
> +		hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, a);
> +		drm_err("found");
> +		hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, b);
> +	}

Mildly concerned about padding fields (since these are the not-compatified
structs). Maybe dump the mismatching byte too, plus byte offset? Or maybe
I'm just too paranoid.

> +}
> +
>  static void __printf(3, 4)
>  pipe_config_err(bool adjust, const char *name, const char *format, ...)
>  {
> @@ -11541,7 +11572,17 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
>  	} \
>  } while (0)
>  
> -#define PIPE_CONF_QUIRK(quirk)	\
> +#define PIPE_CONF_CHECK_INFOFRAME(name) do { \
> +	if (!intel_compare_infoframe(&current_config->infoframes.name, \
> +				     &pipe_config->infoframes.name)) { \
> +		pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \
> +					  &current_config->infoframes.name, \
> +					  &pipe_config->infoframes.name); \
> +		ret = false; \
> +	} \
> +} while (0)
> +
> +#define PIPE_CONF_QUIRK(quirk) \
>  	((current_config->quirks | pipe_config->quirks) & (quirk))
>  
>  	PIPE_CONF_CHECK_I(cpu_transcoder);
> @@ -11670,6 +11711,12 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
>  
>  	PIPE_CONF_CHECK_I(min_voltage_level);
>  
> +	PIPE_CONF_CHECK_X(infoframes.enable);
> +	PIPE_CONF_CHECK_X(infoframes.gcp);
> +	PIPE_CONF_CHECK_INFOFRAME(avi);
> +	PIPE_CONF_CHECK_INFOFRAME(spd);
> +	PIPE_CONF_CHECK_INFOFRAME(hdmi);
> +
>  #undef PIPE_CONF_CHECK_X
>  #undef PIPE_CONF_CHECK_I
>  #undef PIPE_CONF_CHECK_BOOL
> -- 
> 2.16.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Intel-gfx] [PATCH 18/18] drm/i915: Include infoframes in the crtc state dump
  2018-09-20 18:51 ` [PATCH 18/18] drm/i915: Include infoframes in the crtc state dump Ville Syrjala
@ 2018-09-24 16:14   ` Daniel Vetter
  0 siblings, 0 replies; 95+ messages in thread
From: Daniel Vetter @ 2018-09-24 16:14 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx, dri-devel

On Thu, Sep 20, 2018 at 09:51:45PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Dump out the infoframes in the normal crtc state dump.
> 
> TODO: Try to better integrate the infoframe dumps with
>       drm state dumps
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Going to make dmesg with state debugging enabled even more noisier, but
hey, whatever gives us more data to drown in :-)

More seriously, maybe eventually someone ports drm debug over to one of
the more scalable logging thingies.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/intel_display.c | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 3dce49e36a05..27ac33a2a4d3 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -10924,6 +10924,16 @@ intel_dump_m_n_config(struct intel_crtc_state *pipe_config, char *id,
>  		      m_n->link_m, m_n->link_n, m_n->tu);
>  }
>  
> +static void
> +intel_dump_infoframe(struct drm_i915_private *dev_priv,
> +		     const union hdmi_infoframe *frame)
> +{
> +	if ((drm_debug & DRM_UT_KMS) == 0)
> +		return;
> +
> +	hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, frame);
> +}
> +
>  #define OUTPUT_TYPE(x) [INTEL_OUTPUT_ ## x] = #x
>  
>  static const char * const output_type_str[] = {
> @@ -11013,6 +11023,22 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
>  	DRM_DEBUG_KMS("audio: %i, infoframes: %i\n",
>  		      pipe_config->has_audio, pipe_config->has_infoframe);
>  
> +	DRM_DEBUG_KMS("infoframes enabled: 0x%x\n",
> +		      pipe_config->infoframes.enable);
> +
> +	if (pipe_config->infoframes.enable &
> +	    intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL))
> +		DRM_DEBUG_KMS("GCP: 0x%x\n", pipe_config->infoframes.gcp);
> +	if (pipe_config->infoframes.enable &
> +	    intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI))
> +		intel_dump_infoframe(dev_priv, &pipe_config->infoframes.avi);
> +	if (pipe_config->infoframes.enable &
> +	    intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD))
> +		intel_dump_infoframe(dev_priv, &pipe_config->infoframes.spd);
> +	if (pipe_config->infoframes.enable &
> +	    intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_VENDOR))
> +		intel_dump_infoframe(dev_priv, &pipe_config->infoframes.hdmi);
> +
>  	DRM_DEBUG_KMS("requested mode:\n");
>  	drm_mode_debug_printmodeline(&pipe_config->base.mode);
>  	DRM_DEBUG_KMS("adjusted mode:\n");
> -- 
> 2.16.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Intel-gfx] [PATCH 11/18] drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
  2018-09-24 15:51   ` Daniel Vetter
@ 2018-09-24 16:36     ` Ville Syrjälä
  2018-10-01  6:55       ` Daniel Vetter
  0 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-24 16:36 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Mon, Sep 24, 2018 at 05:51:16PM +0200, Daniel Vetter wrote:
> On Thu, Sep 20, 2018 at 09:51:38PM +0300, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > We want to start tracking which infoframes are enabled, so let's replace
> > the boolean flag with a bitmask.
> > 
> > We'll abstract the bitmask so that it's not platform dependent. That
> > will allow us to examine the bitmask later in platform independent code.
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c  |  2 +-
> >  drivers/gpu/drm/i915/intel_drv.h  |  4 +-
> >  drivers/gpu/drm/i915/intel_hdmi.c | 87 ++++++++++++++++++++++++++++-----------
> >  3 files changed, 68 insertions(+), 25 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > index 086e3f940586..098a0e4edf2a 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -3390,7 +3390,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
> >  		pipe_config->has_hdmi_sink = true;
> >  		intel_dig_port = enc_to_dig_port(&encoder->base);
> >  
> > -		if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
> > +		if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
> >  			pipe_config->has_infoframe = true;
> >  
> >  		if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index e0f3a79fc75e..6815c69aac2f 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1181,7 +1181,7 @@ struct intel_digital_port {
> >  			       bool enable,
> >  			       const struct intel_crtc_state *crtc_state,
> >  			       const struct drm_connector_state *conn_state);
> > -	bool (*infoframe_enabled)(struct intel_encoder *encoder,
> > +	u32 (*infoframes_enabled)(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config);
> >  };
> >  
> > @@ -1856,6 +1856,8 @@ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
> >  				       bool scrambling);
> >  void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
> >  void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
> > +u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> > +				  const struct intel_crtc_state *crtc_state);
> >  
> >  
> >  /* intel_lvds.c */
> > diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> > index c3c2a638d062..a8fcddb199ae 100644
> > --- a/drivers/gpu/drm/i915/intel_hdmi.c
> > +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> > @@ -100,10 +100,14 @@ static u32 g4x_infoframe_index(unsigned int type)
> >  static u32 g4x_infoframe_enable(unsigned int type)
> >  {
> >  	switch (type) {
> > +	case HDMI_PACKET_TYPE_NULL:
> > +		return VIDEO_DIP_ENABLE; /* slight lie */
> 
> Not exactly sure why we're tracking this one here, but not for hsw.

HSW+ doesn't have a DIP enable bit like this. It only has the
bits to enable specific infoframes.

> Shouldn't we include that one if the DDI port is in hdmi mode? Would be
> more consistent I think.

Yes that would seem like the more correct thing. I think the reason
I did this here was so that I could map the DIP_ENABLE bit to
something unique. Would allow us to differentiate between the
"DIP enabled with no infoframes enabled" vs. "DIP enabled with
some infoframes enabled" cases. But seeing as we always enable some
infoframes I guess this doesn't really provide us with anything
particularly useful.

That said, I'm actually not sure whether the hw will send the null
packets if we don't enable the DIP. Would require a HDMI analyzer
to confirm.

Hmm. Actually gen4 bspec tells me:
"If DIP is enabled but DIP types are all disabled, no DIP is sent.
 However, a single Null DIP will be sent at the same point in the
 stream that DIP packets would have been sent. This is done to
 keep the port in HDMI mode, otherwise it would revert to DVI mode.
 The "Null packets enabled during vsync" mode (bit #9 of port
 control register) overrides this behavior."

So I guess mapping the null packet to the DIP enable bit is more or
less correct. Although the spec doesn't quite say whether the null
packet is also sent when some DIP types are also enabled, or if it
is only send when no DIP types are enabled.

So to match the hw I guess the readout should really do something
like:

if (hdmi & HDMI_MODE || dip_ctl & DIP_ENABLE)
	infoframes |= TYPE_NULL;

but that would again mean that we can't tell the two cases
apart.

> 
> Aside from that lgtm, has my
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> once we figured the TYPE_NULL thing out.
> -Daniel
> 
> >  	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
> >  		return VIDEO_DIP_ENABLE_GCP;
> >  	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> >  		return VIDEO_DIP_ENABLE_GAMUT;
> > +	case DP_SDP_VSC:
> > +		return 0;
> >  	case HDMI_INFOFRAME_TYPE_AVI:
> >  		return VIDEO_DIP_ENABLE_AVI;
> >  	case HDMI_INFOFRAME_TYPE_SPD:
> > @@ -119,6 +123,8 @@ static u32 g4x_infoframe_enable(unsigned int type)
> >  static u32 hsw_infoframe_enable(unsigned int type)
> >  {
> >  	switch (type) {
> > +	case HDMI_PACKET_TYPE_NULL:
> > +		return 0;
> >  	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
> >  		return VIDEO_DIP_ENABLE_GCP_HSW;
> >  	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> > @@ -197,19 +203,19 @@ static void g4x_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(VIDEO_DIP_CTL);
> >  }
> >  
> > -static bool g4x_infoframe_enabled(struct intel_encoder *encoder,
> > +static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> >  	u32 val = I915_READ(VIDEO_DIP_CTL);
> >  
> >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > -		return false;
> > +		return 0;
> >  
> >  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> > -		return false;
> > +		return 0;
> >  
> > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
> >  }
> >  
> > @@ -252,7 +258,7 @@ static void ibx_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(reg);
> >  }
> >  
> > -static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
> > +static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > @@ -261,12 +267,12 @@ static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
> >  	u32 val = I915_READ(reg);
> >  
> >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > -		return false;
> > +		return 0;
> >  
> >  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> > -		return false;
> > +		return 0;
> >  
> > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
> >  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
> >  }
> > @@ -313,7 +319,7 @@ static void cpt_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(reg);
> >  }
> >  
> > -static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
> > +static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > @@ -321,9 +327,9 @@ static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
> >  	u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
> >  
> >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > -		return false;
> > +		return 0;
> >  
> > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
> >  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
> >  }
> > @@ -367,7 +373,7 @@ static void vlv_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(reg);
> >  }
> >  
> > -static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
> > +static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > @@ -375,12 +381,12 @@ static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
> >  	u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
> >  
> >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > -		return false;
> > +		return 0;
> >  
> >  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> > -		return false;
> > +		return 0;
> >  
> > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
> >  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
> >  }
> > @@ -419,7 +425,7 @@ static void hsw_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(ctl_reg);
> >  }
> >  
> > -static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
> > +static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > @@ -430,6 +436,42 @@ static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
> >  		      VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
> >  }
> >  
> > +static const u8 infoframe_type_to_idx[] = {
> > +	HDMI_PACKET_TYPE_NULL,
> > +	HDMI_PACKET_TYPE_GENERAL_CONTROL,
> > +	HDMI_PACKET_TYPE_GAMUT_METADATA,
> > +	DP_SDP_VSC,
> > +	HDMI_INFOFRAME_TYPE_AVI,
> > +	HDMI_INFOFRAME_TYPE_SPD,
> > +	HDMI_INFOFRAME_TYPE_VENDOR,
> > +};
> > +
> > +u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> > +				  const struct intel_crtc_state *crtc_state)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
> > +	u32 val, ret = 0;
> > +	int i;
> > +
> > +	val = dig_port->infoframes_enabled(encoder, crtc_state);
> > +
> > +	/* map from hardware bits to dip idx */
> > +	for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
> > +		unsigned int type = infoframe_type_to_idx[i];
> > +
> > +		if (HAS_DDI(dev_priv)) {
> > +			if (val & hsw_infoframe_enable(type))
> > +				ret |= BIT(i);
> > +		} else {
> > +			if (val & g4x_infoframe_enable(type))
> > +				ret |= BIT(i);
> > +		}
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> >  /*
> >   * The data we write to the DIP data buffer registers is 1 byte bigger than the
> >   * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
> > @@ -1200,7 +1242,6 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
> >  				  struct intel_crtc_state *pipe_config)
> >  {
> >  	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> > -	struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi);
> >  	struct drm_device *dev = encoder->base.dev;
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> >  	u32 tmp, flags = 0;
> > @@ -1223,7 +1264,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
> >  	if (tmp & HDMI_MODE_SELECT_HDMI)
> >  		pipe_config->has_hdmi_sink = true;
> >  
> > -	if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
> > +	if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
> >  		pipe_config->has_infoframe = true;
> >  
> >  	if (tmp & SDVO_AUDIO_ENABLE)
> > @@ -2325,23 +2366,23 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
> >  	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
> >  		intel_dig_port->write_infoframe = vlv_write_infoframe;
> >  		intel_dig_port->set_infoframes = vlv_set_infoframes;
> > -		intel_dig_port->infoframe_enabled = vlv_infoframe_enabled;
> > +		intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
> >  	} else if (IS_G4X(dev_priv)) {
> >  		intel_dig_port->write_infoframe = g4x_write_infoframe;
> >  		intel_dig_port->set_infoframes = g4x_set_infoframes;
> > -		intel_dig_port->infoframe_enabled = g4x_infoframe_enabled;
> > +		intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
> >  	} else if (HAS_DDI(dev_priv)) {
> >  		intel_dig_port->write_infoframe = hsw_write_infoframe;
> >  		intel_dig_port->set_infoframes = hsw_set_infoframes;
> > -		intel_dig_port->infoframe_enabled = hsw_infoframe_enabled;
> > +		intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
> >  	} else if (HAS_PCH_IBX(dev_priv)) {
> >  		intel_dig_port->write_infoframe = ibx_write_infoframe;
> >  		intel_dig_port->set_infoframes = ibx_set_infoframes;
> > -		intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
> > +		intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
> >  	} else {
> >  		intel_dig_port->write_infoframe = cpt_write_infoframe;
> >  		intel_dig_port->set_infoframes = cpt_set_infoframes;
> > -		intel_dig_port->infoframe_enabled = cpt_infoframe_enabled;
> > +		intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
> >  	}
> >  }
> >  
> > -- 
> > 2.16.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 13/18] drm/i915: Precompute HDMI infoframes
  2018-09-24 15:58   ` Daniel Vetter
@ 2018-09-24 16:42     ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-24 16:42 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Mon, Sep 24, 2018 at 05:58:25PM +0200, Daniel Vetter wrote:
> On Thu, Sep 20, 2018 at 09:51:40PM +0300, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Store the infoframes in the crtc state and precompute them in
> > .compute_config(). While precomputing we'll also fill out the
> > inforames.enable bitmask appropriately.
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c  |   1 +
> >  drivers/gpu/drm/i915/intel_drv.h  |   5 +
> >  drivers/gpu/drm/i915/intel_hdmi.c | 249 +++++++++++++++++++++++++++-----------
> >  3 files changed, 187 insertions(+), 68 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > index 19fef88e680e..5f3bd536d261 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -3391,6 +3391,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
> >  		intel_dig_port = enc_to_dig_port(&encoder->base);
> >  
> >  		pipe_config->infoframes.enable |=
> > +			intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_NULL) |
> 
> Misplaced hunk? Assuming I'm reading this correctly, this will give you a
> 0. Not exactly sure what's going on here ... I guess I'm not following why
> we care about TYPE_NULL, and why we have to reconstruct it here?

I rather wanted the infoframes bitmask to be truthful about which
packets we're sending out. But not quite sure why I included it in
this particular patch.

> 
> I thought TYPE_NULL is equivalent to state->has_hdmi_sink? Comment
> (unfortunately not yet kerneldoc) even explains that ...

Yeah it's the same thing (apart from the g4x DIP enable thing). Maybe
I should remove has_hdmi_sink entirely and just rely on the null packet
bit instead...

> 
> Maybe just nuke all the TYPE_NULL tracking here, perhaps with the g4x
> (except for g4x itself, because it's shared there) decoder to also take
> DIP_ENABLE into account for has_hdmi_sink.

That would the other option I suppose. Though I might like the idea
of dropping the bool for the bitmask a bit more perhaps.

> 
> Or update the comment in intel_crtc_state.
> 
> Otherwise lgtm, thought admittedly I did clean over the details a bit,
> trusting CI and gcc to catch the small stuff :-)
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> with the TYPE_NULL
> story somehow figured out.
> -Daniel
> 
> 
> >  			intel_hdmi_infoframes_enabled(encoder, pipe_config);
> >  
> >  		if (pipe_config->infoframes.enable)
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index 50c0c049ee15..357624a6bfe2 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -895,6 +895,10 @@ struct intel_crtc_state {
> >  
> >  	struct {
> >  		u32 enable;
> > +		u32 gcp;
> > +		union hdmi_infoframe avi;
> > +		union hdmi_infoframe spd;
> > +		union hdmi_infoframe hdmi;
> >  	} infoframes;
> >  
> >  	/* HDMI scrambling status */
> > @@ -1862,6 +1866,7 @@ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
> >  void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
> >  u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *crtc_state);
> > +u32 intel_hdmi_infoframe_enable(unsigned int type);
> >  
> >  
> >  /* intel_lvds.c */
> > diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> > index 98a44084324c..491001fc0fad 100644
> > --- a/drivers/gpu/drm/i915/intel_hdmi.c
> > +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> > @@ -446,6 +446,18 @@ static const u8 infoframe_type_to_idx[] = {
> >  	HDMI_INFOFRAME_TYPE_VENDOR,
> >  };
> >  
> > +u32 intel_hdmi_infoframe_enable(unsigned int type)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
> > +		if (infoframe_type_to_idx[i] == type)
> > +			return BIT(i);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *crtc_state)
> >  {
> > @@ -491,15 +503,23 @@ u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> >   */
> >  static void intel_write_infoframe(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *crtc_state,
> > -				  union hdmi_infoframe *frame)
> > +				  enum hdmi_infoframe_type type,
> > +				  const union hdmi_infoframe *frame)
> >  {
> >  	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
> >  	u8 buffer[VIDEO_DIP_DATA_SIZE];
> >  	ssize_t len;
> >  
> > +	if ((crtc_state->infoframes.enable &
> > +	     intel_hdmi_infoframe_enable(type)) == 0)
> > +		return;
> > +
> > +	if (WARN_ON(frame->any.type != type))
> > +		return;
> > +
> >  	/* see comment above for the reason for this offset */
> > -	len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1);
> > -	if (len < 0)
> > +	len = hdmi_infoframe_pack_only(frame, buffer + 1, sizeof(buffer) - 1);
> > +	if (WARN_ON(len < 0))
> >  		return;
> >  
> >  	/* Insert the 'hole' (see big comment above) at position 3 */
> > @@ -507,85 +527,111 @@ static void intel_write_infoframe(struct intel_encoder *encoder,
> >  	buffer[3] = 0;
> >  	len++;
> >  
> > -	intel_dig_port->write_infoframe(encoder,
> > -					crtc_state,
> > -					frame->any.type, buffer, len);
> > +	intel_dig_port->write_infoframe(encoder, crtc_state, type, buffer, len);
> >  }
> >  
> > -static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder,
> > -					 const struct intel_crtc_state *crtc_state,
> > -					 const struct drm_connector_state *conn_state)
> > +static bool
> > +intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder,
> > +				 struct intel_crtc_state *crtc_state,
> > +				 struct drm_connector_state *conn_state)
> >  {
> >  	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> > +	struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi;
> > +	bool is_hdmi2_sink = conn_state->connector->display_info.hdmi.scdc.supported;
> >  	const struct drm_display_mode *adjusted_mode =
> >  		&crtc_state->base.adjusted_mode;
> > -	struct drm_connector *connector = &intel_hdmi->attached_connector->base;
> > -	bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
> > -	union hdmi_infoframe frame;
> >  	int ret;
> >  
> > -	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
> > +	if (!crtc_state->has_infoframe)
> > +		return true;
> > +
> > +	crtc_state->infoframes.enable |=
> > +		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
> > +
> > +	ret = drm_hdmi_avi_infoframe_from_display_mode(frame,
> >  						       adjusted_mode,
> >  						       is_hdmi2_sink);
> > -	if (ret < 0) {
> > -		DRM_ERROR("couldn't fill AVI infoframe\n");
> > -		return;
> > -	}
> > +	if (ret)
> > +		return false;
> >  
> >  	if (crtc_state->ycbcr420)
> > -		frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
> > +		frame->colorspace = HDMI_COLORSPACE_YUV420;
> >  	else
> > -		frame.avi.colorspace = HDMI_COLORSPACE_RGB;
> > +		frame->colorspace = HDMI_COLORSPACE_RGB;
> >  
> > -	drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode,
> > +	drm_hdmi_avi_infoframe_quant_range(frame, adjusted_mode,
> >  					   crtc_state->limited_color_range ?
> >  					   HDMI_QUANTIZATION_RANGE_LIMITED :
> >  					   HDMI_QUANTIZATION_RANGE_FULL,
> >  					   intel_hdmi->rgb_quant_range_selectable,
> >  					   is_hdmi2_sink);
> >  
> > -	drm_hdmi_avi_infoframe_content_type(&frame.avi,
> > -					    conn_state);
> > +	drm_hdmi_avi_infoframe_content_type(frame, conn_state);
> >  
> >  	/* TODO: handle pixel repetition for YCBCR420 outputs */
> > -	intel_write_infoframe(encoder, crtc_state,
> > -			      &frame);
> > +
> > +	ret = hdmi_avi_infoframe_check(frame);
> > +	if (WARN_ON(ret))
> > +		return false;
> > +
> > +	return true;
> >  }
> >  
> > -static void intel_hdmi_set_spd_infoframe(struct intel_encoder *encoder,
> > -					 const struct intel_crtc_state *crtc_state)
> > +static bool
> > +intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder,
> > +				 struct intel_crtc_state *crtc_state,
> > +				 struct drm_connector_state *conn_state)
> >  {
> > -	union hdmi_infoframe frame;
> > +	struct hdmi_spd_infoframe *frame = &crtc_state->infoframes.spd.spd;
> >  	int ret;
> >  
> > -	ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx");
> > -	if (ret < 0) {
> > -		DRM_ERROR("couldn't fill SPD infoframe\n");
> > -		return;
> > -	}
> > +	if (!crtc_state->has_infoframe)
> > +		return true;
> >  
> > -	frame.spd.sdi = HDMI_SPD_SDI_PC;
> > +	crtc_state->infoframes.enable |=
> > +		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD);
> >  
> > -	intel_write_infoframe(encoder, crtc_state,
> > -			      &frame);
> > +	ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx");
> > +	if (WARN_ON(ret))
> > +		return false;
> > +
> > +	frame->sdi = HDMI_SPD_SDI_PC;
> > +
> > +	ret = hdmi_spd_infoframe_check(frame);
> > +	if (WARN_ON(ret))
> > +		return false;
> > +
> > +	return true;
> >  }
> >  
> > -static void
> > -intel_hdmi_set_hdmi_infoframe(struct intel_encoder *encoder,
> > -			      const struct intel_crtc_state *crtc_state,
> > -			      const struct drm_connector_state *conn_state)
> > -{
> > -	union hdmi_infoframe frame;
> > +static bool
> > +intel_hdmi_compute_hdmi_infoframe(struct intel_encoder *encoder,
> > +				  struct intel_crtc_state *crtc_state,
> > +				  struct drm_connector_state *conn_state)
> > +{
> > +	struct hdmi_vendor_infoframe *frame =
> > +		&crtc_state->infoframes.hdmi.vendor.hdmi;
> > +	const struct drm_display_info *info =
> > +		&conn_state->connector->display_info;
> >  	int ret;
> >  
> > -	ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
> > +	if (!crtc_state->has_infoframe || !info->has_hdmi_infoframe)
> > +		return true;
> > +
> > +	crtc_state->infoframes.enable |=
> > +		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_VENDOR);
> > +
> > +	ret = drm_hdmi_vendor_infoframe_from_display_mode(frame,
> >  							  conn_state->connector,
> >  							  &crtc_state->base.adjusted_mode);
> > -	if (ret < 0)
> > -		return;
> > +	if (WARN_ON(ret))
> > +		return false;
> >  
> > -	intel_write_infoframe(encoder, crtc_state,
> > -			      &frame);
> > +	ret = hdmi_vendor_infoframe_check(frame);
> > +	if (WARN_ON(ret))
> > +		return false;
> > +
> > +	return true;
> >  }
> >  
> >  static void g4x_set_infoframes(struct intel_encoder *encoder,
> > @@ -645,9 +691,15 @@ static void g4x_set_infoframes(struct intel_encoder *encoder,
> >  	I915_WRITE(reg, val);
> >  	POSTING_READ(reg);
> >  
> > -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> > -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> > -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_AVI,
> > +			      &crtc_state->infoframes.avi);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_SPD,
> > +			      &crtc_state->infoframes.spd);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_VENDOR,
> > +			      &crtc_state->infoframes.hdmi);
> >  }
> >  
> >  static bool hdmi_sink_is_deep_color(const struct drm_connector_state *conn_state)
> > @@ -713,7 +765,10 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> >  	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> >  	i915_reg_t reg;
> > -	u32 val = 0;
> > +
> > +	if ((crtc_state->infoframes.enable &
> > +	     intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
> > +		return false;
> >  
> >  	if (HAS_DDI(dev_priv))
> >  		reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
> > @@ -724,18 +779,31 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
> >  	else
> >  		return false;
> >  
> > +	I915_WRITE(reg, crtc_state->infoframes.gcp);
> > +
> > +	return true;
> > +}
> > +
> > +static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder,
> > +					     struct intel_crtc_state *crtc_state,
> > +					     struct drm_connector_state *conn_state)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +
> > +	if (IS_G4X(dev_priv) || !crtc_state->has_infoframe)
> > +		return;
> > +
> > +	crtc_state->infoframes.enable |=
> > +		intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL);
> > +
> >  	/* Indicate color depth whenever the sink supports deep color */
> >  	if (hdmi_sink_is_deep_color(conn_state))
> > -		val |= GCP_COLOR_INDICATION;
> > +		crtc_state->infoframes.gcp |= GCP_COLOR_INDICATION;
> >  
> >  	/* Enable default_phase whenever the display mode is suitably aligned */
> >  	if (gcp_default_phase_possible(crtc_state->pipe_bpp,
> >  				       &crtc_state->base.adjusted_mode))
> > -		val |= GCP_DEFAULT_PHASE_ENABLE;
> > -
> > -	I915_WRITE(reg, val);
> > -
> > -	return val != 0;
> > +		crtc_state->infoframes.gcp |= GCP_DEFAULT_PHASE_ENABLE;
> >  }
> >  
> >  static void ibx_set_infoframes(struct intel_encoder *encoder,
> > @@ -786,9 +854,15 @@ static void ibx_set_infoframes(struct intel_encoder *encoder,
> >  	I915_WRITE(reg, val);
> >  	POSTING_READ(reg);
> >  
> > -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> > -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> > -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_AVI,
> > +			      &crtc_state->infoframes.avi);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_SPD,
> > +			      &crtc_state->infoframes.spd);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_VENDOR,
> > +			      &crtc_state->infoframes.hdmi);
> >  }
> >  
> >  static void cpt_set_infoframes(struct intel_encoder *encoder,
> > @@ -829,9 +903,15 @@ static void cpt_set_infoframes(struct intel_encoder *encoder,
> >  	I915_WRITE(reg, val);
> >  	POSTING_READ(reg);
> >  
> > -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> > -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> > -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_AVI,
> > +			      &crtc_state->infoframes.avi);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_SPD,
> > +			      &crtc_state->infoframes.spd);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_VENDOR,
> > +			      &crtc_state->infoframes.hdmi);
> >  }
> >  
> >  static void vlv_set_infoframes(struct intel_encoder *encoder,
> > @@ -881,9 +961,15 @@ static void vlv_set_infoframes(struct intel_encoder *encoder,
> >  	I915_WRITE(reg, val);
> >  	POSTING_READ(reg);
> >  
> > -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> > -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> > -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_AVI,
> > +			      &crtc_state->infoframes.avi);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_SPD,
> > +			      &crtc_state->infoframes.spd);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_VENDOR,
> > +			      &crtc_state->infoframes.hdmi);
> >  }
> >  
> >  static void hsw_set_infoframes(struct intel_encoder *encoder,
> > @@ -914,9 +1000,15 @@ static void hsw_set_infoframes(struct intel_encoder *encoder,
> >  	I915_WRITE(reg, val);
> >  	POSTING_READ(reg);
> >  
> > -	intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state);
> > -	intel_hdmi_set_spd_infoframe(encoder, crtc_state);
> > -	intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_AVI,
> > +			      &crtc_state->infoframes.avi);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_SPD,
> > +			      &crtc_state->infoframes.spd);
> > +	intel_write_infoframe(encoder, crtc_state,
> > +			      HDMI_INFOFRAME_TYPE_VENDOR,
> > +			      &crtc_state->infoframes.hdmi);
> >  }
> >  
> >  void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
> > @@ -1851,6 +1943,27 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
> >  		}
> >  	}
> >  
> > +	if (pipe_config->has_hdmi_sink)
> > +		pipe_config->infoframes.enable |=
> > +			intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_NULL);
> > +
> > +	intel_hdmi_compute_gcp_infoframe(encoder, pipe_config, conn_state);
> > +
> > +	if (!intel_hdmi_compute_avi_infoframe(encoder, pipe_config, conn_state)) {
> > +		DRM_DEBUG_KMS("bad AVI infoframe\n");
> > +		return false;
> > +	}
> > +
> > +	if (!intel_hdmi_compute_spd_infoframe(encoder, pipe_config, conn_state)) {
> > +		DRM_DEBUG_KMS("bad SPD infoframe\n");
> > +		return false;
> > +	}
> > +
> > +	if (!intel_hdmi_compute_hdmi_infoframe(encoder, pipe_config, conn_state)) {
> > +		DRM_DEBUG_KMS("bad HDMI infoframe\n");
> > +		return false;
> > +	}
> > +
> >  	return true;
> >  }
> >  
> > -- 
> > 2.16.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 14/18] drm/i915: Read out HDMI infoframes
  2018-09-24 16:08   ` Daniel Vetter
@ 2018-09-24 16:52     ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-24 16:52 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Mon, Sep 24, 2018 at 06:08:09PM +0200, Daniel Vetter wrote:
> On Thu, Sep 20, 2018 at 09:51:41PM +0300, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Add code to read the infoframes from the video DIP and unpack them into
> > the crtc state.
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c  |  17 ++++
> >  drivers/gpu/drm/i915/intel_drv.h  |  10 ++
> >  drivers/gpu/drm/i915/intel_hdmi.c | 203 ++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 230 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > index 5f3bd536d261..a56289f78326 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -3459,6 +3459,23 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
> >  			bxt_ddi_phy_get_lane_lat_optim_mask(encoder);
> >  
> >  	intel_ddi_compute_min_voltage_level(dev_priv, pipe_config);
> > +
> > +	intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
> > +
> > +	if (!intel_read_infoframe(encoder, pipe_config,
> > +				  HDMI_INFOFRAME_TYPE_AVI,
> > +				  &pipe_config->infoframes.avi))
> > +		DRM_ERROR("failed to read AVI infoframe\n");
> > +
> > +	if (!intel_read_infoframe(encoder, pipe_config,
> > +				  HDMI_INFOFRAME_TYPE_SPD,
> > +				  &pipe_config->infoframes.spd))
> > +		DRM_ERROR("failed to read SPD infoframe:\n");
> > +
> > +	if (!intel_read_infoframe(encoder, pipe_config,
> > +				  HDMI_INFOFRAME_TYPE_VENDOR,
> > +				  &pipe_config->infoframes.hdmi))
> > +		DRM_ERROR("failed to read HDMI infoframe\n");
> >  }
> >  
> >  static enum intel_output_type
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index 357624a6bfe2..75ec99b85232 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1185,6 +1185,10 @@ struct intel_digital_port {
> >  				const struct intel_crtc_state *crtc_state,
> >  				unsigned int type,
> >  				const void *frame, ssize_t len);
> > +	ssize_t (*read_infoframe)(struct intel_encoder *encoder,
> > +				  const struct intel_crtc_state *crtc_state,
> > +				  unsigned int type,
> > +				  void *frame, ssize_t len);
> >  	void (*set_infoframes)(struct intel_encoder *encoder,
> >  			       bool enable,
> >  			       const struct intel_crtc_state *crtc_state,
> > @@ -1867,6 +1871,12 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
> >  u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *crtc_state);
> >  u32 intel_hdmi_infoframe_enable(unsigned int type);
> > +void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
> > +				   struct intel_crtc_state *crtc_state);
> > +bool intel_read_infoframe(struct intel_encoder *encoder,
> > +			  const struct intel_crtc_state *crtc_state,
> > +			  enum hdmi_infoframe_type type,
> > +			  union hdmi_infoframe *frame);
> >  
> >  
> >  /* intel_lvds.c */
> > diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> > index 491001fc0fad..27cb6ec32e94 100644
> > --- a/drivers/gpu/drm/i915/intel_hdmi.c
> > +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> > @@ -203,6 +203,31 @@ static void g4x_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(VIDEO_DIP_CTL);
> >  }
> >  
> > +static ssize_t g4x_read_infoframe(struct intel_encoder *encoder,
> > +				  const struct intel_crtc_state *crtc_state,
> > +				  unsigned int type,
> > +				  void *frame, ssize_t len)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	u32 val, *data = frame;
> > +	int i;
> > +
> > +	val = I915_READ(VIDEO_DIP_CTL);
> > +
> > +	if ((val & g4x_infoframe_enable(type)) == 0)
> > +		return 0;
> > +
> > +	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
> > +	val |= g4x_infoframe_index(type);
> > +
> > +	I915_WRITE(VIDEO_DIP_CTL, val);
> > +
> > +	for (i = 0; i < len; i += 4)
> > +		*data++ = I915_READ(VIDEO_DIP_DATA);
> > +
> > +	return len;
> > +}
> > +
> >  static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> > @@ -258,6 +283,32 @@ static void ibx_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(reg);
> >  }
> >  
> > +static ssize_t ibx_read_infoframe(struct intel_encoder *encoder,
> > +				  const struct intel_crtc_state *crtc_state,
> > +				  unsigned int type,
> > +				  void *frame, ssize_t len)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> > +	u32 val, *data = frame;
> > +	int i;
> > +
> > +	val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
> > +
> > +	if ((val & g4x_infoframe_enable(type)) == 0)
> > +		return 0;
> > +
> > +	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
> > +	val |= g4x_infoframe_index(type);
> > +
> > +	I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
> > +
> > +	for (i = 0; i < len; i += 4)
> > +		*data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
> > +
> > +	return len;
> > +}
> > +
> >  static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> > @@ -319,6 +370,32 @@ static void cpt_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(reg);
> >  }
> >  
> > +static ssize_t cpt_read_infoframe(struct intel_encoder *encoder,
> > +				  const struct intel_crtc_state *crtc_state,
> > +				  unsigned int type,
> > +				  void *frame, ssize_t len)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> > +	u32 val, *data = frame;
> > +	int i;
> > +
> > +	val = I915_READ(TVIDEO_DIP_CTL(crtc->pipe));
> > +
> > +	if ((val & g4x_infoframe_enable(type)) == 0)
> > +		return 0;
> > +
> > +	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
> > +	val |= g4x_infoframe_index(type);
> > +
> > +	I915_WRITE(TVIDEO_DIP_CTL(crtc->pipe), val);
> > +
> > +	for (i = 0; i < len; i += 4)
> > +		*data++ = I915_READ(TVIDEO_DIP_DATA(crtc->pipe));
> > +
> > +	return len;
> > +}
> > +
> >  static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> > @@ -373,6 +450,32 @@ static void vlv_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(reg);
> >  }
> >  
> > +static ssize_t vlv_read_infoframe(struct intel_encoder *encoder,
> > +				  const struct intel_crtc_state *crtc_state,
> > +				  unsigned int type,
> > +				  void *frame, ssize_t len)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> > +	u32 val, *data = frame;
> > +	int i;
> > +
> > +	val = I915_READ(VLV_TVIDEO_DIP_CTL(crtc->pipe));
> > +
> > +	if ((val & g4x_infoframe_enable(type)) == 0)
> > +		return 0;
> > +
> > +	val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
> > +	val |= g4x_infoframe_index(type);
> > +
> > +	I915_WRITE(VLV_TVIDEO_DIP_CTL(crtc->pipe), val);
> > +
> > +	for (i = 0; i < len; i += 4)
> > +		*data++ = I915_READ(VLV_TVIDEO_DIP_DATA(crtc->pipe));
> > +
> > +	return len;
> > +}
> > +
> >  static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> > @@ -425,6 +528,28 @@ static void hsw_write_infoframe(struct intel_encoder *encoder,
> >  	POSTING_READ(ctl_reg);
> >  }
> >  
> > +static ssize_t hsw_read_infoframe(struct intel_encoder *encoder,
> > +				  const struct intel_crtc_state *crtc_state,
> > +				  unsigned int type,
> > +				  void *frame, ssize_t len)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
> > +	u32 val, *data = frame;
> > +	int i;
> > +
> > +	val = I915_READ(HSW_TVIDEO_DIP_CTL(cpu_transcoder));
> > +
> > +	if ((val & hsw_infoframe_enable(type)) == 0)
> > +		return 0;
> > +
> > +	for (i = 0; i < len; i += 4)
> > +		*data++ = I915_READ(hsw_dip_data_reg(dev_priv, cpu_transcoder,
> > +						     type, i >> 2));
> > +
> > +	return len;
> > +}
> > +
> >  static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
> >  				  const struct intel_crtc_state *pipe_config)
> >  {
> > @@ -530,6 +655,39 @@ static void intel_write_infoframe(struct intel_encoder *encoder,
> >  	intel_dig_port->write_infoframe(encoder, crtc_state, type, buffer, len);
> >  }
> >  
> > +bool intel_read_infoframe(struct intel_encoder *encoder,
> > +			  const struct intel_crtc_state *crtc_state,
> > +			  enum hdmi_infoframe_type type,
> > +			  union hdmi_infoframe *frame)
> 
> Bit a bikeshed: I'd drop the boolean here and pull the debug output in.
> That way you can give a bit better hint about what's going wrong. And less
> duplicated code. You can still print the type.

Sure.

> 
> > +{
> > +	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
> > +	u8 buffer[VIDEO_DIP_DATA_SIZE];
> > +	ssize_t len;
> > +	int ret;
> > +
> > +	if ((crtc_state->infoframes.enable &
> > +	     intel_hdmi_infoframe_enable(type)) == 0)
> > +		return true;
> 
> Afaiui you only need this because g4x doesn't check the pipe (well, port)
> association. But then all the tests once again check this by confirming
> that the infoframe they should read out is enabled. I'd drop the check in
> the various hw-specific readout functions (it's duplicated). That should
> still work with g4x here, as long as you filter at this level here.

Yeah, that seems like a good idea.

I do have additional fixes for g4x infoframes/audio somewhere
that I should also send out at some point. The state checker
gets rather upset with the current code when more than one
port wants infoframes/audio enabled.

> 
> With or without the bikesheds:
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> > +
> > +	len = intel_dig_port->read_infoframe(encoder, crtc_state,
> > +					     type, buffer, sizeof(buffer));
> > +	if (len == 0)
> > +		return true;
> > +
> > +	/* Fill the 'hole' (see big comment above) at position 3 */
> > +	memmove(&buffer[1], &buffer[0], 3);
> > +
> > +	/* see comment above for the reason for this offset */
> > +	ret = hdmi_infoframe_unpack(frame, buffer + 1, sizeof(buffer) - 1);
> > +	if (ret)
> > +		return false;
> > +
> > +	if (frame->any.type != type)
> > +		return false;
> > +
> > +	return true;
> > +}
> > +
> >  static bool
> >  intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder,
> >  				 struct intel_crtc_state *crtc_state,
> > @@ -784,6 +942,29 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder,
> >  	return true;
> >  }
> >  
> > +void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder,
> > +				   struct intel_crtc_state *crtc_state)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> > +	i915_reg_t reg;
> > +
> > +	if ((crtc_state->infoframes.enable &
> > +	     intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0)
> > +		return;
> > +
> > +	if (HAS_DDI(dev_priv))
> > +		reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder);
> > +	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> > +		reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
> > +	else if (HAS_PCH_SPLIT(dev_priv))
> > +		reg = TVIDEO_DIP_GCP(crtc->pipe);
> > +	else
> > +		return;
> > +
> > +	crtc_state->infoframes.gcp = I915_READ(reg);
> > +}
> > +
> >  static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder,
> >  					     struct intel_crtc_state *crtc_state,
> >  					     struct drm_connector_state *conn_state)
> > @@ -1382,6 +1563,23 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
> >  	pipe_config->base.adjusted_mode.crtc_clock = dotclock;
> >  
> >  	pipe_config->lane_count = 4;
> > +
> > +	intel_hdmi_read_gcp_infoframe(encoder, pipe_config);
> > +
> > +	if (!intel_read_infoframe(encoder, pipe_config,
> > +				  HDMI_INFOFRAME_TYPE_AVI,
> > +				  &pipe_config->infoframes.avi))
> > +		DRM_ERROR("failed to read AVI infoframe\n");
> > +
> > +	if (!intel_read_infoframe(encoder, pipe_config,
> > +				  HDMI_INFOFRAME_TYPE_SPD,
> > +				  &pipe_config->infoframes.spd))
> > +		DRM_ERROR("failed to read SPD infoframe:\n");
> > +
> > +	if (!intel_read_infoframe(encoder, pipe_config,
> > +				  HDMI_INFOFRAME_TYPE_VENDOR,
> > +				  &pipe_config->infoframes.hdmi))
> > +		DRM_ERROR("failed to read HDMI infoframe\n");
> >  }
> >  
> >  static void intel_enable_hdmi_audio(struct intel_encoder *encoder,
> > @@ -2481,22 +2679,27 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
> >  
> >  	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
> >  		intel_dig_port->write_infoframe = vlv_write_infoframe;
> > +		intel_dig_port->read_infoframe = vlv_read_infoframe;
> >  		intel_dig_port->set_infoframes = vlv_set_infoframes;
> >  		intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
> >  	} else if (IS_G4X(dev_priv)) {
> >  		intel_dig_port->write_infoframe = g4x_write_infoframe;
> > +		intel_dig_port->read_infoframe = g4x_read_infoframe;
> >  		intel_dig_port->set_infoframes = g4x_set_infoframes;
> >  		intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
> >  	} else if (HAS_DDI(dev_priv)) {
> >  		intel_dig_port->write_infoframe = hsw_write_infoframe;
> > +		intel_dig_port->read_infoframe = hsw_read_infoframe;
> >  		intel_dig_port->set_infoframes = hsw_set_infoframes;
> >  		intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
> >  	} else if (HAS_PCH_IBX(dev_priv)) {
> >  		intel_dig_port->write_infoframe = ibx_write_infoframe;
> > +		intel_dig_port->read_infoframe = ibx_read_infoframe;
> >  		intel_dig_port->set_infoframes = ibx_set_infoframes;
> >  		intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
> >  	} else {
> >  		intel_dig_port->write_infoframe = cpt_write_infoframe;
> > +		intel_dig_port->read_infoframe = cpt_read_infoframe;
> >  		intel_dig_port->set_infoframes = cpt_set_infoframes;
> >  		intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
> >  	}
> > -- 
> > 2.16.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 16/18] drm/i915/sdvo: Read out HDMI infoframes
  2018-09-24 16:10   ` [Intel-gfx] " Daniel Vetter
@ 2018-09-24 17:13     ` Ville Syrjälä
  2018-10-01  6:59       ` Daniel Vetter
  0 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjälä @ 2018-09-24 17:13 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Mon, Sep 24, 2018 at 06:10:14PM +0200, Daniel Vetter wrote:
> On Thu, Sep 20, 2018 at 09:51:43PM +0300, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Read the HDMI infoframes from the hbuf and unpack them into
> > the crtc state.
> > 
> > Well, actually just AVI infoframe for now but let's write the
> > infoframe readout code in a more generic fashion in case we
> > expand this later.
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Hm, caring about sdvo seems a bit overkill. And afaik we don't have any
> sdvo (much less hdmi) in CI. I'm leaning towards just adding a
> PIPE_CONFIG_QUIRK_INFOFRAMES for sdvo, and short-circuiting the checks if
> that's set. Except if you can somehow convince CI folks to add an sdvo
> hdmi card to CI :-)

Unfortunately I only have one SDVO HDMI device and it has the chip
straight on the motherboard. I can't give mine up for ci :) I guess
we could try to find another one of those as that model doesn't
even seem super rare. Just the annoying usual problem of getting
one from somewhere approved.

I think having to maintain a quirk is ~500% more annoying than
adding the readout code.

> 
> > ---
> >  drivers/gpu/drm/i915/intel_sdvo.c | 92 +++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 89 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> > index d8c78aebaf01..4d787c86df6d 100644
> > --- a/drivers/gpu/drm/i915/intel_sdvo.c
> > +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> > @@ -981,6 +981,58 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
> >  				    &tx_rate, 1);
> >  }
> >  
> > +static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
> > +					 unsigned int if_index,
> > +					 u8 *data, unsigned int length)
> > +{
> > +	u8 set_buf_index[2] = { if_index, 0 };
> > +	u8 hbuf_size, tx_rate, av_split;
> > +	int i;
> > +
> > +	if (!intel_sdvo_get_value(intel_sdvo,
> > +				  SDVO_CMD_GET_HBUF_AV_SPLIT,
> > +				  &av_split, 1))
> > +		return -ENXIO;
> > +
> > +	if (av_split < if_index)
> > +		return 0;
> > +
> > +	if (!intel_sdvo_get_value(intel_sdvo,
> > +				  SDVO_CMD_GET_HBUF_TXRATE,
> > +				  &tx_rate, 1))
> > +		return -ENXIO;
> > +
> > +	if (tx_rate == SDVO_HBUF_TX_DISABLED)
> > +		return 0;
> > +
> > +	if (!intel_sdvo_set_value(intel_sdvo,
> > +				  SDVO_CMD_SET_HBUF_INDEX,
> > +				  set_buf_index, 2))
> > +		return -ENXIO;
> > +
> > +	if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
> > +				  &hbuf_size, 1))
> > +		return -ENXIO;
> > +
> > +	/* Buffer size is 0 based, hooray! */
> > +	hbuf_size++;
> > +
> > +	DRM_DEBUG_KMS("reading sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
> > +		      if_index, length, hbuf_size);
> > +
> > +	hbuf_size = min_t(unsigned int, length, hbuf_size);
> > +
> > +	for (i = 0; i < hbuf_size; i += 8) {
> > +		if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HBUF_DATA, NULL, 0))
> > +			return -ENXIO;
> > +		if (!intel_sdvo_read_response(intel_sdvo, &data[i],
> > +					      min_t(unsigned int, 8, hbuf_size - i)))
> > +			return -ENXIO;
> > +	}
> > +
> > +	return hbuf_size;
> > +}
> > +
> >  static bool intel_sdvo_compute_avi_infoframe(struct intel_sdvo *intel_sdvo,
> >  					     struct intel_crtc_state *crtc_state,
> >  					     struct drm_connector_state *conn_state)
> > @@ -1039,6 +1091,37 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
> >  					  sdvo_data, sizeof(sdvo_data));
> >  }
> >  
> > +static bool intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
> > +					 struct intel_crtc_state *crtc_state)
> > +{
> > +	u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
> > +	union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
> > +	ssize_t len;
> > +	int ret;
> > +
> > +	if (!crtc_state->has_hdmi_sink)
> > +		return true;
> > +
> > +	len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
> > +					sdvo_data, sizeof(sdvo_data));
> > +	if (len < 0)
> > +		return false;
> > +	else if (len == 0)
> > +		return true;
> > +
> > +	crtc_state->infoframes.enable |=
> > +		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
> > +
> > +	ret = hdmi_infoframe_unpack(frame, sdvo_data, sizeof(sdvo_data));
> > +	if (ret)
> > +		return false;
> > +
> > +	if (frame->any.type != HDMI_INFOFRAME_TYPE_AVI)
> > +		return false;
> > +
> > +	return true;
> > +}
> > +
> >  static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
> >  				     const struct drm_connector_state *conn_state)
> >  {
> > @@ -1535,6 +1618,10 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
> >  		}
> >  	}
> >  
> > +	WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
> > +	     "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
> > +	     pipe_config->pixel_multiplier, encoder_pixel_multiplier);
> > +
> >  	if (sdvox & HDMI_COLOR_RANGE_16_235)
> >  		pipe_config->limited_color_range = true;
> >  
> > @@ -1547,9 +1634,8 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
> >  			pipe_config->has_hdmi_sink = true;
> >  	}
> >  
> > -	WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
> > -	     "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
> > -	     pipe_config->pixel_multiplier, encoder_pixel_multiplier);
> > +	if (!intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config))
> > +		DRM_ERROR("failed to read AVI infoframe\n");
> >  }
> >  
> >  static void intel_disable_sdvo(struct intel_encoder *encoder,
> > -- 
> > 2.16.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 11/18] drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
  2018-09-24 16:36     ` [Intel-gfx] " Ville Syrjälä
@ 2018-10-01  6:55       ` Daniel Vetter
  2018-10-01 19:29         ` Ville Syrjälä
  0 siblings, 1 reply; 95+ messages in thread
From: Daniel Vetter @ 2018-10-01  6:55 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, dri-devel

On Mon, Sep 24, 2018 at 07:36:08PM +0300, Ville Syrjälä wrote:
> On Mon, Sep 24, 2018 at 05:51:16PM +0200, Daniel Vetter wrote:
> > On Thu, Sep 20, 2018 at 09:51:38PM +0300, Ville Syrjala wrote:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > We want to start tracking which infoframes are enabled, so let's replace
> > > the boolean flag with a bitmask.
> > > 
> > > We'll abstract the bitmask so that it's not platform dependent. That
> > > will allow us to examine the bitmask later in platform independent code.
> > > 
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/intel_ddi.c  |  2 +-
> > >  drivers/gpu/drm/i915/intel_drv.h  |  4 +-
> > >  drivers/gpu/drm/i915/intel_hdmi.c | 87 ++++++++++++++++++++++++++++-----------
> > >  3 files changed, 68 insertions(+), 25 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > > index 086e3f940586..098a0e4edf2a 100644
> > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > @@ -3390,7 +3390,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
> > >  		pipe_config->has_hdmi_sink = true;
> > >  		intel_dig_port = enc_to_dig_port(&encoder->base);
> > >  
> > > -		if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
> > > +		if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
> > >  			pipe_config->has_infoframe = true;
> > >  
> > >  		if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
> > > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > > index e0f3a79fc75e..6815c69aac2f 100644
> > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > @@ -1181,7 +1181,7 @@ struct intel_digital_port {
> > >  			       bool enable,
> > >  			       const struct intel_crtc_state *crtc_state,
> > >  			       const struct drm_connector_state *conn_state);
> > > -	bool (*infoframe_enabled)(struct intel_encoder *encoder,
> > > +	u32 (*infoframes_enabled)(struct intel_encoder *encoder,
> > >  				  const struct intel_crtc_state *pipe_config);
> > >  };
> > >  
> > > @@ -1856,6 +1856,8 @@ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
> > >  				       bool scrambling);
> > >  void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
> > >  void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
> > > +u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> > > +				  const struct intel_crtc_state *crtc_state);
> > >  
> > >  
> > >  /* intel_lvds.c */
> > > diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> > > index c3c2a638d062..a8fcddb199ae 100644
> > > --- a/drivers/gpu/drm/i915/intel_hdmi.c
> > > +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> > > @@ -100,10 +100,14 @@ static u32 g4x_infoframe_index(unsigned int type)
> > >  static u32 g4x_infoframe_enable(unsigned int type)
> > >  {
> > >  	switch (type) {
> > > +	case HDMI_PACKET_TYPE_NULL:
> > > +		return VIDEO_DIP_ENABLE; /* slight lie */
> > 
> > Not exactly sure why we're tracking this one here, but not for hsw.
> 
> HSW+ doesn't have a DIP enable bit like this. It only has the
> bits to enable specific infoframes.
> 
> > Shouldn't we include that one if the DDI port is in hdmi mode? Would be
> > more consistent I think.
> 
> Yes that would seem like the more correct thing. I think the reason
> I did this here was so that I could map the DIP_ENABLE bit to
> something unique. Would allow us to differentiate between the
> "DIP enabled with no infoframes enabled" vs. "DIP enabled with
> some infoframes enabled" cases. But seeing as we always enable some
> infoframes I guess this doesn't really provide us with anything
> particularly useful.
> 
> That said, I'm actually not sure whether the hw will send the null
> packets if we don't enable the DIP. Would require a HDMI analyzer
> to confirm.
> 
> Hmm. Actually gen4 bspec tells me:
> "If DIP is enabled but DIP types are all disabled, no DIP is sent.
>  However, a single Null DIP will be sent at the same point in the
>  stream that DIP packets would have been sent. This is done to
>  keep the port in HDMI mode, otherwise it would revert to DVI mode.
>  The "Null packets enabled during vsync" mode (bit #9 of port
>  control register) overrides this behavior."
> 
> So I guess mapping the null packet to the DIP enable bit is more or
> less correct. Although the spec doesn't quite say whether the null
> packet is also sent when some DIP types are also enabled, or if it
> is only send when no DIP types are enabled.
> 
> So to match the hw I guess the readout should really do something
> like:
> 
> if (hdmi & HDMI_MODE || dip_ctl & DIP_ENABLE)
> 	infoframes |= TYPE_NULL;
> 
> but that would again mean that we can't tell the two cases
> apart.

From a functionality pov, do we actually care about the null DIP? HDMI
mode y/n for sure, but we track that already. Feels like just never
reading out the null packet state and never setting it in the state
structure is the cheap way out here, and also the least confusing way out
here. Trying to second guess what the hw does for something that doesn't
seem to matter feels a bit silly.
-Daniel

> 
> > 
> > Aside from that lgtm, has my
> > 
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > 
> > once we figured the TYPE_NULL thing out.
> > -Daniel
> > 
> > >  	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
> > >  		return VIDEO_DIP_ENABLE_GCP;
> > >  	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> > >  		return VIDEO_DIP_ENABLE_GAMUT;
> > > +	case DP_SDP_VSC:
> > > +		return 0;
> > >  	case HDMI_INFOFRAME_TYPE_AVI:
> > >  		return VIDEO_DIP_ENABLE_AVI;
> > >  	case HDMI_INFOFRAME_TYPE_SPD:
> > > @@ -119,6 +123,8 @@ static u32 g4x_infoframe_enable(unsigned int type)
> > >  static u32 hsw_infoframe_enable(unsigned int type)
> > >  {
> > >  	switch (type) {
> > > +	case HDMI_PACKET_TYPE_NULL:
> > > +		return 0;
> > >  	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
> > >  		return VIDEO_DIP_ENABLE_GCP_HSW;
> > >  	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> > > @@ -197,19 +203,19 @@ static void g4x_write_infoframe(struct intel_encoder *encoder,
> > >  	POSTING_READ(VIDEO_DIP_CTL);
> > >  }
> > >  
> > > -static bool g4x_infoframe_enabled(struct intel_encoder *encoder,
> > > +static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
> > >  				  const struct intel_crtc_state *pipe_config)
> > >  {
> > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > >  	u32 val = I915_READ(VIDEO_DIP_CTL);
> > >  
> > >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > > -		return false;
> > > +		return 0;
> > >  
> > >  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> > > -		return false;
> > > +		return 0;
> > >  
> > > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> > >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
> > >  }
> > >  
> > > @@ -252,7 +258,7 @@ static void ibx_write_infoframe(struct intel_encoder *encoder,
> > >  	POSTING_READ(reg);
> > >  }
> > >  
> > > -static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
> > > +static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
> > >  				  const struct intel_crtc_state *pipe_config)
> > >  {
> > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > @@ -261,12 +267,12 @@ static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
> > >  	u32 val = I915_READ(reg);
> > >  
> > >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > > -		return false;
> > > +		return 0;
> > >  
> > >  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> > > -		return false;
> > > +		return 0;
> > >  
> > > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> > >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
> > >  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
> > >  }
> > > @@ -313,7 +319,7 @@ static void cpt_write_infoframe(struct intel_encoder *encoder,
> > >  	POSTING_READ(reg);
> > >  }
> > >  
> > > -static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
> > > +static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
> > >  				  const struct intel_crtc_state *pipe_config)
> > >  {
> > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > @@ -321,9 +327,9 @@ static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
> > >  	u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
> > >  
> > >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > > -		return false;
> > > +		return 0;
> > >  
> > > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> > >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
> > >  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
> > >  }
> > > @@ -367,7 +373,7 @@ static void vlv_write_infoframe(struct intel_encoder *encoder,
> > >  	POSTING_READ(reg);
> > >  }
> > >  
> > > -static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
> > > +static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
> > >  				  const struct intel_crtc_state *pipe_config)
> > >  {
> > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > @@ -375,12 +381,12 @@ static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
> > >  	u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
> > >  
> > >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > > -		return false;
> > > +		return 0;
> > >  
> > >  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> > > -		return false;
> > > +		return 0;
> > >  
> > > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> > >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
> > >  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
> > >  }
> > > @@ -419,7 +425,7 @@ static void hsw_write_infoframe(struct intel_encoder *encoder,
> > >  	POSTING_READ(ctl_reg);
> > >  }
> > >  
> > > -static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
> > > +static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
> > >  				  const struct intel_crtc_state *pipe_config)
> > >  {
> > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > @@ -430,6 +436,42 @@ static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
> > >  		      VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
> > >  }
> > >  
> > > +static const u8 infoframe_type_to_idx[] = {
> > > +	HDMI_PACKET_TYPE_NULL,
> > > +	HDMI_PACKET_TYPE_GENERAL_CONTROL,
> > > +	HDMI_PACKET_TYPE_GAMUT_METADATA,
> > > +	DP_SDP_VSC,
> > > +	HDMI_INFOFRAME_TYPE_AVI,
> > > +	HDMI_INFOFRAME_TYPE_SPD,
> > > +	HDMI_INFOFRAME_TYPE_VENDOR,
> > > +};
> > > +
> > > +u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> > > +				  const struct intel_crtc_state *crtc_state)
> > > +{
> > > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > +	struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
> > > +	u32 val, ret = 0;
> > > +	int i;
> > > +
> > > +	val = dig_port->infoframes_enabled(encoder, crtc_state);
> > > +
> > > +	/* map from hardware bits to dip idx */
> > > +	for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
> > > +		unsigned int type = infoframe_type_to_idx[i];
> > > +
> > > +		if (HAS_DDI(dev_priv)) {
> > > +			if (val & hsw_infoframe_enable(type))
> > > +				ret |= BIT(i);
> > > +		} else {
> > > +			if (val & g4x_infoframe_enable(type))
> > > +				ret |= BIT(i);
> > > +		}
> > > +	}
> > > +
> > > +	return ret;
> > > +}
> > > +
> > >  /*
> > >   * The data we write to the DIP data buffer registers is 1 byte bigger than the
> > >   * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
> > > @@ -1200,7 +1242,6 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
> > >  				  struct intel_crtc_state *pipe_config)
> > >  {
> > >  	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> > > -	struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi);
> > >  	struct drm_device *dev = encoder->base.dev;
> > >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > >  	u32 tmp, flags = 0;
> > > @@ -1223,7 +1264,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
> > >  	if (tmp & HDMI_MODE_SELECT_HDMI)
> > >  		pipe_config->has_hdmi_sink = true;
> > >  
> > > -	if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
> > > +	if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
> > >  		pipe_config->has_infoframe = true;
> > >  
> > >  	if (tmp & SDVO_AUDIO_ENABLE)
> > > @@ -2325,23 +2366,23 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
> > >  	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
> > >  		intel_dig_port->write_infoframe = vlv_write_infoframe;
> > >  		intel_dig_port->set_infoframes = vlv_set_infoframes;
> > > -		intel_dig_port->infoframe_enabled = vlv_infoframe_enabled;
> > > +		intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
> > >  	} else if (IS_G4X(dev_priv)) {
> > >  		intel_dig_port->write_infoframe = g4x_write_infoframe;
> > >  		intel_dig_port->set_infoframes = g4x_set_infoframes;
> > > -		intel_dig_port->infoframe_enabled = g4x_infoframe_enabled;
> > > +		intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
> > >  	} else if (HAS_DDI(dev_priv)) {
> > >  		intel_dig_port->write_infoframe = hsw_write_infoframe;
> > >  		intel_dig_port->set_infoframes = hsw_set_infoframes;
> > > -		intel_dig_port->infoframe_enabled = hsw_infoframe_enabled;
> > > +		intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
> > >  	} else if (HAS_PCH_IBX(dev_priv)) {
> > >  		intel_dig_port->write_infoframe = ibx_write_infoframe;
> > >  		intel_dig_port->set_infoframes = ibx_set_infoframes;
> > > -		intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
> > > +		intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
> > >  	} else {
> > >  		intel_dig_port->write_infoframe = cpt_write_infoframe;
> > >  		intel_dig_port->set_infoframes = cpt_set_infoframes;
> > > -		intel_dig_port->infoframe_enabled = cpt_infoframe_enabled;
> > > +		intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
> > >  	}
> > >  }
> > >  
> > > -- 
> > > 2.16.4
> > > 
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > 
> > -- 
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch
> 
> -- 
> Ville Syrjälä
> Intel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 16/18] drm/i915/sdvo: Read out HDMI infoframes
  2018-09-24 17:13     ` Ville Syrjälä
@ 2018-10-01  6:59       ` Daniel Vetter
  2018-10-01 13:35         ` Ville Syrjälä
  0 siblings, 1 reply; 95+ messages in thread
From: Daniel Vetter @ 2018-10-01  6:59 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, dri-devel

On Mon, Sep 24, 2018 at 08:13:08PM +0300, Ville Syrjälä wrote:
> On Mon, Sep 24, 2018 at 06:10:14PM +0200, Daniel Vetter wrote:
> > On Thu, Sep 20, 2018 at 09:51:43PM +0300, Ville Syrjala wrote:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > Read the HDMI infoframes from the hbuf and unpack them into
> > > the crtc state.
> > > 
> > > Well, actually just AVI infoframe for now but let's write the
> > > infoframe readout code in a more generic fashion in case we
> > > expand this later.
> > > 
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Hm, caring about sdvo seems a bit overkill. And afaik we don't have any
> > sdvo (much less hdmi) in CI. I'm leaning towards just adding a
> > PIPE_CONFIG_QUIRK_INFOFRAMES for sdvo, and short-circuiting the checks if
> > that's set. Except if you can somehow convince CI folks to add an sdvo
> > hdmi card to CI :-)
> 
> Unfortunately I only have one SDVO HDMI device and it has the chip
> straight on the motherboard. I can't give mine up for ci :) I guess
> we could try to find another one of those as that model doesn't
> even seem super rare. Just the annoying usual problem of getting
> one from somewhere approved.
> 
> I think having to maintain a quirk is ~500% more annoying than
> adding the readout code.

My experience disagrees, a bunch of the (early?) sdvo chips don't bother
to implement all the get stuff. I had a pile of these (but some of them
died, and plugging them all into machines is a pain), and just because it
works on 1 chip doesn't mean it's actually all that useful. That's why I
suggested we do the same thing as with the other stuff we read out from
the sdvo chip (as opposed to things we can read out from
crtc/sdvo-host-side registers).
-Daniel

> 
> > 
> > > ---
> > >  drivers/gpu/drm/i915/intel_sdvo.c | 92 +++++++++++++++++++++++++++++++++++++--
> > >  1 file changed, 89 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> > > index d8c78aebaf01..4d787c86df6d 100644
> > > --- a/drivers/gpu/drm/i915/intel_sdvo.c
> > > +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> > > @@ -981,6 +981,58 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
> > >  				    &tx_rate, 1);
> > >  }
> > >  
> > > +static ssize_t intel_sdvo_read_infoframe(struct intel_sdvo *intel_sdvo,
> > > +					 unsigned int if_index,
> > > +					 u8 *data, unsigned int length)
> > > +{
> > > +	u8 set_buf_index[2] = { if_index, 0 };
> > > +	u8 hbuf_size, tx_rate, av_split;
> > > +	int i;
> > > +
> > > +	if (!intel_sdvo_get_value(intel_sdvo,
> > > +				  SDVO_CMD_GET_HBUF_AV_SPLIT,
> > > +				  &av_split, 1))
> > > +		return -ENXIO;
> > > +
> > > +	if (av_split < if_index)
> > > +		return 0;
> > > +
> > > +	if (!intel_sdvo_get_value(intel_sdvo,
> > > +				  SDVO_CMD_GET_HBUF_TXRATE,
> > > +				  &tx_rate, 1))
> > > +		return -ENXIO;
> > > +
> > > +	if (tx_rate == SDVO_HBUF_TX_DISABLED)
> > > +		return 0;
> > > +
> > > +	if (!intel_sdvo_set_value(intel_sdvo,
> > > +				  SDVO_CMD_SET_HBUF_INDEX,
> > > +				  set_buf_index, 2))
> > > +		return -ENXIO;
> > > +
> > > +	if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
> > > +				  &hbuf_size, 1))
> > > +		return -ENXIO;
> > > +
> > > +	/* Buffer size is 0 based, hooray! */
> > > +	hbuf_size++;
> > > +
> > > +	DRM_DEBUG_KMS("reading sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
> > > +		      if_index, length, hbuf_size);
> > > +
> > > +	hbuf_size = min_t(unsigned int, length, hbuf_size);
> > > +
> > > +	for (i = 0; i < hbuf_size; i += 8) {
> > > +		if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HBUF_DATA, NULL, 0))
> > > +			return -ENXIO;
> > > +		if (!intel_sdvo_read_response(intel_sdvo, &data[i],
> > > +					      min_t(unsigned int, 8, hbuf_size - i)))
> > > +			return -ENXIO;
> > > +	}
> > > +
> > > +	return hbuf_size;
> > > +}
> > > +
> > >  static bool intel_sdvo_compute_avi_infoframe(struct intel_sdvo *intel_sdvo,
> > >  					     struct intel_crtc_state *crtc_state,
> > >  					     struct drm_connector_state *conn_state)
> > > @@ -1039,6 +1091,37 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
> > >  					  sdvo_data, sizeof(sdvo_data));
> > >  }
> > >  
> > > +static bool intel_sdvo_get_avi_infoframe(struct intel_sdvo *intel_sdvo,
> > > +					 struct intel_crtc_state *crtc_state)
> > > +{
> > > +	u8 sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
> > > +	union hdmi_infoframe *frame = &crtc_state->infoframes.avi;
> > > +	ssize_t len;
> > > +	int ret;
> > > +
> > > +	if (!crtc_state->has_hdmi_sink)
> > > +		return true;
> > > +
> > > +	len = intel_sdvo_read_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
> > > +					sdvo_data, sizeof(sdvo_data));
> > > +	if (len < 0)
> > > +		return false;
> > > +	else if (len == 0)
> > > +		return true;
> > > +
> > > +	crtc_state->infoframes.enable |=
> > > +		intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
> > > +
> > > +	ret = hdmi_infoframe_unpack(frame, sdvo_data, sizeof(sdvo_data));
> > > +	if (ret)
> > > +		return false;
> > > +
> > > +	if (frame->any.type != HDMI_INFOFRAME_TYPE_AVI)
> > > +		return false;
> > > +
> > > +	return true;
> > > +}
> > > +
> > >  static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
> > >  				     const struct drm_connector_state *conn_state)
> > >  {
> > > @@ -1535,6 +1618,10 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
> > >  		}
> > >  	}
> > >  
> > > +	WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
> > > +	     "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
> > > +	     pipe_config->pixel_multiplier, encoder_pixel_multiplier);
> > > +
> > >  	if (sdvox & HDMI_COLOR_RANGE_16_235)
> > >  		pipe_config->limited_color_range = true;
> > >  
> > > @@ -1547,9 +1634,8 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
> > >  			pipe_config->has_hdmi_sink = true;
> > >  	}
> > >  
> > > -	WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
> > > -	     "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
> > > -	     pipe_config->pixel_multiplier, encoder_pixel_multiplier);
> > > +	if (!intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config))
> > > +		DRM_ERROR("failed to read AVI infoframe\n");
> > >  }
> > >  
> > >  static void intel_disable_sdvo(struct intel_encoder *encoder,
> > > -- 
> > > 2.16.4
> > > 
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > 
> > -- 
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch
> 
> -- 
> Ville Syrjälä
> Intel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 16/18] drm/i915/sdvo: Read out HDMI infoframes
  2018-10-01  6:59       ` Daniel Vetter
@ 2018-10-01 13:35         ` Ville Syrjälä
  2018-10-01 16:48           ` Daniel Vetter
  0 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjälä @ 2018-10-01 13:35 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Mon, Oct 01, 2018 at 08:59:41AM +0200, Daniel Vetter wrote:
> On Mon, Sep 24, 2018 at 08:13:08PM +0300, Ville Syrjälä wrote:
> > On Mon, Sep 24, 2018 at 06:10:14PM +0200, Daniel Vetter wrote:
> > > On Thu, Sep 20, 2018 at 09:51:43PM +0300, Ville Syrjala wrote:
> > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > 
> > > > Read the HDMI infoframes from the hbuf and unpack them into
> > > > the crtc state.
> > > > 
> > > > Well, actually just AVI infoframe for now but let's write the
> > > > infoframe readout code in a more generic fashion in case we
> > > > expand this later.
> > > > 
> > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > Hm, caring about sdvo seems a bit overkill. And afaik we don't have any
> > > sdvo (much less hdmi) in CI. I'm leaning towards just adding a
> > > PIPE_CONFIG_QUIRK_INFOFRAMES for sdvo, and short-circuiting the checks if
> > > that's set. Except if you can somehow convince CI folks to add an sdvo
> > > hdmi card to CI :-)
> > 
> > Unfortunately I only have one SDVO HDMI device and it has the chip
> > straight on the motherboard. I can't give mine up for ci :) I guess
> > we could try to find another one of those as that model doesn't
> > even seem super rare. Just the annoying usual problem of getting
> > one from somewhere approved.
> > 
> > I think having to maintain a quirk is ~500% more annoying than
> > adding the readout code.
> 
> My experience disagrees, a bunch of the (early?) sdvo chips don't bother
> to implement all the get stuff. I had a pile of these (but some of them
> died, and plugging them all into machines is a pain), and just because it
> works on 1 chip doesn't mean it's actually all that useful. That's why I
> suggested we do the same thing as with the other stuff we read out from
> the sdvo chip (as opposed to things we can read out from
> crtc/sdvo-host-side registers).

We do read out the hdmi encoding and pixel multipler from
the sdvo chip already. If the chips don't implement the hdmi
stuff we treat them as dvi. I have some (supposedly) hdmi
add2 cards like that. So I don't think those pose any kind
of real problem.

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 16/18] drm/i915/sdvo: Read out HDMI infoframes
  2018-10-01 13:35         ` Ville Syrjälä
@ 2018-10-01 16:48           ` Daniel Vetter
  0 siblings, 0 replies; 95+ messages in thread
From: Daniel Vetter @ 2018-10-01 16:48 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, dri-devel

On Mon, Oct 01, 2018 at 04:35:50PM +0300, Ville Syrjälä wrote:
> On Mon, Oct 01, 2018 at 08:59:41AM +0200, Daniel Vetter wrote:
> > On Mon, Sep 24, 2018 at 08:13:08PM +0300, Ville Syrjälä wrote:
> > > On Mon, Sep 24, 2018 at 06:10:14PM +0200, Daniel Vetter wrote:
> > > > On Thu, Sep 20, 2018 at 09:51:43PM +0300, Ville Syrjala wrote:
> > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > 
> > > > > Read the HDMI infoframes from the hbuf and unpack them into
> > > > > the crtc state.
> > > > > 
> > > > > Well, actually just AVI infoframe for now but let's write the
> > > > > infoframe readout code in a more generic fashion in case we
> > > > > expand this later.
> > > > > 
> > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > 
> > > > Hm, caring about sdvo seems a bit overkill. And afaik we don't have any
> > > > sdvo (much less hdmi) in CI. I'm leaning towards just adding a
> > > > PIPE_CONFIG_QUIRK_INFOFRAMES for sdvo, and short-circuiting the checks if
> > > > that's set. Except if you can somehow convince CI folks to add an sdvo
> > > > hdmi card to CI :-)
> > > 
> > > Unfortunately I only have one SDVO HDMI device and it has the chip
> > > straight on the motherboard. I can't give mine up for ci :) I guess
> > > we could try to find another one of those as that model doesn't
> > > even seem super rare. Just the annoying usual problem of getting
> > > one from somewhere approved.
> > > 
> > > I think having to maintain a quirk is ~500% more annoying than
> > > adding the readout code.
> > 
> > My experience disagrees, a bunch of the (early?) sdvo chips don't bother
> > to implement all the get stuff. I had a pile of these (but some of them
> > died, and plugging them all into machines is a pain), and just because it
> > works on 1 chip doesn't mean it's actually all that useful. That's why I
> > suggested we do the same thing as with the other stuff we read out from
> > the sdvo chip (as opposed to things we can read out from
> > crtc/sdvo-host-side registers).
> 
> We do read out the hdmi encoding and pixel multipler from
> the sdvo chip already. If the chips don't implement the hdmi
> stuff we treat them as dvi. I have some (supposedly) hdmi
> add2 cards like that. So I don't think those pose any kind
> of real problem.

Hm ok, but you get to keep the pieces if there's an sdvo regression report
:-) I.e. in that case I'd vote for a revert + quirk flag, and call it a
day. But I guess for now we could assume that hdmi sdvo cards are less
garbage, and implement the spec better.

On both this and the previous patch:

Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

(Since I'm too lazy to dig out the hdmi sdvo spec and check all the
details, imo not quite worth it).

It would be good to capture the gist of this discussion here in the commit
message, for future reference. Maybe stuff it into the readout patch.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-09-21 14:33     ` Ville Syrjala
@ 2018-10-01 19:10       ` Ville Syrjälä
  -1 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-10-01 19:10 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 05:33:32PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Let's make the infoframe pack functions usable with a const infoframe
> structure. This allows us to precompute the infoframe earlier, and still
> pack it later when we're no longer allowed to modify the structure.
> So now we end up with a _check()+_pack_only() or _pack() functions
> depending on whether you want to precompute the infoframes or not.
> The names aren't great but I was lazy and didn't want to change all the
> drivers.
> 
> v2: Deal with exynos churn
>     Actually export the new funcs
> v3: Fix various documentation fails (Hans)

Hans, any more concerns about this patch?

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
>  include/linux/hdmi.h |  19 ++-
>  2 files changed, 416 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 53e7ee2c83fc..08d94ab00467 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>  
> +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
> +	    frame->version != 2 ||
> +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
> + * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
> + * @frame: HDMI AVI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
> +{
> +	return hdmi_avi_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
> +
> +/**
> + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
>   * @frame: HDMI AVI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
>  	if (size < length)
>  		return -ENOSPC;
>  
> -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> -		return -EINVAL;
> -
>  	memset(buffer, 0, size);
>  
>  	ptr[0] = frame->type;
> @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
> +
> +/**
> + * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI AVI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
>  
>  /**
> @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  }
>  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>  
> +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
> + * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
> + * @frame: HDMI SPD infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
> +{
> +	return hdmi_spd_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
> +
> +/**
> + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
>   * @frame: HDMI SPD infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
> +
> +/**
> + * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI SPD infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
>  
>  /**
> @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>  
> +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
> + * @frame: HDMI audio infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
> +{
> +	return hdmi_audio_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
> +
>  /**
> - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
> + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
>   * @frame: HDMI audio infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> -				  void *buffer, size_t size)
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size)
>  {
>  	unsigned char channels;
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
> +
> +/**
> + * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
> + *                               and write it to binary buffer
> + * @frame: HDMI Audio infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> +				  void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
>  
>  /**
> @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
>  	 * value
>  	 */
>  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
> +	frame->length = 4;
>  
>  	return 0;
>  }
> @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>  		return 4;
>  }
>  
> +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->version != 1 ||
> +	    frame->oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	/* only one of those can be supplied */
> +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> +		return -EINVAL;
> +
> +	if (frame->length != hdmi_vendor_infoframe_length(frame))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
> + * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
> +{
> +	frame->length = hdmi_vendor_infoframe_length(frame);
> +
> +	return hdmi_vendor_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
> +
> +/**
> + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> -				 void *buffer, size_t size)
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
>  
> -	/* only one of those can be supplied */
> -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> -		return -EINVAL;
> -
> -	frame->length = hdmi_vendor_infoframe_length(frame);
> +	ret = hdmi_vendor_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
> +
> +/**
> + * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
> + *                                and write it to binary buffer
> + * @frame: HDMI Vendor infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> +				   void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
>  
> +static int
> +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
> +{
> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->any.version != 1)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
> - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
> + * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
> + */
> +static int
> +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	/* we only know about HDMI vendor infoframes */
> +	if (frame->any.oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	return hdmi_vendor_infoframe_check(&frame->hdmi);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
>   */
>  static ssize_t
> -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> -			   void *buffer, size_t size)
> +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
> +				    void *buffer, size_t size)
>  {
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
>  	/* we only know about HDMI vendor infoframes */
>  	if (frame->any.oui != HDMI_IEEE_OUI)
>  		return -EINVAL;
>  
> -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
> +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
> + *                                    and write it to binary buffer
> + */
> +static ssize_t
> +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> +			       void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> +}
> +
> +/**
> + * hdmi_infoframe_check() - check a HDMI infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int
> +hdmi_infoframe_check(union hdmi_infoframe *frame)
> +{
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		return hdmi_avi_infoframe_check(&frame->avi);
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		return hdmi_spd_infoframe_check(&frame->spd);
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		return hdmi_audio_infoframe_check(&frame->audio);
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		return -EINVAL;
> +	}
>  }
> +EXPORT_SYMBOL(hdmi_infoframe_check);
>  
>  /**
> - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
> + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>   * error code on failure.
>   */
>  ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
> +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
> +{
> +	ssize_t length;
> +
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
> +							buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> +							     buffer, size);
> +		break;
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		length = -EINVAL;
> +	}
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
> +
> +/**
> + * hdmi_infoframe_pack() - check a HDMI infoframe,
> + *                         and write it to binary buffer
> + * @frame: HDMI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t
> +hdmi_infoframe_pack(union hdmi_infoframe *frame,
> +		    void *buffer, size_t size)
>  {
>  	ssize_t length;
>  
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index bce1abb1fe57..c76b50a48e48 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
>  int 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);
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
>  
>  enum hdmi_spd_sdi {
>  	HDMI_SPD_SDI_UNKNOWN,
> @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  			    const char *vendor, const char *product);
>  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  				size_t size);
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
>  
>  enum hdmi_audio_coding_type {
>  	HDMI_AUDIO_CODING_TYPE_STREAM,
> @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
>  int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
>  ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  				  void *buffer, size_t size);
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size);
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
>  
>  enum hdmi_3d_structure {
>  	HDMI_3D_STRUCTURE_INVALID = -1,
> @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
>  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
>  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  				   void *buffer, size_t size);
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size);
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
>  
>  union hdmi_vendor_any_infoframe {
>  	struct {
> @@ -330,8 +342,11 @@ union hdmi_infoframe {
>  	struct hdmi_audio_infoframe audio;
>  };
>  
> -ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> +			    size_t size);
> +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
> +				 void *buffer, size_t size);
> +int hdmi_infoframe_check(union hdmi_infoframe *frame);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
> -- 
> 2.16.4

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 04/18] video/hdmi: Constify infoframe passed to the pack functions
@ 2018-10-01 19:10       ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-10-01 19:10 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Hans Verkuil, linux-media

On Fri, Sep 21, 2018 at 05:33:32PM +0300, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Let's make the infoframe pack functions usable with a const infoframe
> structure. This allows us to precompute the infoframe earlier, and still
> pack it later when we're no longer allowed to modify the structure.
> So now we end up with a _check()+_pack_only() or _pack() functions
> depending on whether you want to precompute the infoframes or not.
> The names aren't great but I was lazy and didn't want to change all the
> drivers.
> 
> v2: Deal with exynos churn
>     Actually export the new funcs
> v3: Fix various documentation fails (Hans)

Hans, any more concerns about this patch?

> 
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
>  include/linux/hdmi.h |  19 ++-
>  2 files changed, 416 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
> index 53e7ee2c83fc..08d94ab00467 100644
> --- a/drivers/video/hdmi.c
> +++ b/drivers/video/hdmi.c
> @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>  
> +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
> +	    frame->version != 2 ||
> +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
> + * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
> + * @frame: HDMI AVI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
> +{
> +	return hdmi_avi_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
> +
> +/**
> + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
>   * @frame: HDMI AVI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
>  	if (size < length)
>  		return -ENOSPC;
>  
> -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
> -		return -EINVAL;
> -
>  	memset(buffer, 0, size);
>  
>  	ptr[0] = frame->type;
> @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
> +
> +/**
> + * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI AVI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_avi_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
>  
>  /**
> @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  }
>  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>  
> +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
> + * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
> + * @frame: HDMI SPD infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
> +{
> +	return hdmi_spd_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
> +
> +/**
> + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
>   * @frame: HDMI SPD infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
> -				size_t size)
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
> +
> +/**
> + * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
> + *                             and write it to binary buffer
> + * @frame: HDMI SPD infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
> +				void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_spd_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
>  
>  /**
> @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
>  }
>  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>  
> +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
> +	    frame->version != 1 ||
> +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
> + * @frame: HDMI audio infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
> +{
> +	return hdmi_audio_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
> +
>  /**
> - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
> + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
>   * @frame: HDMI audio infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> -				  void *buffer, size_t size)
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size)
>  {
>  	unsigned char channels;
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
> +
> +/**
> + * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
> + *                               and write it to binary buffer
> + * @frame: HDMI Audio infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
> +				  void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_audio_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
>  
>  /**
> @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
>  	 * value
>  	 */
>  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
> +	frame->length = 4;
>  
>  	return 0;
>  }
> @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>  		return 4;
>  }
>  
> +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
> +{
> +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->version != 1 ||
> +	    frame->oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	/* only one of those can be supplied */
> +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> +		return -EINVAL;
> +
> +	if (frame->length != hdmi_vendor_infoframe_length(frame))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /**
> - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
> + * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
> +{
> +	frame->length = hdmi_vendor_infoframe_length(frame);
> +
> +	return hdmi_vendor_infoframe_check_only(frame);
> +}
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
> +
> +/**
> + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>   * Returns the number of bytes packed into the binary buffer or a negative
>   * error code on failure.
>   */
> -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> -				 void *buffer, size_t size)
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size)
>  {
>  	u8 *ptr = buffer;
>  	size_t length;
> +	int ret;
>  
> -	/* only one of those can be supplied */
> -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
> -		return -EINVAL;
> -
> -	frame->length = hdmi_vendor_infoframe_length(frame);
> +	ret = hdmi_vendor_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
>  
>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>  
> @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  
>  	return length;
>  }
> +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
> +
> +/**
> + * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
> + *                                and write it to binary buffer
> + * @frame: HDMI Vendor infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
> +				   void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
> +}
>  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
>  
> +static int
> +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
> +{
> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
> +	    frame->any.version != 1)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>  /*
> - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
> + * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
> + */
> +static int
> +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
> +	/* we only know about HDMI vendor infoframes */
> +	if (frame->any.oui != HDMI_IEEE_OUI)
> +		return -EINVAL;
> +
> +	return hdmi_vendor_infoframe_check(&frame->hdmi);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
>   */
>  static ssize_t
> -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> -			   void *buffer, size_t size)
> +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
> +				    void *buffer, size_t size)
>  {
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
> +	if (ret)
> +		return ret;
> +
>  	/* we only know about HDMI vendor infoframes */
>  	if (frame->any.oui != HDMI_IEEE_OUI)
>  		return -EINVAL;
>  
> -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
> +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
> +}
> +
> +/*
> + * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
> + *                                    and write it to binary buffer
> + */
> +static ssize_t
> +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
> +			       void *buffer, size_t size)
> +{
> +	int ret;
> +
> +	ret = hdmi_vendor_any_infoframe_check(frame);
> +	if (ret)
> +		return ret;
> +
> +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
> +}
> +
> +/**
> + * hdmi_infoframe_check() - check a HDMI infoframe
> + * @frame: HDMI infoframe
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int
> +hdmi_infoframe_check(union hdmi_infoframe *frame)
> +{
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		return hdmi_avi_infoframe_check(&frame->avi);
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		return hdmi_spd_infoframe_check(&frame->spd);
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		return hdmi_audio_infoframe_check(&frame->audio);
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		return -EINVAL;
> +	}
>  }
> +EXPORT_SYMBOL(hdmi_infoframe_check);
>  
>  /**
> - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
> + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
>   * @frame: HDMI infoframe
>   * @buffer: destination buffer
>   * @size: size of buffer
> @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>   * error code on failure.
>   */
>  ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
> +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
> +{
> +	ssize_t length;
> +
> +	switch (frame->any.type) {
> +	case HDMI_INFOFRAME_TYPE_AVI:
> +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_SPD:
> +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
> +						      buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_AUDIO:
> +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
> +							buffer, size);
> +		break;
> +	case HDMI_INFOFRAME_TYPE_VENDOR:
> +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
> +							     buffer, size);
> +		break;
> +	default:
> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
> +		length = -EINVAL;
> +	}
> +
> +	return length;
> +}
> +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
> +
> +/**
> + * hdmi_infoframe_pack() - check a HDMI infoframe,
> + *                         and write it to binary buffer
> + * @frame: HDMI infoframe
> + * @buffer: destination buffer
> + * @size: size of buffer
> + *
> + * Validates that the infoframe is consistent and updates derived fields
> + * (eg. length) based on other fields, after which it packs the information
> + * contained in the @frame structure into a binary representation that
> + * can be written into the corresponding controller registers. This function
> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
> + * specification.
> + *
> + * Returns the number of bytes packed into the binary buffer or a negative
> + * error code on failure.
> + */
> +ssize_t
> +hdmi_infoframe_pack(union hdmi_infoframe *frame,
> +		    void *buffer, size_t size)
>  {
>  	ssize_t length;
>  
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index bce1abb1fe57..c76b50a48e48 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
>  int 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);
> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
>  
>  enum hdmi_spd_sdi {
>  	HDMI_SPD_SDI_UNKNOWN,
> @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>  			    const char *vendor, const char *product);
>  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>  				size_t size);
> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
> +				     void *buffer, size_t size);
> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
>  
>  enum hdmi_audio_coding_type {
>  	HDMI_AUDIO_CODING_TYPE_STREAM,
> @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
>  int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
>  ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>  				  void *buffer, size_t size);
> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
> +				       void *buffer, size_t size);
> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
>  
>  enum hdmi_3d_structure {
>  	HDMI_3D_STRUCTURE_INVALID = -1,
> @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
>  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
>  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>  				   void *buffer, size_t size);
> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
> +					void *buffer, size_t size);
> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
>  
>  union hdmi_vendor_any_infoframe {
>  	struct {
> @@ -330,8 +342,11 @@ union hdmi_infoframe {
>  	struct hdmi_audio_infoframe audio;
>  };
>  
> -ssize_t
> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
> +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
> +			    size_t size);
> +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
> +				 void *buffer, size_t size);
> +int hdmi_infoframe_check(union hdmi_infoframe *frame);
>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>  			  const void *buffer, size_t size);
>  void hdmi_infoframe_log(const char *level, struct device *dev,
> -- 
> 2.16.4

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 11/18] drm/i915: Return the mask of enabled infoframes from ->inforame_enabled()
  2018-10-01  6:55       ` Daniel Vetter
@ 2018-10-01 19:29         ` Ville Syrjälä
  0 siblings, 0 replies; 95+ messages in thread
From: Ville Syrjälä @ 2018-10-01 19:29 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Mon, Oct 01, 2018 at 08:55:51AM +0200, Daniel Vetter wrote:
> On Mon, Sep 24, 2018 at 07:36:08PM +0300, Ville Syrjälä wrote:
> > On Mon, Sep 24, 2018 at 05:51:16PM +0200, Daniel Vetter wrote:
> > > On Thu, Sep 20, 2018 at 09:51:38PM +0300, Ville Syrjala wrote:
> > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > 
> > > > We want to start tracking which infoframes are enabled, so let's replace
> > > > the boolean flag with a bitmask.
> > > > 
> > > > We'll abstract the bitmask so that it's not platform dependent. That
> > > > will allow us to examine the bitmask later in platform independent code.
> > > > 
> > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > ---
> > > >  drivers/gpu/drm/i915/intel_ddi.c  |  2 +-
> > > >  drivers/gpu/drm/i915/intel_drv.h  |  4 +-
> > > >  drivers/gpu/drm/i915/intel_hdmi.c | 87 ++++++++++++++++++++++++++++-----------
> > > >  3 files changed, 68 insertions(+), 25 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > > > index 086e3f940586..098a0e4edf2a 100644
> > > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > > @@ -3390,7 +3390,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
> > > >  		pipe_config->has_hdmi_sink = true;
> > > >  		intel_dig_port = enc_to_dig_port(&encoder->base);
> > > >  
> > > > -		if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
> > > > +		if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
> > > >  			pipe_config->has_infoframe = true;
> > > >  
> > > >  		if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
> > > > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > > > index e0f3a79fc75e..6815c69aac2f 100644
> > > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > > @@ -1181,7 +1181,7 @@ struct intel_digital_port {
> > > >  			       bool enable,
> > > >  			       const struct intel_crtc_state *crtc_state,
> > > >  			       const struct drm_connector_state *conn_state);
> > > > -	bool (*infoframe_enabled)(struct intel_encoder *encoder,
> > > > +	u32 (*infoframes_enabled)(struct intel_encoder *encoder,
> > > >  				  const struct intel_crtc_state *pipe_config);
> > > >  };
> > > >  
> > > > @@ -1856,6 +1856,8 @@ bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder,
> > > >  				       bool scrambling);
> > > >  void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
> > > >  void intel_infoframe_init(struct intel_digital_port *intel_dig_port);
> > > > +u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> > > > +				  const struct intel_crtc_state *crtc_state);
> > > >  
> > > >  
> > > >  /* intel_lvds.c */
> > > > diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> > > > index c3c2a638d062..a8fcddb199ae 100644
> > > > --- a/drivers/gpu/drm/i915/intel_hdmi.c
> > > > +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> > > > @@ -100,10 +100,14 @@ static u32 g4x_infoframe_index(unsigned int type)
> > > >  static u32 g4x_infoframe_enable(unsigned int type)
> > > >  {
> > > >  	switch (type) {
> > > > +	case HDMI_PACKET_TYPE_NULL:
> > > > +		return VIDEO_DIP_ENABLE; /* slight lie */
> > > 
> > > Not exactly sure why we're tracking this one here, but not for hsw.
> > 
> > HSW+ doesn't have a DIP enable bit like this. It only has the
> > bits to enable specific infoframes.
> > 
> > > Shouldn't we include that one if the DDI port is in hdmi mode? Would be
> > > more consistent I think.
> > 
> > Yes that would seem like the more correct thing. I think the reason
> > I did this here was so that I could map the DIP_ENABLE bit to
> > something unique. Would allow us to differentiate between the
> > "DIP enabled with no infoframes enabled" vs. "DIP enabled with
> > some infoframes enabled" cases. But seeing as we always enable some
> > infoframes I guess this doesn't really provide us with anything
> > particularly useful.
> > 
> > That said, I'm actually not sure whether the hw will send the null
> > packets if we don't enable the DIP. Would require a HDMI analyzer
> > to confirm.
> > 
> > Hmm. Actually gen4 bspec tells me:
> > "If DIP is enabled but DIP types are all disabled, no DIP is sent.
> >  However, a single Null DIP will be sent at the same point in the
> >  stream that DIP packets would have been sent. This is done to
> >  keep the port in HDMI mode, otherwise it would revert to DVI mode.
> >  The "Null packets enabled during vsync" mode (bit #9 of port
> >  control register) overrides this behavior."
> > 
> > So I guess mapping the null packet to the DIP enable bit is more or
> > less correct. Although the spec doesn't quite say whether the null
> > packet is also sent when some DIP types are also enabled, or if it
> > is only send when no DIP types are enabled.
> > 
> > So to match the hw I guess the readout should really do something
> > like:
> > 
> > if (hdmi & HDMI_MODE || dip_ctl & DIP_ENABLE)
> > 	infoframes |= TYPE_NULL;
> > 
> > but that would again mean that we can't tell the two cases
> > apart.
> 
> >From a functionality pov, do we actually care about the null DIP? HDMI
> mode y/n for sure, but we track that already. Feels like just never
> reading out the null packet state and never setting it in the state
> structure is the cheap way out here, and also the least confusing way out
> here. Trying to second guess what the hw does for something that doesn't
> seem to matter feels a bit silly.

I suppose. I just liked the idea of the bitmask reflecting reality, and
the fact that it gave one extra sanity check for free seemed like a nice
bonus. But the practical benefit is likely near zero so I don't see a
problem leaving it behind. I'll go rip it out.


> -Daniel
> 
> > 
> > > 
> > > Aside from that lgtm, has my
> > > 
> > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > 
> > > once we figured the TYPE_NULL thing out.
> > > -Daniel
> > > 
> > > >  	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
> > > >  		return VIDEO_DIP_ENABLE_GCP;
> > > >  	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> > > >  		return VIDEO_DIP_ENABLE_GAMUT;
> > > > +	case DP_SDP_VSC:
> > > > +		return 0;
> > > >  	case HDMI_INFOFRAME_TYPE_AVI:
> > > >  		return VIDEO_DIP_ENABLE_AVI;
> > > >  	case HDMI_INFOFRAME_TYPE_SPD:
> > > > @@ -119,6 +123,8 @@ static u32 g4x_infoframe_enable(unsigned int type)
> > > >  static u32 hsw_infoframe_enable(unsigned int type)
> > > >  {
> > > >  	switch (type) {
> > > > +	case HDMI_PACKET_TYPE_NULL:
> > > > +		return 0;
> > > >  	case HDMI_PACKET_TYPE_GENERAL_CONTROL:
> > > >  		return VIDEO_DIP_ENABLE_GCP_HSW;
> > > >  	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> > > > @@ -197,19 +203,19 @@ static void g4x_write_infoframe(struct intel_encoder *encoder,
> > > >  	POSTING_READ(VIDEO_DIP_CTL);
> > > >  }
> > > >  
> > > > -static bool g4x_infoframe_enabled(struct intel_encoder *encoder,
> > > > +static u32 g4x_infoframes_enabled(struct intel_encoder *encoder,
> > > >  				  const struct intel_crtc_state *pipe_config)
> > > >  {
> > > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > >  	u32 val = I915_READ(VIDEO_DIP_CTL);
> > > >  
> > > >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > > > -		return false;
> > > > +		return 0;
> > > >  
> > > >  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> > > > -		return false;
> > > > +		return 0;
> > > >  
> > > > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > > > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> > > >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD);
> > > >  }
> > > >  
> > > > @@ -252,7 +258,7 @@ static void ibx_write_infoframe(struct intel_encoder *encoder,
> > > >  	POSTING_READ(reg);
> > > >  }
> > > >  
> > > > -static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
> > > > +static u32 ibx_infoframes_enabled(struct intel_encoder *encoder,
> > > >  				  const struct intel_crtc_state *pipe_config)
> > > >  {
> > > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > > @@ -261,12 +267,12 @@ static bool ibx_infoframe_enabled(struct intel_encoder *encoder,
> > > >  	u32 val = I915_READ(reg);
> > > >  
> > > >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > > > -		return false;
> > > > +		return 0;
> > > >  
> > > >  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> > > > -		return false;
> > > > +		return 0;
> > > >  
> > > > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > > > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> > > >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
> > > >  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
> > > >  }
> > > > @@ -313,7 +319,7 @@ static void cpt_write_infoframe(struct intel_encoder *encoder,
> > > >  	POSTING_READ(reg);
> > > >  }
> > > >  
> > > > -static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
> > > > +static u32 cpt_infoframes_enabled(struct intel_encoder *encoder,
> > > >  				  const struct intel_crtc_state *pipe_config)
> > > >  {
> > > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > > @@ -321,9 +327,9 @@ static bool cpt_infoframe_enabled(struct intel_encoder *encoder,
> > > >  	u32 val = I915_READ(TVIDEO_DIP_CTL(pipe));
> > > >  
> > > >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > > > -		return false;
> > > > +		return 0;
> > > >  
> > > > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > > > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> > > >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
> > > >  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
> > > >  }
> > > > @@ -367,7 +373,7 @@ static void vlv_write_infoframe(struct intel_encoder *encoder,
> > > >  	POSTING_READ(reg);
> > > >  }
> > > >  
> > > > -static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
> > > > +static u32 vlv_infoframes_enabled(struct intel_encoder *encoder,
> > > >  				  const struct intel_crtc_state *pipe_config)
> > > >  {
> > > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > > @@ -375,12 +381,12 @@ static bool vlv_infoframe_enabled(struct intel_encoder *encoder,
> > > >  	u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(pipe));
> > > >  
> > > >  	if ((val & VIDEO_DIP_ENABLE) == 0)
> > > > -		return false;
> > > > +		return 0;
> > > >  
> > > >  	if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port))
> > > > -		return false;
> > > > +		return 0;
> > > >  
> > > > -	return val & (VIDEO_DIP_ENABLE_AVI |
> > > > +	return val & (VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI |
> > > >  		      VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
> > > >  		      VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP);
> > > >  }
> > > > @@ -419,7 +425,7 @@ static void hsw_write_infoframe(struct intel_encoder *encoder,
> > > >  	POSTING_READ(ctl_reg);
> > > >  }
> > > >  
> > > > -static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
> > > > +static u32 hsw_infoframes_enabled(struct intel_encoder *encoder,
> > > >  				  const struct intel_crtc_state *pipe_config)
> > > >  {
> > > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > > @@ -430,6 +436,42 @@ static bool hsw_infoframe_enabled(struct intel_encoder *encoder,
> > > >  		      VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW);
> > > >  }
> > > >  
> > > > +static const u8 infoframe_type_to_idx[] = {
> > > > +	HDMI_PACKET_TYPE_NULL,
> > > > +	HDMI_PACKET_TYPE_GENERAL_CONTROL,
> > > > +	HDMI_PACKET_TYPE_GAMUT_METADATA,
> > > > +	DP_SDP_VSC,
> > > > +	HDMI_INFOFRAME_TYPE_AVI,
> > > > +	HDMI_INFOFRAME_TYPE_SPD,
> > > > +	HDMI_INFOFRAME_TYPE_VENDOR,
> > > > +};
> > > > +
> > > > +u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder,
> > > > +				  const struct intel_crtc_state *crtc_state)
> > > > +{
> > > > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > > +	struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
> > > > +	u32 val, ret = 0;
> > > > +	int i;
> > > > +
> > > > +	val = dig_port->infoframes_enabled(encoder, crtc_state);
> > > > +
> > > > +	/* map from hardware bits to dip idx */
> > > > +	for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) {
> > > > +		unsigned int type = infoframe_type_to_idx[i];
> > > > +
> > > > +		if (HAS_DDI(dev_priv)) {
> > > > +			if (val & hsw_infoframe_enable(type))
> > > > +				ret |= BIT(i);
> > > > +		} else {
> > > > +			if (val & g4x_infoframe_enable(type))
> > > > +				ret |= BIT(i);
> > > > +		}
> > > > +	}
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +
> > > >  /*
> > > >   * The data we write to the DIP data buffer registers is 1 byte bigger than the
> > > >   * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting
> > > > @@ -1200,7 +1242,6 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
> > > >  				  struct intel_crtc_state *pipe_config)
> > > >  {
> > > >  	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> > > > -	struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi);
> > > >  	struct drm_device *dev = encoder->base.dev;
> > > >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > > >  	u32 tmp, flags = 0;
> > > > @@ -1223,7 +1264,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
> > > >  	if (tmp & HDMI_MODE_SELECT_HDMI)
> > > >  		pipe_config->has_hdmi_sink = true;
> > > >  
> > > > -	if (intel_dig_port->infoframe_enabled(encoder, pipe_config))
> > > > +	if (intel_hdmi_infoframes_enabled(encoder, pipe_config))
> > > >  		pipe_config->has_infoframe = true;
> > > >  
> > > >  	if (tmp & SDVO_AUDIO_ENABLE)
> > > > @@ -2325,23 +2366,23 @@ void intel_infoframe_init(struct intel_digital_port *intel_dig_port)
> > > >  	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
> > > >  		intel_dig_port->write_infoframe = vlv_write_infoframe;
> > > >  		intel_dig_port->set_infoframes = vlv_set_infoframes;
> > > > -		intel_dig_port->infoframe_enabled = vlv_infoframe_enabled;
> > > > +		intel_dig_port->infoframes_enabled = vlv_infoframes_enabled;
> > > >  	} else if (IS_G4X(dev_priv)) {
> > > >  		intel_dig_port->write_infoframe = g4x_write_infoframe;
> > > >  		intel_dig_port->set_infoframes = g4x_set_infoframes;
> > > > -		intel_dig_port->infoframe_enabled = g4x_infoframe_enabled;
> > > > +		intel_dig_port->infoframes_enabled = g4x_infoframes_enabled;
> > > >  	} else if (HAS_DDI(dev_priv)) {
> > > >  		intel_dig_port->write_infoframe = hsw_write_infoframe;
> > > >  		intel_dig_port->set_infoframes = hsw_set_infoframes;
> > > > -		intel_dig_port->infoframe_enabled = hsw_infoframe_enabled;
> > > > +		intel_dig_port->infoframes_enabled = hsw_infoframes_enabled;
> > > >  	} else if (HAS_PCH_IBX(dev_priv)) {
> > > >  		intel_dig_port->write_infoframe = ibx_write_infoframe;
> > > >  		intel_dig_port->set_infoframes = ibx_set_infoframes;
> > > > -		intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
> > > > +		intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
> > > >  	} else {
> > > >  		intel_dig_port->write_infoframe = cpt_write_infoframe;
> > > >  		intel_dig_port->set_infoframes = cpt_set_infoframes;
> > > > -		intel_dig_port->infoframe_enabled = cpt_infoframe_enabled;
> > > > +		intel_dig_port->infoframes_enabled = cpt_infoframes_enabled;
> > > >  	}
> > > >  }
> > > >  
> > > > -- 
> > > > 2.16.4
> > > > 
> > > > _______________________________________________
> > > > Intel-gfx mailing list
> > > > Intel-gfx@lists.freedesktop.org
> > > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > > 
> > > -- 
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > http://blog.ffwll.ch
> > 
> > -- 
> > Ville Syrjälä
> > Intel
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Intel-gfx] [PATCH 17/18] drm/i915: Check infoframe state in intel_pipe_config_compare()
  2018-09-24 16:12   ` Daniel Vetter
@ 2018-10-01 20:35     ` Ville Syrjälä
  2018-10-02  8:16       ` Daniel Vetter
  0 siblings, 1 reply; 95+ messages in thread
From: Ville Syrjälä @ 2018-10-01 20:35 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel

On Mon, Sep 24, 2018 at 06:12:27PM +0200, Daniel Vetter wrote:
> On Thu, Sep 20, 2018 at 09:51:44PM +0300, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Check the infoframes and infoframe enable state when comparing two
> > crtc states.
> > 
> > We'll use the infoframe logging functions from video/hdmi.c to
> > show the infoframes as part of the state dump.
> > 
> > TODO: Try to better integrate the infoframe dumps with
> >       drm state dumps
> > 
> > v2: drm_printk() is no more
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> 
> Might need adapting to PIPE_CONFIG_QUIRK_INFOFRAME, but aside from that
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> >  drivers/gpu/drm/i915/intel_display.c | 49 +++++++++++++++++++++++++++++++++++-
> >  1 file changed, 48 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index fbcc56caffb6..3dce49e36a05 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -11380,6 +11380,37 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n,
> >  	return false;
> >  }
> >  
> > +static bool
> > +intel_compare_infoframe(const union hdmi_infoframe *a,
> > +			const union hdmi_infoframe *b)
> > +{
> > +	return memcmp(a, b, sizeof(*a)) == 0;
> > +}
> > +
> > +static void
> > +pipe_config_infoframe_err(struct drm_i915_private *dev_priv,
> > +			  bool adjust, const char *name,
> > +			  const union hdmi_infoframe *a,
> > +			  const union hdmi_infoframe *b)
> > +{
> > +	if (adjust) {
> > +		if ((drm_debug & DRM_UT_KMS) == 0)
> > +			return;
> > +
> > +		drm_dbg(DRM_UT_KMS, "mismatch in %s infoframe", name);
> > +		drm_dbg(DRM_UT_KMS, "expected:");
> > +		hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, a);
> > +		drm_dbg(DRM_UT_KMS, "found");
> > +		hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, b);
> > +	} else {
> > +		drm_err("mismatch in %s infoframe", name);
> > +		drm_err("expected:");
> > +		hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, a);
> > +		drm_err("found");
> > +		hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, b);
> > +	}
> 
> Mildly concerned about padding fields (since these are the not-compatified
> structs). Maybe dump the mismatching byte too, plus byte offset? Or maybe
> I'm just too paranoid.

Not sure. Maybe just wait and see how crazy the compiler really is?
Apart from the dmesg noise no real harm should befall the user from
getting this wrong.

> 
> > +}
> > +
> >  static void __printf(3, 4)
> >  pipe_config_err(bool adjust, const char *name, const char *format, ...)
> >  {
> > @@ -11541,7 +11572,17 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
> >  	} \
> >  } while (0)
> >  
> > -#define PIPE_CONF_QUIRK(quirk)	\
> > +#define PIPE_CONF_CHECK_INFOFRAME(name) do { \
> > +	if (!intel_compare_infoframe(&current_config->infoframes.name, \
> > +				     &pipe_config->infoframes.name)) { \
> > +		pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \
> > +					  &current_config->infoframes.name, \
> > +					  &pipe_config->infoframes.name); \
> > +		ret = false; \
> > +	} \
> > +} while (0)
> > +
> > +#define PIPE_CONF_QUIRK(quirk) \
> >  	((current_config->quirks | pipe_config->quirks) & (quirk))
> >  
> >  	PIPE_CONF_CHECK_I(cpu_transcoder);
> > @@ -11670,6 +11711,12 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
> >  
> >  	PIPE_CONF_CHECK_I(min_voltage_level);
> >  
> > +	PIPE_CONF_CHECK_X(infoframes.enable);
> > +	PIPE_CONF_CHECK_X(infoframes.gcp);
> > +	PIPE_CONF_CHECK_INFOFRAME(avi);
> > +	PIPE_CONF_CHECK_INFOFRAME(spd);
> > +	PIPE_CONF_CHECK_INFOFRAME(hdmi);
> > +
> >  #undef PIPE_CONF_CHECK_X
> >  #undef PIPE_CONF_CHECK_I
> >  #undef PIPE_CONF_CHECK_BOOL
> > -- 
> > 2.16.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 04/18] video/hdmi: Constify infoframe passed to the pack functions
  2018-10-01 19:10       ` Ville Syrjälä
@ 2018-10-02  6:37         ` Hans Verkuil
  -1 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-10-02  6:37 UTC (permalink / raw)
  To: Ville Syrjälä, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 10/01/2018 09:10 PM, Ville Syrjälä wrote:
> On Fri, Sep 21, 2018 at 05:33:32PM +0300, Ville Syrjala wrote:
>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>
>> Let's make the infoframe pack functions usable with a const infoframe
>> structure. This allows us to precompute the infoframe earlier, and still
>> pack it later when we're no longer allowed to modify the structure.
>> So now we end up with a _check()+_pack_only() or _pack() functions
>> depending on whether you want to precompute the infoframes or not.
>> The names aren't great but I was lazy and didn't want to change all the
>> drivers.
>>
>> v2: Deal with exynos churn
>>     Actually export the new funcs
>> v3: Fix various documentation fails (Hans)
> 
> Hans, any more concerns about this patch?

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Regards,

	Hans

> 
>>
>> Cc: Thierry Reding <thierry.reding@gmail.com>
>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
>> Cc: linux-media@vger.kernel.org
>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> ---
>>  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
>>  include/linux/hdmi.h |  19 ++-
>>  2 files changed, 416 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
>> index 53e7ee2c83fc..08d94ab00467 100644
>> --- a/drivers/video/hdmi.c
>> +++ b/drivers/video/hdmi.c
>> @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
>>  }
>>  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>>  
>> +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
>> +	    frame->version != 2 ||
>> +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
>> +		return -EINVAL;
>> +
>> +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /**
>> - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
>> + * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
>> + * @frame: HDMI AVI infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
>> +{
>> +	return hdmi_avi_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
>> +
>> +/**
>> + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
>>   * @frame: HDMI AVI infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>> -				size_t size)
>> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
>> +				     void *buffer, size_t size)
>>  {
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>> +
>> +	ret = hdmi_avi_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>>  	if (size < length)
>>  		return -ENOSPC;
>>  
>> -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
>> -		return -EINVAL;
>> -
>>  	memset(buffer, 0, size);
>>  
>>  	ptr[0] = frame->type;
>> @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
>> + *                             and write it to binary buffer
>> + * @frame: HDMI AVI infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
>> +				void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_avi_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
>>  
>>  /**
>> @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>>  }
>>  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>>  
>> +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
>> +	    frame->version != 1 ||
>> +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /**
>> - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
>> + * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
>> + * @frame: HDMI SPD infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
>> +{
>> +	return hdmi_spd_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
>> +
>> +/**
>> + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
>>   * @frame: HDMI SPD infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>> -				size_t size)
>> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
>> +				     void *buffer, size_t size)
>>  {
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>> +
>> +	ret = hdmi_spd_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>> @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
>> + *                             and write it to binary buffer
>> + * @frame: HDMI SPD infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
>> +				void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_spd_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
>>  
>>  /**
>> @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
>>  }
>>  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>>  
>> +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
>> +	    frame->version != 1 ||
>> +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
>> + * @frame: HDMI audio infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
>> +{
>> +	return hdmi_audio_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
>> +
>>  /**
>> - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
>> + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
>>   * @frame: HDMI audio infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>> -				  void *buffer, size_t size)
>> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
>> +				       void *buffer, size_t size)
>>  {
>>  	unsigned char channels;
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>> +
>> +	ret = hdmi_audio_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>> @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
>> + *                               and write it to binary buffer
>> + * @frame: HDMI Audio infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>> +				  void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_audio_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
>>  
>>  /**
>> @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
>>  	 * value
>>  	 */
>>  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
>> +	frame->length = 4;
>>  
>>  	return 0;
>>  }
>> @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>>  		return 4;
>>  }
>>  
>> +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
>> +	    frame->version != 1 ||
>> +	    frame->oui != HDMI_IEEE_OUI)
>> +		return -EINVAL;
>> +
>> +	/* only one of those can be supplied */
>> +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
>> +		return -EINVAL;
>> +
>> +	if (frame->length != hdmi_vendor_infoframe_length(frame))
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /**
>> - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
>> + * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
>> + * @frame: HDMI infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
>> +{
>> +	frame->length = hdmi_vendor_infoframe_length(frame);
>> +
>> +	return hdmi_vendor_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
>> +
>> +/**
>> + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
>>   * @frame: HDMI infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>> -				 void *buffer, size_t size)
>> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
>> +					void *buffer, size_t size)
>>  {
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>>  
>> -	/* only one of those can be supplied */
>> -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
>> -		return -EINVAL;
>> -
>> -	frame->length = hdmi_vendor_infoframe_length(frame);
>> +	ret = hdmi_vendor_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>> @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
>> + *                                and write it to binary buffer
>> + * @frame: HDMI Vendor infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>> +				   void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
>>  
>> +static int
>> +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
>> +{
>> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
>> +	    frame->any.version != 1)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /*
>> - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
>> + * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
>> + */
>> +static int
>> +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* we only know about HDMI vendor infoframes */
>> +	if (frame->any.oui != HDMI_IEEE_OUI)
>> +		return -EINVAL;
>> +
>> +	return hdmi_vendor_infoframe_check(&frame->hdmi);
>> +}
>> +
>> +/*
>> + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
>>   */
>>  static ssize_t
>> -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>> -			   void *buffer, size_t size)
>> +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
>> +				    void *buffer, size_t size)
>>  {
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>> +
>>  	/* we only know about HDMI vendor infoframes */
>>  	if (frame->any.oui != HDMI_IEEE_OUI)
>>  		return -EINVAL;
>>  
>> -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
>> +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
>> +}
>> +
>> +/*
>> + * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
>> + *                                    and write it to binary buffer
>> + */
>> +static ssize_t
>> +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>> +			       void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_any_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
>> +}
>> +
>> +/**
>> + * hdmi_infoframe_check() - check a HDMI infoframe
>> + * @frame: HDMI infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int
>> +hdmi_infoframe_check(union hdmi_infoframe *frame)
>> +{
>> +	switch (frame->any.type) {
>> +	case HDMI_INFOFRAME_TYPE_AVI:
>> +		return hdmi_avi_infoframe_check(&frame->avi);
>> +	case HDMI_INFOFRAME_TYPE_SPD:
>> +		return hdmi_spd_infoframe_check(&frame->spd);
>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>> +		return hdmi_audio_infoframe_check(&frame->audio);
>> +	case HDMI_INFOFRAME_TYPE_VENDOR:
>> +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
>> +	default:
>> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>> +		return -EINVAL;
>> +	}
>>  }
>> +EXPORT_SYMBOL(hdmi_infoframe_check);
>>  
>>  /**
>> - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
>> + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
>>   * @frame: HDMI infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>>   * error code on failure.
>>   */
>>  ssize_t
>> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
>> +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
>> +{
>> +	ssize_t length;
>> +
>> +	switch (frame->any.type) {
>> +	case HDMI_INFOFRAME_TYPE_AVI:
>> +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
>> +						      buffer, size);
>> +		break;
>> +	case HDMI_INFOFRAME_TYPE_SPD:
>> +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
>> +						      buffer, size);
>> +		break;
>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>> +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
>> +							buffer, size);
>> +		break;
>> +	case HDMI_INFOFRAME_TYPE_VENDOR:
>> +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
>> +							     buffer, size);
>> +		break;
>> +	default:
>> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>> +		length = -EINVAL;
>> +	}
>> +
>> +	return length;
>> +}
>> +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_infoframe_pack() - check a HDMI infoframe,
>> + *                         and write it to binary buffer
>> + * @frame: HDMI infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t
>> +hdmi_infoframe_pack(union hdmi_infoframe *frame,
>> +		    void *buffer, size_t size)
>>  {
>>  	ssize_t length;
>>  
>> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
>> index bce1abb1fe57..c76b50a48e48 100644
>> --- a/include/linux/hdmi.h
>> +++ b/include/linux/hdmi.h
>> @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
>>  int 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);
>> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
>> +				     void *buffer, size_t size);
>> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
>>  
>>  enum hdmi_spd_sdi {
>>  	HDMI_SPD_SDI_UNKNOWN,
>> @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>>  			    const char *vendor, const char *product);
>>  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>>  				size_t size);
>> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
>> +				     void *buffer, size_t size);
>> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
>>  
>>  enum hdmi_audio_coding_type {
>>  	HDMI_AUDIO_CODING_TYPE_STREAM,
>> @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
>>  int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
>>  ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>>  				  void *buffer, size_t size);
>> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
>> +				       void *buffer, size_t size);
>> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
>>  
>>  enum hdmi_3d_structure {
>>  	HDMI_3D_STRUCTURE_INVALID = -1,
>> @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
>>  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
>>  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>>  				   void *buffer, size_t size);
>> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
>> +					void *buffer, size_t size);
>> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
>>  
>>  union hdmi_vendor_any_infoframe {
>>  	struct {
>> @@ -330,8 +342,11 @@ union hdmi_infoframe {
>>  	struct hdmi_audio_infoframe audio;
>>  };
>>  
>> -ssize_t
>> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
>> +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
>> +			    size_t size);
>> +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
>> +				 void *buffer, size_t size);
>> +int hdmi_infoframe_check(union hdmi_infoframe *frame);
>>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>>  			  const void *buffer, size_t size);
>>  void hdmi_infoframe_log(const char *level, struct device *dev,
>> -- 
>> 2.16.4
> 

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH v3 04/18] video/hdmi: Constify infoframe passed to the pack functions
@ 2018-10-02  6:37         ` Hans Verkuil
  0 siblings, 0 replies; 95+ messages in thread
From: Hans Verkuil @ 2018-10-02  6:37 UTC (permalink / raw)
  To: Ville Syrjälä, dri-devel
  Cc: intel-gfx, Thierry Reding, Hans Verkuil, linux-media

On 10/01/2018 09:10 PM, Ville Syrjälä wrote:
> On Fri, Sep 21, 2018 at 05:33:32PM +0300, Ville Syrjala wrote:
>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>
>> Let's make the infoframe pack functions usable with a const infoframe
>> structure. This allows us to precompute the infoframe earlier, and still
>> pack it later when we're no longer allowed to modify the structure.
>> So now we end up with a _check()+_pack_only() or _pack() functions
>> depending on whether you want to precompute the infoframes or not.
>> The names aren't great but I was lazy and didn't want to change all the
>> drivers.
>>
>> v2: Deal with exynos churn
>>     Actually export the new funcs
>> v3: Fix various documentation fails (Hans)
> 
> Hans, any more concerns about this patch?

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Regards,

	Hans

> 
>>
>> Cc: Thierry Reding <thierry.reding@gmail.com>
>> Cc: Hans Verkuil <hans.verkuil@cisco.com>
>> Cc: linux-media@vger.kernel.org
>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> ---
>>  drivers/video/hdmi.c | 425 +++++++++++++++++++++++++++++++++++++++++++++++----
>>  include/linux/hdmi.h |  19 ++-
>>  2 files changed, 416 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
>> index 53e7ee2c83fc..08d94ab00467 100644
>> --- a/drivers/video/hdmi.c
>> +++ b/drivers/video/hdmi.c
>> @@ -68,8 +68,36 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
>>  }
>>  EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>>  
>> +static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
>> +	    frame->version != 2 ||
>> +	    frame->length != HDMI_AVI_INFOFRAME_SIZE)
>> +		return -EINVAL;
>> +
>> +	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /**
>> - * hdmi_avi_infoframe_pack() - write HDMI AVI infoframe to binary buffer
>> + * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
>> + * @frame: HDMI AVI infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
>> +{
>> +	return hdmi_avi_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_avi_infoframe_check);
>> +
>> +/**
>> + * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
>>   * @frame: HDMI AVI infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -82,20 +110,22 @@ EXPORT_SYMBOL(hdmi_avi_infoframe_init);
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>> -				size_t size)
>> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
>> +				     void *buffer, size_t size)
>>  {
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>> +
>> +	ret = hdmi_avi_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>>  	if (size < length)
>>  		return -ENOSPC;
>>  
>> -	if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
>> -		return -EINVAL;
>> -
>>  	memset(buffer, 0, size);
>>  
>>  	ptr[0] = frame->type;
>> @@ -152,6 +182,36 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
>> + *                             and write it to binary buffer
>> + * @frame: HDMI AVI infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
>> +				void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_avi_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_avi_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
>>  
>>  /**
>> @@ -178,8 +238,33 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>>  }
>>  EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>>  
>> +static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
>> +	    frame->version != 1 ||
>> +	    frame->length != HDMI_SPD_INFOFRAME_SIZE)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /**
>> - * hdmi_spd_infoframe_pack() - write HDMI SPD infoframe to binary buffer
>> + * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
>> + * @frame: HDMI SPD infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
>> +{
>> +	return hdmi_spd_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_spd_infoframe_check);
>> +
>> +/**
>> + * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
>>   * @frame: HDMI SPD infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -192,11 +277,16 @@ EXPORT_SYMBOL(hdmi_spd_infoframe_init);
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>> -				size_t size)
>> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
>> +				     void *buffer, size_t size)
>>  {
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>> +
>> +	ret = hdmi_spd_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>> @@ -222,6 +312,36 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
>> + *                             and write it to binary buffer
>> + * @frame: HDMI SPD infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
>> +				void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_spd_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_spd_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
>>  
>>  /**
>> @@ -242,8 +362,33 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
>>  }
>>  EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>>  
>> +static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
>> +	    frame->version != 1 ||
>> +	    frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
>> + * @frame: HDMI audio infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
>> +{
>> +	return hdmi_audio_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_audio_infoframe_check);
>> +
>>  /**
>> - * hdmi_audio_infoframe_pack() - write HDMI audio infoframe to binary buffer
>> + * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
>>   * @frame: HDMI audio infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -256,12 +401,17 @@ EXPORT_SYMBOL(hdmi_audio_infoframe_init);
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>> -				  void *buffer, size_t size)
>> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
>> +				       void *buffer, size_t size)
>>  {
>>  	unsigned char channels;
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>> +
>> +	ret = hdmi_audio_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>> @@ -297,6 +447,36 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
>> + *                               and write it to binary buffer
>> + * @frame: HDMI Audio infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>> +				  void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_audio_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_audio_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
>>  
>>  /**
>> @@ -319,6 +499,7 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
>>  	 * value
>>  	 */
>>  	frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
>> +	frame->length = 4;
>>  
>>  	return 0;
>>  }
>> @@ -335,8 +516,42 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>>  		return 4;
>>  }
>>  
>> +static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
>> +{
>> +	if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
>> +	    frame->version != 1 ||
>> +	    frame->oui != HDMI_IEEE_OUI)
>> +		return -EINVAL;
>> +
>> +	/* only one of those can be supplied */
>> +	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
>> +		return -EINVAL;
>> +
>> +	if (frame->length != hdmi_vendor_infoframe_length(frame))
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /**
>> - * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
>> + * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
>> + * @frame: HDMI infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
>> +{
>> +	frame->length = hdmi_vendor_infoframe_length(frame);
>> +
>> +	return hdmi_vendor_infoframe_check_only(frame);
>> +}
>> +EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
>> +
>> +/**
>> + * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
>>   * @frame: HDMI infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -349,17 +564,16 @@ static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *fram
>>   * Returns the number of bytes packed into the binary buffer or a negative
>>   * error code on failure.
>>   */
>> -ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>> -				 void *buffer, size_t size)
>> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
>> +					void *buffer, size_t size)
>>  {
>>  	u8 *ptr = buffer;
>>  	size_t length;
>> +	int ret;
>>  
>> -	/* only one of those can be supplied */
>> -	if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
>> -		return -EINVAL;
>> -
>> -	frame->length = hdmi_vendor_infoframe_length(frame);
>> +	ret = hdmi_vendor_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>>  
>>  	length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
>>  
>> @@ -394,24 +608,134 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>>  
>>  	return length;
>>  }
>> +EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
>> + *                                and write it to binary buffer
>> + * @frame: HDMI Vendor infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>> +				   void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
>> +}
>>  EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
>>  
>> +static int
>> +hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
>> +{
>> +	if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
>> +	    frame->any.version != 1)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>  /*
>> - * hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
>> + * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
>> + */
>> +static int
>> +hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* we only know about HDMI vendor infoframes */
>> +	if (frame->any.oui != HDMI_IEEE_OUI)
>> +		return -EINVAL;
>> +
>> +	return hdmi_vendor_infoframe_check(&frame->hdmi);
>> +}
>> +
>> +/*
>> + * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
>>   */
>>  static ssize_t
>> -hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>> -			   void *buffer, size_t size)
>> +hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
>> +				    void *buffer, size_t size)
>>  {
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_any_infoframe_check_only(frame);
>> +	if (ret)
>> +		return ret;
>> +
>>  	/* we only know about HDMI vendor infoframes */
>>  	if (frame->any.oui != HDMI_IEEE_OUI)
>>  		return -EINVAL;
>>  
>> -	return hdmi_vendor_infoframe_pack(&frame->hdmi, buffer, size);
>> +	return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
>> +}
>> +
>> +/*
>> + * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
>> + *                                    and write it to binary buffer
>> + */
>> +static ssize_t
>> +hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>> +			       void *buffer, size_t size)
>> +{
>> +	int ret;
>> +
>> +	ret = hdmi_vendor_any_infoframe_check(frame);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
>> +}
>> +
>> +/**
>> + * hdmi_infoframe_check() - check a HDMI infoframe
>> + * @frame: HDMI infoframe
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields.
>> + *
>> + * Returns 0 on success or a negative error code on failure.
>> + */
>> +int
>> +hdmi_infoframe_check(union hdmi_infoframe *frame)
>> +{
>> +	switch (frame->any.type) {
>> +	case HDMI_INFOFRAME_TYPE_AVI:
>> +		return hdmi_avi_infoframe_check(&frame->avi);
>> +	case HDMI_INFOFRAME_TYPE_SPD:
>> +		return hdmi_spd_infoframe_check(&frame->spd);
>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>> +		return hdmi_audio_infoframe_check(&frame->audio);
>> +	case HDMI_INFOFRAME_TYPE_VENDOR:
>> +		return hdmi_vendor_any_infoframe_check(&frame->vendor);
>> +	default:
>> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>> +		return -EINVAL;
>> +	}
>>  }
>> +EXPORT_SYMBOL(hdmi_infoframe_check);
>>  
>>  /**
>> - * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer
>> + * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
>>   * @frame: HDMI infoframe
>>   * @buffer: destination buffer
>>   * @size: size of buffer
>> @@ -425,7 +749,56 @@ hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
>>   * error code on failure.
>>   */
>>  ssize_t
>> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
>> +hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
>> +{
>> +	ssize_t length;
>> +
>> +	switch (frame->any.type) {
>> +	case HDMI_INFOFRAME_TYPE_AVI:
>> +		length = hdmi_avi_infoframe_pack_only(&frame->avi,
>> +						      buffer, size);
>> +		break;
>> +	case HDMI_INFOFRAME_TYPE_SPD:
>> +		length = hdmi_spd_infoframe_pack_only(&frame->spd,
>> +						      buffer, size);
>> +		break;
>> +	case HDMI_INFOFRAME_TYPE_AUDIO:
>> +		length = hdmi_audio_infoframe_pack_only(&frame->audio,
>> +							buffer, size);
>> +		break;
>> +	case HDMI_INFOFRAME_TYPE_VENDOR:
>> +		length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
>> +							     buffer, size);
>> +		break;
>> +	default:
>> +		WARN(1, "Bad infoframe type %d\n", frame->any.type);
>> +		length = -EINVAL;
>> +	}
>> +
>> +	return length;
>> +}
>> +EXPORT_SYMBOL(hdmi_infoframe_pack_only);
>> +
>> +/**
>> + * hdmi_infoframe_pack() - check a HDMI infoframe,
>> + *                         and write it to binary buffer
>> + * @frame: HDMI infoframe
>> + * @buffer: destination buffer
>> + * @size: size of buffer
>> + *
>> + * Validates that the infoframe is consistent and updates derived fields
>> + * (eg. length) based on other fields, after which it packs the information
>> + * contained in the @frame structure into a binary representation that
>> + * can be written into the corresponding controller registers. This function
>> + * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
>> + * specification.
>> + *
>> + * Returns the number of bytes packed into the binary buffer or a negative
>> + * error code on failure.
>> + */
>> +ssize_t
>> +hdmi_infoframe_pack(union hdmi_infoframe *frame,
>> +		    void *buffer, size_t size)
>>  {
>>  	ssize_t length;
>>  
>> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
>> index bce1abb1fe57..c76b50a48e48 100644
>> --- a/include/linux/hdmi.h
>> +++ b/include/linux/hdmi.h
>> @@ -163,6 +163,9 @@ struct hdmi_avi_infoframe {
>>  int 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);
>> +ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
>> +				     void *buffer, size_t size);
>> +int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
>>  
>>  enum hdmi_spd_sdi {
>>  	HDMI_SPD_SDI_UNKNOWN,
>> @@ -194,6 +197,9 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
>>  			    const char *vendor, const char *product);
>>  ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
>>  				size_t size);
>> +ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
>> +				     void *buffer, size_t size);
>> +int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
>>  
>>  enum hdmi_audio_coding_type {
>>  	HDMI_AUDIO_CODING_TYPE_STREAM,
>> @@ -272,6 +278,9 @@ struct hdmi_audio_infoframe {
>>  int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
>>  ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
>>  				  void *buffer, size_t size);
>> +ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
>> +				       void *buffer, size_t size);
>> +int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
>>  
>>  enum hdmi_3d_structure {
>>  	HDMI_3D_STRUCTURE_INVALID = -1,
>> @@ -299,6 +308,9 @@ struct hdmi_vendor_infoframe {
>>  int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
>>  ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
>>  				   void *buffer, size_t size);
>> +ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
>> +					void *buffer, size_t size);
>> +int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
>>  
>>  union hdmi_vendor_any_infoframe {
>>  	struct {
>> @@ -330,8 +342,11 @@ union hdmi_infoframe {
>>  	struct hdmi_audio_infoframe audio;
>>  };
>>  
>> -ssize_t
>> -hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
>> +ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
>> +			    size_t size);
>> +ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
>> +				 void *buffer, size_t size);
>> +int hdmi_infoframe_check(union hdmi_infoframe *frame);
>>  int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
>>  			  const void *buffer, size_t size);
>>  void hdmi_infoframe_log(const char *level, struct device *dev,
>> -- 
>> 2.16.4
> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [Intel-gfx] [PATCH 17/18] drm/i915: Check infoframe state in intel_pipe_config_compare()
  2018-10-01 20:35     ` [Intel-gfx] " Ville Syrjälä
@ 2018-10-02  8:16       ` Daniel Vetter
  0 siblings, 0 replies; 95+ messages in thread
From: Daniel Vetter @ 2018-10-02  8:16 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx, dri-devel

On Mon, Oct 01, 2018 at 11:35:05PM +0300, Ville Syrjälä wrote:
> On Mon, Sep 24, 2018 at 06:12:27PM +0200, Daniel Vetter wrote:
> > On Thu, Sep 20, 2018 at 09:51:44PM +0300, Ville Syrjala wrote:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > Check the infoframes and infoframe enable state when comparing two
> > > crtc states.
> > > 
> > > We'll use the infoframe logging functions from video/hdmi.c to
> > > show the infoframes as part of the state dump.
> > > 
> > > TODO: Try to better integrate the infoframe dumps with
> > >       drm state dumps
> > > 
> > > v2: drm_printk() is no more
> > > 
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > ---
> > 
> > Might need adapting to PIPE_CONFIG_QUIRK_INFOFRAME, but aside from that
> > 
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > 
> > >  drivers/gpu/drm/i915/intel_display.c | 49 +++++++++++++++++++++++++++++++++++-
> > >  1 file changed, 48 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > > index fbcc56caffb6..3dce49e36a05 100644
> > > --- a/drivers/gpu/drm/i915/intel_display.c
> > > +++ b/drivers/gpu/drm/i915/intel_display.c
> > > @@ -11380,6 +11380,37 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n,
> > >  	return false;
> > >  }
> > >  
> > > +static bool
> > > +intel_compare_infoframe(const union hdmi_infoframe *a,
> > > +			const union hdmi_infoframe *b)
> > > +{
> > > +	return memcmp(a, b, sizeof(*a)) == 0;
> > > +}
> > > +
> > > +static void
> > > +pipe_config_infoframe_err(struct drm_i915_private *dev_priv,
> > > +			  bool adjust, const char *name,
> > > +			  const union hdmi_infoframe *a,
> > > +			  const union hdmi_infoframe *b)
> > > +{
> > > +	if (adjust) {
> > > +		if ((drm_debug & DRM_UT_KMS) == 0)
> > > +			return;
> > > +
> > > +		drm_dbg(DRM_UT_KMS, "mismatch in %s infoframe", name);
> > > +		drm_dbg(DRM_UT_KMS, "expected:");
> > > +		hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, a);
> > > +		drm_dbg(DRM_UT_KMS, "found");
> > > +		hdmi_infoframe_log(KERN_DEBUG, dev_priv->drm.dev, b);
> > > +	} else {
> > > +		drm_err("mismatch in %s infoframe", name);
> > > +		drm_err("expected:");
> > > +		hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, a);
> > > +		drm_err("found");
> > > +		hdmi_infoframe_log(KERN_ERR, dev_priv->drm.dev, b);
> > > +	}
> > 
> > Mildly concerned about padding fields (since these are the not-compatified
> > structs). Maybe dump the mismatching byte too, plus byte offset? Or maybe
> > I'm just too paranoid.
> 
> Not sure. Maybe just wait and see how crazy the compiler really is?
> Apart from the dmesg noise no real harm should befall the user from
> getting this wrong.

The scenario I have in mind is padding fields + someone didn't use
kzalloc. Dumping the mismatching byte would help in debugging this.
-Daniel

> 
> > 
> > > +}
> > > +
> > >  static void __printf(3, 4)
> > >  pipe_config_err(bool adjust, const char *name, const char *format, ...)
> > >  {
> > > @@ -11541,7 +11572,17 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
> > >  	} \
> > >  } while (0)
> > >  
> > > -#define PIPE_CONF_QUIRK(quirk)	\
> > > +#define PIPE_CONF_CHECK_INFOFRAME(name) do { \
> > > +	if (!intel_compare_infoframe(&current_config->infoframes.name, \
> > > +				     &pipe_config->infoframes.name)) { \
> > > +		pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \
> > > +					  &current_config->infoframes.name, \
> > > +					  &pipe_config->infoframes.name); \
> > > +		ret = false; \
> > > +	} \
> > > +} while (0)
> > > +
> > > +#define PIPE_CONF_QUIRK(quirk) \
> > >  	((current_config->quirks | pipe_config->quirks) & (quirk))
> > >  
> > >  	PIPE_CONF_CHECK_I(cpu_transcoder);
> > > @@ -11670,6 +11711,12 @@ intel_pipe_config_compare(struct drm_i915_private *dev_priv,
> > >  
> > >  	PIPE_CONF_CHECK_I(min_voltage_level);
> > >  
> > > +	PIPE_CONF_CHECK_X(infoframes.enable);
> > > +	PIPE_CONF_CHECK_X(infoframes.gcp);
> > > +	PIPE_CONF_CHECK_INFOFRAME(avi);
> > > +	PIPE_CONF_CHECK_INFOFRAME(spd);
> > > +	PIPE_CONF_CHECK_INFOFRAME(hdmi);
> > > +
> > >  #undef PIPE_CONF_CHECK_X
> > >  #undef PIPE_CONF_CHECK_I
> > >  #undef PIPE_CONF_CHECK_BOOL
> > > -- 
> > > 2.16.4
> > > 
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > 
> > -- 
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch
> 
> -- 
> Ville Syrjälä
> Intel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 95+ messages in thread

* Re: [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types
  2018-09-20 18:51   ` Ville Syrjala
  (?)
  (?)
@ 2018-12-20 11:27   ` Sharma, Shashank
  -1 siblings, 0 replies; 95+ messages in thread
From: Sharma, Shashank @ 2018-12-20 11:27 UTC (permalink / raw)
  To: intel-gfx

Regards

Shashank


On 9/21/2018 12:21 AM, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> We'll be wanting to send more than just infoframes over HDMI. So add an
> enum for other packet types.
>
> TODO: Maybe just include the infoframe types in the packet type enum
>        and get rid of the infoframe type enum?
>
> Cc: Thierry Reding <thierry.reding@gmail.com>
> Cc: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: linux-media@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>   include/linux/hdmi.h | 15 +++++++++++++++
>   1 file changed, 15 insertions(+)
>
> diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
> index c76b50a48e48..80521d9591a1 100644
> --- a/include/linux/hdmi.h
> +++ b/include/linux/hdmi.h
> @@ -27,6 +27,21 @@
>   #include <linux/types.h>
>   #include <linux/device.h>
>   
> +enum hdmi_packet_type {
> +	HDMI_PACKET_TYPE_NULL = 0x00,
> +	HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
> +	HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
> +	HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
> +	HDMI_PACKET_TYPE_AUDIO_CP = 0x04,
Call it TYPE_ACP instead of AUDIO_CP just to be inline with H14b spec 
description ?
> +	HDMI_PACKET_TYPE_ISRC1 = 0x05,
> +	HDMI_PACKET_TYPE_ISRC2 = 0x06,
> +	HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
> +	HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
> +	HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
> +	HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
> +	/* + enum hdmi_infoframe_type */
> +};
> +
With or without the change suggested above:
Reviewed-by: Shashank Sharma <shashank.sharma@intel.com>
>   enum hdmi_infoframe_type {
>   	HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
>   	HDMI_INFOFRAME_TYPE_AVI = 0x82,
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 95+ messages in thread

end of thread, other threads:[~2018-12-20 11:27 UTC | newest]

Thread overview: 95+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-20 18:51 [PATCH 00/18] drm/i915: Infoframe precompute/check Ville Syrjala
2018-09-20 18:51 ` Ville Syrjala
2018-09-20 18:51 ` [PATCH 01/18] video/hdmi: Constify 'buffer' to the unpack functions Ville Syrjala
2018-09-20 18:51   ` Ville Syrjala
2018-09-21  8:03   ` Hans Verkuil
2018-09-21  8:03     ` Hans Verkuil
2018-09-20 18:51 ` [PATCH 02/18] video/hdmi: Pass buffer size to infoframe " Ville Syrjala
2018-09-20 18:51   ` Ville Syrjala
2018-09-21  8:06   ` Hans Verkuil
2018-09-21  8:06     ` Hans Verkuil
2018-09-20 18:51 ` [PATCH 03/18] video/hdmi: Constify infoframe passed to the log functions Ville Syrjala
2018-09-20 18:51   ` Ville Syrjala
2018-09-21  8:06   ` Hans Verkuil
2018-09-21  8:06     ` Hans Verkuil
2018-09-20 18:51 ` [PATCH 04/18] video/hdmi: Constify infoframe passed to the pack functions Ville Syrjala
2018-09-20 18:51   ` Ville Syrjala
2018-09-21  8:24   ` Hans Verkuil
2018-09-21  8:24     ` Hans Verkuil
2018-09-21 14:30     ` Ville Syrjälä
2018-09-21 14:30       ` Ville Syrjälä
2018-09-21 14:33   ` [PATCH v3 " Ville Syrjala
2018-09-21 14:33     ` Ville Syrjala
2018-10-01 19:10     ` Ville Syrjälä
2018-10-01 19:10       ` Ville Syrjälä
2018-10-02  6:37       ` Hans Verkuil
2018-10-02  6:37         ` Hans Verkuil
2018-09-20 18:51 ` [PATCH 05/18] video/hdmi: Add an enum for HDMI packet types Ville Syrjala
2018-09-20 18:51   ` Ville Syrjala
2018-09-21  8:41   ` Hans Verkuil
2018-09-21  8:41     ` Hans Verkuil
2018-09-21 14:01     ` Ville Syrjälä
2018-09-21 14:01       ` Ville Syrjälä
2018-09-21 14:12       ` Hans Verkuil
2018-09-21 14:12         ` Hans Verkuil
2018-09-21 15:07         ` Ville Syrjälä
2018-09-21 15:07           ` Ville Syrjälä
2018-12-20 11:27   ` Sharma, Shashank
2018-09-20 18:51 ` [PATCH 06/18] video/hdmi: Handle the MPEG Source infoframe Ville Syrjala
2018-09-20 18:51   ` Ville Syrjala
2018-09-21  8:28   ` Hans Verkuil
2018-09-21  8:28     ` Hans Verkuil
2018-09-21 13:53     ` Ville Syrjälä
2018-09-21 13:53       ` Ville Syrjälä
2018-09-21 15:09   ` [PATCH v2 " Ville Syrjala
2018-09-21 15:09     ` Ville Syrjala
2018-09-20 18:51 ` [PATCH 07/18] video/hdmi: Handle the NTSC VBI infoframe Ville Syrjala
2018-09-20 18:51   ` Ville Syrjala
2018-09-21  8:30   ` Hans Verkuil
2018-09-21  8:30     ` Hans Verkuil
2018-09-21 13:54     ` Ville Syrjälä
2018-09-21 13:54       ` Ville Syrjälä
2018-09-21 15:10   ` [PATCH v2 " Ville Syrjala
2018-09-21 15:10     ` Ville Syrjala
2018-09-20 18:51 ` [PATCH 08/18] drm/i915: Use memmove() for punching the hole into infoframes Ville Syrjala
2018-09-21 13:52   ` Daniel Vetter
2018-09-20 18:51 ` [PATCH 09/18] drm/i915: Pass intel_encoder to infoframe functions Ville Syrjala
2018-09-21 13:59   ` Daniel Vetter
2018-09-21 15:03     ` Ville Syrjälä
2018-09-20 18:51 ` [PATCH 10/18] drm/i915: Add the missing HDMI gamut metadata packet stuff Ville Syrjala
2018-09-21 14:15   ` [Intel-gfx] " Daniel Vetter
2018-09-20 18:51 ` [PATCH 11/18] drm/i915: Return the mask of enabled infoframes from ->inforame_enabled() Ville Syrjala
2018-09-24 15:51   ` Daniel Vetter
2018-09-24 16:36     ` [Intel-gfx] " Ville Syrjälä
2018-10-01  6:55       ` Daniel Vetter
2018-10-01 19:29         ` Ville Syrjälä
2018-09-20 18:51 ` [PATCH 12/18] drm/i915: Store mask of enabled infoframes in the crtc state Ville Syrjala
2018-09-24 15:51   ` [Intel-gfx] " Daniel Vetter
2018-09-20 18:51 ` [PATCH 13/18] drm/i915: Precompute HDMI infoframes Ville Syrjala
2018-09-24 15:58   ` Daniel Vetter
2018-09-24 16:42     ` Ville Syrjälä
2018-09-20 18:51 ` [PATCH 14/18] drm/i915: Read out " Ville Syrjala
2018-09-24 16:08   ` Daniel Vetter
2018-09-24 16:52     ` Ville Syrjälä
2018-09-20 18:51 ` [PATCH 15/18] drm/i915/sdvo: Precompute " Ville Syrjala
2018-09-20 18:51 ` [PATCH 16/18] drm/i915/sdvo: Read out " Ville Syrjala
2018-09-24 16:10   ` [Intel-gfx] " Daniel Vetter
2018-09-24 17:13     ` Ville Syrjälä
2018-10-01  6:59       ` Daniel Vetter
2018-10-01 13:35         ` Ville Syrjälä
2018-10-01 16:48           ` Daniel Vetter
2018-09-20 18:51 ` [PATCH 17/18] drm/i915: Check infoframe state in intel_pipe_config_compare() Ville Syrjala
2018-09-24 16:12   ` Daniel Vetter
2018-10-01 20:35     ` [Intel-gfx] " Ville Syrjälä
2018-10-02  8:16       ` Daniel Vetter
2018-09-20 18:51 ` [PATCH 18/18] drm/i915: Include infoframes in the crtc state dump Ville Syrjala
2018-09-24 16:14   ` [Intel-gfx] " Daniel Vetter
2018-09-20 19:02 ` ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Infoframe precompute/check Patchwork
2018-09-20 19:12 ` ✗ Fi.CI.SPARSE: " Patchwork
2018-09-20 19:26 ` ✓ Fi.CI.BAT: success " Patchwork
2018-09-20 22:30 ` ✓ Fi.CI.IGT: " Patchwork
2018-09-21 14:40 ` ✗ Fi.CI.BAT: failure for drm/i915: Infoframe precompute/check (rev2) Patchwork
2018-09-21 15:25 ` ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Infoframe precompute/check (rev4) Patchwork
2018-09-21 15:35 ` ✗ Fi.CI.SPARSE: " Patchwork
2018-09-21 15:46 ` ✓ Fi.CI.BAT: success " Patchwork
2018-09-21 17:04 ` ✓ Fi.CI.IGT: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.