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(-)
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);
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);
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);
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);
break; case HDMI_INFOFRAME_TYPE_SPD:ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
break; case HDMI_INFOFRAME_TYPE_AUDIO:ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
break; case HDMI_INFOFRAME_TYPE_VENDOR:ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
break; default: ret = -EINVAL;ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
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);
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 */
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 */
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,
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
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
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,
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
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
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,
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,
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,
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,
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,
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,
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:
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); return -EINVAL;return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
@@ -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);
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length = -EINVAL;break;
@@ -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);
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length = -EINVAL;break;
@@ -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 "Reserved";return "MPEG Source";
} @@ -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);
default: ret = -EINVAL; break;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,
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:
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); return -EINVAL;return hdmi_mpeg_source_infoframe_check(&frame->mpeg_source);
@@ -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);
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length = -EINVAL;break;
@@ -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);
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length = -EINVAL;break;
@@ -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 "Reserved";return "MPEG Source";
} @@ -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);
default: ret = -EINVAL; break;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,
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,
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,
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:
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); return -EINVAL;return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
@@ -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);
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length = -EINVAL;break;
@@ -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);
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length = -EINVAL;break;
@@ -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 "Reserved";return "NTSC VBI";
} @@ -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);
default: ret = -EINVAL; break;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,
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:
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); return -EINVAL;return hdmi_ntsc_vbi_infoframe_check(&frame->ntsc_vbi);
@@ -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);
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length = -EINVAL;break;
@@ -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);
default: WARN(1, "Bad infoframe type %d\n", frame->any.type); length = -EINVAL;break;
@@ -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 "Reserved";return "NTSC VBI";
} @@ -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);
default: ret = -EINVAL; break;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,
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,
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++;
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
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)); }
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
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.
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:
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:
case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_SELECT_AVI; case HDMI_INFOFRAME_TYPE_SPD:return VIDEO_DIP_SELECT_GAMUT;
@@ -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:
case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_ENABLE_AVI; case HDMI_INFOFRAME_TYPE_SPD:return VIDEO_DIP_ENABLE_GAMUT;
@@ -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:
case DP_SDP_VSC: return VIDEO_DIP_ENABLE_VSC_HSW; case HDMI_INFOFRAME_TYPE_AVI:return VIDEO_DIP_ENABLE_GMP_HSW;
@@ -134,6 +144,8 @@ hsw_dip_data_reg(struct drm_i915_private *dev_priv, int i) { switch (type) {
- case HDMI_PACKET_TYPE_GAMUT_METADATA:
case DP_SDP_VSC: return HSW_TVIDEO_DIP_VSC_DATA(cpu_transcoder, i); case HDMI_INFOFRAME_TYPE_AVI:return HSW_TVIDEO_DIP_GMP_DATA(cpu_transcoder, i);
-- 2.16.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/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; } }
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:
case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_ENABLE_AVI; case HDMI_INFOFRAME_TYPE_SPD:return 0;
@@ -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:
case HDMI_PACKET_TYPE_GENERAL_CONTROL: return VIDEO_DIP_ENABLE_GCP_HSW; case HDMI_PACKET_TYPE_GAMUT_METADATA:return 0;
@@ -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;
} 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->infoframes_enabled = vlv_infoframes_enabled;
intel_dig_port->infoframe_enabled = g4x_infoframe_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->infoframes_enabled = g4x_infoframes_enabled;
intel_dig_port->infoframe_enabled = hsw_infoframe_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->infoframes_enabled = hsw_infoframes_enabled;
intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
} else { intel_dig_port->write_infoframe = cpt_write_infoframe; intel_dig_port->set_infoframes = cpt_set_infoframes;intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
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
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:
case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_ENABLE_AVI; case HDMI_INFOFRAME_TYPE_SPD:return 0;
@@ -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:
case HDMI_PACKET_TYPE_GENERAL_CONTROL: return VIDEO_DIP_ENABLE_GCP_HSW; case HDMI_PACKET_TYPE_GAMUT_METADATA:return 0;
@@ -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;
} 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->infoframes_enabled = vlv_infoframes_enabled;
intel_dig_port->infoframe_enabled = g4x_infoframe_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->infoframes_enabled = g4x_infoframes_enabled;
intel_dig_port->infoframe_enabled = hsw_infoframe_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->infoframes_enabled = hsw_infoframes_enabled;
intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
} else { intel_dig_port->write_infoframe = cpt_write_infoframe; intel_dig_port->set_infoframes = cpt_set_infoframes;intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
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
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:
case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_ENABLE_AVI; case HDMI_INFOFRAME_TYPE_SPD:return 0;
@@ -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:
case HDMI_PACKET_TYPE_GENERAL_CONTROL: return VIDEO_DIP_ENABLE_GCP_HSW; case HDMI_PACKET_TYPE_GAMUT_METADATA:return 0;
@@ -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;
} 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->infoframes_enabled = vlv_infoframes_enabled;
intel_dig_port->infoframe_enabled = g4x_infoframe_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->infoframes_enabled = g4x_infoframes_enabled;
intel_dig_port->infoframe_enabled = hsw_infoframe_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->infoframes_enabled = hsw_infoframes_enabled;
intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
} else { intel_dig_port->write_infoframe = cpt_write_infoframe; intel_dig_port->set_infoframes = cpt_set_infoframes;intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
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
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:
case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_ENABLE_AVI; case HDMI_INFOFRAME_TYPE_SPD:return 0;
@@ -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:
case HDMI_PACKET_TYPE_GENERAL_CONTROL: return VIDEO_DIP_ENABLE_GCP_HSW; case HDMI_PACKET_TYPE_GAMUT_METADATA:return 0;
@@ -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;
} 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->infoframes_enabled = vlv_infoframes_enabled;
intel_dig_port->infoframe_enabled = g4x_infoframe_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->infoframes_enabled = g4x_infoframes_enabled;
intel_dig_port->infoframe_enabled = hsw_infoframe_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->infoframes_enabled = hsw_infoframes_enabled;
intel_dig_port->infoframe_enabled = ibx_infoframe_enabled;
} else { intel_dig_port->write_infoframe = cpt_write_infoframe; intel_dig_port->set_infoframes = cpt_set_infoframes;intel_dig_port->infoframes_enabled = ibx_infoframes_enabled;
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
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)
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
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; }
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;
elseframe->colorspace = HDMI_COLORSPACE_YUV420;
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 =
int ret;&conn_state->connector->display_info;
- 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
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;
elseframe->colorspace = HDMI_COLORSPACE_YUV420;
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 =
int ret;&conn_state->connector->display_info;
- 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
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; }
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 (*set_infoframes)(struct intel_encoder *encoder, bool enable, const struct intel_crtc_state *crtc_state,void *frame, ssize_t len);
@@ -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->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 = vlv_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 = g4x_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 = hsw_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 = ibx_read_infoframe;
intel_dig_port->set_infoframes = cpt_set_infoframes; intel_dig_port->infoframes_enabled = cpt_infoframes_enabled; }intel_dig_port->read_infoframe = cpt_read_infoframe;
-- 2.16.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
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 (*set_infoframes)(struct intel_encoder *encoder, bool enable, const struct intel_crtc_state *crtc_state,void *frame, ssize_t len);
@@ -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->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 = vlv_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 = g4x_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 = hsw_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 = ibx_read_infoframe;
intel_dig_port->set_infoframes = cpt_set_infoframes; intel_dig_port->infoframes_enabled = cpt_infoframes_enabled; }intel_dig_port->read_infoframe = cpt_read_infoframe;
-- 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
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; }
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,
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
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
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
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.
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
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(¤t_config->infoframes.name, \ + &pipe_config->infoframes.name)) { \ + pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \ + ¤t_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
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(¤t_config->infoframes.name, \
&pipe_config->infoframes.name)) { \
pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \
¤t_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
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(¤t_config->infoframes.name, \
&pipe_config->infoframes.name)) { \
pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \
¤t_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
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(¤t_config->infoframes.name, \
&pipe_config->infoframes.name)) { \
pipe_config_infoframe_err(dev_priv, adjust, __stringify(name), \
¤t_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
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");
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
dri-devel@lists.freedesktop.org