[PATCH 2/5] drm/amd/amdgpu: Add HDMI Stereo 3D (non-DC) support

Jeff Smith whydoubt at gmail.com
Sat Feb 25 00:14:36 UTC 2017


Signed-off-by: Jeff Smith <whydoubt at gmail.com>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c |  5 ++
 drivers/gpu/drm/amd/amdgpu/atombios_crtc.c     | 27 ++++----
 drivers/gpu/drm/amd/amdgpu/atombios_encoders.c |  2 +-
 drivers/gpu/drm/amd/amdgpu/dce_v11_0.c         | 86 ++++++++++++++++++++++++--
 4 files changed, 100 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index b487aa0..5a40ef4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -1175,6 +1175,10 @@ static int amdgpu_connector_dvi_mode_valid(struct drm_connector *connector,
 	struct amdgpu_device *adev = dev->dev_private;
 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
 
+	if (((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) &&
+	     (mode->flags & DRM_MODE_FLAG_INTERLACE))
+		return MODE_BAD;
+
 	/* XXX check mode bandwidth */
 
 	if (amdgpu_connector->use_digital && (mode->clock > 165000)) {
@@ -1815,6 +1819,7 @@ amdgpu_connector_add(struct amdgpu_device *adev,
 						   AMDGPU_FMT_DITHER_DISABLE);
 			subpixel_order = SubPixelHorizontalRGB;
 			connector->interlace_allowed = true;
+			connector->stereo_allowed = true;
 			if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
 				connector->doublescan_allowed = true;
 			else
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
index 8c9bc75..475393e 100644
--- a/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_crtc.c
@@ -302,8 +302,7 @@ union adjust_pixel_clock {
 	ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
 };
 
-static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc,
-				    struct drm_display_mode *mode)
+static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc, u32 clock)
 {
 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
@@ -311,12 +310,11 @@ static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc,
 	struct drm_encoder *encoder = amdgpu_crtc->encoder;
 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
 	struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
-	u32 adjusted_clock = mode->clock;
+	u32 adjusted_clock = clock;
 	int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
-	u32 dp_clock = mode->clock;
-	u32 clock = mode->clock;
+	u32 dp_clock = clock;
 	int bpc = amdgpu_crtc->bpc;
-	bool is_duallink = amdgpu_dig_monitor_is_duallink(encoder, mode->clock);
+	bool is_duallink = amdgpu_dig_monitor_is_duallink(encoder, clock);
 	union adjust_pixel_clock args;
 	u8 frev, crev;
 	int index;
@@ -347,7 +345,7 @@ static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc,
 
 	/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
 	if (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
-		adjusted_clock = mode->clock * 2;
+		adjusted_clock = clock * 2;
 	if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
 		amdgpu_crtc->pll_flags |= AMDGPU_PLL_PREFER_CLOSEST_LOWER;
 	if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
@@ -753,6 +751,7 @@ int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
 	struct amdgpu_encoder *amdgpu_encoder =
 		to_amdgpu_encoder(amdgpu_crtc->encoder);
 	int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
+	u32 clock = mode->crtc_clock;
 
 	amdgpu_crtc->bpc = 8;
 	amdgpu_crtc->ss_enabled = false;
@@ -769,7 +768,7 @@ int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
 		int dp_clock;
 
 		/* Assign mode clock for hdmi deep color max clock limit check */
-		amdgpu_connector->pixelclock_for_modeset = mode->clock;
+		amdgpu_connector->pixelclock_for_modeset = clock;
 		amdgpu_crtc->bpc = amdgpu_connector_get_monitor_bpc(connector);
 
 		switch (encoder_mode) {
@@ -787,21 +786,21 @@ int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
 				amdgpu_atombios_get_asic_ss_info(adev,
 								 &amdgpu_crtc->ss,
 								 dig->lcd_ss_id,
-								 mode->clock / 10);
+								 clock / 10);
 			break;
 		case ATOM_ENCODER_MODE_DVI:
 			amdgpu_crtc->ss_enabled =
 				amdgpu_atombios_get_asic_ss_info(adev,
 								 &amdgpu_crtc->ss,
 								 ASIC_INTERNAL_SS_ON_TMDS,
-								 mode->clock / 10);
+								 clock / 10);
 			break;
 		case ATOM_ENCODER_MODE_HDMI:
 			amdgpu_crtc->ss_enabled =
 				amdgpu_atombios_get_asic_ss_info(adev,
 								 &amdgpu_crtc->ss,
 								 ASIC_INTERNAL_SS_ON_HDMI,
-								 mode->clock / 10);
+								 clock / 10);
 			break;
 		default:
 			break;
@@ -809,7 +808,7 @@ int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
 	}
 
 	/* adjust pixel clock as needed */
-	amdgpu_crtc->adjusted_clock = amdgpu_atombios_crtc_adjust_pll(crtc, mode);
+	amdgpu_crtc->adjusted_clock = amdgpu_atombios_crtc_adjust_pll(crtc, clock);
 
 	return 0;
 }
@@ -821,8 +820,8 @@ void amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
 	struct amdgpu_device *adev = dev->dev_private;
 	struct amdgpu_encoder *amdgpu_encoder =
 		to_amdgpu_encoder(amdgpu_crtc->encoder);
-	u32 pll_clock = mode->clock;
-	u32 clock = mode->clock;
+	u32 pll_clock = mode->crtc_clock;
+	u32 clock = mode->crtc_clock;
 	u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
 	struct amdgpu_pll *pll;
 	int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
index 2af26d2..540dc08 100644
--- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
+++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
@@ -286,7 +286,7 @@ bool amdgpu_atombios_encoder_mode_fixup(struct drm_encoder *encoder,
 
 	/* set the active encoder to connector routing */
 	amdgpu_encoder_set_active_device(encoder);
-	drm_mode_set_crtcinfo(adjusted_mode, 0);
+	drm_mode_set_crtcinfo(adjusted_mode, CRTC_STEREO_DOUBLE);
 
 	/* hw bug */
 	if ((mode->flags & DRM_MODE_FLAG_INTERLACE)
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
index 459afac..b4df662 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -1689,6 +1689,51 @@ static void dce_v11_0_afmt_update_avi_infoframe(struct drm_encoder *encoder,
 		frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
 }
 
+/*
+ * build a HDMI Generic Packet
+ */
+static void dce_v11_0_afmt_update_generic_packet(struct drm_encoder *encoder,
+					       void *buffer, size_t size, uint32_t generic_index)
+{
+	struct amdgpu_device *adev = encoder->dev->dev_private;
+	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
+	uint8_t *frame = buffer + 3;
+	uint8_t *header = buffer;
+	u32 tmp;
+
+	tmp = RREG32(mmAFMT_VBI_PACKET_CONTROL + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_INDEX, generic_index);
+	WREG32(mmAFMT_VBI_PACKET_CONTROL + dig->afmt->offset, tmp);
+
+	tmp = REG_SET_FIELD(0, AFMT_GENERIC_HDR, AFMT_GENERIC_HB0, header[0]);
+	tmp = REG_SET_FIELD(tmp, AFMT_GENERIC_HDR, AFMT_GENERIC_HB1, header[1]);
+	tmp = REG_SET_FIELD(tmp, AFMT_GENERIC_HDR, AFMT_GENERIC_HB2, header[2]);
+	WREG32(mmAFMT_GENERIC_HDR + dig->afmt->offset, tmp);
+
+	WREG32(mmAFMT_GENERIC_0 + dig->afmt->offset,
+		frame[0x00] | (frame[0x01] << 8) | (frame[0x02] << 16) | (frame[0x03] << 24));
+	WREG32(mmAFMT_GENERIC_1 + dig->afmt->offset,
+		frame[0x04] | (frame[0x05] << 8) | (frame[0x06] << 16) | (frame[0x07] << 24));
+	WREG32(mmAFMT_GENERIC_2 + dig->afmt->offset,
+		frame[0x08] | (frame[0x09] << 8) | (frame[0x0A] << 16) | (frame[0x0B] << 24));
+	WREG32(mmAFMT_GENERIC_3 + dig->afmt->offset,
+		frame[0x0C] | (frame[0x0D] << 8) | (frame[0x0E] << 16) | (frame[0x0F] << 24));
+	WREG32(mmAFMT_GENERIC_4 + dig->afmt->offset,
+		frame[0x10] | (frame[0x11] << 8) | (frame[0x12] << 16) | (frame[0x13] << 24));
+	WREG32(mmAFMT_GENERIC_5 + dig->afmt->offset,
+		frame[0x14] | (frame[0x15] << 8) | (frame[0x16] << 16) | (frame[0x17] << 24));
+	WREG32(mmAFMT_GENERIC_6 + dig->afmt->offset,
+		frame[0x18] | (frame[0x19] << 8) | (frame[0x1A] << 16) | (frame[0x1B] << 24));
+	WREG32(mmAFMT_GENERIC_7 + dig->afmt->offset, 0);
+
+	tmp = RREG32(mmAFMT_VBI_PACKET_CONTROL + dig->afmt->offset);
+	/* AFMT_GENERIC1_UPDATE, AFMT_GENERIC3_UPDATE are not defined */
+	tmp = REG_SET_FIELD(tmp, AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC0_UPDATE, (generic_index == 0));
+	tmp = REG_SET_FIELD(tmp, AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC2_UPDATE, (generic_index == 2));
+	WREG32(mmAFMT_VBI_PACKET_CONTROL + dig->afmt->offset, tmp);
+}
+
 static void dce_v11_0_audio_set_dto(struct drm_encoder *encoder, u32 clock)
 {
 	struct drm_device *dev = encoder->dev;
@@ -1716,6 +1761,8 @@ static void dce_v11_0_audio_set_dto(struct drm_encoder *encoder, u32 clock)
 	WREG32(mmDCCG_AUDIO_DTO0_MODULE, dto_modulo);
 }
 
+#define HDMI_MAX_INFOFRAME_SIZE    27
+
 /*
  * update the info frames with the data from the current display mode
  */
@@ -1727,8 +1774,9 @@ static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder,
 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
 	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
 	struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
-	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
+	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_MAX_INFOFRAME_SIZE];
 	struct hdmi_avi_infoframe frame;
+	struct hdmi_vendor_infoframe frame_vendor;
 	ssize_t err;
 	u32 tmp;
 	int bpc = 8;
@@ -1746,6 +1794,13 @@ static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder,
 		bpc = amdgpu_crtc->bpc;
 	}
 
+	/* Disable sending generic packet */
+	tmp = RREG32(mmHDMI_GENERIC_PACKET_CONTROL0 + dig->afmt->offset);
+	tmp = REG_SET_FIELD(tmp, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND, 0);
+	tmp = REG_SET_FIELD(tmp, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT, 0);
+	tmp = REG_SET_FIELD(tmp, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_LINE, 0);
+	WREG32(mmHDMI_GENERIC_PACKET_CONTROL0 + dig->afmt->offset, tmp);
+
 	/* disable audio prior to setting up hw */
 	dig->afmt->pin = dce_v11_0_audio_get_pin(adev);
 	dce_v11_0_audio_enable(adev, dig->afmt->pin, false);
@@ -1886,6 +1941,27 @@ static void dce_v11_0_afmt_setmode(struct drm_encoder *encoder,
 	tmp = REG_SET_FIELD(tmp, HDMI_INFOFRAME_CONTROL1, HDMI_AVI_INFO_LINE, 2);
 	WREG32(mmHDMI_INFOFRAME_CONTROL1 + dig->afmt->offset, tmp);
 
+	err = drm_hdmi_vendor_infoframe_from_display_mode(&frame_vendor, mode);
+	if (err == -EINVAL) {
+	} else if (err < 0) {
+		DRM_ERROR("failed to set up HDMI vendor infoframe: %zd\n", err);
+	} else {
+		err = hdmi_vendor_infoframe_pack(&frame_vendor, buffer, sizeof(buffer));
+		if (err < 0) {
+			DRM_ERROR("failed to pack HDMI vendor infoframe: %zd\n", err);
+			return;
+		}
+
+		dce_v11_0_afmt_update_generic_packet(encoder, buffer, sizeof(buffer), 0);
+
+		/* Enable sending generic packet */
+		tmp = RREG32(mmHDMI_GENERIC_PACKET_CONTROL0 + dig->afmt->offset);
+		tmp = REG_SET_FIELD(tmp, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND, 1);
+		tmp = REG_SET_FIELD(tmp, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT, 1);
+		tmp = REG_SET_FIELD(tmp, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_LINE, 2);
+		WREG32(mmHDMI_GENERIC_PACKET_CONTROL0 + dig->afmt->offset, tmp);
+	}
+
 	tmp = RREG32(mmAFMT_AUDIO_PACKET_CONTROL + dig->afmt->offset);
 	/* send audio packets */
 	tmp = REG_SET_FIELD(tmp, AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, 1);
@@ -2217,8 +2293,8 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc,
 	y &= ~1;
 	WREG32(mmVIEWPORT_START + amdgpu_crtc->crtc_offset,
 	       (x << 16) | y);
-	viewport_w = crtc->mode.hdisplay;
-	viewport_h = (crtc->mode.vdisplay + 1) & ~1;
+	drm_crtc_get_hv_timing(&crtc->mode, &viewport_w, &viewport_h);
+	viewport_h = (viewport_h + 1) & ~1;
 	WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset,
 	       (viewport_w << 16) | viewport_h);
 
@@ -2830,7 +2906,7 @@ static int dce_v11_0_crtc_mode_set(struct drm_crtc *crtc,
 		amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id,
 						 amdgpu_crtc->pll_id,
 						 encoder_mode, amdgpu_encoder->encoder_id,
-						 adjusted_mode->clock, 0, 0, 0, 0,
+						 adjusted_mode->crtc_clock, 0, 0, 0, 0,
 						 amdgpu_crtc->bpc, amdgpu_crtc->ss_enabled, &amdgpu_crtc->ss);
 	} else {
 		amdgpu_atombios_crtc_set_pll(crtc, adjusted_mode);
@@ -3554,7 +3630,7 @@ dce_v11_0_encoder_mode_set(struct drm_encoder *encoder,
 {
 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
 
-	amdgpu_encoder->pixel_clock = adjusted_mode->clock;
+	amdgpu_encoder->pixel_clock = adjusted_mode->crtc_clock;
 
 	/* need to call this here rather than in prepare() since we need some crtc info */
 	amdgpu_atombios_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-- 
2.9.3



More information about the dri-devel mailing list