On Thu, Sep 20, 2018 at 09:51:40PM +0300, Ville Syrjala wrote: > From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > Store the infoframes in the crtc state and precompute them in > .compute_config(). While precomputing we'll also fill out the > inforames.enable bitmask appropriately. > > Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/i915/intel_ddi.c | 1 + > drivers/gpu/drm/i915/intel_drv.h | 5 + > drivers/gpu/drm/i915/intel_hdmi.c | 249 +++++++++++++++++++++++++++----------- > 3 files changed, 187 insertions(+), 68 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c > index 19fef88e680e..5f3bd536d261 100644 > --- a/drivers/gpu/drm/i915/intel_ddi.c > +++ b/drivers/gpu/drm/i915/intel_ddi.c > @@ -3391,6 +3391,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder, > intel_dig_port = enc_to_dig_port(&encoder->base); > > pipe_config->infoframes.enable |= > + intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_NULL) | Misplaced hunk? Assuming I'm reading this correctly, this will give you a 0. Not exactly sure what's going on here ... I guess I'm not following why we care about TYPE_NULL, and why we have to reconstruct it here? I thought TYPE_NULL is equivalent to state->has_hdmi_sink? Comment (unfortunately not yet kerneldoc) even explains that ... Maybe just nuke all the TYPE_NULL tracking here, perhaps with the g4x (except for g4x itself, because it's shared there) decoder to also take DIP_ENABLE into account for has_hdmi_sink. Or update the comment in intel_crtc_state. Otherwise lgtm, thought admittedly I did clean over the details a bit, trusting CI and gcc to catch the small stuff :-) Reviewed-by: Daniel Vetter <daniel.vetter@xxxxxxxx> with the TYPE_NULL story somehow figured out. -Daniel > intel_hdmi_infoframes_enabled(encoder, pipe_config); > > if (pipe_config->infoframes.enable) > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 50c0c049ee15..357624a6bfe2 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -895,6 +895,10 @@ struct intel_crtc_state { > > struct { > u32 enable; > + u32 gcp; > + union hdmi_infoframe avi; > + union hdmi_infoframe spd; > + union hdmi_infoframe hdmi; > } infoframes; > > /* HDMI scrambling status */ > @@ -1862,6 +1866,7 @@ void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable); > void intel_infoframe_init(struct intel_digital_port *intel_dig_port); > u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder, > const struct intel_crtc_state *crtc_state); > +u32 intel_hdmi_infoframe_enable(unsigned int type); > > > /* intel_lvds.c */ > diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c > index 98a44084324c..491001fc0fad 100644 > --- a/drivers/gpu/drm/i915/intel_hdmi.c > +++ b/drivers/gpu/drm/i915/intel_hdmi.c > @@ -446,6 +446,18 @@ static const u8 infoframe_type_to_idx[] = { > HDMI_INFOFRAME_TYPE_VENDOR, > }; > > +u32 intel_hdmi_infoframe_enable(unsigned int type) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) { > + if (infoframe_type_to_idx[i] == type) > + return BIT(i); > + } > + > + return 0; > +} > + > u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder, > const struct intel_crtc_state *crtc_state) > { > @@ -491,15 +503,23 @@ u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder, > */ > static void intel_write_infoframe(struct intel_encoder *encoder, > const struct intel_crtc_state *crtc_state, > - union hdmi_infoframe *frame) > + enum hdmi_infoframe_type type, > + const union hdmi_infoframe *frame) > { > struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base); > u8 buffer[VIDEO_DIP_DATA_SIZE]; > ssize_t len; > > + if ((crtc_state->infoframes.enable & > + intel_hdmi_infoframe_enable(type)) == 0) > + return; > + > + if (WARN_ON(frame->any.type != type)) > + return; > + > /* see comment above for the reason for this offset */ > - len = hdmi_infoframe_pack(frame, buffer + 1, sizeof(buffer) - 1); > - if (len < 0) > + len = hdmi_infoframe_pack_only(frame, buffer + 1, sizeof(buffer) - 1); > + if (WARN_ON(len < 0)) > return; > > /* Insert the 'hole' (see big comment above) at position 3 */ > @@ -507,85 +527,111 @@ static void intel_write_infoframe(struct intel_encoder *encoder, > buffer[3] = 0; > len++; > > - intel_dig_port->write_infoframe(encoder, > - crtc_state, > - frame->any.type, buffer, len); > + intel_dig_port->write_infoframe(encoder, crtc_state, type, buffer, len); > } > > -static void intel_hdmi_set_avi_infoframe(struct intel_encoder *encoder, > - const struct intel_crtc_state *crtc_state, > - const struct drm_connector_state *conn_state) > +static bool > +intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder, > + struct intel_crtc_state *crtc_state, > + struct drm_connector_state *conn_state) > { > struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); > + struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi; > + bool is_hdmi2_sink = conn_state->connector->display_info.hdmi.scdc.supported; > const struct drm_display_mode *adjusted_mode = > &crtc_state->base.adjusted_mode; > - struct drm_connector *connector = &intel_hdmi->attached_connector->base; > - bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; > - union hdmi_infoframe frame; > int ret; > > - ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, > + if (!crtc_state->has_infoframe) > + return true; > + > + crtc_state->infoframes.enable |= > + intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI); > + > + ret = drm_hdmi_avi_infoframe_from_display_mode(frame, > adjusted_mode, > is_hdmi2_sink); > - if (ret < 0) { > - DRM_ERROR("couldn't fill AVI infoframe\n"); > - return; > - } > + if (ret) > + return false; > > if (crtc_state->ycbcr420) > - frame.avi.colorspace = HDMI_COLORSPACE_YUV420; > + frame->colorspace = HDMI_COLORSPACE_YUV420; > else > - frame.avi.colorspace = HDMI_COLORSPACE_RGB; > + frame->colorspace = HDMI_COLORSPACE_RGB; > > - drm_hdmi_avi_infoframe_quant_range(&frame.avi, adjusted_mode, > + drm_hdmi_avi_infoframe_quant_range(frame, adjusted_mode, > crtc_state->limited_color_range ? > HDMI_QUANTIZATION_RANGE_LIMITED : > HDMI_QUANTIZATION_RANGE_FULL, > intel_hdmi->rgb_quant_range_selectable, > is_hdmi2_sink); > > - drm_hdmi_avi_infoframe_content_type(&frame.avi, > - conn_state); > + drm_hdmi_avi_infoframe_content_type(frame, conn_state); > > /* TODO: handle pixel repetition for YCBCR420 outputs */ > - intel_write_infoframe(encoder, crtc_state, > - &frame); > + > + ret = hdmi_avi_infoframe_check(frame); > + if (WARN_ON(ret)) > + return false; > + > + return true; > } > > -static void intel_hdmi_set_spd_infoframe(struct intel_encoder *encoder, > - const struct intel_crtc_state *crtc_state) > +static bool > +intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder, > + struct intel_crtc_state *crtc_state, > + struct drm_connector_state *conn_state) > { > - union hdmi_infoframe frame; > + struct hdmi_spd_infoframe *frame = &crtc_state->infoframes.spd.spd; > int ret; > > - ret = hdmi_spd_infoframe_init(&frame.spd, "Intel", "Integrated gfx"); > - if (ret < 0) { > - DRM_ERROR("couldn't fill SPD infoframe\n"); > - return; > - } > + if (!crtc_state->has_infoframe) > + return true; > > - frame.spd.sdi = HDMI_SPD_SDI_PC; > + crtc_state->infoframes.enable |= > + intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD); > > - intel_write_infoframe(encoder, crtc_state, > - &frame); > + ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx"); > + if (WARN_ON(ret)) > + return false; > + > + frame->sdi = HDMI_SPD_SDI_PC; > + > + ret = hdmi_spd_infoframe_check(frame); > + if (WARN_ON(ret)) > + return false; > + > + return true; > } > > -static void > -intel_hdmi_set_hdmi_infoframe(struct intel_encoder *encoder, > - const struct intel_crtc_state *crtc_state, > - const struct drm_connector_state *conn_state) > -{ > - union hdmi_infoframe frame; > +static bool > +intel_hdmi_compute_hdmi_infoframe(struct intel_encoder *encoder, > + struct intel_crtc_state *crtc_state, > + struct drm_connector_state *conn_state) > +{ > + struct hdmi_vendor_infoframe *frame = > + &crtc_state->infoframes.hdmi.vendor.hdmi; > + const struct drm_display_info *info = > + &conn_state->connector->display_info; > int ret; > > - ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, > + if (!crtc_state->has_infoframe || !info->has_hdmi_infoframe) > + return true; > + > + crtc_state->infoframes.enable |= > + intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_VENDOR); > + > + ret = drm_hdmi_vendor_infoframe_from_display_mode(frame, > conn_state->connector, > &crtc_state->base.adjusted_mode); > - if (ret < 0) > - return; > + if (WARN_ON(ret)) > + return false; > > - intel_write_infoframe(encoder, crtc_state, > - &frame); > + ret = hdmi_vendor_infoframe_check(frame); > + if (WARN_ON(ret)) > + return false; > + > + return true; > } > > static void g4x_set_infoframes(struct intel_encoder *encoder, > @@ -645,9 +691,15 @@ static void g4x_set_infoframes(struct intel_encoder *encoder, > I915_WRITE(reg, val); > POSTING_READ(reg); > > - intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); > - intel_hdmi_set_spd_infoframe(encoder, crtc_state); > - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_AVI, > + &crtc_state->infoframes.avi); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_SPD, > + &crtc_state->infoframes.spd); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_VENDOR, > + &crtc_state->infoframes.hdmi); > } > > static bool hdmi_sink_is_deep_color(const struct drm_connector_state *conn_state) > @@ -713,7 +765,10 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder, > struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); > struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); > i915_reg_t reg; > - u32 val = 0; > + > + if ((crtc_state->infoframes.enable & > + intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0) > + return false; > > if (HAS_DDI(dev_priv)) > reg = HSW_TVIDEO_DIP_GCP(crtc_state->cpu_transcoder); > @@ -724,18 +779,31 @@ static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder, > else > return false; > > + I915_WRITE(reg, crtc_state->infoframes.gcp); > + > + return true; > +} > + > +static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder, > + struct intel_crtc_state *crtc_state, > + struct drm_connector_state *conn_state) > +{ > + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); > + > + if (IS_G4X(dev_priv) || !crtc_state->has_infoframe) > + return; > + > + crtc_state->infoframes.enable |= > + intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL); > + > /* Indicate color depth whenever the sink supports deep color */ > if (hdmi_sink_is_deep_color(conn_state)) > - val |= GCP_COLOR_INDICATION; > + crtc_state->infoframes.gcp |= GCP_COLOR_INDICATION; > > /* Enable default_phase whenever the display mode is suitably aligned */ > if (gcp_default_phase_possible(crtc_state->pipe_bpp, > &crtc_state->base.adjusted_mode)) > - val |= GCP_DEFAULT_PHASE_ENABLE; > - > - I915_WRITE(reg, val); > - > - return val != 0; > + crtc_state->infoframes.gcp |= GCP_DEFAULT_PHASE_ENABLE; > } > > static void ibx_set_infoframes(struct intel_encoder *encoder, > @@ -786,9 +854,15 @@ static void ibx_set_infoframes(struct intel_encoder *encoder, > I915_WRITE(reg, val); > POSTING_READ(reg); > > - intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); > - intel_hdmi_set_spd_infoframe(encoder, crtc_state); > - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_AVI, > + &crtc_state->infoframes.avi); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_SPD, > + &crtc_state->infoframes.spd); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_VENDOR, > + &crtc_state->infoframes.hdmi); > } > > static void cpt_set_infoframes(struct intel_encoder *encoder, > @@ -829,9 +903,15 @@ static void cpt_set_infoframes(struct intel_encoder *encoder, > I915_WRITE(reg, val); > POSTING_READ(reg); > > - intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); > - intel_hdmi_set_spd_infoframe(encoder, crtc_state); > - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_AVI, > + &crtc_state->infoframes.avi); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_SPD, > + &crtc_state->infoframes.spd); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_VENDOR, > + &crtc_state->infoframes.hdmi); > } > > static void vlv_set_infoframes(struct intel_encoder *encoder, > @@ -881,9 +961,15 @@ static void vlv_set_infoframes(struct intel_encoder *encoder, > I915_WRITE(reg, val); > POSTING_READ(reg); > > - intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); > - intel_hdmi_set_spd_infoframe(encoder, crtc_state); > - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_AVI, > + &crtc_state->infoframes.avi); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_SPD, > + &crtc_state->infoframes.spd); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_VENDOR, > + &crtc_state->infoframes.hdmi); > } > > static void hsw_set_infoframes(struct intel_encoder *encoder, > @@ -914,9 +1000,15 @@ static void hsw_set_infoframes(struct intel_encoder *encoder, > I915_WRITE(reg, val); > POSTING_READ(reg); > > - intel_hdmi_set_avi_infoframe(encoder, crtc_state, conn_state); > - intel_hdmi_set_spd_infoframe(encoder, crtc_state); > - intel_hdmi_set_hdmi_infoframe(encoder, crtc_state, conn_state); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_AVI, > + &crtc_state->infoframes.avi); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_SPD, > + &crtc_state->infoframes.spd); > + intel_write_infoframe(encoder, crtc_state, > + HDMI_INFOFRAME_TYPE_VENDOR, > + &crtc_state->infoframes.hdmi); > } > > void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable) > @@ -1851,6 +1943,27 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, > } > } > > + if (pipe_config->has_hdmi_sink) > + pipe_config->infoframes.enable |= > + intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_NULL); > + > + intel_hdmi_compute_gcp_infoframe(encoder, pipe_config, conn_state); > + > + if (!intel_hdmi_compute_avi_infoframe(encoder, pipe_config, conn_state)) { > + DRM_DEBUG_KMS("bad AVI infoframe\n"); > + return false; > + } > + > + if (!intel_hdmi_compute_spd_infoframe(encoder, pipe_config, conn_state)) { > + DRM_DEBUG_KMS("bad SPD infoframe\n"); > + return false; > + } > + > + if (!intel_hdmi_compute_hdmi_infoframe(encoder, pipe_config, conn_state)) { > + DRM_DEBUG_KMS("bad HDMI infoframe\n"); > + return false; > + } > + > return true; > } > > -- > 2.16.4 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx