drm/amdgpu/display: add support for LVDS (v5)
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 Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
ae74da3e14
commit
11c3ee48bd
|
@ -3358,6 +3358,8 @@ static int to_drm_connector_type(enum signal_type st)
|
||||||
return DRM_MODE_CONNECTOR_HDMIA;
|
return DRM_MODE_CONNECTOR_HDMIA;
|
||||||
case SIGNAL_TYPE_EDP:
|
case SIGNAL_TYPE_EDP:
|
||||||
return DRM_MODE_CONNECTOR_eDP;
|
return DRM_MODE_CONNECTOR_eDP;
|
||||||
|
case SIGNAL_TYPE_LVDS:
|
||||||
|
return DRM_MODE_CONNECTOR_LVDS;
|
||||||
case SIGNAL_TYPE_RGB:
|
case SIGNAL_TYPE_RGB:
|
||||||
return DRM_MODE_CONNECTOR_VGA;
|
return DRM_MODE_CONNECTOR_VGA;
|
||||||
case SIGNAL_TYPE_DISPLAY_PORT:
|
case SIGNAL_TYPE_DISPLAY_PORT:
|
||||||
|
|
|
@ -203,6 +203,11 @@ static bool detect_sink(struct dc_link *link, enum dc_connection_type *type)
|
||||||
uint32_t is_hpd_high = 0;
|
uint32_t is_hpd_high = 0;
|
||||||
struct gpio *hpd_pin;
|
struct gpio *hpd_pin;
|
||||||
|
|
||||||
|
if (link->connector_signal == SIGNAL_TYPE_LVDS) {
|
||||||
|
*type = dc_connection_single;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* todo: may need to lock gpio access */
|
/* todo: may need to lock gpio access */
|
||||||
hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
|
hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
|
||||||
if (hpd_pin == NULL)
|
if (hpd_pin == NULL)
|
||||||
|
@ -616,6 +621,10 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
|
||||||
link->local_sink)
|
link->local_sink)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (link->connector_signal == SIGNAL_TYPE_LVDS &&
|
||||||
|
link->local_sink)
|
||||||
|
return true;
|
||||||
|
|
||||||
prev_sink = link->local_sink;
|
prev_sink = link->local_sink;
|
||||||
if (prev_sink != NULL) {
|
if (prev_sink != NULL) {
|
||||||
dc_sink_retain(prev_sink);
|
dc_sink_retain(prev_sink);
|
||||||
|
@ -649,6 +658,12 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SIGNAL_TYPE_LVDS: {
|
||||||
|
sink_caps.transaction_type = DDC_TRANSACTION_TYPE_I2C;
|
||||||
|
sink_caps.signal = SIGNAL_TYPE_LVDS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SIGNAL_TYPE_EDP: {
|
case SIGNAL_TYPE_EDP: {
|
||||||
detect_edp_sink_caps(link);
|
detect_edp_sink_caps(link);
|
||||||
sink_caps.transaction_type =
|
sink_caps.transaction_type =
|
||||||
|
@ -1087,6 +1102,9 @@ static bool construct(
|
||||||
dal_irq_get_rx_source(hpd_gpio);
|
dal_irq_get_rx_source(hpd_gpio);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CONNECTOR_ID_LVDS:
|
||||||
|
link->connector_signal = SIGNAL_TYPE_LVDS;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DC_LOG_WARNING("Unsupported Connector type:%d!\n", link->link_id.id);
|
DC_LOG_WARNING("Unsupported Connector type:%d!\n", link->link_id.id);
|
||||||
goto create_fail;
|
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);
|
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***********************************/
|
/****************************enable_link***********************************/
|
||||||
static enum dc_status enable_link(
|
static enum dc_status enable_link(
|
||||||
struct dc_state *state,
|
struct dc_state *state,
|
||||||
|
@ -1943,6 +1979,10 @@ static enum dc_status enable_link(
|
||||||
enable_link_hdmi(pipe_ctx);
|
enable_link_hdmi(pipe_ctx);
|
||||||
status = DC_OK;
|
status = DC_OK;
|
||||||
break;
|
break;
|
||||||
|
case SIGNAL_TYPE_LVDS:
|
||||||
|
enable_link_lvds(pipe_ctx);
|
||||||
|
status = DC_OK;
|
||||||
|
break;
|
||||||
case SIGNAL_TYPE_VIRTUAL:
|
case SIGNAL_TYPE_VIRTUAL:
|
||||||
status = DC_OK;
|
status = DC_OK;
|
||||||
break;
|
break;
|
||||||
|
@ -2492,6 +2532,11 @@ void core_link_enable_stream(
|
||||||
(pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
|
(pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
|
||||||
true : false);
|
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);
|
resource_build_info_frame(pipe_ctx);
|
||||||
core_dc->hwss.update_info_frame(pipe_ctx);
|
core_dc->hwss.update_info_frame(pipe_ctx);
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,11 @@ static const struct spread_spectrum_data *get_ss_data_entry(
|
||||||
entrys_num = clk_src->hdmi_ss_params_cnt;
|
entrys_num = clk_src->hdmi_ss_params_cnt;
|
||||||
break;
|
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:
|
||||||
case SIGNAL_TYPE_DISPLAY_PORT_MST:
|
case SIGNAL_TYPE_DISPLAY_PORT_MST:
|
||||||
case SIGNAL_TYPE_EDP:
|
case SIGNAL_TYPE_EDP:
|
||||||
|
@ -1184,6 +1189,11 @@ static void ss_info_from_atombios_create(
|
||||||
AS_SIGNAL_TYPE_DVI,
|
AS_SIGNAL_TYPE_DVI,
|
||||||
&clk_src->dvi_ss_params,
|
&clk_src->dvi_ss_params,
|
||||||
&clk_src->dvi_ss_params_cnt);
|
&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(
|
static bool calc_pll_max_vco_construct(
|
||||||
|
|
|
@ -125,6 +125,8 @@ struct dce110_clk_src {
|
||||||
uint32_t hdmi_ss_params_cnt;
|
uint32_t hdmi_ss_params_cnt;
|
||||||
struct spread_spectrum_data *dvi_ss_params;
|
struct spread_spectrum_data *dvi_ss_params;
|
||||||
uint32_t dvi_ss_params_cnt;
|
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 ext_clk_khz;
|
||||||
uint32_t ref_freq_khz;
|
uint32_t ref_freq_khz;
|
||||||
|
|
|
@ -102,6 +102,7 @@ static const struct link_encoder_funcs dce110_lnk_enc_funcs = {
|
||||||
.enable_tmds_output = dce110_link_encoder_enable_tmds_output,
|
.enable_tmds_output = dce110_link_encoder_enable_tmds_output,
|
||||||
.enable_dp_output = dce110_link_encoder_enable_dp_output,
|
.enable_dp_output = dce110_link_encoder_enable_dp_output,
|
||||||
.enable_dp_mst_output = dce110_link_encoder_enable_dp_mst_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,
|
.disable_output = dce110_link_encoder_disable_output,
|
||||||
.dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings,
|
.dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings,
|
||||||
.dp_set_phy_pattern = dce110_link_encoder_dp_set_phy_pattern,
|
.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);
|
enc110, &stream->timing);
|
||||||
break;
|
break;
|
||||||
case SIGNAL_TYPE_EDP:
|
case SIGNAL_TYPE_EDP:
|
||||||
|
case SIGNAL_TYPE_LVDS:
|
||||||
is_valid =
|
is_valid =
|
||||||
(stream->timing.
|
(stream->timing.
|
||||||
pixel_encoding == PIXEL_ENCODING_RGB) ? true : false;
|
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 */
|
/* enables DP PHY output */
|
||||||
void dce110_link_encoder_enable_dp_output(
|
void dce110_link_encoder_enable_dp_output(
|
||||||
struct link_encoder *enc,
|
struct link_encoder *enc,
|
||||||
|
|
|
@ -225,6 +225,12 @@ void dce110_link_encoder_enable_dp_mst_output(
|
||||||
const struct dc_link_settings *link_settings,
|
const struct dc_link_settings *link_settings,
|
||||||
enum clock_source_id clock_source);
|
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 */
|
/* disable PHY output */
|
||||||
void dce110_link_encoder_disable_output(
|
void dce110_link_encoder_disable_output(
|
||||||
struct link_encoder *enc,
|
struct link_encoder *enc,
|
||||||
|
|
|
@ -674,6 +674,28 @@ static void dce110_stream_encoder_dvi_set_stream_attribute(
|
||||||
dce110_stream_encoder_set_stream_attribute_helper(enc110, crtc_timing);
|
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(
|
static void dce110_stream_encoder_set_mst_bandwidth(
|
||||||
struct stream_encoder *enc,
|
struct stream_encoder *enc,
|
||||||
struct fixed31_32 avg_time_slots_per_mtp)
|
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,
|
dce110_stream_encoder_hdmi_set_stream_attribute,
|
||||||
.dvi_set_stream_attribute =
|
.dvi_set_stream_attribute =
|
||||||
dce110_stream_encoder_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 =
|
.set_mst_bandwidth =
|
||||||
dce110_stream_encoder_set_mst_bandwidth,
|
dce110_stream_encoder_set_mst_bandwidth,
|
||||||
.update_hdmi_info_packets =
|
.update_hdmi_info_packets =
|
||||||
|
|
|
@ -131,6 +131,9 @@ struct link_encoder_funcs {
|
||||||
void (*enable_dp_mst_output)(struct link_encoder *enc,
|
void (*enable_dp_mst_output)(struct link_encoder *enc,
|
||||||
const struct dc_link_settings *link_settings,
|
const struct dc_link_settings *link_settings,
|
||||||
enum clock_source_id clock_source);
|
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,
|
void (*disable_output)(struct link_encoder *link_enc,
|
||||||
enum signal_type signal);
|
enum signal_type signal);
|
||||||
void (*dp_set_lane_settings)(struct link_encoder *enc,
|
void (*dp_set_lane_settings)(struct link_encoder *enc,
|
||||||
|
|
|
@ -101,6 +101,10 @@ struct stream_encoder_funcs {
|
||||||
struct dc_crtc_timing *crtc_timing,
|
struct dc_crtc_timing *crtc_timing,
|
||||||
bool is_dual_link);
|
bool is_dual_link);
|
||||||
|
|
||||||
|
void (*lvds_set_stream_attribute)(
|
||||||
|
struct stream_encoder *enc,
|
||||||
|
struct dc_crtc_timing *crtc_timing);
|
||||||
|
|
||||||
void (*set_mst_bandwidth)(
|
void (*set_mst_bandwidth)(
|
||||||
struct stream_encoder *enc,
|
struct stream_encoder *enc,
|
||||||
struct fixed31_32 avg_time_slots_per_mtp);
|
struct fixed31_32 avg_time_slots_per_mtp);
|
||||||
|
|
|
@ -68,6 +68,11 @@ static inline bool dc_is_embedded_signal(enum signal_type signal)
|
||||||
return (signal == SIGNAL_TYPE_EDP || signal == SIGNAL_TYPE_LVDS);
|
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)
|
static inline bool dc_is_dvi_signal(enum signal_type signal)
|
||||||
{
|
{
|
||||||
switch (signal) {
|
switch (signal) {
|
||||||
|
|
Loading…
Reference in New Issue