Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright 2022 Advanced Micro Devices, Inc.
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining a
0006  * copy of this software and associated documentation files (the "Software"),
0007  * to deal in the Software without restriction, including without limitation
0008  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0009  * and/or sell copies of the Software, and to permit persons to whom the
0010  * Software is furnished to do so, subject to the following conditions:
0011  *
0012  * The above copyright notice and this permission notice shall be included in
0013  * all copies or substantial portions of the Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0019  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0020  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0021  * OTHER DEALINGS IN THE SOFTWARE.
0022  *
0023  * Authors: AMD
0024  *
0025  */
0026 
0027 
0028 #include "dm_services.h"
0029 #include "dm_helpers.h"
0030 #include "core_types.h"
0031 #include "resource.h"
0032 #include "dccg.h"
0033 #include "dce/dce_hwseq.h"
0034 #include "clk_mgr.h"
0035 #include "reg_helper.h"
0036 #include "abm.h"
0037 #include "hubp.h"
0038 #include "dchubbub.h"
0039 #include "timing_generator.h"
0040 #include "opp.h"
0041 #include "ipp.h"
0042 #include "mpc.h"
0043 #include "mcif_wb.h"
0044 #include "dc_dmub_srv.h"
0045 #include "dcn314_hwseq.h"
0046 #include "link_hwss.h"
0047 #include "dpcd_defs.h"
0048 #include "dce/dmub_outbox.h"
0049 #include "dc_link_dp.h"
0050 #include "inc/dc_link_dp.h"
0051 #include "inc/link_dpcd.h"
0052 #include "dcn10/dcn10_hw_sequencer.h"
0053 #include "inc/link_enc_cfg.h"
0054 #include "dcn30/dcn30_vpg.h"
0055 #include "dce/dce_i2c_hw.h"
0056 #include "dsc.h"
0057 #include "dcn20/dcn20_optc.h"
0058 #include "dcn30/dcn30_cm_common.h"
0059 
0060 #define DC_LOGGER_INIT(logger)
0061 
0062 #define CTX \
0063     hws->ctx
0064 #define REG(reg)\
0065     hws->regs->reg
0066 #define DC_LOGGER \
0067         dc->ctx->logger
0068 
0069 
0070 #undef FN
0071 #define FN(reg_name, field_name) \
0072     hws->shifts->field_name, hws->masks->field_name
0073 
0074 static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
0075         int opp_cnt)
0076 {
0077     bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing);
0078     int flow_ctrl_cnt;
0079 
0080     if (opp_cnt >= 2)
0081         hblank_halved = true;
0082 
0083     flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable -
0084             stream->timing.h_border_left -
0085             stream->timing.h_border_right;
0086 
0087     if (hblank_halved)
0088         flow_ctrl_cnt /= 2;
0089 
0090     /* ODM combine 4:1 case */
0091     if (opp_cnt == 4)
0092         flow_ctrl_cnt /= 2;
0093 
0094     return flow_ctrl_cnt;
0095 }
0096 
0097 static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
0098 {
0099     struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
0100     struct dc_stream_state *stream = pipe_ctx->stream;
0101     struct pipe_ctx *odm_pipe;
0102     int opp_cnt = 1;
0103 
0104     ASSERT(dsc);
0105     for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
0106         opp_cnt++;
0107 
0108     if (enable) {
0109         struct dsc_config dsc_cfg;
0110         struct dsc_optc_config dsc_optc_cfg;
0111         enum optc_dsc_mode optc_dsc_mode;
0112 
0113         /* Enable DSC hw block */
0114         dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
0115         dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
0116         dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
0117         dsc_cfg.color_depth = stream->timing.display_color_depth;
0118         dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
0119         dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
0120         ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
0121         dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
0122 
0123         dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
0124         dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
0125         for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
0126             struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
0127 
0128             ASSERT(odm_dsc);
0129             odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
0130             odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
0131         }
0132         dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
0133         dsc_cfg.pic_width *= opp_cnt;
0134 
0135         optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
0136 
0137         /* Enable DSC in OPTC */
0138         DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
0139         pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
0140                             optc_dsc_mode,
0141                             dsc_optc_cfg.bytes_per_pixel,
0142                             dsc_optc_cfg.slice_width);
0143     } else {
0144         /* disable DSC in OPTC */
0145         pipe_ctx->stream_res.tg->funcs->set_dsc_config(
0146                 pipe_ctx->stream_res.tg,
0147                 OPTC_DSC_DISABLED, 0, 0);
0148 
0149         /* disable DSC block */
0150         dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
0151         for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
0152             ASSERT(odm_pipe->stream_res.dsc);
0153             odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
0154         }
0155     }
0156 }
0157 
0158 // Given any pipe_ctx, return the total ODM combine factor, and optionally return
0159 // the OPPids which are used
0160 static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances)
0161 {
0162     unsigned int opp_count = 1;
0163     struct pipe_ctx *odm_pipe;
0164 
0165     // First get to the top pipe
0166     for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe)
0167         ;
0168 
0169     // First pipe is always used
0170     if (opp_instances)
0171         opp_instances[0] = odm_pipe->stream_res.opp->inst;
0172 
0173     // Find and count odm pipes, if any
0174     for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
0175         if (opp_instances)
0176             opp_instances[opp_count] = odm_pipe->stream_res.opp->inst;
0177         opp_count++;
0178     }
0179 
0180     return opp_count;
0181 }
0182 
0183 void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)
0184 {
0185     struct pipe_ctx *odm_pipe;
0186     int opp_cnt = 0;
0187     int opp_inst[MAX_PIPES] = {0};
0188     bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing));
0189     struct mpc_dwb_flow_control flow_control;
0190     struct mpc *mpc = dc->res_pool->mpc;
0191     int i;
0192 
0193     opp_cnt = get_odm_config(pipe_ctx, opp_inst);
0194 
0195     if (opp_cnt > 1)
0196         pipe_ctx->stream_res.tg->funcs->set_odm_combine(
0197                 pipe_ctx->stream_res.tg,
0198                 opp_inst, opp_cnt,
0199                 &pipe_ctx->stream->timing);
0200     else
0201         pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
0202                 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
0203 
0204     rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1;
0205     flow_control.flow_ctrl_mode = 0;
0206     flow_control.flow_ctrl_cnt0 = 0x80;
0207     flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(pipe_ctx->stream, opp_cnt);
0208     if (mpc->funcs->set_out_rate_control) {
0209         for (i = 0; i < opp_cnt; ++i) {
0210             mpc->funcs->set_out_rate_control(
0211                     mpc, opp_inst[i],
0212                     true,
0213                     rate_control_2x_pclk,
0214                     &flow_control);
0215         }
0216     }
0217 
0218     for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
0219         odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
0220                 odm_pipe->stream_res.opp,
0221                 true);
0222     }
0223 
0224     if (pipe_ctx->stream_res.dsc) {
0225         struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
0226 
0227         update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC);
0228 
0229         /* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */
0230         if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe &&
0231                 current_pipe_ctx->next_odm_pipe->stream_res.dsc) {
0232             struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc;
0233             /* disconnect DSC block from stream */
0234             dsc->funcs->dsc_disconnect(dsc);
0235         }
0236     }
0237 }
0238 
0239 void dcn314_dsc_pg_control(
0240         struct dce_hwseq *hws,
0241         unsigned int dsc_inst,
0242         bool power_on)
0243 {
0244     uint32_t power_gate = power_on ? 0 : 1;
0245     uint32_t pwr_status = power_on ? 0 : 2;
0246     uint32_t org_ip_request_cntl = 0;
0247 
0248     if (hws->ctx->dc->debug.disable_dsc_power_gate)
0249         return;
0250 
0251     if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc &&
0252         hws->ctx->dc->res_pool->dccg->funcs->enable_dsc &&
0253         power_on)
0254         hws->ctx->dc->res_pool->dccg->funcs->enable_dsc(
0255             hws->ctx->dc->res_pool->dccg, dsc_inst);
0256 
0257     REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
0258     if (org_ip_request_cntl == 0)
0259         REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
0260 
0261     switch (dsc_inst) {
0262     case 0: /* DSC0 */
0263         REG_UPDATE(DOMAIN16_PG_CONFIG,
0264                 DOMAIN_POWER_GATE, power_gate);
0265 
0266         REG_WAIT(DOMAIN16_PG_STATUS,
0267                 DOMAIN_PGFSM_PWR_STATUS, pwr_status,
0268                 1, 1000);
0269         break;
0270     case 1: /* DSC1 */
0271         REG_UPDATE(DOMAIN17_PG_CONFIG,
0272                 DOMAIN_POWER_GATE, power_gate);
0273 
0274         REG_WAIT(DOMAIN17_PG_STATUS,
0275                 DOMAIN_PGFSM_PWR_STATUS, pwr_status,
0276                 1, 1000);
0277         break;
0278     case 2: /* DSC2 */
0279         REG_UPDATE(DOMAIN18_PG_CONFIG,
0280                 DOMAIN_POWER_GATE, power_gate);
0281 
0282         REG_WAIT(DOMAIN18_PG_STATUS,
0283                 DOMAIN_PGFSM_PWR_STATUS, pwr_status,
0284                 1, 1000);
0285         break;
0286     case 3: /* DSC3 */
0287         REG_UPDATE(DOMAIN19_PG_CONFIG,
0288                 DOMAIN_POWER_GATE, power_gate);
0289 
0290         REG_WAIT(DOMAIN19_PG_STATUS,
0291                 DOMAIN_PGFSM_PWR_STATUS, pwr_status,
0292                 1, 1000);
0293         break;
0294     default:
0295         BREAK_TO_DEBUGGER();
0296         break;
0297     }
0298 
0299     if (org_ip_request_cntl == 0)
0300         REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
0301 
0302     if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc) {
0303         if (hws->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on)
0304             hws->ctx->dc->res_pool->dccg->funcs->disable_dsc(
0305                 hws->ctx->dc->res_pool->dccg, dsc_inst);
0306     }
0307 
0308 }
0309 
0310 void dcn314_enable_power_gating_plane(struct dce_hwseq *hws, bool enable)
0311 {
0312     bool force_on = true; /* disable power gating */
0313     uint32_t org_ip_request_cntl = 0;
0314 
0315     if (enable && !hws->ctx->dc->debug.disable_hubp_power_gate)
0316         force_on = false;
0317 
0318     REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
0319     if (org_ip_request_cntl == 0)
0320         REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
0321     /* DCHUBP0/1/2/3/4/5 */
0322     REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
0323     REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
0324     /* DPP0/1/2/3/4/5 */
0325     REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
0326     REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
0327 
0328     force_on = true; /* disable power gating */
0329     if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate)
0330         force_on = false;
0331 
0332     /* DCS0/1/2/3/4 */
0333     REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
0334     REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
0335     REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
0336     REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
0337 
0338     if (org_ip_request_cntl == 0)
0339         REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
0340 }
0341 
0342 unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div)
0343 {
0344     struct dc_stream_state *stream = pipe_ctx->stream;
0345     unsigned int odm_combine_factor = 0;
0346     bool two_pix_per_container = false;
0347 
0348     two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
0349     odm_combine_factor = get_odm_config(pipe_ctx, NULL);
0350 
0351     if (is_dp_128b_132b_signal(pipe_ctx)) {
0352         *k2_div = PIXEL_RATE_DIV_BY_1;
0353     } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) {
0354         *k1_div = PIXEL_RATE_DIV_BY_1;
0355         if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
0356             *k2_div = PIXEL_RATE_DIV_BY_2;
0357         else
0358             *k2_div = PIXEL_RATE_DIV_BY_4;
0359     } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
0360         if (two_pix_per_container) {
0361             *k1_div = PIXEL_RATE_DIV_BY_1;
0362             *k2_div = PIXEL_RATE_DIV_BY_2;
0363         } else {
0364             *k1_div = PIXEL_RATE_DIV_BY_1;
0365             *k2_div = PIXEL_RATE_DIV_BY_4;
0366             if (odm_combine_factor == 2)
0367                 *k2_div = PIXEL_RATE_DIV_BY_2;
0368         }
0369     }
0370 
0371     if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA))
0372         ASSERT(false);
0373 
0374     return odm_combine_factor;
0375 }
0376 
0377 void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
0378 {
0379     uint32_t pix_per_cycle = 1;
0380     uint32_t odm_combine_factor = 1;
0381 
0382     if (!pipe_ctx || !pipe_ctx->stream || !pipe_ctx->stream_res.stream_enc)
0383         return;
0384 
0385     odm_combine_factor = get_odm_config(pipe_ctx, NULL);
0386     if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1)
0387         pix_per_cycle = 2;
0388 
0389     if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode)
0390         pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc,
0391                 pix_per_cycle);
0392 }