Signed-off-by: Jeff Smith <whydoubt@xxxxxxxxx> --- 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 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel