Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2016 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "dm_services.h"
0027 #include "basics/dc_common.h"
0028 #include "core_types.h"
0029 #include "resource.h"
0030 #include "dcn201_hwseq.h"
0031 #include "dcn201_optc.h"
0032 #include "dce/dce_hwseq.h"
0033 #include "hubp.h"
0034 #include "dchubbub.h"
0035 #include "timing_generator.h"
0036 #include "opp.h"
0037 #include "ipp.h"
0038 #include "mpc.h"
0039 #include "dccg.h"
0040 #include "clk_mgr.h"
0041 #include "reg_helper.h"
0042 
0043 #define CTX \
0044     hws->ctx
0045 
0046 #define REG(reg)\
0047     hws->regs->reg
0048 
0049 #define DC_LOGGER \
0050     dc->ctx->logger
0051 
0052 #undef FN
0053 #define FN(reg_name, field_name) \
0054     hws->shifts->field_name, hws->masks->field_name
0055 
0056 static bool patch_address_for_sbs_tb_stereo(
0057         struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
0058 {
0059     struct dc_plane_state *plane_state = pipe_ctx->plane_state;
0060     bool sec_split = pipe_ctx->top_pipe &&
0061         pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
0062 
0063     if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
0064         (pipe_ctx->stream->timing.timing_3d_format ==
0065             TIMING_3D_FORMAT_SIDE_BY_SIDE ||
0066         pipe_ctx->stream->timing.timing_3d_format ==
0067             TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
0068         *addr = plane_state->address.grph_stereo.left_addr;
0069         plane_state->address.grph_stereo.left_addr =
0070             plane_state->address.grph_stereo.right_addr;
0071         return true;
0072     } else {
0073         if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
0074             plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
0075             plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
0076             plane_state->address.grph_stereo.right_addr =
0077             plane_state->address.grph_stereo.left_addr;
0078             plane_state->address.grph_stereo.right_meta_addr =
0079             plane_state->address.grph_stereo.left_meta_addr;
0080         }
0081     }
0082     return false;
0083 }
0084 
0085 static void gpu_addr_to_uma(struct dce_hwseq *hwseq,
0086         PHYSICAL_ADDRESS_LOC *addr)
0087 {
0088     bool is_in_uma;
0089 
0090     if (hwseq->fb_base.quad_part <= addr->quad_part &&
0091             addr->quad_part < hwseq->fb_top.quad_part) {
0092         addr->quad_part -= hwseq->fb_base.quad_part;
0093         addr->quad_part += hwseq->fb_offset.quad_part;
0094         is_in_uma = true;
0095     } else if (hwseq->fb_offset.quad_part <= addr->quad_part &&
0096             addr->quad_part <= hwseq->uma_top.quad_part) {
0097         is_in_uma = true;
0098     } else {
0099         is_in_uma = false;
0100     }
0101 }
0102 
0103 static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq,
0104         struct dc_plane_address *addr)
0105 {
0106     switch (addr->type) {
0107     case PLN_ADDR_TYPE_GRAPHICS:
0108         gpu_addr_to_uma(hwseq, &addr->grph.addr);
0109         gpu_addr_to_uma(hwseq, &addr->grph.meta_addr);
0110         break;
0111     case PLN_ADDR_TYPE_GRPH_STEREO:
0112         gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_addr);
0113         gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_meta_addr);
0114         gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_addr);
0115         gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_meta_addr);
0116         break;
0117     case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
0118         gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_addr);
0119         gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_meta_addr);
0120         gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_addr);
0121         gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_meta_addr);
0122         break;
0123     default:
0124         BREAK_TO_DEBUGGER();
0125         break;
0126     }
0127 }
0128 
0129 void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
0130 {
0131     bool addr_patched = false;
0132     PHYSICAL_ADDRESS_LOC addr;
0133     struct dc_plane_state *plane_state = pipe_ctx->plane_state;
0134     struct dce_hwseq *hws = dc->hwseq;
0135     struct dc_plane_address uma;
0136 
0137     if (plane_state == NULL)
0138         return;
0139 
0140     uma = plane_state->address;
0141     addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
0142 
0143     plane_address_in_gpu_space_to_uma(hws, &uma);
0144 
0145     pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
0146             pipe_ctx->plane_res.hubp,
0147             &uma,
0148             plane_state->flip_immediate);
0149 
0150     plane_state->status.requested_address = plane_state->address;
0151 
0152     if (plane_state->flip_immediate)
0153         plane_state->status.current_address = plane_state->address;
0154 
0155     if (addr_patched)
0156         pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
0157 }
0158 
0159 /* Blank pixel data during initialization */
0160 void dcn201_init_blank(
0161         struct dc *dc,
0162         struct timing_generator *tg)
0163 {
0164     struct dce_hwseq *hws = dc->hwseq;
0165     enum dc_color_space color_space;
0166     struct tg_color black_color = {0};
0167     struct output_pixel_processor *opp = NULL;
0168     uint32_t num_opps, opp_id_src0, opp_id_src1;
0169     uint32_t otg_active_width, otg_active_height;
0170 
0171     /* program opp dpg blank color */
0172     color_space = COLOR_SPACE_SRGB;
0173     color_space_to_black_color(dc, color_space, &black_color);
0174 
0175     /* get the OTG active size */
0176     tg->funcs->get_otg_active_size(tg,
0177             &otg_active_width,
0178             &otg_active_height);
0179 
0180     /* get the OPTC source */
0181     tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
0182     ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp);
0183     opp = dc->res_pool->opps[opp_id_src0];
0184 
0185     opp->funcs->opp_set_disp_pattern_generator(
0186             opp,
0187             CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
0188             CONTROLLER_DP_COLOR_SPACE_UDEFINED,
0189             COLOR_DEPTH_UNDEFINED,
0190             &black_color,
0191             otg_active_width,
0192             otg_active_height,
0193             0);
0194 
0195     hws->funcs.wait_for_blank_complete(opp);
0196 }
0197 
0198 static void read_mmhub_vm_setup(struct dce_hwseq *hws)
0199 {
0200     uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE);
0201     uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP);
0202     uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET);
0203 
0204     /* MC_VM_FB_LOCATION_TOP is in pages, actual top should add 1 */
0205     fb_top++;
0206 
0207     /* bit 23:0 in register map to bit 47:24 in address */
0208     hws->fb_base.low_part = fb_base;
0209     hws->fb_base.quad_part <<= 24;
0210 
0211     hws->fb_top.low_part  = fb_top;
0212     hws->fb_top.quad_part <<= 24;
0213     hws->fb_offset.low_part = fb_offset;
0214     hws->fb_offset.quad_part <<= 24;
0215 
0216     hws->uma_top.quad_part = hws->fb_top.quad_part
0217             - hws->fb_base.quad_part + hws->fb_offset.quad_part;
0218 }
0219 
0220 void dcn201_init_hw(struct dc *dc)
0221 {
0222     int i, j;
0223     struct dce_hwseq *hws = dc->hwseq;
0224     struct resource_pool *res_pool = dc->res_pool;
0225     struct dc_state  *context = dc->current_state;
0226 
0227     if (res_pool->dccg->funcs->dccg_init)
0228         res_pool->dccg->funcs->dccg_init(res_pool->dccg);
0229 
0230     if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
0231         dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
0232 
0233     if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
0234         REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);
0235         REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);
0236 
0237         hws->funcs.dccg_init(hws);
0238 
0239         REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);
0240         REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
0241         REG_WRITE(REFCLK_CNTL, 0);
0242     } else {
0243         hws->funcs.bios_golden_init(dc);
0244 
0245         if (dc->ctx->dc_bios->fw_info_valid) {
0246             res_pool->ref_clocks.xtalin_clock_inKhz =
0247                 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
0248 
0249             if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
0250                 if (res_pool->dccg && res_pool->hubbub) {
0251                     (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
0252                             dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
0253                             &res_pool->ref_clocks.dccg_ref_clock_inKhz);
0254 
0255                     (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
0256                             res_pool->ref_clocks.dccg_ref_clock_inKhz,
0257                             &res_pool->ref_clocks.dchub_ref_clock_inKhz);
0258                 } else {
0259                     res_pool->ref_clocks.dccg_ref_clock_inKhz =
0260                             res_pool->ref_clocks.xtalin_clock_inKhz;
0261                     res_pool->ref_clocks.dchub_ref_clock_inKhz =
0262                             res_pool->ref_clocks.xtalin_clock_inKhz;
0263                 }
0264             }
0265         } else
0266             ASSERT_CRITICAL(false);
0267         for (i = 0; i < dc->link_count; i++) {
0268             /* Power up AND update implementation according to the
0269              * required signal (which may be different from the
0270              * default signal on connector).
0271              */
0272             struct dc_link *link = dc->links[i];
0273 
0274             link->link_enc->funcs->hw_init(link->link_enc);
0275         }
0276         if (hws->fb_offset.quad_part == 0)
0277             read_mmhub_vm_setup(hws);
0278     }
0279 
0280     /* Blank pixel data with OPP DPG */
0281     for (i = 0; i < res_pool->timing_generator_count; i++) {
0282         struct timing_generator *tg = res_pool->timing_generators[i];
0283 
0284         if (tg->funcs->is_tg_enabled(tg)) {
0285             dcn201_init_blank(dc, tg);
0286         }
0287     }
0288 
0289     for (i = 0; i < res_pool->timing_generator_count; i++) {
0290         struct timing_generator *tg = res_pool->timing_generators[i];
0291 
0292         if (tg->funcs->is_tg_enabled(tg))
0293             tg->funcs->lock(tg);
0294     }
0295 
0296     for (i = 0; i < res_pool->pipe_count; i++) {
0297         struct dpp *dpp = res_pool->dpps[i];
0298 
0299         dpp->funcs->dpp_reset(dpp);
0300     }
0301 
0302     /* Reset all MPCC muxes */
0303     res_pool->mpc->funcs->mpc_init(res_pool->mpc);
0304 
0305     /* initialize OPP mpc_tree parameter */
0306     for (i = 0; i < res_pool->res_cap->num_opp; i++) {
0307         res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
0308         res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
0309         for (j = 0; j < MAX_PIPES; j++)
0310             res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
0311     }
0312 
0313     for (i = 0; i < res_pool->timing_generator_count; i++) {
0314         struct timing_generator *tg = res_pool->timing_generators[i];
0315         struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
0316         struct hubp *hubp = res_pool->hubps[i];
0317         struct dpp *dpp = res_pool->dpps[i];
0318 
0319         pipe_ctx->stream_res.tg = tg;
0320         pipe_ctx->pipe_idx = i;
0321 
0322         pipe_ctx->plane_res.hubp = hubp;
0323         pipe_ctx->plane_res.dpp = dpp;
0324         pipe_ctx->plane_res.mpcc_inst = dpp->inst;
0325         hubp->mpcc_id = dpp->inst;
0326         hubp->opp_id = OPP_ID_INVALID;
0327         hubp->power_gated = false;
0328         pipe_ctx->stream_res.opp = NULL;
0329 
0330         hubp->funcs->hubp_init(hubp);
0331 
0332         res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
0333         pipe_ctx->stream_res.opp = res_pool->opps[i];
0334         /*To do: number of MPCC != number of opp*/
0335         hws->funcs.plane_atomic_disconnect(dc, pipe_ctx);
0336     }
0337 
0338     /* initialize DWB pointer to MCIF_WB */
0339     for (i = 0; i < res_pool->res_cap->num_dwb; i++)
0340         res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
0341 
0342     for (i = 0; i < res_pool->timing_generator_count; i++) {
0343         struct timing_generator *tg = res_pool->timing_generators[i];
0344 
0345         if (tg->funcs->is_tg_enabled(tg))
0346             tg->funcs->unlock(tg);
0347     }
0348 
0349     for (i = 0; i < res_pool->pipe_count; i++) {
0350         struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
0351 
0352         dc->hwss.disable_plane(dc, pipe_ctx);
0353 
0354         pipe_ctx->stream_res.tg = NULL;
0355         pipe_ctx->plane_res.hubp = NULL;
0356     }
0357 
0358     for (i = 0; i < res_pool->timing_generator_count; i++) {
0359         struct timing_generator *tg = res_pool->timing_generators[i];
0360 
0361         tg->funcs->tg_init(tg);
0362     }
0363 
0364     /* end of FPGA. Below if real ASIC */
0365     if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
0366         return;
0367 
0368     for (i = 0; i < res_pool->audio_count; i++) {
0369         struct audio *audio = res_pool->audios[i];
0370 
0371         audio->funcs->hw_init(audio);
0372     }
0373 
0374     /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
0375     REG_WRITE(DIO_MEM_PWR_CTRL, 0);
0376 
0377     if (!dc->debug.disable_clock_gate) {
0378         /* enable all DCN clock gating */
0379         REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
0380 
0381         REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
0382 
0383         REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
0384     }
0385 }
0386 
0387 /* trigger HW to start disconnect plane from stream on the next vsync */
0388 void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx)
0389 {
0390     struct dce_hwseq *hws = dc->hwseq;
0391     struct hubp *hubp = pipe_ctx->plane_res.hubp;
0392     int dpp_id = pipe_ctx->plane_res.dpp->inst;
0393     struct mpc *mpc = dc->res_pool->mpc;
0394     struct mpc_tree *mpc_tree_params;
0395     struct mpcc *mpcc_to_remove = NULL;
0396     struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
0397     bool mpcc_removed = false;
0398 
0399     mpc_tree_params = &(opp->mpc_tree_params);
0400 
0401     /* check if this plane is being used by an MPCC in the secondary blending chain */
0402     if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
0403         mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
0404 
0405     /* remove MPCC from secondary if being used */
0406     if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) {
0407         mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove);
0408         mpcc_removed = true;
0409     }
0410 
0411     /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
0412     mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
0413     if (mpcc_to_remove != NULL) {
0414         mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
0415         mpcc_removed = true;
0416     }
0417 
0418     /*Already reset*/
0419     if (mpcc_removed == false)
0420         return;
0421 
0422     if (opp != NULL)
0423         opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
0424 
0425     dc->optimized_required = true;
0426 
0427     if (hubp->funcs->hubp_disconnect)
0428         hubp->funcs->hubp_disconnect(hubp);
0429 
0430     if (dc->debug.sanity_checks)
0431         hws->funcs.verify_allow_pstate_change_high(dc);
0432 }
0433 
0434 void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
0435 {
0436     struct hubp *hubp = pipe_ctx->plane_res.hubp;
0437     struct mpcc_blnd_cfg blnd_cfg;
0438     bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
0439     int mpcc_id, dpp_id;
0440     struct mpcc *new_mpcc;
0441     struct mpcc *remove_mpcc = NULL;
0442     struct mpc *mpc = dc->res_pool->mpc;
0443     struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
0444 
0445     if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
0446         get_hdr_visual_confirm_color(
0447                 pipe_ctx, &blnd_cfg.black_color);
0448     } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) {
0449         get_surface_visual_confirm_color(
0450                 pipe_ctx, &blnd_cfg.black_color);
0451     } else {
0452         color_space_to_black_color(
0453                 dc, pipe_ctx->stream->output_color_space,
0454                 &blnd_cfg.black_color);
0455     }
0456 
0457     if (per_pixel_alpha)
0458         blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
0459     else
0460         blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
0461 
0462     blnd_cfg.overlap_only = false;
0463 
0464     if (pipe_ctx->plane_state->global_alpha_value)
0465         blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
0466     else
0467         blnd_cfg.global_alpha = 0xff;
0468 
0469     blnd_cfg.global_gain = 0xff;
0470     blnd_cfg.background_color_bpc = 4;
0471     blnd_cfg.bottom_gain_mode = 0;
0472     blnd_cfg.top_gain = 0x1f000;
0473     blnd_cfg.bottom_inside_gain = 0x1f000;
0474     blnd_cfg.bottom_outside_gain = 0x1f000;
0475     /*the input to MPCC is RGB*/
0476     blnd_cfg.black_color.color_b_cb = 0;
0477     blnd_cfg.black_color.color_g_y = 0;
0478     blnd_cfg.black_color.color_r_cr = 0;
0479 
0480     /* DCN1.0 has output CM before MPC which seems to screw with
0481      * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2.
0482      */
0483     blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
0484 
0485     /*
0486      * TODO: remove hack
0487      * Note: currently there is a bug in init_hw such that
0488      * on resume from hibernate, BIOS sets up MPCC0, and
0489      * we do mpcc_remove but the mpcc cannot go to idle
0490      * after remove. This cause us to pick mpcc1 here,
0491      * which causes a pstate hang for yet unknown reason.
0492      */
0493     dpp_id = hubp->inst;
0494     mpcc_id = dpp_id;
0495 
0496     /* If there is no full update, don't need to touch MPC tree*/
0497     if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
0498         dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
0499         mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
0500         return;
0501     }
0502 
0503     /* check if this plane is being used by an MPCC in the secondary blending chain */
0504     if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
0505         remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
0506 
0507     /* remove MPCC from secondary if being used */
0508     if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary)
0509         mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc);
0510 
0511     /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
0512     remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
0513     /* remove MPCC if being used */
0514 
0515     if (remove_mpcc != NULL)
0516         mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc);
0517     else
0518         if (dc->debug.sanity_checks)
0519             mpc->funcs->assert_mpcc_idle_before_connect(
0520                     dc->res_pool->mpc, mpcc_id);
0521 
0522     /* Call MPC to insert new plane */
0523     dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
0524     new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
0525             mpc_tree_params,
0526             &blnd_cfg,
0527             NULL,
0528             NULL,
0529             dpp_id,
0530             mpcc_id);
0531 
0532     ASSERT(new_mpcc != NULL);
0533     hubp->opp_id = pipe_ctx->stream_res.opp->inst;
0534     hubp->mpcc_id = mpcc_id;
0535 }
0536 
0537 void dcn201_pipe_control_lock(
0538     struct dc *dc,
0539     struct pipe_ctx *pipe,
0540     bool lock)
0541 {
0542     struct dce_hwseq *hws = dc->hwseq;
0543     struct hubp *hubp = NULL;
0544     hubp = dc->res_pool->hubps[pipe->pipe_idx];
0545     /* use TG master update lock to lock everything on the TG
0546      * therefore only top pipe need to lock
0547      */
0548     if (pipe->top_pipe)
0549         return;
0550 
0551     if (dc->debug.sanity_checks)
0552         hws->funcs.verify_allow_pstate_change_high(dc);
0553 
0554     if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
0555         if (lock)
0556             pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
0557         else
0558             pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
0559     } else {
0560         if (lock)
0561             pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
0562         else
0563             pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
0564     }
0565 
0566     if (dc->debug.sanity_checks)
0567         hws->funcs.verify_allow_pstate_change_high(dc);
0568 }
0569 
0570 void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
0571 {
0572     struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
0573 
0574     gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address);
0575 
0576     pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
0577             pipe_ctx->plane_res.hubp, attributes);
0578     pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
0579         pipe_ctx->plane_res.dpp, attributes);
0580 }
0581 
0582 void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
0583 {
0584     struct dc_dmdata_attributes attr = { 0 };
0585     struct hubp *hubp = pipe_ctx->plane_res.hubp;
0586 
0587     gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq,
0588             &pipe_ctx->stream->dmdata_address);
0589 
0590     attr.dmdata_mode = DMDATA_HW_MODE;
0591     attr.dmdata_size =
0592         dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
0593     attr.address.quad_part =
0594             pipe_ctx->stream->dmdata_address.quad_part;
0595     attr.dmdata_dl_delta = 0;
0596     attr.dmdata_qos_mode = 0;
0597     attr.dmdata_qos_level = 0;
0598     attr.dmdata_repeat = 1; /* always repeat */
0599     attr.dmdata_updated = 1;
0600     attr.dmdata_sw_data = NULL;
0601 
0602     hubp->funcs->dmdata_set_attributes(hubp, &attr);
0603 }
0604 
0605 void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
0606         struct dc_link_settings *link_settings)
0607 {
0608     struct encoder_unblank_param params = { { 0 } };
0609     struct dc_stream_state *stream = pipe_ctx->stream;
0610     struct dc_link *link = stream->link;
0611     struct dce_hwseq *hws = link->dc->hwseq;
0612 
0613     /* only 3 items below are used by unblank */
0614     params.timing = pipe_ctx->stream->timing;
0615 
0616     params.link_settings.link_rate = link_settings->link_rate;
0617 
0618     if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
0619         /*check whether it is half the rate*/
0620         if (optc201_is_two_pixels_per_containter(&stream->timing))
0621             params.timing.pix_clk_100hz /= 2;
0622 
0623         pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
0624     }
0625 
0626     if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
0627         hws->funcs.edp_backlight_control(link, true);
0628     }
0629 }