Commit 93c2340b authored by Martin Leung's avatar Martin Leung Committed by Alex Deucher

drm/amd/display: add more checks to validate seamless boot timing

[why]
we found using an active DP to HDMI panel that we weren't validating
dp_pixel_format and hardware timing v_front_porch, causing screen to
blank and/or corrupt while attempting a seamless boot.

[how]
added checks during dc_validate_seamless_boot_timing for these values
Signed-off-by: default avatarMartin Leung <martin.leung@amd.com>
Reviewed-by: default avatarAnthony Koo <Anthony.Koo@amd.com>
Acked-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 566b4252
...@@ -1004,6 +1004,10 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, ...@@ -1004,6 +1004,10 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
struct dc_crtc_timing *crtc_timing) struct dc_crtc_timing *crtc_timing)
{ {
struct timing_generator *tg; struct timing_generator *tg;
struct stream_encoder *se;
struct dc_crtc_timing hw_crtc_timing = {0};
struct dc_link *link = sink->link; struct dc_link *link = sink->link;
unsigned int i, enc_inst, tg_inst = 0; unsigned int i, enc_inst, tg_inst = 0;
...@@ -1023,6 +1027,9 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, ...@@ -1023,6 +1027,9 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
for (i = 0; i < dc->res_pool->stream_enc_count; i++) { for (i = 0; i < dc->res_pool->stream_enc_count; i++) {
if (dc->res_pool->stream_enc[i]->id == enc_inst) { if (dc->res_pool->stream_enc[i]->id == enc_inst) {
se = dc->res_pool->stream_enc[i];
tg_inst = dc->res_pool->stream_enc[i]->funcs->dig_source_otg( tg_inst = dc->res_pool->stream_enc[i]->funcs->dig_source_otg(
dc->res_pool->stream_enc[i]); dc->res_pool->stream_enc[i]);
break; break;
...@@ -1038,10 +1045,46 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, ...@@ -1038,10 +1045,46 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
tg = dc->res_pool->timing_generators[tg_inst]; tg = dc->res_pool->timing_generators[tg_inst];
if (!tg->funcs->is_matching_timing) if (!tg->funcs->get_hw_timing)
return false;
if (!tg->funcs->get_hw_timing(tg, &hw_crtc_timing))
return false;
if (crtc_timing->h_total != hw_crtc_timing.h_total)
return false;
if (crtc_timing->h_border_left != hw_crtc_timing.h_border_left)
return false;
if (crtc_timing->h_addressable != hw_crtc_timing.h_addressable)
return false;
if (crtc_timing->h_border_right != hw_crtc_timing.h_border_right)
return false;
if (crtc_timing->h_front_porch != hw_crtc_timing.h_front_porch)
return false;
if (crtc_timing->h_sync_width != hw_crtc_timing.h_sync_width)
return false; return false;
if (!tg->funcs->is_matching_timing(tg, crtc_timing)) if (crtc_timing->v_total != hw_crtc_timing.v_total)
return false;
if (crtc_timing->v_border_top != hw_crtc_timing.v_border_top)
return false;
if (crtc_timing->v_addressable != hw_crtc_timing.v_addressable)
return false;
if (crtc_timing->v_border_bottom != hw_crtc_timing.v_border_bottom)
return false;
if (crtc_timing->v_front_porch != hw_crtc_timing.v_front_porch)
return false;
if (crtc_timing->v_sync_width != hw_crtc_timing.v_sync_width)
return false; return false;
if (dc_is_dp_signal(link->connector_signal)) { if (dc_is_dp_signal(link->connector_signal)) {
...@@ -1054,6 +1097,20 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, ...@@ -1054,6 +1097,20 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
if (crtc_timing->pix_clk_100hz != pix_clk_100hz) if (crtc_timing->pix_clk_100hz != pix_clk_100hz)
return false; return false;
if (!se->funcs->dp_get_pixel_format)
return false;
if (!se->funcs->dp_get_pixel_format(
se,
&hw_crtc_timing.pixel_encoding,
&hw_crtc_timing.display_color_depth))
return false;
if (hw_crtc_timing.display_color_depth != crtc_timing->display_color_depth)
return false;
if (hw_crtc_timing.pixel_encoding != crtc_timing->pixel_encoding)
return false;
} }
return true; return true;
......
...@@ -1230,59 +1230,25 @@ bool optc1_is_stereo_left_eye(struct timing_generator *optc) ...@@ -1230,59 +1230,25 @@ bool optc1_is_stereo_left_eye(struct timing_generator *optc)
return ret; return ret;
} }
bool optc1_is_matching_timing(struct timing_generator *tg, bool optc1_get_hw_timing(struct timing_generator *tg,
const struct dc_crtc_timing *otg_timing) struct dc_crtc_timing *hw_crtc_timing)
{ {
struct dc_crtc_timing hw_crtc_timing = {0};
struct dcn_otg_state s = {0}; struct dcn_otg_state s = {0};
if (tg == NULL || otg_timing == NULL) if (tg == NULL || hw_crtc_timing == NULL)
return false; return false;
optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
hw_crtc_timing.h_total = s.h_total + 1; hw_crtc_timing->h_total = s.h_total + 1;
hw_crtc_timing.h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end); hw_crtc_timing->h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end);
hw_crtc_timing.h_front_porch = s.h_total + 1 - s.h_blank_start; hw_crtc_timing->h_front_porch = s.h_total + 1 - s.h_blank_start;
hw_crtc_timing.h_sync_width = s.h_sync_a_end - s.h_sync_a_start; hw_crtc_timing->h_sync_width = s.h_sync_a_end - s.h_sync_a_start;
hw_crtc_timing.v_total = s.v_total + 1; hw_crtc_timing->v_total = s.v_total + 1;
hw_crtc_timing.v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end); hw_crtc_timing->v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end);
hw_crtc_timing.v_front_porch = s.v_total + 1 - s.v_blank_start; hw_crtc_timing->v_front_porch = s.v_total + 1 - s.v_blank_start;
hw_crtc_timing.v_sync_width = s.v_sync_a_end - s.v_sync_a_start; hw_crtc_timing->v_sync_width = s.v_sync_a_end - s.v_sync_a_start;
if (otg_timing->h_total != hw_crtc_timing.h_total)
return false;
if (otg_timing->h_border_left != hw_crtc_timing.h_border_left)
return false;
if (otg_timing->h_addressable != hw_crtc_timing.h_addressable)
return false;
if (otg_timing->h_border_right != hw_crtc_timing.h_border_right)
return false;
if (otg_timing->h_front_porch != hw_crtc_timing.h_front_porch)
return false;
if (otg_timing->h_sync_width != hw_crtc_timing.h_sync_width)
return false;
if (otg_timing->v_total != hw_crtc_timing.v_total)
return false;
if (otg_timing->v_border_top != hw_crtc_timing.v_border_top)
return false;
if (otg_timing->v_addressable != hw_crtc_timing.v_addressable)
return false;
if (otg_timing->v_border_bottom != hw_crtc_timing.v_border_bottom)
return false;
if (otg_timing->v_sync_width != hw_crtc_timing.v_sync_width)
return false;
return true; return true;
} }
...@@ -1486,7 +1452,6 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { ...@@ -1486,7 +1452,6 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
.get_frame_count = optc1_get_vblank_counter, .get_frame_count = optc1_get_vblank_counter,
.get_scanoutpos = optc1_get_crtc_scanoutpos, .get_scanoutpos = optc1_get_crtc_scanoutpos,
.get_otg_active_size = optc1_get_otg_active_size, .get_otg_active_size = optc1_get_otg_active_size,
.is_matching_timing = optc1_is_matching_timing,
.set_early_control = optc1_set_early_control, .set_early_control = optc1_set_early_control,
/* used by enable_timing_synchronization. Not need for FPGA */ /* used by enable_timing_synchronization. Not need for FPGA */
.wait_for_state = optc1_wait_for_state, .wait_for_state = optc1_wait_for_state,
...@@ -1514,7 +1479,8 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { ...@@ -1514,7 +1479,8 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
.configure_crc = optc1_configure_crc, .configure_crc = optc1_configure_crc,
.set_vtg_params = optc1_set_vtg_params, .set_vtg_params = optc1_set_vtg_params,
.program_manual_trigger = optc1_program_manual_trigger, .program_manual_trigger = optc1_program_manual_trigger,
.setup_manual_trigger = optc1_setup_manual_trigger .setup_manual_trigger = optc1_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
}; };
void dcn10_timing_generator_init(struct optc *optc1) void dcn10_timing_generator_init(struct optc *optc1)
......
...@@ -547,9 +547,8 @@ struct dcn_otg_state { ...@@ -547,9 +547,8 @@ struct dcn_otg_state {
void optc1_read_otg_state(struct optc *optc1, void optc1_read_otg_state(struct optc *optc1,
struct dcn_otg_state *s); struct dcn_otg_state *s);
bool optc1_is_matching_timing( bool optc1_get_hw_timing(struct timing_generator *tg,
struct timing_generator *tg, struct dc_crtc_timing *hw_crtc_timing);
const struct dc_crtc_timing *otg_timing);
bool optc1_validate_timing( bool optc1_validate_timing(
struct timing_generator *optc, struct timing_generator *optc,
......
...@@ -1553,6 +1553,66 @@ unsigned int enc1_dig_source_otg( ...@@ -1553,6 +1553,66 @@ unsigned int enc1_dig_source_otg(
return tg_inst; return tg_inst;
} }
bool enc1_stream_encoder_dp_get_pixel_format(
struct stream_encoder *enc,
enum dc_pixel_encoding *encoding,
enum dc_color_depth *depth)
{
uint32_t hw_encoding = 0;
uint32_t hw_depth = 0;
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
if (enc == NULL ||
encoding == NULL ||
depth == NULL)
return false;
REG_GET_2(DP_PIXEL_FORMAT,
DP_PIXEL_ENCODING, &hw_encoding,
DP_COMPONENT_DEPTH, &hw_depth);
switch (hw_depth) {
case DP_COMPONENT_PIXEL_DEPTH_6BPC:
*depth = COLOR_DEPTH_666;
break;
case DP_COMPONENT_PIXEL_DEPTH_8BPC:
*depth = COLOR_DEPTH_888;
break;
case DP_COMPONENT_PIXEL_DEPTH_10BPC:
*depth = COLOR_DEPTH_101010;
break;
case DP_COMPONENT_PIXEL_DEPTH_12BPC:
*depth = COLOR_DEPTH_121212;
break;
case DP_COMPONENT_PIXEL_DEPTH_16BPC:
*depth = COLOR_DEPTH_161616;
break;
default:
*depth = COLOR_DEPTH_UNDEFINED;
break;
}
switch (hw_encoding) {
case DP_PIXEL_ENCODING_TYPE_RGB444:
*encoding = PIXEL_ENCODING_RGB;
break;
case DP_PIXEL_ENCODING_TYPE_YCBCR422:
*encoding = PIXEL_ENCODING_YCBCR422;
break;
case DP_PIXEL_ENCODING_TYPE_YCBCR444:
case DP_PIXEL_ENCODING_TYPE_Y_ONLY:
*encoding = PIXEL_ENCODING_YCBCR444;
break;
case DP_PIXEL_ENCODING_TYPE_YCBCR420:
*encoding = PIXEL_ENCODING_YCBCR420;
break;
default:
*encoding = PIXEL_ENCODING_UNDEFINED;
break;
}
return true;
}
static const struct stream_encoder_funcs dcn10_str_enc_funcs = { static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
.dp_set_stream_attribute = .dp_set_stream_attribute =
enc1_stream_encoder_dp_set_stream_attribute, enc1_stream_encoder_dp_set_stream_attribute,
...@@ -1589,6 +1649,8 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = { ...@@ -1589,6 +1649,8 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
.dig_connect_to_otg = enc1_dig_connect_to_otg, .dig_connect_to_otg = enc1_dig_connect_to_otg,
.hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute, .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute,
.dig_source_otg = enc1_dig_source_otg, .dig_source_otg = enc1_dig_source_otg,
.dp_get_pixel_format = enc1_stream_encoder_dp_get_pixel_format,
}; };
void dcn10_stream_encoder_construct( void dcn10_stream_encoder_construct(
......
...@@ -621,4 +621,9 @@ void get_audio_clock_info( ...@@ -621,4 +621,9 @@ void get_audio_clock_info(
void enc1_reset_hdmi_stream_attribute( void enc1_reset_hdmi_stream_attribute(
struct stream_encoder *enc); struct stream_encoder *enc);
bool enc1_stream_encoder_dp_get_pixel_format(
struct stream_encoder *enc,
enum dc_pixel_encoding *encoding,
enum dc_color_depth *depth);
#endif /* __DC_STREAM_ENCODER_DCN10_H__ */ #endif /* __DC_STREAM_ENCODER_DCN10_H__ */
...@@ -460,7 +460,7 @@ static struct timing_generator_funcs dcn20_tg_funcs = { ...@@ -460,7 +460,7 @@ static struct timing_generator_funcs dcn20_tg_funcs = {
.set_vtg_params = optc1_set_vtg_params, .set_vtg_params = optc1_set_vtg_params,
.program_manual_trigger = optc2_program_manual_trigger, .program_manual_trigger = optc2_program_manual_trigger,
.setup_manual_trigger = optc2_setup_manual_trigger, .setup_manual_trigger = optc2_setup_manual_trigger,
.is_matching_timing = optc1_is_matching_timing .get_hw_timing = optc1_get_hw_timing,
}; };
void dcn20_timing_generator_init(struct optc *optc1) void dcn20_timing_generator_init(struct optc *optc1)
......
...@@ -578,6 +578,10 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = { ...@@ -578,6 +578,10 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = {
.set_avmute = enc1_stream_encoder_set_avmute, .set_avmute = enc1_stream_encoder_set_avmute,
.dig_connect_to_otg = enc1_dig_connect_to_otg, .dig_connect_to_otg = enc1_dig_connect_to_otg,
.dig_source_otg = enc1_dig_source_otg, .dig_source_otg = enc1_dig_source_otg,
.dp_get_pixel_format =
enc1_stream_encoder_dp_get_pixel_format,
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
.enc_read_state = enc2_read_state, .enc_read_state = enc2_read_state,
.dp_set_dsc_config = enc2_dp_set_dsc_config, .dp_set_dsc_config = enc2_dp_set_dsc_config,
......
...@@ -214,6 +214,11 @@ struct stream_encoder_funcs { ...@@ -214,6 +214,11 @@ struct stream_encoder_funcs {
unsigned int (*dig_source_otg)( unsigned int (*dig_source_otg)(
struct stream_encoder *enc); struct stream_encoder *enc);
bool (*dp_get_pixel_format)(
struct stream_encoder *enc,
enum dc_pixel_encoding *encoding,
enum dc_color_depth *depth);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
void (*enc_read_state)(struct stream_encoder *enc, struct enc_state *s); void (*enc_read_state)(struct stream_encoder *enc, struct enc_state *s);
......
...@@ -261,6 +261,8 @@ struct timing_generator_funcs { ...@@ -261,6 +261,8 @@ struct timing_generator_funcs {
void (*program_manual_trigger)(struct timing_generator *optc); void (*program_manual_trigger)(struct timing_generator *optc);
void (*setup_manual_trigger)(struct timing_generator *optc); void (*setup_manual_trigger)(struct timing_generator *optc);
bool (*get_hw_timing)(struct timing_generator *optc,
struct dc_crtc_timing *hw_crtc_timing);
void (*set_vtg_params)(struct timing_generator *optc, void (*set_vtg_params)(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing); const struct dc_crtc_timing *dc_crtc_timing);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment