On 2018-08-16 09:31 AM, Alex Deucher wrote: > This adds support for LVDS displays. > > v2: add support for spread spectrum, sink detect > v3: clean up enable_lvds_output > v4: fix up link_detect > v5: remove assert on 888 format > > Bug: https://bugs.freedesktop.org/show_bug.cgi?id=105880 > Signed-off-by: Alex Deucher <alexander.deucher at amd.com> > --- > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 + > drivers/gpu/drm/amd/display/dc/core/dc_link.c | 45 ++++++++++++++++++++++ > .../gpu/drm/amd/display/dc/dce/dce_clock_source.c | 10 +++++ > .../gpu/drm/amd/display/dc/dce/dce_clock_source.h | 2 + > .../gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 34 ++++++++++++++++ > .../gpu/drm/amd/display/dc/dce/dce_link_encoder.h | 6 +++ > .../drm/amd/display/dc/dce/dce_stream_encoder.c | 24 ++++++++++++ > .../gpu/drm/amd/display/dc/inc/hw/link_encoder.h | 3 ++ > .../gpu/drm/amd/display/dc/inc/hw/stream_encoder.h | 4 ++ > drivers/gpu/drm/amd/display/include/signal_types.h | 5 +++ > 10 files changed, 135 insertions(+) > > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > index 1828e4382b24..818b5ec32f37 100644 > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > @@ -3360,6 +3360,8 @@ static int to_drm_connector_type(enum signal_type st) > return DRM_MODE_CONNECTOR_HDMIA; > case SIGNAL_TYPE_EDP: > return DRM_MODE_CONNECTOR_eDP; > + case SIGNAL_TYPE_LVDS: > + return DRM_MODE_CONNECTOR_LVDS; > case SIGNAL_TYPE_RGB: > return DRM_MODE_CONNECTOR_VGA; > case SIGNAL_TYPE_DISPLAY_PORT: > diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c > index 981f7cbd31cc..0f044fd5baf4 100644 > --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c > +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c > @@ -203,6 +203,11 @@ static bool detect_sink(struct dc_link *link, enum dc_connection_type *type) > uint32_t is_hpd_high = 0; > struct gpio *hpd_pin; > > + if (link->connector_signal == SIGNAL_TYPE_LVDS) { > + *type = dc_connection_single; > + return true; > + } > + Would it be better to still do HPD detection? Or is this failing here? > /* todo: may need to lock gpio access */ > hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); > if (hpd_pin == NULL) > @@ -616,6 +621,10 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) > link->local_sink) > return true; > > + if (link->connector_signal == SIGNAL_TYPE_LVDS && > + link->local_sink) > + return true; > + > prev_sink = link->local_sink; > if (prev_sink != NULL) { > dc_sink_retain(prev_sink); > @@ -649,6 +658,12 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) > break; > } > > + case SIGNAL_TYPE_LVDS: { > + sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C; > + sink_caps.signal = SIGNAL_TYPE_LVDS; > + break; > + } > + > case SIGNAL_TYPE_EDP: { > detect_edp_sink_caps(link); > sink_caps.transaction_type = > @@ -1087,6 +1102,9 @@ static bool construct( > dal_irq_get_rx_source(hpd_gpio); > } > break; > + case CONNECTOR_ID_LVDS: > + link->connector_signal = SIGNAL_TYPE_LVDS; > + break; > default: > DC_LOG_WARNING("Unsupported Connector type:%d!\n", link->link_id.id); > goto create_fail; > @@ -1920,6 +1938,24 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) > dal_ddc_service_read_scdc_data(link->ddc); > } > > +static void enable_link_lvds(struct pipe_ctx *pipe_ctx) > +{ > + struct dc_stream_state *stream = pipe_ctx->stream; > + struct dc_link *link = stream->sink->link; > + > + if (stream->phy_pix_clk == 0) > + stream->phy_pix_clk = stream->timing.pix_clk_khz; > + > + memset(&stream->sink->link->cur_link_settings, 0, > + sizeof(struct dc_link_settings)); > + The cur_link_settings. should only by used by eDP/DP/MST. Shouldn't need to touch them here. Otherwise the change looks good. Harry > + link->link_enc->funcs->enable_lvds_output( > + link->link_enc, > + pipe_ctx->clock_source->id, > + stream->phy_pix_clk); > + > +} > + > /****************************enable_link***********************************/ > static enum dc_status enable_link( > struct dc_state *state, > @@ -1943,6 +1979,10 @@ static enum dc_status enable_link( > enable_link_hdmi(pipe_ctx); > status = DC_OK; > break; > + case SIGNAL_TYPE_LVDS: > + enable_link_lvds(pipe_ctx); > + status = DC_OK; > + break; > case SIGNAL_TYPE_VIRTUAL: > status = DC_OK; > break; > @@ -2492,6 +2532,11 @@ void core_link_enable_stream( > (pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ? > true : false); > > + if (dc_is_lvds_signal(pipe_ctx->stream->signal)) > + pipe_ctx->stream_res.stream_enc->funcs->lvds_set_stream_attribute( > + pipe_ctx->stream_res.stream_enc, > + &stream->timing); > + > resource_build_info_frame(pipe_ctx); > core_dc->hwss.update_info_frame(pipe_ctx); > > diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c > index 439dcf3b596c..5873bc82701e 100644 > --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c > +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c > @@ -75,6 +75,11 @@ static const struct spread_spectrum_data *get_ss_data_entry( > entrys_num = clk_src->hdmi_ss_params_cnt; > break; > > + case SIGNAL_TYPE_LVDS: > + ss_parm = clk_src->lvds_ss_params; > + entrys_num = clk_src->lvds_ss_params_cnt; > + break; > + > case SIGNAL_TYPE_DISPLAY_PORT: > case SIGNAL_TYPE_DISPLAY_PORT_MST: > case SIGNAL_TYPE_EDP: > @@ -1184,6 +1189,11 @@ static void ss_info_from_atombios_create( > AS_SIGNAL_TYPE_DVI, > &clk_src->dvi_ss_params, > &clk_src->dvi_ss_params_cnt); > + get_ss_info_from_atombios( > + clk_src, > + AS_SIGNAL_TYPE_LVDS, > + &clk_src->lvds_ss_params, > + &clk_src->lvds_ss_params_cnt); > } > > static bool calc_pll_max_vco_construct( > diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h > index 801bb65707b3..e1f20ed18e3e 100644 > --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h > +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h > @@ -125,6 +125,8 @@ struct dce110_clk_src { > uint32_t hdmi_ss_params_cnt; > struct spread_spectrum_data *dvi_ss_params; > uint32_t dvi_ss_params_cnt; > + struct spread_spectrum_data *lvds_ss_params; > + uint32_t lvds_ss_params_cnt; > > uint32_t ext_clk_khz; > uint32_t ref_freq_khz; > diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c > index eff7d22d78fb..4942590e8b9c 100644 > --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c > +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c > @@ -102,6 +102,7 @@ static const struct link_encoder_funcs dce110_lnk_enc_funcs = { > .enable_tmds_output = dce110_link_encoder_enable_tmds_output, > .enable_dp_output = dce110_link_encoder_enable_dp_output, > .enable_dp_mst_output = dce110_link_encoder_enable_dp_mst_output, > + .enable_lvds_output = dce110_link_encoder_enable_lvds_output, > .disable_output = dce110_link_encoder_disable_output, > .dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings, > .dp_set_phy_pattern = dce110_link_encoder_dp_set_phy_pattern, > @@ -814,6 +815,7 @@ bool dce110_link_encoder_validate_output_with_stream( > enc110, &stream->timing); > break; > case SIGNAL_TYPE_EDP: > + case SIGNAL_TYPE_LVDS: > is_valid = > (stream->timing. > pixel_encoding == PIXEL_ENCODING_RGB) ? true : false; > @@ -955,6 +957,38 @@ void dce110_link_encoder_enable_tmds_output( > } > } > > +/* TODO: still need depth or just pass in adjusted pixel clock? */ > +void dce110_link_encoder_enable_lvds_output( > + struct link_encoder *enc, > + enum clock_source_id clock_source, > + uint32_t pixel_clock) > +{ > + struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); > + struct bp_transmitter_control cntl = { 0 }; > + enum bp_result result; > + > + /* Enable the PHY */ > + cntl.connector_obj_id = enc110->base.connector; > + cntl.action = TRANSMITTER_CONTROL_ENABLE; > + cntl.engine_id = enc->preferred_engine; > + cntl.transmitter = enc110->base.transmitter; > + cntl.pll_id = clock_source; > + cntl.signal = SIGNAL_TYPE_LVDS; > + cntl.lanes_number = 4; > + > + cntl.hpd_sel = enc110->base.hpd_source; > + > + cntl.pixel_clock = pixel_clock; > + > + result = link_transmitter_control(enc110, &cntl); > + > + if (result != BP_RESULT_OK) { > + DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n", > + __func__); > + BREAK_TO_DEBUGGER(); > + } > +} > + > /* enables DP PHY output */ > void dce110_link_encoder_enable_dp_output( > struct link_encoder *enc, > diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h > index 347069461a22..3c9368df4093 100644 > --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h > +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h > @@ -225,6 +225,12 @@ void dce110_link_encoder_enable_dp_mst_output( > const struct dc_link_settings *link_settings, > enum clock_source_id clock_source); > > +/* enables LVDS PHY output */ > +void dce110_link_encoder_enable_lvds_output( > + struct link_encoder *enc, > + enum clock_source_id clock_source, > + uint32_t pixel_clock); > + > /* disable PHY output */ > void dce110_link_encoder_disable_output( > struct link_encoder *enc, > diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c > index b139b4017820..d65cc8ca1f6b 100644 > --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c > +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c > @@ -674,6 +674,28 @@ static void dce110_stream_encoder_dvi_set_stream_attribute( > dce110_stream_encoder_set_stream_attribute_helper(enc110, crtc_timing); > } > > +/* setup stream encoder in LVDS mode */ > +static void dce110_stream_encoder_lvds_set_stream_attribute( > + struct stream_encoder *enc, > + struct dc_crtc_timing *crtc_timing) > +{ > + struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); > + struct bp_encoder_control cntl = {0}; > + > + cntl.action = ENCODER_CONTROL_SETUP; > + cntl.engine_id = enc110->base.id; > + cntl.signal = SIGNAL_TYPE_LVDS; > + cntl.enable_dp_audio = false; > + cntl.pixel_clock = crtc_timing->pix_clk_khz; > + cntl.lanes_number = LANE_COUNT_FOUR; > + > + if (enc110->base.bp->funcs->encoder_control( > + enc110->base.bp, &cntl) != BP_RESULT_OK) > + return; > + > + ASSERT(crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB); > +} > + > static void dce110_stream_encoder_set_mst_bandwidth( > struct stream_encoder *enc, > struct fixed31_32 avg_time_slots_per_mtp) > @@ -1564,6 +1586,8 @@ static const struct stream_encoder_funcs dce110_str_enc_funcs = { > dce110_stream_encoder_hdmi_set_stream_attribute, > .dvi_set_stream_attribute = > dce110_stream_encoder_dvi_set_stream_attribute, > + .lvds_set_stream_attribute = > + dce110_stream_encoder_lvds_set_stream_attribute, > .set_mst_bandwidth = > dce110_stream_encoder_set_mst_bandwidth, > .update_hdmi_info_packets = > diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h > index cf6df2e7beb2..58818920ed41 100644 > --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h > +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h > @@ -131,6 +131,9 @@ struct link_encoder_funcs { > void (*enable_dp_mst_output)(struct link_encoder *enc, > const struct dc_link_settings *link_settings, > enum clock_source_id clock_source); > + void (*enable_lvds_output)(struct link_encoder *enc, > + enum clock_source_id clock_source, > + uint32_t pixel_clock); > void (*disable_output)(struct link_encoder *link_enc, > enum signal_type signal); > void (*dp_set_lane_settings)(struct link_encoder *enc, > diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h > index cfa7ec9517ae..53a9b64df11a 100644 > --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h > +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h > @@ -101,6 +101,10 @@ struct stream_encoder_funcs { > struct dc_crtc_timing *crtc_timing, > bool is_dual_link); > > + void (*lvds_set_stream_attribute)( > + struct stream_encoder *enc, > + struct dc_crtc_timing *crtc_timing); > + > void (*set_mst_bandwidth)( > struct stream_encoder *enc, > struct fixed31_32 avg_time_slots_per_mtp); > diff --git a/drivers/gpu/drm/amd/display/include/signal_types.h b/drivers/gpu/drm/amd/display/include/signal_types.h > index 199c5db67cbc..03476b142d8e 100644 > --- a/drivers/gpu/drm/amd/display/include/signal_types.h > +++ b/drivers/gpu/drm/amd/display/include/signal_types.h > @@ -68,6 +68,11 @@ static inline bool dc_is_embedded_signal(enum signal_type signal) > return (signal == SIGNAL_TYPE_EDP || signal == SIGNAL_TYPE_LVDS); > } > > +static inline bool dc_is_lvds_signal(enum signal_type signal) > +{ > + return (signal == SIGNAL_TYPE_LVDS); > +} > + > static inline bool dc_is_dvi_signal(enum signal_type signal) > { > switch (signal) { >