[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