diff -ur a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 2018-08-17 10:22:53.259002899 +0200 @@ -3313,6 +3313,8 @@ 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 -ur a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c 2018-08-17 10:24:59.250004005 +0200 @@ -192,6 +192,11 @@ uint32_t is_hpd_high = 0; struct gpio *hpd_pin; + if (link->connector_signal == SIGNAL_TYPE_LVDS) { + *type = dc_connection_single; + return true; + } + /* 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) @@ -597,6 +602,10 @@ 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); @@ -630,6 +639,12 @@ 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 = @@ -1042,6 +1057,9 @@ 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; @@ -1831,6 +1849,24 @@ 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)); + + 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, @@ -1854,6 +1890,10 @@ 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; @@ -2382,6 +2422,7 @@ struct pipe_ctx *pipe_ctx) { struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc_stream_state *stream = pipe_ctx->stream; enum dc_status status; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); @@ -2396,6 +2437,11 @@ if (pipe_ctx->stream->dpms_off) return; + 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); + status = enable_link(state, pipe_ctx); if (status != DC_OK) { diff -ur a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c 2018-08-17 10:22:53.263002899 +0200 @@ -75,6 +75,11 @@ 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 @@ 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 -ur a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h 2018-08-17 10:22:53.263002899 +0200 @@ -125,6 +125,8 @@ 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 -ur a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c 2018-08-17 10:22:53.264002899 +0200 @@ -102,6 +102,7 @@ .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, @@ -803,6 +804,7 @@ enc110, &stream->timing); break; case SIGNAL_TYPE_EDP: + case SIGNAL_TYPE_LVDS: is_valid = (stream->timing. pixel_encoding == PIXEL_ENCODING_RGB) ? true : false; @@ -937,6 +939,38 @@ 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(); + } +} + +/* 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__); diff -ur a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h 2018-08-17 10:22:53.265002899 +0200 @@ -225,6 +225,12 @@ 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 -ur a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c 2018-08-17 10:22:53.266002899 +0200 @@ -679,6 +679,29 @@ 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); + ASSERT(crtc_timing->display_color_depth == COLOR_DEPTH_888); +} + static void dce110_stream_encoder_set_mst_bandwidth( struct stream_encoder *enc, struct fixed31_32 avg_time_slots_per_mtp) @@ -1569,6 +1592,8 @@ 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 -ur a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h 2018-08-17 10:22:53.266002899 +0200 @@ -131,6 +131,9 @@ 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 -ur a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h 2018-08-17 10:22:53.267002899 +0200 @@ -101,6 +101,10 @@ 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 -ur a/drivers/gpu/drm/amd/display/include/signal_types.h b/drivers/gpu/drm/amd/display/include/signal_types.h --- a/drivers/gpu/drm/amd/display/include/signal_types.h 2018-08-12 22:41:04.000000000 +0200 +++ b/drivers/gpu/drm/amd/display/include/signal_types.h 2018-08-17 10:22:53.267002899 +0200 @@ -68,6 +68,11 @@ 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) {