Re-posting the whole series because I forgot dri-devel in the first version and also added a few patches from the review.
Version 2 of the series: http://lists.freedesktop.org/archives/intel-gfx/2013-August/031183.html
With Ville's comments so far addressed.
I've also added the already posted drm patch: http://lists.freedesktop.org/archives/dri-devel/2013-August/042900.html in this version as we depend on it to not generate invalid infoframe after having ported i915 to the generic helpers.
Cc: Thierry Reding thierry.reding@avionic-design.de Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/video/hdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 4017833..dbd882f 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -52,7 +52,7 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
frame->type = HDMI_INFOFRAME_TYPE_AVI; frame->version = 2; - frame->length = 13; + frame->length = HDMI_AVI_INFOFRAME_SIZE;
return 0; } @@ -151,7 +151,7 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
frame->type = HDMI_INFOFRAME_TYPE_SPD; frame->version = 1; - frame->length = 25; + frame->length = HDMI_SPD_INFOFRAME_SIZE;
strncpy(frame->vendor, vendor, sizeof(frame->vendor)); strncpy(frame->product, product, sizeof(frame->product)); @@ -218,7 +218,7 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
frame->type = HDMI_INFOFRAME_TYPE_AUDIO; frame->version = 1; - frame->length = 10; + frame->length = HDMI_AUDIO_INFOFRAME_SIZE;
return 0; }
Patches 1-5, 10, 11 are:
Reviewed-by: Alex Deucher alexander.deucher@amd.com
On Tue, Aug 6, 2013 at 3:32 PM, Damien Lespiau damien.lespiau@intel.com wrote:
Cc: Thierry Reding thierry.reding@avionic-design.de Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com
drivers/video/hdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 4017833..dbd882f 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -52,7 +52,7 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
frame->type = HDMI_INFOFRAME_TYPE_AVI; frame->version = 2;
frame->length = 13;
frame->length = HDMI_AVI_INFOFRAME_SIZE; return 0;
} @@ -151,7 +151,7 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
frame->type = HDMI_INFOFRAME_TYPE_SPD; frame->version = 1;
frame->length = 25;
frame->length = HDMI_SPD_INFOFRAME_SIZE; strncpy(frame->vendor, vendor, sizeof(frame->vendor)); strncpy(frame->product, product, sizeof(frame->product));
@@ -218,7 +218,7 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
frame->type = HDMI_INFOFRAME_TYPE_AUDIO; frame->version = 1;
frame->length = 10;
frame->length = HDMI_AUDIO_INFOFRAME_SIZE; return 0;
}
1.8.3.1
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
On Tue, Aug 06, 2013 at 10:06:16PM -0400, Alex Deucher wrote:
Patches 1-5, 10, 11 are:
Reviewed-by: Alex Deucher alexander.deucher@amd.com
Entire series merged to drm-intel-next-queue with Dave's irc ack. Thanks for the patches and review. -Daniel
On Tue, Aug 6, 2013 at 3:32 PM, Damien Lespiau damien.lespiau@intel.com wrote:
Cc: Thierry Reding thierry.reding@avionic-design.de Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com
drivers/video/hdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 4017833..dbd882f 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -52,7 +52,7 @@ int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
frame->type = HDMI_INFOFRAME_TYPE_AVI; frame->version = 2;
frame->length = 13;
frame->length = HDMI_AVI_INFOFRAME_SIZE; return 0;
} @@ -151,7 +151,7 @@ int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
frame->type = HDMI_INFOFRAME_TYPE_SPD; frame->version = 1;
frame->length = 25;
frame->length = HDMI_SPD_INFOFRAME_SIZE; strncpy(frame->vendor, vendor, sizeof(frame->vendor)); strncpy(frame->product, product, sizeof(frame->product));
@@ -218,7 +218,7 @@ int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
frame->type = HDMI_INFOFRAME_TYPE_AUDIO; frame->version = 1;
frame->length = 10;
frame->length = HDMI_AUDIO_INFOFRAME_SIZE; return 0;
}
1.8.3.1
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
And a way to pack hdmi_infoframe generically.
Cc: Thierry Reding thierry.reding@avionic-design.de Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/video/hdmi.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/hdmi.h | 17 +++++++++++++++++ 2 files changed, 60 insertions(+)
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index dbd882f..f7a85e5 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -22,6 +22,7 @@ */
#include <linux/bitops.h> +#include <linux/bug.h> #include <linux/errno.h> #include <linux/export.h> #include <linux/hdmi.h> @@ -321,3 +322,45 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, return length; } EXPORT_SYMBOL(hdmi_vendor_infoframe_pack); + +/** + * hdmi_infoframe_pack() - write a HDMI infoframe to binary buffer + * @frame: HDMI 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_infoframe_pack(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(&frame->avi, buffer, size); + break; + case HDMI_INFOFRAME_TYPE_SPD: + length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size); + break; + case HDMI_INFOFRAME_TYPE_AUDIO: + length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size); + break; + case HDMI_INFOFRAME_TYPE_VENDOR: + length = hdmi_vendor_infoframe_pack(&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); diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index 3b58944..0f3f82e 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -23,6 +23,12 @@ enum hdmi_infoframe_type { #define HDMI_SPD_INFOFRAME_SIZE 25 #define HDMI_AUDIO_INFOFRAME_SIZE 10
+struct hdmi_any_infoframe { + enum hdmi_infoframe_type type; + unsigned char version; + unsigned char length; +}; + enum hdmi_colorspace { HDMI_COLORSPACE_RGB, HDMI_COLORSPACE_YUV422, @@ -228,4 +234,15 @@ struct hdmi_vendor_infoframe { ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, void *buffer, size_t size);
+union hdmi_infoframe { + struct hdmi_any_infoframe any; + struct hdmi_avi_infoframe avi; + struct hdmi_spd_infoframe spd; + struct hdmi_vendor_infoframe vendor; + struct hdmi_audio_infoframe audio; +}; + +ssize_t +hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size); + #endif /* _DRM_HDMI_H */
Cc: Thierry Reding thierry.reding@avionic-design.de Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- include/linux/hdmi.h | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h index 0f3f82e..bc6743e 100644 --- a/include/linux/hdmi.h +++ b/include/linux/hdmi.h @@ -23,6 +23,9 @@ enum hdmi_infoframe_type { #define HDMI_SPD_INFOFRAME_SIZE 25 #define HDMI_AUDIO_INFOFRAME_SIZE 10
+#define HDMI_INFOFRAME_SIZE(type) \ + (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE) + struct hdmi_any_infoframe { enum hdmi_infoframe_type type; unsigned char version;
If the user if this API is providing a bigger buffer than the infoframe size, it could be for a could reason. For instance it could be because it gives the buffer that will be written to the hardware, up to the maximum of an infoframe size.
Instead of just zeroing up to the infoframe size, let's zero the whole incoming buffer as those extra bytes are also used to compute the ECC and need to be 0.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/video/hdmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index f7a85e5..635d569 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -84,7 +84,7 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, if (size < length) return -ENOSPC;
- memset(buffer, 0, length); + memset(buffer, 0, size);
ptr[0] = frame->type; ptr[1] = frame->version; @@ -186,7 +186,7 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer, if (size < length) return -ENOSPC;
- memset(buffer, 0, length); + memset(buffer, 0, size);
ptr[0] = frame->type; ptr[1] = frame->version; @@ -251,7 +251,7 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, if (size < length) return -ENOSPC;
- memset(buffer, 0, length); + memset(buffer, 0, size);
if (frame->channels >= 2) channels = frame->channels - 1; @@ -308,7 +308,7 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, if (size < length) return -ENOSPC;
- memset(buffer, 0, length); + memset(buffer, 0, size);
ptr[0] = frame->type; ptr[1] = frame->version;
On Tue, Aug 06, 2013 at 08:32:16PM +0100, Damien Lespiau wrote:
If the user if this API is providing a bigger buffer than the infoframe size, it could be for a could reason. For instance it could be because it gives the buffer that will be written to the hardware, up to the maximum of an infoframe size.
Instead of just zeroing up to the infoframe size, let's zero the whole incoming buffer as those extra bytes are also used to compute the ECC and need to be 0.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com
One concern that came to mind was someone needing to preserve the buffer contents beyond the infoframe. But I guess if someone really needs to do that, they can go and figure out the exact length of the infoframe and pass that.
Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com
drivers/video/hdmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index f7a85e5..635d569 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -84,7 +84,7 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer, if (size < length) return -ENOSPC;
- memset(buffer, 0, length);
memset(buffer, 0, size);
ptr[0] = frame->type; ptr[1] = frame->version;
@@ -186,7 +186,7 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer, if (size < length) return -ENOSPC;
- memset(buffer, 0, length);
memset(buffer, 0, size);
ptr[0] = frame->type; ptr[1] = frame->version;
@@ -251,7 +251,7 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame, if (size < length) return -ENOSPC;
- memset(buffer, 0, length);
memset(buffer, 0, size);
if (frame->channels >= 2) channels = frame->channels - 1;
@@ -308,7 +308,7 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, if (size < length) return -ENOSPC;
- memset(buffer, 0, length);
memset(buffer, 0, size);
ptr[0] = frame->type; ptr[1] = frame->version;
-- 1.8.3.1
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx
On Wed, Aug 07, 2013 at 01:56:58PM +0300, Ville Syrjälä wrote:
On Tue, Aug 06, 2013 at 08:32:16PM +0100, Damien Lespiau wrote:
If the user if this API is providing a bigger buffer than the infoframe size, it could be for a could reason. For instance it could be because it gives the buffer that will be written to the hardware, up to the maximum of an infoframe size.
Instead of just zeroing up to the infoframe size, let's zero the whole incoming buffer as those extra bytes are also used to compute the ECC and need to be 0.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com
One concern that came to mind was someone needing to preserve the buffer contents beyond the infoframe. But I guess if someone really needs to do that, they can go and figure out the exact length of the infoframe and pass that.
Right, that was my thinking as well. We even have a macro for that now.
From CEA-861:
Data Byte 1, bit A0 indicates whether Active Format Data is present in Data Byte 2 bits R3 through R0. A source device shall set A0=1 when any of the AFD bits are set.
ie. if we want to set active_aspect, we need to set the active_info_valid bit to 1 as well.
Cc: Thierry Reding thierry.reding@avionic-design.de Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_edid.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 95d6f4b..8d1139f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3107,6 +3107,7 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, return 0;
frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE; + frame->active_info_valid = 1; frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
return 0;
First step in the move to the shared infoframe infrastructure, let's move the different infoframe helpers and the write_infoframe() vfunc to a type (enum hdmi_infoframe_type) and a buffer + len instead of using our struct dip_infoframe.
v2: constify the infoframe pointer and don't mix signs (Ville Syrjälä)
Signed-off-by: Damien Lespiau damien.lespiau@intel.com Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com> Signed-off-by: Thierry Reding <thierry.reding at avionic-design.de> --- drivers/gpu/drm/i915/intel_drv.h | 4 +- drivers/gpu/drm/i915/intel_hdmi.c | 106 ++++++++++++++++++++------------------ 2 files changed, 59 insertions(+), 51 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 474797b..273acfd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -26,6 +26,7 @@ #define __INTEL_DRV_H__
#include <linux/i2c.h> +#include <linux/hdmi.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include <drm/drm_crtc.h> @@ -463,7 +464,8 @@ struct intel_hdmi { enum hdmi_force_audio force_audio; bool rgb_quant_range_selectable; void (*write_infoframe)(struct drm_encoder *encoder, - struct dip_infoframe *frame); + enum hdmi_infoframe_type type, + const uint8_t *frame, ssize_t len); void (*set_infoframes)(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode); }; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index e82cd81..ee67e23 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -29,6 +29,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/hdmi.h> #include <drm/drmP.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> @@ -81,74 +82,75 @@ void intel_dip_infoframe_csum(struct dip_infoframe *frame) frame->checksum = 0x100 - sum; }
-static u32 g4x_infoframe_index(struct dip_infoframe *frame) +static u32 g4x_infoframe_index(enum hdmi_infoframe_type type) { - switch (frame->type) { - case DIP_TYPE_AVI: + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_SELECT_AVI; - case DIP_TYPE_SPD: + case HDMI_INFOFRAME_TYPE_SPD: return VIDEO_DIP_SELECT_SPD; default: - DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); return 0; } }
-static u32 g4x_infoframe_enable(struct dip_infoframe *frame) +static u32 g4x_infoframe_enable(enum hdmi_infoframe_type type) { - switch (frame->type) { - case DIP_TYPE_AVI: + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_ENABLE_AVI; - case DIP_TYPE_SPD: + case HDMI_INFOFRAME_TYPE_SPD: return VIDEO_DIP_ENABLE_SPD; default: - DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); return 0; } }
-static u32 hsw_infoframe_enable(struct dip_infoframe *frame) +static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type) { - switch (frame->type) { - case DIP_TYPE_AVI: + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_ENABLE_AVI_HSW; - case DIP_TYPE_SPD: + case HDMI_INFOFRAME_TYPE_SPD: return VIDEO_DIP_ENABLE_SPD_HSW; default: - DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); return 0; } }
-static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, +static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, enum transcoder cpu_transcoder) { - switch (frame->type) { - case DIP_TYPE_AVI: + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder); - case DIP_TYPE_SPD: + case HDMI_INFOFRAME_TYPE_SPD: return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); default: - DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); return 0; } }
static void g4x_write_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) + enum hdmi_infoframe_type type, + const uint8_t *frame, ssize_t len) { uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 val = I915_READ(VIDEO_DIP_CTL); - unsigned i, len = DIP_HEADER_SIZE + frame->len; + int i;
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ - val |= g4x_infoframe_index(frame); + val |= g4x_infoframe_index(type);
- val &= ~g4x_infoframe_enable(frame); + val &= ~g4x_infoframe_enable(type);
I915_WRITE(VIDEO_DIP_CTL, val);
@@ -162,7 +164,7 @@ static void g4x_write_infoframe(struct drm_encoder *encoder, I915_WRITE(VIDEO_DIP_DATA, 0); mmiowb();
- val |= g4x_infoframe_enable(frame); + val |= g4x_infoframe_enable(type); val &= ~VIDEO_DIP_FREQ_MASK; val |= VIDEO_DIP_FREQ_VSYNC;
@@ -171,22 +173,22 @@ static void g4x_write_infoframe(struct drm_encoder *encoder, }
static void ibx_write_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) + enum hdmi_infoframe_type type, + const uint8_t *frame, ssize_t len) { uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); - unsigned i, len = DIP_HEADER_SIZE + frame->len; + int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg);
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ - val |= g4x_infoframe_index(frame); + val |= g4x_infoframe_index(type);
- val &= ~g4x_infoframe_enable(frame); + val &= ~g4x_infoframe_enable(type);
I915_WRITE(reg, val);
@@ -200,7 +202,7 @@ static void ibx_write_infoframe(struct drm_encoder *encoder, I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); mmiowb();
- val |= g4x_infoframe_enable(frame); + val |= g4x_infoframe_enable(type); val &= ~VIDEO_DIP_FREQ_MASK; val |= VIDEO_DIP_FREQ_VSYNC;
@@ -209,25 +211,25 @@ static void ibx_write_infoframe(struct drm_encoder *encoder, }
static void cpt_write_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) + enum hdmi_infoframe_type type, + const uint8_t *frame, ssize_t len) { uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); - unsigned i, len = DIP_HEADER_SIZE + frame->len; + int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg);
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ - val |= g4x_infoframe_index(frame); + val |= g4x_infoframe_index(type);
/* The DIP control register spec says that we need to update the AVI * infoframe without clearing its enable bit */ - if (frame->type != DIP_TYPE_AVI) - val &= ~g4x_infoframe_enable(frame); + if (type != HDMI_INFOFRAME_TYPE_AVI) + val &= ~g4x_infoframe_enable(type);
I915_WRITE(reg, val);
@@ -241,7 +243,7 @@ static void cpt_write_infoframe(struct drm_encoder *encoder, I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); mmiowb();
- val |= g4x_infoframe_enable(frame); + val |= g4x_infoframe_enable(type); val &= ~VIDEO_DIP_FREQ_MASK; val |= VIDEO_DIP_FREQ_VSYNC;
@@ -250,22 +252,22 @@ static void cpt_write_infoframe(struct drm_encoder *encoder, }
static void vlv_write_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) + enum hdmi_infoframe_type type, + const uint8_t *frame, ssize_t len) { uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); - unsigned i, len = DIP_HEADER_SIZE + frame->len; + int i, reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg);
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ - val |= g4x_infoframe_index(frame); + val |= g4x_infoframe_index(type);
- val &= ~g4x_infoframe_enable(frame); + val &= ~g4x_infoframe_enable(type);
I915_WRITE(reg, val);
@@ -279,7 +281,7 @@ static void vlv_write_infoframe(struct drm_encoder *encoder, I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0); mmiowb();
- val |= g4x_infoframe_enable(frame); + val |= g4x_infoframe_enable(type); val &= ~VIDEO_DIP_FREQ_MASK; val |= VIDEO_DIP_FREQ_VSYNC;
@@ -288,21 +290,24 @@ static void vlv_write_infoframe(struct drm_encoder *encoder, }
static void hsw_write_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) + enum hdmi_infoframe_type type, + const uint8_t *frame, ssize_t len) { uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); - u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->config.cpu_transcoder); - unsigned int i, len = DIP_HEADER_SIZE + frame->len; + u32 data_reg; + int i; u32 val = I915_READ(ctl_reg);
+ data_reg = hsw_infoframe_data_reg(type, + intel_crtc->config.cpu_transcoder); if (data_reg == 0) return;
- val &= ~hsw_infoframe_enable(frame); + val &= ~hsw_infoframe_enable(type); I915_WRITE(ctl_reg, val);
mmiowb(); @@ -315,7 +320,7 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, I915_WRITE(data_reg + i, 0); mmiowb();
- val |= hsw_infoframe_enable(frame); + val |= hsw_infoframe_enable(type); I915_WRITE(ctl_reg, val); POSTING_READ(ctl_reg); } @@ -326,7 +331,8 @@ static void intel_set_infoframe(struct drm_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
intel_dip_infoframe_csum(frame); - intel_hdmi->write_infoframe(encoder, frame); + intel_hdmi->write_infoframe(encoder, frame->type, (uint8_t *)frame, + DIP_HEADER_SIZE + frame->len); }
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
On Tue, Aug 06, 2013 at 08:32:18PM +0100, Damien Lespiau wrote:
First step in the move to the shared infoframe infrastructure, let's move the different infoframe helpers and the write_infoframe() vfunc to a type (enum hdmi_infoframe_type) and a buffer + len instead of using our struct dip_infoframe.
v2: constify the infoframe pointer and don't mix signs (Ville Syrjälä)
Signed-off-by: Damien Lespiau damien.lespiau@intel.com Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com> Signed-off-by: Thierry Reding <thierry.reding at avionic-design.de>
Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/intel_drv.h | 4 +- drivers/gpu/drm/i915/intel_hdmi.c | 106 ++++++++++++++++++++------------------ 2 files changed, 59 insertions(+), 51 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 474797b..273acfd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -26,6 +26,7 @@ #define __INTEL_DRV_H__
#include <linux/i2c.h> +#include <linux/hdmi.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include <drm/drm_crtc.h> @@ -463,7 +464,8 @@ struct intel_hdmi { enum hdmi_force_audio force_audio; bool rgb_quant_range_selectable; void (*write_infoframe)(struct drm_encoder *encoder,
struct dip_infoframe *frame);
enum hdmi_infoframe_type type,
void (*set_infoframes)(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode);const uint8_t *frame, ssize_t len);
}; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index e82cd81..ee67e23 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -29,6 +29,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/hdmi.h> #include <drm/drmP.h> #include <drm/drm_crtc.h> #include <drm/drm_edid.h> @@ -81,74 +82,75 @@ void intel_dip_infoframe_csum(struct dip_infoframe *frame) frame->checksum = 0x100 - sum; }
-static u32 g4x_infoframe_index(struct dip_infoframe *frame) +static u32 g4x_infoframe_index(enum hdmi_infoframe_type type) {
- switch (frame->type) {
- case DIP_TYPE_AVI:
- switch (type) {
- case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_SELECT_AVI;
- case DIP_TYPE_SPD:
- case HDMI_INFOFRAME_TYPE_SPD: return VIDEO_DIP_SELECT_SPD; default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
return 0; }DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
}
-static u32 g4x_infoframe_enable(struct dip_infoframe *frame) +static u32 g4x_infoframe_enable(enum hdmi_infoframe_type type) {
- switch (frame->type) {
- case DIP_TYPE_AVI:
- switch (type) {
- case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_ENABLE_AVI;
- case DIP_TYPE_SPD:
- case HDMI_INFOFRAME_TYPE_SPD: return VIDEO_DIP_ENABLE_SPD; default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
return 0; }DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
}
-static u32 hsw_infoframe_enable(struct dip_infoframe *frame) +static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type) {
- switch (frame->type) {
- case DIP_TYPE_AVI:
- switch (type) {
- case HDMI_INFOFRAME_TYPE_AVI: return VIDEO_DIP_ENABLE_AVI_HSW;
- case DIP_TYPE_SPD:
- case HDMI_INFOFRAME_TYPE_SPD: return VIDEO_DIP_ENABLE_SPD_HSW; default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
return 0; }DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
}
-static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, +static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, enum transcoder cpu_transcoder) {
- switch (frame->type) {
- case DIP_TYPE_AVI:
- switch (type) {
- case HDMI_INFOFRAME_TYPE_AVI: return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder);
- case DIP_TYPE_SPD:
- case HDMI_INFOFRAME_TYPE_SPD: return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder); default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
return 0; }DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
}
static void g4x_write_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
enum hdmi_infoframe_type type,
const uint8_t *frame, ssize_t len)
{ uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 val = I915_READ(VIDEO_DIP_CTL);
- unsigned i, len = DIP_HEADER_SIZE + frame->len;
int i;
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
- val |= g4x_infoframe_index(frame);
- val |= g4x_infoframe_index(type);
- val &= ~g4x_infoframe_enable(frame);
val &= ~g4x_infoframe_enable(type);
I915_WRITE(VIDEO_DIP_CTL, val);
@@ -162,7 +164,7 @@ static void g4x_write_infoframe(struct drm_encoder *encoder, I915_WRITE(VIDEO_DIP_DATA, 0); mmiowb();
- val |= g4x_infoframe_enable(frame);
- val |= g4x_infoframe_enable(type); val &= ~VIDEO_DIP_FREQ_MASK; val |= VIDEO_DIP_FREQ_VSYNC;
@@ -171,22 +173,22 @@ static void g4x_write_infoframe(struct drm_encoder *encoder, }
static void ibx_write_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
enum hdmi_infoframe_type type,
const uint8_t *frame, ssize_t len)
{ uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
- unsigned i, len = DIP_HEADER_SIZE + frame->len;
int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg);
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
- val |= g4x_infoframe_index(frame);
- val |= g4x_infoframe_index(type);
- val &= ~g4x_infoframe_enable(frame);
val &= ~g4x_infoframe_enable(type);
I915_WRITE(reg, val);
@@ -200,7 +202,7 @@ static void ibx_write_infoframe(struct drm_encoder *encoder, I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); mmiowb();
- val |= g4x_infoframe_enable(frame);
- val |= g4x_infoframe_enable(type); val &= ~VIDEO_DIP_FREQ_MASK; val |= VIDEO_DIP_FREQ_VSYNC;
@@ -209,25 +211,25 @@ static void ibx_write_infoframe(struct drm_encoder *encoder, }
static void cpt_write_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
enum hdmi_infoframe_type type,
const uint8_t *frame, ssize_t len)
{ uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
- unsigned i, len = DIP_HEADER_SIZE + frame->len;
int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg);
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
- val |= g4x_infoframe_index(frame);
val |= g4x_infoframe_index(type);
/* The DIP control register spec says that we need to update the AVI
- infoframe without clearing its enable bit */
- if (frame->type != DIP_TYPE_AVI)
val &= ~g4x_infoframe_enable(frame);
if (type != HDMI_INFOFRAME_TYPE_AVI)
val &= ~g4x_infoframe_enable(type);
I915_WRITE(reg, val);
@@ -241,7 +243,7 @@ static void cpt_write_infoframe(struct drm_encoder *encoder, I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0); mmiowb();
- val |= g4x_infoframe_enable(frame);
- val |= g4x_infoframe_enable(type); val &= ~VIDEO_DIP_FREQ_MASK; val |= VIDEO_DIP_FREQ_VSYNC;
@@ -250,22 +252,22 @@ static void cpt_write_infoframe(struct drm_encoder *encoder, }
static void vlv_write_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
enum hdmi_infoframe_type type,
const uint8_t *frame, ssize_t len)
{ uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
- unsigned i, len = DIP_HEADER_SIZE + frame->len;
int i, reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg);
WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n");
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
- val |= g4x_infoframe_index(frame);
- val |= g4x_infoframe_index(type);
- val &= ~g4x_infoframe_enable(frame);
val &= ~g4x_infoframe_enable(type);
I915_WRITE(reg, val);
@@ -279,7 +281,7 @@ static void vlv_write_infoframe(struct drm_encoder *encoder, I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0); mmiowb();
- val |= g4x_infoframe_enable(frame);
- val |= g4x_infoframe_enable(type); val &= ~VIDEO_DIP_FREQ_MASK; val |= VIDEO_DIP_FREQ_VSYNC;
@@ -288,21 +290,24 @@ static void vlv_write_infoframe(struct drm_encoder *encoder, }
static void hsw_write_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
enum hdmi_infoframe_type type,
const uint8_t *frame, ssize_t len)
{ uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder);
- u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->config.cpu_transcoder);
- unsigned int i, len = DIP_HEADER_SIZE + frame->len;
u32 data_reg;
int i; u32 val = I915_READ(ctl_reg);
data_reg = hsw_infoframe_data_reg(type,
intel_crtc->config.cpu_transcoder);
if (data_reg == 0) return;
- val &= ~hsw_infoframe_enable(frame);
val &= ~hsw_infoframe_enable(type); I915_WRITE(ctl_reg, val);
mmiowb();
@@ -315,7 +320,7 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, I915_WRITE(data_reg + i, 0); mmiowb();
- val |= hsw_infoframe_enable(frame);
- val |= hsw_infoframe_enable(type); I915_WRITE(ctl_reg, val); POSTING_READ(ctl_reg);
} @@ -326,7 +331,8 @@ static void intel_set_infoframe(struct drm_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
intel_dip_infoframe_csum(frame);
- intel_hdmi->write_infoframe(encoder, frame);
- intel_hdmi->write_infoframe(encoder, frame->type, (uint8_t *)frame,
DIP_HEADER_SIZE + frame->len);
}
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
1.8.3.1
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
Let's use the drivers/video/hmdi.c and drm infoframe helpers to build our infoframes.
v2: Simplify the logic to compute the buffer size. We can just take the maximum infoframe size rounded to 32, which happens to be what the hardware let us write anyway.
v3: Remove unnecessary memset() (Ville Syrjälä)
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 82 +++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ee67e23..455dfa7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -325,14 +325,43 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, POSTING_READ(ctl_reg); }
+/* + * 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 + * at 0). It's also a byte used by DisplayPort so the same DIP registers can be + * used for both technologies. + * + * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0 + * DW1: DB3 | DB2 | DB1 | DB0 + * DW2: DB7 | DB6 | DB5 | DB4 + * DW3: ... + * + * (HB is Header Byte, DB is Data Byte) + * + * The hdmi pack() functions don't know about that hardware specific hole so we + * trick them by giving an offset into the buffer and moving back the header + * bytes by one. + */ static void intel_set_infoframe(struct drm_encoder *encoder, - struct dip_infoframe *frame) + union hdmi_infoframe *frame) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + uint8_t buffer[VIDEO_DIP_DATA_SIZE]; + ssize_t len;
- intel_dip_infoframe_csum(frame); - intel_hdmi->write_infoframe(encoder, frame->type, (uint8_t *)frame, - DIP_HEADER_SIZE + frame->len); + /* see comment above for the reason for this offset */ + len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1); + if (len < 0) + return; + + /* Insert the 'hole' (see big comment above) at position 3 */ + buffer[0] = buffer[1]; + buffer[1] = buffer[2]; + buffer[2] = buffer[3]; + buffer[3] = 0; + len++; + + intel_hdmi->write_infoframe(encoder, frame->any.type, buffer, len); }
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, @@ -340,40 +369,45 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - struct dip_infoframe avi_if = { - .type = DIP_TYPE_AVI, - .ver = DIP_VERSION_AVI, - .len = DIP_LEN_AVI, - }; + union hdmi_infoframe frame; + int ret; + + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, + adjusted_mode); + if (ret < 0) { + DRM_ERROR("couldn't fill AVI infoframe\n"); + return; + }
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) - avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; + frame.avi.pixel_repeat = 1;
if (intel_hdmi->rgb_quant_range_selectable) { if (intel_crtc->config.limited_color_range) - avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_LIMITED; else - avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_FULL; }
- avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode); - - intel_set_infoframe(encoder, &avi_if); + intel_set_infoframe(encoder, &frame); }
static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) { - struct dip_infoframe spd_if; + union hdmi_infoframe frame; + int ret; + + ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx"); + if (ret < 0) { + DRM_ERROR("couldn't fill SPD infoframe\n"); + return; + }
- memset(&spd_if, 0, sizeof(spd_if)); - spd_if.type = DIP_TYPE_SPD; - spd_if.ver = DIP_VERSION_SPD; - spd_if.len = DIP_LEN_SPD; - strcpy(spd_if.body.spd.vn, "Intel"); - strcpy(spd_if.body.spd.pd, "Integrated gfx"); - spd_if.body.spd.sdi = DIP_SPD_PC; + frame.spd.sdi = HDMI_SPD_SDI_PC;
- intel_set_infoframe(encoder, &spd_if); + intel_set_infoframe(encoder, &frame); }
static void g4x_set_infoframes(struct drm_encoder *encoder,
On Tue, Aug 06, 2013 at 08:32:19PM +0100, Damien Lespiau wrote:
Let's use the drivers/video/hmdi.c and drm infoframe helpers to build our infoframes.
v2: Simplify the logic to compute the buffer size. We can just take the maximum infoframe size rounded to 32, which happens to be what the hardware let us write anyway.
v3: Remove unnecessary memset() (Ville Syrjälä)
Signed-off-by: Damien Lespiau damien.lespiau@intel.com
Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/intel_hdmi.c | 82 +++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ee67e23..455dfa7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -325,14 +325,43 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, POSTING_READ(ctl_reg); }
+/*
- 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
- at 0). It's also a byte used by DisplayPort so the same DIP registers can be
- used for both technologies.
- DW0: Reserved/ECC/DP | HB2 | HB1 | HB0
- DW1: DB3 | DB2 | DB1 | DB0
- DW2: DB7 | DB6 | DB5 | DB4
- DW3: ...
- (HB is Header Byte, DB is Data Byte)
- The hdmi pack() functions don't know about that hardware specific hole so we
- trick them by giving an offset into the buffer and moving back the header
- bytes by one.
- */
static void intel_set_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
union hdmi_infoframe *frame)
{ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- uint8_t buffer[VIDEO_DIP_DATA_SIZE];
- ssize_t len;
- intel_dip_infoframe_csum(frame);
- intel_hdmi->write_infoframe(encoder, frame->type, (uint8_t *)frame,
DIP_HEADER_SIZE + frame->len);
- /* see comment above for the reason for this offset */
- len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1);
- if (len < 0)
return;
- /* Insert the 'hole' (see big comment above) at position 3 */
- buffer[0] = buffer[1];
- buffer[1] = buffer[2];
- buffer[2] = buffer[3];
- buffer[3] = 0;
- len++;
- intel_hdmi->write_infoframe(encoder, frame->any.type, buffer, len);
}
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, @@ -340,40 +369,45 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- struct dip_infoframe avi_if = {
.type = DIP_TYPE_AVI,
.ver = DIP_VERSION_AVI,
.len = DIP_LEN_AVI,
- };
union hdmi_infoframe frame;
int ret;
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
adjusted_mode);
if (ret < 0) {
DRM_ERROR("couldn't fill AVI infoframe\n");
return;
}
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2;
frame.avi.pixel_repeat = 1;
if (intel_hdmi->rgb_quant_range_selectable) { if (intel_crtc->config.limited_color_range)
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED;
frame.avi.quantization_range =
elseHDMI_QUANTIZATION_RANGE_LIMITED;
avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL;
frame.avi.quantization_range =
}HDMI_QUANTIZATION_RANGE_FULL;
- avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode);
- intel_set_infoframe(encoder, &avi_if);
- intel_set_infoframe(encoder, &frame);
}
static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) {
- struct dip_infoframe spd_if;
- union hdmi_infoframe frame;
- int ret;
- ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx");
- if (ret < 0) {
DRM_ERROR("couldn't fill SPD infoframe\n");
return;
- }
- memset(&spd_if, 0, sizeof(spd_if));
- spd_if.type = DIP_TYPE_SPD;
- spd_if.ver = DIP_VERSION_SPD;
- spd_if.len = DIP_LEN_SPD;
- strcpy(spd_if.body.spd.vn, "Intel");
- strcpy(spd_if.body.spd.pd, "Integrated gfx");
- spd_if.body.spd.sdi = DIP_SPD_PC;
- frame.spd.sdi = HDMI_SPD_SDI_PC;
- intel_set_infoframe(encoder, &spd_if);
- intel_set_infoframe(encoder, &frame);
}
static void g4x_set_infoframes(struct drm_encoder *encoder,
1.8.3.1
dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel
Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com> Signed-off-by: Thierry Reding <thierry.reding at avionic-design.de> --- drivers/gpu/drm/i915/intel_sdvo.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 47423f3..02f220b 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -963,30 +963,32 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, const struct drm_display_mode *adjusted_mode) { - struct dip_infoframe avi_if = { - .type = DIP_TYPE_AVI, - .ver = DIP_VERSION_AVI, - .len = DIP_LEN_AVI, - }; - uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; - struct intel_crtc *intel_crtc = to_intel_crtc(intel_sdvo->base.base.crtc); + uint8_t sdvo_data[HDMI_INFOFRAME_SIZE(AVI)]; + struct drm_crtc *crtc = intel_sdvo->base.base.crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + union hdmi_infoframe frame; + int ret; + ssize_t len; + + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, + adjusted_mode); + if (ret < 0) { + DRM_ERROR("couldn't fill AVI infoframe\n"); + return false; + }
if (intel_sdvo->rgb_quant_range_selectable) { if (intel_crtc->config.limited_color_range) - avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_LIMITED; else - avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_FULL; }
- avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode); - - intel_dip_infoframe_csum(&avi_if); - - /* sdvo spec says that the ecc is handled by the hw, and it looks like - * we must not send the ecc field, either. */ - memcpy(sdvo_data, &avi_if, 3); - sdvo_data[3] = avi_if.checksum; - memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi)); + len = hdmi_infoframe_pack(&frame, sdvo_data, sizeof(sdvo_data)); + if (len < 0) + return false;
return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF, SDVO_HBUF_TX_VSYNC,
All the HDMI infoframe code has been ported to use video/hdmi.c, so it's time to say bye bye to this code.
Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/i915/intel_drv.h | 61 --------------------------------------- drivers/gpu/drm/i915/intel_hdmi.c | 15 ---------- 2 files changed, 76 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 273acfd..125df0b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -394,66 +394,6 @@ struct cxsr_latency { #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) #define to_intel_plane(x) container_of(x, struct intel_plane, base)
-#define DIP_HEADER_SIZE 5 - -#define DIP_TYPE_AVI 0x82 -#define DIP_VERSION_AVI 0x2 -#define DIP_LEN_AVI 13 -#define DIP_AVI_PR_1 0 -#define DIP_AVI_PR_2 1 -#define DIP_AVI_RGB_QUANT_RANGE_DEFAULT (0 << 2) -#define DIP_AVI_RGB_QUANT_RANGE_LIMITED (1 << 2) -#define DIP_AVI_RGB_QUANT_RANGE_FULL (2 << 2) - -#define DIP_TYPE_SPD 0x83 -#define DIP_VERSION_SPD 0x1 -#define DIP_LEN_SPD 25 -#define DIP_SPD_UNKNOWN 0 -#define DIP_SPD_DSTB 0x1 -#define DIP_SPD_DVDP 0x2 -#define DIP_SPD_DVHS 0x3 -#define DIP_SPD_HDDVR 0x4 -#define DIP_SPD_DVC 0x5 -#define DIP_SPD_DSC 0x6 -#define DIP_SPD_VCD 0x7 -#define DIP_SPD_GAME 0x8 -#define DIP_SPD_PC 0x9 -#define DIP_SPD_BD 0xa -#define DIP_SPD_SCD 0xb - -struct dip_infoframe { - uint8_t type; /* HB0 */ - uint8_t ver; /* HB1 */ - uint8_t len; /* HB2 - body len, not including checksum */ - uint8_t ecc; /* Header ECC */ - uint8_t checksum; /* PB0 */ - union { - struct { - /* PB1 - Y 6:5, A 4:4, B 3:2, S 1:0 */ - uint8_t Y_A_B_S; - /* PB2 - C 7:6, M 5:4, R 3:0 */ - uint8_t C_M_R; - /* PB3 - ITC 7:7, EC 6:4, Q 3:2, SC 1:0 */ - uint8_t ITC_EC_Q_SC; - /* PB4 - VIC 6:0 */ - uint8_t VIC; - /* PB5 - YQ 7:6, CN 5:4, PR 3:0 */ - uint8_t YQ_CN_PR; - /* PB6 to PB13 */ - uint16_t top_bar_end; - uint16_t bottom_bar_start; - uint16_t left_bar_end; - uint16_t right_bar_start; - } __attribute__ ((packed)) avi; - struct { - uint8_t vn[8]; - uint8_t pd[16]; - uint8_t sdi; - } __attribute__ ((packed)) spd; - uint8_t payload[27]; - } __attribute__ ((packed)) body; -} __attribute__((packed)); - struct intel_hdmi { u32 hdmi_reg; int ddc_bus; @@ -567,7 +507,6 @@ extern void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); extern bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config); -extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); extern void intel_dvo_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 455dfa7..8abb61a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -67,21 +67,6 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) return enc_to_intel_hdmi(&intel_attached_encoder(connector)->base); }
-void intel_dip_infoframe_csum(struct dip_infoframe *frame) -{ - uint8_t *data = (uint8_t *)frame; - uint8_t sum = 0; - unsigned i; - - frame->checksum = 0; - frame->ecc = 0; - - for (i = 0; i < frame->len + DIP_HEADER_SIZE; i++) - sum += data[i]; - - frame->checksum = 0x100 - sum; -} - static u32 g4x_infoframe_index(enum hdmi_infoframe_type type) { switch (type) {
Suggested-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_edid.c | 3 +++ drivers/gpu/drm/i915/intel_hdmi.c | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 8d1139f..a9c8980 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3102,6 +3102,9 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, if (err < 0) return err;
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK) + frame->pixel_repeat = 1; + frame->video_code = drm_match_cea_mode(mode); if (!frame->video_code) return 0; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 8abb61a..80fbe2d 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -364,9 +364,6 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, return; }
- if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) - frame.avi.pixel_repeat = 1; - if (intel_hdmi->rgb_quant_range_selectable) { if (intel_crtc->config.limited_color_range) frame.avi.quantization_range =
I cannot find any evidence what we shouldn't try to set those fields when setting a non-CEA mode on an HDMI sink. So just kill that return.
Suggested-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_edid.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a9c8980..dfc7a1b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3106,8 +3106,6 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, frame->pixel_repeat = 1;
frame->video_code = drm_match_cea_mode(mode); - if (!frame->video_code) - return 0;
frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE; frame->active_info_valid = 1;
set_frame() wraps the write_frame() vfunc. Be consistent and name the wrapping function like the vfunc being called.
It's doubly confusing as we also have a set_infoframes() vfunc and set_infoframe() doesn't wrap it.
Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 80fbe2d..789f909 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -327,8 +327,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, * trick them by giving an offset into the buffer and moving back the header * bytes by one. */ -static void intel_set_infoframe(struct drm_encoder *encoder, - union hdmi_infoframe *frame) +static void intel_write_infoframe(struct drm_encoder *encoder, + union hdmi_infoframe *frame) { struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); uint8_t buffer[VIDEO_DIP_DATA_SIZE]; @@ -373,7 +373,7 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, HDMI_QUANTIZATION_RANGE_FULL; }
- intel_set_infoframe(encoder, &frame); + intel_write_infoframe(encoder, &frame); }
static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) @@ -389,7 +389,7 @@ static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
frame.spd.sdi = HDMI_SPD_SDI_PC;
- intel_set_infoframe(encoder, &frame); + intel_write_infoframe(encoder, &frame); }
static void g4x_set_infoframes(struct drm_encoder *encoder,
dri-devel@lists.freedesktop.org