Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2020 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 
0027 #include "dm_services.h"
0028 #include "dm_helpers.h"
0029 #include "core_types.h"
0030 #include "resource.h"
0031 #include "dcn30_hwseq.h"
0032 #include "dccg.h"
0033 #include "dce/dce_hwseq.h"
0034 #include "dcn30_mpc.h"
0035 #include "dcn30_dpp.h"
0036 #include "dcn10/dcn10_cm_common.h"
0037 #include "dcn30_cm_common.h"
0038 #include "reg_helper.h"
0039 #include "abm.h"
0040 #include "clk_mgr.h"
0041 #include "hubp.h"
0042 #include "dchubbub.h"
0043 #include "timing_generator.h"
0044 #include "opp.h"
0045 #include "ipp.h"
0046 #include "mpc.h"
0047 #include "mcif_wb.h"
0048 #include "dc_dmub_srv.h"
0049 #include "link_hwss.h"
0050 #include "dpcd_defs.h"
0051 #include "../dcn20/dcn20_hwseq.h"
0052 #include "dcn30_resource.h"
0053 #include "inc/dc_link_dp.h"
0054 #include "inc/link_dpcd.h"
0055 
0056 
0057 
0058 
0059 #define DC_LOGGER_INIT(logger)
0060 
0061 #define CTX \
0062     hws->ctx
0063 #define REG(reg)\
0064     hws->regs->reg
0065 #define DC_LOGGER \
0066         dc->ctx->logger
0067 
0068 
0069 #undef FN
0070 #define FN(reg_name, field_name) \
0071     hws->shifts->field_name, hws->masks->field_name
0072 
0073 bool dcn30_set_blend_lut(
0074     struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
0075 {
0076     struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
0077     bool result = true;
0078     struct pwl_params *blend_lut = NULL;
0079 
0080     if (plane_state->blend_tf) {
0081         if (plane_state->blend_tf->type == TF_TYPE_HWPWL)
0082             blend_lut = &plane_state->blend_tf->pwl;
0083         else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
0084             cm3_helper_translate_curve_to_hw_format(
0085                     plane_state->blend_tf, &dpp_base->regamma_params, false);
0086             blend_lut = &dpp_base->regamma_params;
0087         }
0088     }
0089     result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut);
0090 
0091     return result;
0092 }
0093 
0094 static bool dcn30_set_mpc_shaper_3dlut(
0095     struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream)
0096 {
0097     struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
0098     int mpcc_id = pipe_ctx->plane_res.hubp->inst;
0099     struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
0100     bool result = false;
0101     int acquired_rmu = 0;
0102     int mpcc_id_projected = 0;
0103 
0104     const struct pwl_params *shaper_lut = NULL;
0105     //get the shaper lut params
0106     if (stream->func_shaper) {
0107         if (stream->func_shaper->type == TF_TYPE_HWPWL)
0108             shaper_lut = &stream->func_shaper->pwl;
0109         else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
0110             cm_helper_translate_curve_to_hw_format(
0111                     stream->func_shaper,
0112                     &dpp_base->shaper_params, true);
0113             shaper_lut = &dpp_base->shaper_params;
0114         }
0115     }
0116 
0117     if (stream->lut3d_func &&
0118         stream->lut3d_func->state.bits.initialized == 1 &&
0119         stream->lut3d_func->state.bits.rmu_idx_valid == 1) {
0120         if (stream->lut3d_func->state.bits.rmu_mux_num == 0)
0121             mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu0_mux;
0122         else if (stream->lut3d_func->state.bits.rmu_mux_num == 1)
0123             mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu1_mux;
0124         else if (stream->lut3d_func->state.bits.rmu_mux_num == 2)
0125             mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu2_mux;
0126         if (mpcc_id_projected != mpcc_id)
0127             BREAK_TO_DEBUGGER();
0128         /*find the reason why logical layer assigned a differant mpcc_id into acquire_post_bldn_3dlut*/
0129         acquired_rmu = mpc->funcs->acquire_rmu(mpc, mpcc_id,
0130                 stream->lut3d_func->state.bits.rmu_mux_num);
0131         if (acquired_rmu != stream->lut3d_func->state.bits.rmu_mux_num)
0132             BREAK_TO_DEBUGGER();
0133         result = mpc->funcs->program_3dlut(mpc,
0134                                 &stream->lut3d_func->lut_3d,
0135                                 stream->lut3d_func->state.bits.rmu_mux_num);
0136         result = mpc->funcs->program_shaper(mpc, shaper_lut,
0137                 stream->lut3d_func->state.bits.rmu_mux_num);
0138     } else
0139         /*loop through the available mux and release the requested mpcc_id*/
0140         mpc->funcs->release_rmu(mpc, mpcc_id);
0141 
0142 
0143     return result;
0144 }
0145 
0146 bool dcn30_set_input_transfer_func(struct dc *dc,
0147                 struct pipe_ctx *pipe_ctx,
0148                 const struct dc_plane_state *plane_state)
0149 {
0150     struct dce_hwseq *hws = dc->hwseq;
0151     struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
0152     enum dc_transfer_func_predefined tf;
0153     bool result = true;
0154     struct pwl_params *params = NULL;
0155 
0156     if (dpp_base == NULL || plane_state == NULL)
0157         return false;
0158 
0159     tf = TRANSFER_FUNCTION_UNITY;
0160 
0161     if (plane_state->in_transfer_func &&
0162         plane_state->in_transfer_func->type == TF_TYPE_PREDEFINED)
0163         tf = plane_state->in_transfer_func->tf;
0164 
0165     dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf);
0166 
0167     if (plane_state->in_transfer_func) {
0168         if (plane_state->in_transfer_func->type == TF_TYPE_HWPWL)
0169             params = &plane_state->in_transfer_func->pwl;
0170         else if (plane_state->in_transfer_func->type == TF_TYPE_DISTRIBUTED_POINTS &&
0171             cm3_helper_translate_curve_to_hw_format(plane_state->in_transfer_func,
0172                     &dpp_base->degamma_params, false))
0173             params = &dpp_base->degamma_params;
0174     }
0175 
0176     result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
0177 
0178     if (pipe_ctx->stream_res.opp && pipe_ctx->stream_res.opp->ctx) {
0179         if (dpp_base->funcs->dpp_program_blnd_lut)
0180             hws->funcs.set_blend_lut(pipe_ctx, plane_state);
0181         if (dpp_base->funcs->dpp_program_shaper_lut &&
0182                 dpp_base->funcs->dpp_program_3dlut)
0183             hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state);
0184     }
0185 
0186     return result;
0187 }
0188 
0189 bool dcn30_set_output_transfer_func(struct dc *dc,
0190                 struct pipe_ctx *pipe_ctx,
0191                 const struct dc_stream_state *stream)
0192 {
0193     int mpcc_id = pipe_ctx->plane_res.hubp->inst;
0194     struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
0195     struct pwl_params *params = NULL;
0196     bool ret = false;
0197 
0198     /* program OGAM or 3DLUT only for the top pipe*/
0199     if (pipe_ctx->top_pipe == NULL) {
0200         /*program rmu shaper and 3dlut in MPC*/
0201         ret = dcn30_set_mpc_shaper_3dlut(pipe_ctx, stream);
0202         if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) {
0203             if (stream->out_transfer_func->type == TF_TYPE_HWPWL)
0204                 params = &stream->out_transfer_func->pwl;
0205             else if (pipe_ctx->stream->out_transfer_func->type ==
0206                     TF_TYPE_DISTRIBUTED_POINTS &&
0207                     cm3_helper_translate_curve_to_hw_format(
0208                     stream->out_transfer_func,
0209                     &mpc->blender_params, false))
0210                 params = &mpc->blender_params;
0211              /* there are no ROM LUTs in OUTGAM */
0212             if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED)
0213                 BREAK_TO_DEBUGGER();
0214         }
0215     }
0216 
0217     mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
0218     return ret;
0219 }
0220 
0221 static void dcn30_set_writeback(
0222         struct dc *dc,
0223         struct dc_writeback_info *wb_info,
0224         struct dc_state *context)
0225 {
0226     struct mcif_wb *mcif_wb;
0227     struct mcif_buf_params *mcif_buf_params;
0228 
0229     ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES);
0230     ASSERT(wb_info->wb_enabled);
0231     ASSERT(wb_info->mpcc_inst >= 0);
0232     ASSERT(wb_info->mpcc_inst < dc->res_pool->mpcc_count);
0233     mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
0234     mcif_buf_params = &wb_info->mcif_buf_params;
0235 
0236     /* set DWB MPC mux */
0237     dc->res_pool->mpc->funcs->set_dwb_mux(dc->res_pool->mpc,
0238             wb_info->dwb_pipe_inst, wb_info->mpcc_inst);
0239     /* set MCIF_WB buffer and arbitration configuration */
0240     mcif_wb->funcs->config_mcif_buf(mcif_wb, mcif_buf_params, wb_info->dwb_params.dest_height);
0241     mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
0242 }
0243 
0244 void dcn30_update_writeback(
0245         struct dc *dc,
0246         struct dc_writeback_info *wb_info,
0247         struct dc_state *context)
0248 {
0249     struct dwbc *dwb;
0250     dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
0251     DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\
0252         __func__, wb_info->dwb_pipe_inst,\
0253         wb_info->mpcc_inst);
0254 
0255     dcn30_set_writeback(dc, wb_info, context);
0256 
0257     /* update DWB */
0258     dwb->funcs->update(dwb, &wb_info->dwb_params);
0259 }
0260 
0261 bool dcn30_mmhubbub_warmup(
0262     struct dc *dc,
0263     unsigned int num_dwb,
0264     struct dc_writeback_info *wb_info)
0265 {
0266     struct dwbc *dwb;
0267     struct mcif_wb *mcif_wb;
0268     struct mcif_warmup_params warmup_params = {0};
0269     unsigned int  i, i_buf;
0270     /*make sure there is no active DWB eanbled */
0271     for (i = 0; i < num_dwb; i++) {
0272         dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst];
0273         if (dwb->dwb_is_efc_transition || dwb->dwb_is_drc) {
0274             /*can not do warmup while any dwb enabled*/
0275             return false;
0276         }
0277     }
0278 
0279     if (wb_info->mcif_warmup_params.p_vmid == 0)
0280         return false;
0281 
0282     /*check whether this is new interface: warmup big buffer once*/
0283     if (wb_info->mcif_warmup_params.start_address.quad_part != 0 &&
0284         wb_info->mcif_warmup_params.region_size != 0) {
0285         /*mmhubbub is shared, so it does not matter which MCIF*/
0286         mcif_wb = dc->res_pool->mcif_wb[0];
0287         /*warmup a big chunk of VM buffer at once*/
0288         warmup_params.start_address.quad_part = wb_info->mcif_warmup_params.start_address.quad_part;
0289         warmup_params.address_increment =  wb_info->mcif_warmup_params.region_size;
0290         warmup_params.region_size = wb_info->mcif_warmup_params.region_size;
0291         warmup_params.p_vmid = wb_info->mcif_warmup_params.p_vmid;
0292 
0293         if (warmup_params.address_increment == 0)
0294             warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes;
0295 
0296         mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params);
0297         return true;
0298     }
0299     /*following is the original: warmup each DWB's mcif buffer*/
0300     for (i = 0; i < num_dwb; i++) {
0301         dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst];
0302         mcif_wb = dc->res_pool->mcif_wb[wb_info[i].dwb_pipe_inst];
0303         /*warmup is for VM mode only*/
0304         if (wb_info[i].mcif_buf_params.p_vmid == 0)
0305             return false;
0306 
0307         /* Warmup MCIF_WB */
0308         for (i_buf = 0; i_buf < MCIF_BUF_COUNT; i_buf++) {
0309             warmup_params.start_address.quad_part = wb_info[i].mcif_buf_params.luma_address[i_buf];
0310             warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes;
0311             warmup_params.region_size = wb_info[i].mcif_buf_params.luma_pitch * wb_info[i].dwb_params.dest_height;
0312             warmup_params.p_vmid = wb_info[i].mcif_buf_params.p_vmid;
0313             mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params);
0314         }
0315     }
0316     return true;
0317 }
0318 
0319 void dcn30_enable_writeback(
0320         struct dc *dc,
0321         struct dc_writeback_info *wb_info,
0322         struct dc_state *context)
0323 {
0324     struct dwbc *dwb;
0325     struct mcif_wb *mcif_wb;
0326     struct timing_generator *optc;
0327 
0328     dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
0329     mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
0330 
0331     /* set the OPTC source mux */
0332     optc = dc->res_pool->timing_generators[dwb->otg_inst];
0333     DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\
0334         __func__, wb_info->dwb_pipe_inst,\
0335         wb_info->mpcc_inst);
0336     if (IS_DIAG_DC(dc->ctx->dce_environment)) {
0337         /*till diags switch to warmup interface*/
0338         dcn30_mmhubbub_warmup(dc, 1, wb_info);
0339     }
0340     /* Update writeback pipe */
0341     dcn30_set_writeback(dc, wb_info, context);
0342 
0343     /* Enable MCIF_WB */
0344     mcif_wb->funcs->enable_mcif(mcif_wb);
0345     /* Enable DWB */
0346     dwb->funcs->enable(dwb, &wb_info->dwb_params);
0347 }
0348 
0349 void dcn30_disable_writeback(
0350         struct dc *dc,
0351         unsigned int dwb_pipe_inst)
0352 {
0353     struct dwbc *dwb;
0354     struct mcif_wb *mcif_wb;
0355 
0356     ASSERT(dwb_pipe_inst < MAX_DWB_PIPES);
0357     dwb = dc->res_pool->dwbc[dwb_pipe_inst];
0358     mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst];
0359     DC_LOG_DWB("%s dwb_pipe_inst = %d",\
0360         __func__, dwb_pipe_inst);
0361 
0362     /* disable DWB */
0363     dwb->funcs->disable(dwb);
0364     /* disable MCIF */
0365     mcif_wb->funcs->disable_mcif(mcif_wb);
0366     /* disable MPC DWB mux */
0367     dc->res_pool->mpc->funcs->disable_dwb_mux(dc->res_pool->mpc, dwb_pipe_inst);
0368 }
0369 
0370 void dcn30_program_all_writeback_pipes_in_tree(
0371         struct dc *dc,
0372         const struct dc_stream_state *stream,
0373         struct dc_state *context)
0374 {
0375     struct dc_writeback_info wb_info;
0376     struct dwbc *dwb;
0377     struct dc_stream_status *stream_status = NULL;
0378     int i_wb, i_pipe, i_stream;
0379     DC_LOG_DWB("%s", __func__);
0380 
0381     ASSERT(stream);
0382     for (i_stream = 0; i_stream < context->stream_count; i_stream++) {
0383         if (context->streams[i_stream] == stream) {
0384             stream_status = &context->stream_status[i_stream];
0385             break;
0386         }
0387     }
0388     ASSERT(stream_status);
0389 
0390     ASSERT(stream->num_wb_info <= dc->res_pool->res_cap->num_dwb);
0391     /* For each writeback pipe */
0392     for (i_wb = 0; i_wb < stream->num_wb_info; i_wb++) {
0393 
0394         /* copy writeback info to local non-const so mpcc_inst can be set */
0395         wb_info = stream->writeback_info[i_wb];
0396         if (wb_info.wb_enabled) {
0397 
0398             /* get the MPCC instance for writeback_source_plane */
0399             wb_info.mpcc_inst = -1;
0400             for (i_pipe = 0; i_pipe < dc->res_pool->pipe_count; i_pipe++) {
0401                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i_pipe];
0402 
0403                 if (!pipe_ctx->plane_state)
0404                     continue;
0405 
0406                 if (pipe_ctx->plane_state == wb_info.writeback_source_plane) {
0407                     wb_info.mpcc_inst = pipe_ctx->plane_res.mpcc_inst;
0408                     break;
0409                 }
0410             }
0411 
0412             if (wb_info.mpcc_inst == -1) {
0413                 /* Disable writeback pipe and disconnect from MPCC
0414                  * if source plane has been removed
0415                  */
0416                 dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst);
0417                 continue;
0418             }
0419 
0420             ASSERT(wb_info.dwb_pipe_inst < dc->res_pool->res_cap->num_dwb);
0421             dwb = dc->res_pool->dwbc[wb_info.dwb_pipe_inst];
0422             if (dwb->funcs->is_enabled(dwb)) {
0423                 /* writeback pipe already enabled, only need to update */
0424                 dc->hwss.update_writeback(dc, &wb_info, context);
0425             } else {
0426                 /* Enable writeback pipe and connect to MPCC */
0427                 dc->hwss.enable_writeback(dc, &wb_info, context);
0428             }
0429         } else {
0430             /* Disable writeback pipe and disconnect from MPCC */
0431             dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst);
0432         }
0433     }
0434 }
0435 
0436 void dcn30_init_hw(struct dc *dc)
0437 {
0438     struct abm **abms = dc->res_pool->multiple_abms;
0439     struct dce_hwseq *hws = dc->hwseq;
0440     struct dc_bios *dcb = dc->ctx->dc_bios;
0441     struct resource_pool *res_pool = dc->res_pool;
0442     int i;
0443     int edp_num;
0444     uint32_t backlight = MAX_BACKLIGHT_LEVEL;
0445 
0446     if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
0447         dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
0448 
0449     // Initialize the dccg
0450     if (res_pool->dccg->funcs->dccg_init)
0451         res_pool->dccg->funcs->dccg_init(res_pool->dccg);
0452 
0453     if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
0454 
0455         REG_WRITE(REFCLK_CNTL, 0);
0456         REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
0457         REG_WRITE(DIO_MEM_PWR_CTRL, 0);
0458 
0459         if (!dc->debug.disable_clock_gate) {
0460             /* enable all DCN clock gating */
0461             REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
0462 
0463             REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
0464 
0465             REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
0466         }
0467 
0468         //Enable ability to power gate / don't force power on permanently
0469         if (hws->funcs.enable_power_gating_plane)
0470             hws->funcs.enable_power_gating_plane(hws, true);
0471 
0472         return;
0473     }
0474 
0475     if (!dcb->funcs->is_accelerated_mode(dcb)) {
0476         hws->funcs.bios_golden_init(dc);
0477         hws->funcs.disable_vga(dc->hwseq);
0478     }
0479 
0480     if (dc->debug.enable_mem_low_power.bits.dmcu) {
0481         // Force ERAM to shutdown if DMCU is not enabled
0482         if (dc->debug.disable_dmcu || dc->config.disable_dmcu) {
0483             REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3);
0484         }
0485     }
0486 
0487     // Set default OPTC memory power states
0488     if (dc->debug.enable_mem_low_power.bits.optc) {
0489         // Shutdown when unassigned and light sleep in VBLANK
0490         REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
0491     }
0492 
0493     if (dc->ctx->dc_bios->fw_info_valid) {
0494         res_pool->ref_clocks.xtalin_clock_inKhz =
0495                 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
0496 
0497         if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
0498             if (res_pool->dccg && res_pool->hubbub) {
0499 
0500                 (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
0501                         dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
0502                         &res_pool->ref_clocks.dccg_ref_clock_inKhz);
0503 
0504                 (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
0505                         res_pool->ref_clocks.dccg_ref_clock_inKhz,
0506                         &res_pool->ref_clocks.dchub_ref_clock_inKhz);
0507             } else {
0508                 // Not all ASICs have DCCG sw component
0509                 res_pool->ref_clocks.dccg_ref_clock_inKhz =
0510                         res_pool->ref_clocks.xtalin_clock_inKhz;
0511                 res_pool->ref_clocks.dchub_ref_clock_inKhz =
0512                         res_pool->ref_clocks.xtalin_clock_inKhz;
0513             }
0514         }
0515     } else
0516         ASSERT_CRITICAL(false);
0517 
0518     for (i = 0; i < dc->link_count; i++) {
0519         /* Power up AND update implementation according to the
0520          * required signal (which may be different from the
0521          * default signal on connector).
0522          */
0523         struct dc_link *link = dc->links[i];
0524 
0525         link->link_enc->funcs->hw_init(link->link_enc);
0526 
0527         /* Check for enabled DIG to identify enabled display */
0528         if (link->link_enc->funcs->is_dig_enabled &&
0529             link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
0530             link->link_status.link_active = true;
0531             if (link->link_enc->funcs->fec_is_active &&
0532                     link->link_enc->funcs->fec_is_active(link->link_enc))
0533                 link->fec_state = dc_link_fec_enabled;
0534         }
0535     }
0536 
0537     /* Power gate DSCs */
0538     for (i = 0; i < res_pool->res_cap->num_dsc; i++)
0539         if (hws->funcs.dsc_pg_control != NULL)
0540             hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
0541 
0542     /* we want to turn off all dp displays before doing detection */
0543     dc_link_blank_all_dp_displays(dc);
0544 
0545     if (hws->funcs.enable_power_gating_plane)
0546         hws->funcs.enable_power_gating_plane(dc->hwseq, true);
0547 
0548     /* If taking control over from VBIOS, we may want to optimize our first
0549      * mode set, so we need to skip powering down pipes until we know which
0550      * pipes we want to use.
0551      * Otherwise, if taking control is not possible, we need to power
0552      * everything down.
0553      */
0554     if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
0555         hws->funcs.init_pipes(dc, dc->current_state);
0556         if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
0557             dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
0558                     !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
0559     }
0560 
0561     /* In headless boot cases, DIG may be turned
0562      * on which causes HW/SW discrepancies.
0563      * To avoid this, power down hardware on boot
0564      * if DIG is turned on and seamless boot not enabled
0565      */
0566     if (!dc->config.seamless_boot_edp_requested) {
0567         struct dc_link *edp_links[MAX_NUM_EDP];
0568         struct dc_link *edp_link = NULL;
0569 
0570         get_edp_links(dc, edp_links, &edp_num);
0571         if (edp_num)
0572             edp_link = edp_links[0];
0573         if (edp_link && edp_link->link_enc->funcs->is_dig_enabled &&
0574                 edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
0575                 dc->hwss.edp_backlight_control &&
0576                 dc->hwss.power_down &&
0577                 dc->hwss.edp_power_control) {
0578             dc->hwss.edp_backlight_control(edp_link, false);
0579             dc->hwss.power_down(dc);
0580             dc->hwss.edp_power_control(edp_link, false);
0581         } else {
0582             for (i = 0; i < dc->link_count; i++) {
0583                 struct dc_link *link = dc->links[i];
0584 
0585                 if (link->link_enc->funcs->is_dig_enabled &&
0586                         link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
0587                         dc->hwss.power_down) {
0588                     dc->hwss.power_down(dc);
0589                     break;
0590                 }
0591 
0592             }
0593         }
0594     }
0595 
0596     for (i = 0; i < res_pool->audio_count; i++) {
0597         struct audio *audio = res_pool->audios[i];
0598 
0599         audio->funcs->hw_init(audio);
0600     }
0601 
0602     for (i = 0; i < dc->link_count; i++) {
0603         struct dc_link *link = dc->links[i];
0604 
0605         if (link->panel_cntl)
0606             backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
0607     }
0608 
0609     for (i = 0; i < dc->res_pool->pipe_count; i++) {
0610         if (abms[i] != NULL)
0611             abms[i]->funcs->abm_init(abms[i], backlight);
0612     }
0613 
0614     /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
0615     REG_WRITE(DIO_MEM_PWR_CTRL, 0);
0616 
0617     if (!dc->debug.disable_clock_gate) {
0618         /* enable all DCN clock gating */
0619         REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
0620 
0621         REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
0622 
0623         REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
0624     }
0625 
0626     if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
0627         dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
0628 
0629     if (dc->clk_mgr->funcs->notify_wm_ranges)
0630         dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
0631 
0632     if (dc->clk_mgr->funcs->set_hard_max_memclk)
0633         dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
0634 
0635     if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
0636         dc->res_pool->hubbub->funcs->force_pstate_change_control(
0637                 dc->res_pool->hubbub, false, false);
0638     if (dc->res_pool->hubbub->funcs->init_crb)
0639         dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
0640 
0641     // Get DMCUB capabilities
0642     dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub);
0643     dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
0644     dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch;
0645 }
0646 
0647 void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
0648 {
0649     if (pipe_ctx == NULL)
0650         return;
0651 
0652     if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL)
0653         pipe_ctx->stream_res.stream_enc->funcs->set_avmute(
0654                 pipe_ctx->stream_res.stream_enc,
0655                 enable);
0656 }
0657 
0658 void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx)
0659 {
0660     bool is_hdmi_tmds;
0661     bool is_dp;
0662 
0663     ASSERT(pipe_ctx->stream);
0664 
0665     if (pipe_ctx->stream_res.stream_enc == NULL)
0666         return;  /* this is not root pipe */
0667 
0668     is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
0669     is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
0670 
0671     if (!is_hdmi_tmds && !is_dp)
0672         return;
0673 
0674     if (is_hdmi_tmds)
0675         pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
0676             pipe_ctx->stream_res.stream_enc,
0677             &pipe_ctx->stream_res.encoder_info_frame);
0678     else
0679         pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
0680             pipe_ctx->stream_res.stream_enc,
0681             &pipe_ctx->stream_res.encoder_info_frame);
0682 }
0683 
0684 void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
0685 {
0686     struct dc_stream_state    *stream     = pipe_ctx->stream;
0687     struct hubp               *hubp       = pipe_ctx->plane_res.hubp;
0688     bool                       enable     = false;
0689     struct stream_encoder     *stream_enc = pipe_ctx->stream_res.stream_enc;
0690     enum dynamic_metadata_mode mode       = dc_is_dp_signal(stream->signal)
0691                             ? dmdata_dp
0692                             : dmdata_hdmi;
0693 
0694     /* if using dynamic meta, don't set up generic infopackets */
0695     if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
0696         pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
0697         enable = true;
0698     }
0699 
0700     if (!hubp)
0701         return;
0702 
0703     if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
0704         return;
0705 
0706     stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
0707                             hubp->inst, mode);
0708 }
0709 
0710 bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
0711 {
0712     union dmub_rb_cmd cmd;
0713     uint32_t tmr_delay = 0, tmr_scale = 0;
0714     struct dc_cursor_attributes cursor_attr;
0715     bool cursor_cache_enable = false;
0716     struct dc_stream_state *stream = NULL;
0717     struct dc_plane_state *plane = NULL;
0718 
0719     if (!dc->ctx->dmub_srv)
0720         return false;
0721 
0722     if (enable) {
0723         if (dc->current_state) {
0724             int i;
0725 
0726             /* First, check no-memory-requests case */
0727             for (i = 0; i < dc->current_state->stream_count; i++) {
0728                 if (dc->current_state->stream_status[i].plane_count)
0729                     /* Fail eligibility on a visible stream */
0730                     break;
0731             }
0732 
0733             if (i == dc->current_state->stream_count) {
0734                 /* Enable no-memory-requests case */
0735                 memset(&cmd, 0, sizeof(cmd));
0736                 cmd.mall.header.type = DMUB_CMD__MALL;
0737                 cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_NO_DF_REQ;
0738                 cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
0739 
0740                 dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
0741                 dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
0742 
0743                 return true;
0744             }
0745 
0746             stream = dc->current_state->streams[0];
0747             plane = (stream ? dc->current_state->stream_status[0].plane_states[0] : NULL);
0748 
0749             if (stream && plane) {
0750                 cursor_cache_enable = stream->cursor_position.enable &&
0751                         plane->address.grph.cursor_cache_addr.quad_part;
0752                 cursor_attr = stream->cursor_attributes;
0753             }
0754 
0755             /*
0756              * Second, check MALL eligibility
0757              *
0758              * single display only, single surface only, 8 and 16 bit formats only, no VM,
0759              * do not use MALL for displays that support PSR as they use D0i3.2 in DMCUB FW
0760              *
0761              * TODO: When we implement multi-display, PSR displays will be allowed if there is
0762              * a non-PSR display present, since in that case we can't do D0i3.2
0763              */
0764             if (dc->current_state->stream_count == 1 &&
0765                     stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED &&
0766                     dc->current_state->stream_status[0].plane_count == 1 &&
0767                     plane->format <= SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F &&
0768                     plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 &&
0769                     plane->address.page_table_base.quad_part == 0 &&
0770                     dc->hwss.does_plane_fit_in_mall &&
0771                     dc->hwss.does_plane_fit_in_mall(dc, plane,
0772                             cursor_cache_enable ? &cursor_attr : NULL)) {
0773                 unsigned int v_total = stream->adjust.v_total_max ?
0774                         stream->adjust.v_total_max : stream->timing.v_total;
0775                 unsigned int refresh_hz = div_u64((unsigned long long) stream->timing.pix_clk_100hz *
0776                         100LL, (v_total * stream->timing.h_total));
0777 
0778                 /*
0779                  * one frame time in microsec:
0780                  * Delay_Us = 1000000 / refresh
0781                  * dynamic_delay_us = 1000000 / refresh + 2 * stutter_period
0782                  *
0783                  * one frame time modified by 'additional timer percent' (p):
0784                  * Delay_Us_modified = dynamic_delay_us + dynamic_delay_us * p / 100
0785                  *                   = dynamic_delay_us * (1 + p / 100)
0786                  *                   = (1000000 / refresh + 2 * stutter_period) * (100 + p) / 100
0787                  *                   = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh)
0788                  *
0789                  * formula for timer duration based on parameters, from regspec:
0790                  * dynamic_delay_us = 65.28 * (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
0791                  *
0792                  * dynamic_delay_us / 65.28 = (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
0793                  * (dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale = 64 + MallFrameCacheTmrDly
0794                  * MallFrameCacheTmrDly = ((dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale) - 64
0795                  *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) / 65.28 / 2^MallFrameCacheTmrScale - 64
0796                  *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (refresh * 6528 * 2^MallFrameCacheTmrScale) - 64
0797                  *
0798                  * need to round up the result of the division before the subtraction
0799                  */
0800                 unsigned int denom = refresh_hz * 6528;
0801                 unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us;
0802 
0803                 tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
0804                         (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
0805                         denom) - 64LL;
0806 
0807                 /* In some cases the stutter period is really big (tiny modes) in these
0808                  * cases MALL cant be enabled, So skip these cases to avoid a ASSERT()
0809                  *
0810                  * We can check if stutter_period is more than 1/10th the frame time to
0811                  * consider if we can actually meet the range of hysteresis timer
0812                  */
0813                 if (stutter_period > 100000/refresh_hz)
0814                     return false;
0815 
0816                 /* scale should be increased until it fits into 6 bits */
0817                 while (tmr_delay & ~0x3F) {
0818                     tmr_scale++;
0819 
0820                     if (tmr_scale > 3) {
0821                         /* Delay exceeds range of hysteresis timer */
0822                         ASSERT(false);
0823                         return false;
0824                     }
0825 
0826                     denom *= 2;
0827                     tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
0828                             (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
0829                             denom) - 64LL;
0830                 }
0831 
0832                 /* Copy HW cursor */
0833                 if (cursor_cache_enable) {
0834                     memset(&cmd, 0, sizeof(cmd));
0835                     cmd.mall.header.type = DMUB_CMD__MALL;
0836                     cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_COPY_CURSOR;
0837                     cmd.mall.header.payload_bytes =
0838                             sizeof(cmd.mall) - sizeof(cmd.mall.header);
0839 
0840                     switch (cursor_attr.color_format) {
0841                     case CURSOR_MODE_MONO:
0842                         cmd.mall.cursor_bpp = 2;
0843                         break;
0844                     case CURSOR_MODE_COLOR_1BIT_AND:
0845                     case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
0846                     case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
0847                         cmd.mall.cursor_bpp = 32;
0848                         break;
0849 
0850                     case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
0851                     case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
0852                         cmd.mall.cursor_bpp = 64;
0853                         break;
0854                     }
0855 
0856                     cmd.mall.cursor_copy_src.quad_part = cursor_attr.address.quad_part;
0857                     cmd.mall.cursor_copy_dst.quad_part =
0858                             (plane->address.grph.cursor_cache_addr.quad_part + 2047) & ~2047;
0859                     cmd.mall.cursor_width = cursor_attr.width;
0860                     cmd.mall.cursor_height = cursor_attr.height;
0861                     cmd.mall.cursor_pitch = cursor_attr.pitch;
0862 
0863                     dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
0864                     dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
0865                     dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
0866 
0867                     /* Use copied cursor, and it's okay to not switch back */
0868                     cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part;
0869                     dc_stream_set_cursor_attributes(stream, &cursor_attr);
0870                 }
0871 
0872                 /* Enable MALL */
0873                 memset(&cmd, 0, sizeof(cmd));
0874                 cmd.mall.header.type = DMUB_CMD__MALL;
0875                 cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_ALLOW;
0876                 cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
0877                 cmd.mall.tmr_delay = tmr_delay;
0878                 cmd.mall.tmr_scale = tmr_scale;
0879                 cmd.mall.debug_bits = dc->debug.mall_error_as_fatal;
0880 
0881                 dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
0882                 dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
0883 
0884                 return true;
0885             }
0886         }
0887 
0888         /* No applicable optimizations */
0889         return false;
0890     }
0891 
0892     /* Disable MALL */
0893     memset(&cmd, 0, sizeof(cmd));
0894     cmd.mall.header.type = DMUB_CMD__MALL;
0895     cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_DISALLOW;
0896     cmd.mall.header.payload_bytes =
0897         sizeof(cmd.mall) - sizeof(cmd.mall.header);
0898 
0899     dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
0900     dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
0901     dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
0902 
0903     return true;
0904 }
0905 
0906 bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane, struct dc_cursor_attributes *cursor_attr)
0907 {
0908     // add meta size?
0909     unsigned int surface_size = plane->plane_size.surface_pitch * plane->plane_size.surface_size.height *
0910             (plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4);
0911     unsigned int mall_size = dc->caps.mall_size_total;
0912     unsigned int cursor_size = 0;
0913 
0914     if (dc->debug.mall_size_override)
0915         mall_size = 1024 * 1024 * dc->debug.mall_size_override;
0916 
0917     if (cursor_attr) {
0918         cursor_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size;
0919 
0920         switch (cursor_attr->color_format) {
0921         case CURSOR_MODE_MONO:
0922             cursor_size /= 2;
0923             break;
0924         case CURSOR_MODE_COLOR_1BIT_AND:
0925         case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
0926         case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
0927             cursor_size *= 4;
0928             break;
0929 
0930         case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
0931         case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
0932             cursor_size *= 8;
0933             break;
0934         }
0935     }
0936 
0937     return (surface_size + cursor_size) < mall_size;
0938 }
0939 
0940 void dcn30_hardware_release(struct dc *dc)
0941 {
0942     dc_dmub_srv_p_state_delegate(dc, false, NULL);
0943 
0944     /* If pstate unsupported, or still supported
0945      * by firmware, force it supported by dcn
0946      */
0947     if (dc->current_state)
0948         if ((!dc->clk_mgr->clks.p_state_change_support ||
0949                 dc->current_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) &&
0950                 dc->res_pool->hubbub->funcs->force_pstate_change_control)
0951             dc->res_pool->hubbub->funcs->force_pstate_change_control(
0952                     dc->res_pool->hubbub, true, true);
0953 }
0954 
0955 void dcn30_set_disp_pattern_generator(const struct dc *dc,
0956         struct pipe_ctx *pipe_ctx,
0957         enum controller_dp_test_pattern test_pattern,
0958         enum controller_dp_color_space color_space,
0959         enum dc_color_depth color_depth,
0960         const struct tg_color *solid_color,
0961         int width, int height, int offset)
0962 {
0963     pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern,
0964             color_space, color_depth, solid_color, width, height, offset);
0965 }
0966 
0967 void dcn30_prepare_bandwidth(struct dc *dc,
0968     struct dc_state *context)
0969 {
0970     if (dc->clk_mgr->dc_mode_softmax_enabled)
0971         if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
0972                 context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
0973             dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
0974 
0975     dcn20_prepare_bandwidth(dc, context);
0976 
0977     dc_dmub_srv_p_state_delegate(dc,
0978         context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching, context);
0979 }
0980