Commit 45187ace authored by Jesse Barnes's avatar Jesse Barnes Committed by Keith Packard

drm/i915/hdmi: split infoframe setting from infoframe type code

This makes it easier to add support for other infoframes (e.g. SPD,
vendor specific).
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarKeith Packard <keithp@keithp.com>
parent ebec9a7b
...@@ -1506,6 +1506,7 @@ ...@@ -1506,6 +1506,7 @@
#define VIDEO_DIP_SELECT_AVI (0 << 19) #define VIDEO_DIP_SELECT_AVI (0 << 19)
#define VIDEO_DIP_SELECT_VENDOR (1 << 19) #define VIDEO_DIP_SELECT_VENDOR (1 << 19)
#define VIDEO_DIP_SELECT_SPD (3 << 19) #define VIDEO_DIP_SELECT_SPD (3 << 19)
#define VIDEO_DIP_SELECT_MASK (3 << 19)
#define VIDEO_DIP_FREQ_ONCE (0 << 16) #define VIDEO_DIP_FREQ_ONCE (0 << 16)
#define VIDEO_DIP_FREQ_VSYNC (1 << 16) #define VIDEO_DIP_FREQ_VSYNC (1 << 16)
#define VIDEO_DIP_FREQ_2VSYNC (2 << 16) #define VIDEO_DIP_FREQ_2VSYNC (2 << 16)
......
...@@ -178,6 +178,8 @@ struct intel_crtc { ...@@ -178,6 +178,8 @@ struct intel_crtc {
#define to_intel_encoder(x) container_of(x, struct intel_encoder, base) #define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
#define DIP_HEADER_SIZE 5
#define DIP_TYPE_AVI 0x82 #define DIP_TYPE_AVI 0x82
#define DIP_VERSION_AVI 0x2 #define DIP_VERSION_AVI 0x2
#define DIP_LEN_AVI 13 #define DIP_LEN_AVI 13
......
...@@ -45,6 +45,8 @@ struct intel_hdmi { ...@@ -45,6 +45,8 @@ struct intel_hdmi {
bool has_hdmi_sink; bool has_hdmi_sink;
bool has_audio; bool has_audio;
int force_audio; int force_audio;
void (*write_infoframe)(struct drm_encoder *encoder,
struct dip_infoframe *frame);
}; };
static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
...@@ -58,37 +60,70 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) ...@@ -58,37 +60,70 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
struct intel_hdmi, base); struct intel_hdmi, base);
} }
void intel_dip_infoframe_csum(struct dip_infoframe *avi_if) void intel_dip_infoframe_csum(struct dip_infoframe *frame)
{ {
uint8_t *data = (uint8_t *)avi_if; uint8_t *data = (uint8_t *)frame;
uint8_t sum = 0; uint8_t sum = 0;
unsigned i; unsigned i;
avi_if->checksum = 0; frame->checksum = 0;
avi_if->ecc = 0; frame->ecc = 0;
for (i = 0; i < sizeof(*avi_if); i++) /* Header isn't part of the checksum */
for (i = 5; i < frame->len; i++)
sum += data[i]; sum += data[i];
avi_if->checksum = 0x100 - sum; frame->checksum = 0x100 - sum;
} }
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) static u32 intel_infoframe_index(struct dip_infoframe *frame)
{ {
struct dip_infoframe avi_if = { u32 flags = 0;
.type = DIP_TYPE_AVI,
.ver = DIP_VERSION_AVI, switch (frame->type) {
.len = DIP_LEN_AVI, case DIP_TYPE_AVI:
}; flags |= VIDEO_DIP_SELECT_AVI;
uint32_t *data = (uint32_t *)&avi_if; break;
case DIP_TYPE_SPD:
flags |= VIDEO_DIP_SELECT_SPD;
break;
default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
break;
}
return flags;
}
static u32 intel_infoframe_flags(struct dip_infoframe *frame)
{
u32 flags = 0;
switch (frame->type) {
case DIP_TYPE_AVI:
flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC;
break;
case DIP_TYPE_SPD:
flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_2VSYNC;
break;
default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
break;
}
return flags;
}
static void i9xx_write_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
{
uint32_t *data = (uint32_t *)frame;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
u32 port; u32 port, flags, val = I915_READ(VIDEO_DIP_CTL);
unsigned i; unsigned i, len = DIP_HEADER_SIZE + frame->len;
if (!intel_hdmi->has_hdmi_sink)
return;
/* XXX first guess at handling video port, is this corrent? */ /* XXX first guess at handling video port, is this corrent? */
if (intel_hdmi->sdvox_reg == SDVOB) if (intel_hdmi->sdvox_reg == SDVOB)
...@@ -98,52 +133,72 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) ...@@ -98,52 +133,72 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
else else
return; return;
I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | flags = intel_infoframe_index(frame);
VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
val &= ~VIDEO_DIP_SELECT_MASK;
I915_WRITE(VIDEO_DIP_CTL, val | port | flags);
intel_dip_infoframe_csum(&avi_if); for (i = 0; i < len; i += 4) {
for (i = 0; i < sizeof(avi_if); i += 4) {
I915_WRITE(VIDEO_DIP_DATA, *data); I915_WRITE(VIDEO_DIP_DATA, *data);
data++; data++;
} }
I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | flags |= intel_infoframe_flags(frame);
VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC |
VIDEO_DIP_ENABLE_AVI); I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
} }
static void intel_ironlake_hdmi_set_avi_infoframe(struct drm_encoder *encoder) static void ironlake_write_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
{ {
struct dip_infoframe avi_if = { uint32_t *data = (uint32_t *)frame;
.type = DIP_TYPE_AVI,
.ver = DIP_VERSION_AVI,
.len = DIP_LEN_AVI,
};
uint32_t *data = (uint32_t *)&avi_if;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
struct drm_crtc *crtc = encoder->crtc; struct drm_crtc *crtc = encoder->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
unsigned i; unsigned i, len = DIP_HEADER_SIZE + frame->len;
u32 flags, val = I915_READ(reg);
if (!intel_hdmi->has_hdmi_sink)
return;
intel_wait_for_vblank(dev, intel_crtc->pipe); intel_wait_for_vblank(dev, intel_crtc->pipe);
I915_WRITE(reg, VIDEO_DIP_SELECT_AVI); flags = intel_infoframe_index(frame);
intel_dip_infoframe_csum(&avi_if); val &= ~VIDEO_DIP_SELECT_MASK;
for (i = 0; i < sizeof(avi_if); i += 4) {
I915_WRITE(reg, val | flags);
for (i = 0; i < len; i += 4) {
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
data++; data++;
} }
I915_WRITE(reg, VIDEO_DIP_ENABLE | VIDEO_DIP_SELECT_AVI | flags |= intel_infoframe_flags(frame);
VIDEO_DIP_FREQ_VSYNC | (DIP_LEN_AVI << 8) |
VIDEO_DIP_ENABLE_AVI); I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
}
static void intel_set_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
{
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
if (!intel_hdmi->has_hdmi_sink)
return;
intel_dip_infoframe_csum(frame);
intel_hdmi->write_infoframe(encoder, frame);
}
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
{
struct dip_infoframe avi_if = {
.type = DIP_TYPE_AVI,
.ver = DIP_VERSION_AVI,
.len = DIP_LEN_AVI,
};
intel_set_infoframe(encoder, &avi_if);
} }
static void intel_hdmi_mode_set(struct drm_encoder *encoder, static void intel_hdmi_mode_set(struct drm_encoder *encoder,
...@@ -189,10 +244,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, ...@@ -189,10 +244,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
I915_WRITE(intel_hdmi->sdvox_reg, sdvox); I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
POSTING_READ(intel_hdmi->sdvox_reg); POSTING_READ(intel_hdmi->sdvox_reg);
if (HAS_PCH_SPLIT(dev)) intel_hdmi_set_avi_infoframe(encoder);
intel_ironlake_hdmi_set_avi_infoframe(encoder);
else
intel_hdmi_set_avi_infoframe(encoder);
} }
static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
...@@ -470,6 +522,11 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) ...@@ -470,6 +522,11 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
intel_hdmi->sdvox_reg = sdvox_reg; intel_hdmi->sdvox_reg = sdvox_reg;
if (!HAS_PCH_SPLIT(dev))
intel_hdmi->write_infoframe = i9xx_write_infoframe;
else
intel_hdmi->write_infoframe = ironlake_write_infoframe;
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
intel_hdmi_add_properties(intel_hdmi, connector); intel_hdmi_add_properties(intel_hdmi, connector);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment