Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1506,6 +1506,7 @@
#define   VIDEO_DIP_SELECT_AVI		(0 << 19)
#define   VIDEO_DIP_SELECT_VENDOR	(1 << 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_VSYNC		(1 << 16)
#define   VIDEO_DIP_FREQ_2VSYNC		(2 << 16)
+2 −0
Original line number Diff line number Diff line
@@ -178,6 +178,8 @@ struct intel_crtc {
#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 DIP_HEADER_SIZE	5

#define DIP_TYPE_AVI    0x82
#define DIP_VERSION_AVI 0x2
#define DIP_LEN_AVI     13
+103 −46
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ struct intel_hdmi {
	bool has_hdmi_sink;
	bool has_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)
@@ -58,37 +60,70 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
			    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;
	unsigned i;

	avi_if->checksum = 0;
	avi_if->ecc = 0;
	frame->checksum = 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];

	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 = {
		.type = DIP_TYPE_AVI,
		.ver = DIP_VERSION_AVI,
		.len = DIP_LEN_AVI,
	};
	uint32_t *data = (uint32_t *)&avi_if;
	u32 flags = 0;

	switch (frame->type) {
	case DIP_TYPE_AVI:
		flags |= VIDEO_DIP_SELECT_AVI;
		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_i915_private *dev_priv = dev->dev_private;
	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
	u32 port;
	unsigned i;
	u32 port, flags, val = I915_READ(VIDEO_DIP_CTL);
	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? */
	if (intel_hdmi->sdvox_reg == SDVOB)
@@ -98,52 +133,72 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
	else
		return;

	I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
		   VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
	flags = intel_infoframe_index(frame);

	val &= ~VIDEO_DIP_SELECT_MASK;

	intel_dip_infoframe_csum(&avi_if);
	for (i = 0; i < sizeof(avi_if); i += 4) {
	I915_WRITE(VIDEO_DIP_CTL, val | port | flags);

	for (i = 0; i < len; i += 4) {
		I915_WRITE(VIDEO_DIP_DATA, *data);
		data++;
	}

	I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
		   VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC |
		   VIDEO_DIP_ENABLE_AVI);
	flags |= intel_infoframe_flags(frame);

	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 = {
		.type = DIP_TYPE_AVI,
		.ver = DIP_VERSION_AVI,
		.len = DIP_LEN_AVI,
	};
	uint32_t *data = (uint32_t *)&avi_if;
	uint32_t *data = (uint32_t *)frame;
	struct drm_device *dev = encoder->dev;
	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 intel_crtc *intel_crtc = to_intel_crtc(crtc);
	int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
	unsigned i;

	if (!intel_hdmi->has_hdmi_sink)
		return;
	unsigned i, len = DIP_HEADER_SIZE + frame->len;
	u32 flags, val = I915_READ(reg);

	intel_wait_for_vblank(dev, intel_crtc->pipe);

	I915_WRITE(reg, VIDEO_DIP_SELECT_AVI);
	flags = intel_infoframe_index(frame);

	val &= ~VIDEO_DIP_SELECT_MASK;

	intel_dip_infoframe_csum(&avi_if);
	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);
		data++;
	}

	I915_WRITE(reg, VIDEO_DIP_ENABLE | VIDEO_DIP_SELECT_AVI |
		   VIDEO_DIP_FREQ_VSYNC | (DIP_LEN_AVI << 8) |
		   VIDEO_DIP_ENABLE_AVI);
	flags |= intel_infoframe_flags(frame);

	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,
@@ -189,9 +244,6 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
	I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
	POSTING_READ(intel_hdmi->sdvox_reg);

	if (HAS_PCH_SPLIT(dev))
		intel_ironlake_hdmi_set_avi_infoframe(encoder);
	else
	intel_hdmi_set_avi_infoframe(encoder);
}

@@ -470,6 +522,11 @@ void intel_hdmi_init(struct drm_device *dev, int 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);

	intel_hdmi_add_properties(intel_hdmi, connector);