drm/amd/display: enabling seamless boot sequence for dcn2
authorMartin Leung <martin.leung@amd.com>
Wed, 17 Jul 2019 20:08:19 +0000 (16:08 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 15 Aug 2019 15:54:27 +0000 (10:54 -0500)
[Why]
Seamless boot (building SW state inheriting BIOS-initialized timing) was
enabled on DCN2, including fixes

[How]
Includes fixes for MPC, DPPCLK, and DIG FE mapping/OTG source select/
Pixel clock.

This is part 2 of 2 for seamless boot NV10

Signed-off-by: Martin Leung <martin.leung@amd.com>
Reviewed-by: Jun Lei <Jun.Lei@amd.com>
Acked-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
17 files changed:
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c
drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h

index f61eb29..7603845 100644 (file)
@@ -960,7 +960,7 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
 {
        struct timing_generator *tg;
        struct dc_link *link = sink->link;
-       unsigned int inst;
+       unsigned int enc_inst, tg_inst;
 
        /* Check for enabled DIG to identify enabled display */
        if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
@@ -972,13 +972,22 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
         * current implementation always map 1-to-1, so this code makes
         * the same assumption and doesn't check OTG source.
         */
-       inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1;
+       enc_inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
 
        /* Instance should be within the range of the pool */
-       if (inst >= dc->res_pool->pipe_count)
+       if (enc_inst >= dc->res_pool->pipe_count)
                return false;
 
-       tg = dc->res_pool->timing_generators[inst];
+       if (enc_inst >= dc->res_pool->stream_enc_count)
+               return false;
+
+       tg_inst = dc->res_pool->stream_enc[enc_inst]->funcs->dig_source_otg(
+               dc->res_pool->stream_enc[enc_inst]);
+
+       if (tg_inst >= dc->res_pool->timing_generator_count)
+               return false;
+
+       tg = dc->res_pool->timing_generators[tg_inst];
 
        if (!tg->funcs->is_matching_timing)
                return false;
@@ -991,10 +1000,11 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
 
                dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
                        dc->res_pool->dp_clock_source,
-                       inst, &pix_clk_100hz);
+                       tg_inst, &pix_clk_100hz);
 
                if (crtc_timing->pix_clk_100hz != pix_clk_100hz)
                        return false;
+
        }
 
        return true;
@@ -1904,13 +1914,17 @@ static void commit_planes_do_stream_update(struct dc *dc,
 
                        if (stream_update->dpms_off) {
                                dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
+
                                if (*stream_update->dpms_off) {
                                        core_link_disable_stream(pipe_ctx, KEEP_ACQUIRED_RESOURCE);
                                        dc->hwss.optimize_bandwidth(dc, dc->current_state);
                                } else {
-                                       dc->hwss.prepare_bandwidth(dc, dc->current_state);
+                                       if (!dc->optimize_seamless_boot)
+                                               dc->hwss.prepare_bandwidth(dc, dc->current_state);
+
                                        core_link_enable_stream(dc->current_state, pipe_ctx);
                                }
+
                                dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
                        }
 
index 0a66a6f..892542d 100644 (file)
@@ -1421,6 +1421,16 @@ static enum dc_status enable_link_dp(
 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
        bool fec_enable;
 #endif
+       int i;
+       bool apply_seamless_boot_optimization = false;
+
+       // check for seamless boot
+       for (i = 0; i < state->stream_count; i++) {
+               if (state->streams[i]->apply_seamless_boot_optimization) {
+                       apply_seamless_boot_optimization = true;
+                       break;
+               }
+       }
 
        /* get link settings for video mode timing */
        decide_link_settings(stream, &link_settings);
@@ -1442,7 +1452,8 @@ static enum dc_status enable_link_dp(
 
        pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
                        link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
-       state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false);
+       if (!apply_seamless_boot_optimization)
+               state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false);
 
        dp_enable_link_phy(
                link,
index 5956e70..97e992e 100644 (file)
@@ -1893,7 +1893,7 @@ static int acquire_resource_from_hw_enabled_state(
                struct dc_stream_state *stream)
 {
        struct dc_link *link = stream->link;
-       unsigned int inst;
+       unsigned int inst, tg_inst;
 
        /* Check for enabled DIG to identify enabled display */
        if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
@@ -1905,28 +1905,37 @@ static int acquire_resource_from_hw_enabled_state(
         * current implementation always map 1-to-1, so this code makes
         * the same assumption and doesn't check OTG source.
         */
-       inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1;
+       inst = link->link_enc->funcs->get_dig_frontend(link->link_enc);
 
        /* Instance should be within the range of the pool */
        if (inst >= pool->pipe_count)
                return -1;
 
-       if (!res_ctx->pipe_ctx[inst].stream) {
-               struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[inst];
+       if (inst >= pool->stream_enc_count)
+               return -1;
+
+       tg_inst = pool->stream_enc[inst]->funcs->dig_source_otg(pool->stream_enc[inst]);
+
+       if (tg_inst >= pool->timing_generator_count)
+               return false;
+
+       if (!res_ctx->pipe_ctx[tg_inst].stream) {
+               struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
+
+               pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
+               pipe_ctx->plane_res.mi = pool->mis[tg_inst];
+               pipe_ctx->plane_res.hubp = pool->hubps[tg_inst];
+               pipe_ctx->plane_res.ipp = pool->ipps[tg_inst];
+               pipe_ctx->plane_res.xfm = pool->transforms[tg_inst];
+               pipe_ctx->plane_res.dpp = pool->dpps[tg_inst];
+               pipe_ctx->stream_res.opp = pool->opps[tg_inst];
 
-               pipe_ctx->stream_res.tg = pool->timing_generators[inst];
-               pipe_ctx->plane_res.mi = pool->mis[inst];
-               pipe_ctx->plane_res.hubp = pool->hubps[inst];
-               pipe_ctx->plane_res.ipp = pool->ipps[inst];
-               pipe_ctx->plane_res.xfm = pool->transforms[inst];
-               pipe_ctx->plane_res.dpp = pool->dpps[inst];
-               pipe_ctx->stream_res.opp = pool->opps[inst];
-               if (pool->dpps[inst])
-                       pipe_ctx->plane_res.mpcc_inst = pool->dpps[inst]->inst;
-               pipe_ctx->pipe_idx = inst;
+               if (pool->dpps[tg_inst])
+                       pipe_ctx->plane_res.mpcc_inst = pool->dpps[tg_inst]->inst;
+               pipe_ctx->pipe_idx = tg_inst;
 
                pipe_ctx->stream = stream;
-               return inst;
+               return tg_inst;
        }
 
        return -1;
index 1bda7cb..bee81bf 100644 (file)
@@ -1061,7 +1061,8 @@ static bool dcn20_program_pix_clk(
 static const struct clock_source_funcs dcn20_clk_src_funcs = {
        .cs_power_down = dce110_clock_source_power_down,
        .program_pix_clk = dcn20_program_pix_clk,
-       .get_pix_clk_dividers = dce112_get_pix_clk_dividers
+       .get_pix_clk_dividers = dce112_get_pix_clk_dividers,
+       .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
 };
 #endif
 
index b87a265..6ed922a 100644 (file)
@@ -1602,6 +1602,17 @@ static void dig_connect_to_otg(
        REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst);
 }
 
+static unsigned int dig_source_otg(
+       struct stream_encoder *enc)
+{
+       uint32_t tg_inst = 0;
+       struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+
+       REG_GET(DIG_FE_CNTL, DIG_SOURCE_SELECT, &tg_inst);
+
+       return tg_inst;
+}
+
 static const struct stream_encoder_funcs dce110_str_enc_funcs = {
        .dp_set_stream_attribute =
                dce110_stream_encoder_dp_set_stream_attribute,
@@ -1637,6 +1648,7 @@ static const struct stream_encoder_funcs dce110_str_enc_funcs = {
        .set_avmute = dce110_stream_encoder_set_avmute,
        .dig_connect_to_otg  = dig_connect_to_otg,
        .hdmi_reset_stream_attribute = dce110_reset_hdmi_stream_attribute,
+       .dig_source_otg = dig_source_otg,
 };
 
 void dce110_stream_encoder_construct(
index 285a793..d1697a1 100644 (file)
@@ -1098,9 +1098,16 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
                }
        }
 
-       /* Cannot reset the MPC mux if seamless boot */
-       if (!can_apply_seamless_boot)
-               dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc);
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+               /* Cannot reset the MPC mux if seamless boot */
+               if (pipe_ctx->stream != NULL && can_apply_seamless_boot)
+                       continue;
+
+               dc->res_pool->mpc->funcs->mpc_init_single_inst(
+                               dc->res_pool->mpc, i);
+       }
 
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                struct timing_generator *tg = dc->res_pool->timing_generators[i];
index 549d423..5c19661 100644 (file)
@@ -446,6 +446,46 @@ static uint8_t get_frontend_source(
        }
 }
 
+unsigned int dcn10_get_dig_frontend(struct link_encoder *enc)
+{
+       struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
+       int32_t value;
+       enum engine_id result;
+
+       REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &value);
+
+       switch (value) {
+       case DCN10_DIG_FE_SOURCE_SELECT_DIGA:
+               result = ENGINE_ID_DIGA;
+               break;
+       case DCN10_DIG_FE_SOURCE_SELECT_DIGB:
+               result = ENGINE_ID_DIGB;
+               break;
+       case DCN10_DIG_FE_SOURCE_SELECT_DIGC:
+               result = ENGINE_ID_DIGC;
+               break;
+       case DCN10_DIG_FE_SOURCE_SELECT_DIGD:
+               result = ENGINE_ID_DIGD;
+               break;
+       case DCN10_DIG_FE_SOURCE_SELECT_DIGE:
+               result = ENGINE_ID_DIGE;
+               break;
+       case DCN10_DIG_FE_SOURCE_SELECT_DIGF:
+               result = ENGINE_ID_DIGF;
+               break;
+       case DCN10_DIG_FE_SOURCE_SELECT_DIGG:
+               result = ENGINE_ID_DIGG;
+               break;
+       default:
+               // invalid source select DIG
+               ASSERT(false);
+               result = ENGINE_ID_UNKNOWN;
+       }
+
+       return result;
+
+}
+
 void enc1_configure_encoder(
        struct dcn10_link_encoder *enc10,
        const struct dc_link_settings *link_settings)
@@ -501,15 +541,6 @@ bool dcn10_is_dig_enabled(struct link_encoder *enc)
        return value;
 }
 
-unsigned int dcn10_get_dig_frontend(struct link_encoder *enc)
-{
-       struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
-       uint32_t value;
-
-       REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &value);
-       return value;
-}
-
 static void link_encoder_disable(struct dcn10_link_encoder *enc10)
 {
        /* reset training pattern */
index 4f7a103..8b2f29f 100644 (file)
@@ -364,6 +364,24 @@ void mpc1_mpc_init(struct mpc *mpc)
        }
 }
 
+void mpc1_mpc_init_single_inst(struct mpc *mpc, unsigned int mpcc_id)
+{
+       struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
+       int opp_id;
+
+       REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id);
+
+       REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
+       REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
+       REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf);
+
+       mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id);
+
+       if (opp_id < MAX_OPP && REG(MUX[opp_id]))
+               REG_UPDATE(MUX[opp_id], MPC_OUT_MUX, 0xf);
+}
+
+
 void mpc1_init_mpcc_list_from_hw(
        struct mpc *mpc,
        struct mpc_tree *tree)
@@ -433,6 +451,7 @@ static const struct mpc_funcs dcn10_mpc_funcs = {
        .insert_plane = mpc1_insert_plane,
        .remove_mpcc = mpc1_remove_mpcc,
        .mpc_init = mpc1_mpc_init,
+       .mpc_init_single_inst = mpc1_mpc_init_single_inst,
        .get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp,
        .wait_for_idle = mpc1_assert_idle_mpcc,
        .assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect,
index d3d16c4..962a68e 100644 (file)
@@ -149,6 +149,10 @@ void mpc1_remove_mpcc(
 void mpc1_mpc_init(
        struct mpc *mpc);
 
+void mpc1_mpc_init_single_inst(
+       struct mpc *mpc,
+       unsigned int mpcc_id);
+
 void mpc1_assert_idle_mpcc(
        struct mpc *mpc,
        int id);
index 02599eb..66c08d0 100644 (file)
@@ -539,6 +539,10 @@ struct dcn_otg_state {
 void optc1_read_otg_state(struct optc *optc1,
                struct dcn_otg_state *s);
 
+bool optc1_is_matching_timing(
+       struct timing_generator *tg,
+       const struct dc_crtc_timing *otg_timing);
+
 bool optc1_validate_timing(
        struct timing_generator *optc,
        const struct dc_crtc_timing *timing);
index c2bba88..9aa258f 100644 (file)
@@ -1542,6 +1542,17 @@ void enc1_dig_connect_to_otg(
        REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst);
 }
 
+unsigned int enc1_dig_source_otg(
+       struct stream_encoder *enc)
+{
+       uint32_t tg_inst = 0;
+       struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
+
+       REG_GET(DIG_FE_CNTL, DIG_SOURCE_SELECT, &tg_inst);
+
+       return tg_inst;
+}
+
 static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
        .dp_set_stream_attribute =
                enc1_stream_encoder_dp_set_stream_attribute,
@@ -1577,6 +1588,7 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = {
        .set_avmute = enc1_stream_encoder_set_avmute,
        .dig_connect_to_otg  = enc1_dig_connect_to_otg,
        .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute,
+       .dig_source_otg = enc1_dig_source_otg,
 };
 
 void dcn10_stream_encoder_construct(
index 8b8921e..a512cbe 100644 (file)
@@ -598,6 +598,9 @@ void enc1_dig_connect_to_otg(
        struct stream_encoder *enc,
        int tg_inst);
 
+unsigned int enc1_dig_source_otg(
+       struct stream_encoder *enc);
+
 void enc1_stream_encoder_set_stream_attribute_helper(
        struct dcn10_stream_encoder *enc1,
        struct dc_crtc_timing *crtc_timing);
index 67f0128..17950d9 100644 (file)
@@ -498,6 +498,7 @@ const struct mpc_funcs dcn20_mpc_funcs = {
        .insert_plane = mpc1_insert_plane,
        .remove_mpcc = mpc1_remove_mpcc,
        .mpc_init = mpc1_mpc_init,
+       .mpc_init_single_inst = mpc1_mpc_init_single_inst,
        .update_blending = mpc2_update_blending,
        .get_mpcc_for_dpp = mpc2_get_mpcc_for_dpp,
        .wait_for_idle = mpc2_assert_idle_mpcc,
index 1ae9739..6dede49 100644 (file)
@@ -522,7 +522,8 @@ static struct timing_generator_funcs dcn20_tg_funcs = {
                .set_gsl_source_select = optc2_set_gsl_source_select,
                .set_vtg_params = optc1_set_vtg_params,
                .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
 };
 
 void dcn20_timing_generator_init(struct optc *optc1)
index 45df7f5..8842895 100644 (file)
@@ -580,6 +580,7 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = {
        .setup_stereo_sync  = enc1_setup_stereo_sync,
        .set_avmute = enc1_stream_encoder_set_avmute,
        .dig_connect_to_otg  = enc1_dig_connect_to_otg,
+       .dig_source_otg = enc1_dig_source_otg,
 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
        .enc_read_state = enc2_read_state,
 #endif
index 9f00289..9dde88d 100644 (file)
@@ -199,6 +199,9 @@ struct mpc_funcs {
         * Return:  void
         */
        void (*mpc_init)(struct mpc *mpc);
+       void (*mpc_init_single_inst)(
+                       struct mpc *mpc,
+                       unsigned int mpcc_id);
 
        /*
         * Update the blending configuration for a specified MPCC.
index 38e2c3e..067ba6f 100644 (file)
@@ -214,6 +214,9 @@ struct stream_encoder_funcs {
        void (*hdmi_reset_stream_attribute)(
                struct stream_encoder *enc);
 
+       unsigned int (*dig_source_otg)(
+               struct stream_encoder *enc);
+
 #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
        void (*dp_set_dsc_config)(