LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/display/dc/dcn32 - dcn32_hwseq.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 575 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 23 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Advanced Micro Devices, Inc.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      18             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      19             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      20             :  * OTHER DEALINGS IN THE SOFTWARE.
      21             :  *
      22             :  * Authors: AMD
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : #include "dm_services.h"
      28             : #include "dm_helpers.h"
      29             : #include "core_types.h"
      30             : #include "resource.h"
      31             : #include "dccg.h"
      32             : #include "dce/dce_hwseq.h"
      33             : #include "dcn30/dcn30_cm_common.h"
      34             : #include "reg_helper.h"
      35             : #include "abm.h"
      36             : #include "hubp.h"
      37             : #include "dchubbub.h"
      38             : #include "timing_generator.h"
      39             : #include "opp.h"
      40             : #include "ipp.h"
      41             : #include "mpc.h"
      42             : #include "mcif_wb.h"
      43             : #include "dc_dmub_srv.h"
      44             : #include "link_hwss.h"
      45             : #include "dpcd_defs.h"
      46             : #include "dcn32_hwseq.h"
      47             : #include "clk_mgr.h"
      48             : #include "dsc.h"
      49             : #include "dcn20/dcn20_optc.h"
      50             : #include "dmub_subvp_state.h"
      51             : #include "dce/dmub_hw_lock_mgr.h"
      52             : #include "dc_link_dp.h"
      53             : #include "dmub/inc/dmub_subvp_state.h"
      54             : 
      55             : #define DC_LOGGER_INIT(logger)
      56             : 
      57             : #define CTX \
      58             :         hws->ctx
      59             : #define REG(reg)\
      60             :         hws->regs->reg
      61             : #define DC_LOGGER \
      62             :                 dc->ctx->logger
      63             : 
      64             : 
      65             : #undef FN
      66             : #define FN(reg_name, field_name) \
      67             :         hws->shifts->field_name, hws->masks->field_name
      68             : 
      69           0 : void dcn32_dsc_pg_control(
      70             :                 struct dce_hwseq *hws,
      71             :                 unsigned int dsc_inst,
      72             :                 bool power_on)
      73             : {
      74           0 :         uint32_t power_gate = power_on ? 0 : 1;
      75           0 :         uint32_t pwr_status = power_on ? 0 : 2;
      76           0 :         uint32_t org_ip_request_cntl = 0;
      77             : 
      78           0 :         if (hws->ctx->dc->debug.disable_dsc_power_gate)
      79           0 :                 return;
      80             : 
      81           0 :         REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
      82           0 :         if (org_ip_request_cntl == 0)
      83           0 :                 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
      84             : 
      85           0 :         switch (dsc_inst) {
      86             :         case 0: /* DSC0 */
      87           0 :                 REG_UPDATE(DOMAIN16_PG_CONFIG,
      88             :                                 DOMAIN_POWER_GATE, power_gate);
      89             : 
      90           0 :                 REG_WAIT(DOMAIN16_PG_STATUS,
      91             :                                 DOMAIN_PGFSM_PWR_STATUS, pwr_status,
      92             :                                 1, 1000);
      93           0 :                 break;
      94             :         case 1: /* DSC1 */
      95           0 :                 REG_UPDATE(DOMAIN17_PG_CONFIG,
      96             :                                 DOMAIN_POWER_GATE, power_gate);
      97             : 
      98           0 :                 REG_WAIT(DOMAIN17_PG_STATUS,
      99             :                                 DOMAIN_PGFSM_PWR_STATUS, pwr_status,
     100             :                                 1, 1000);
     101           0 :                 break;
     102             :         case 2: /* DSC2 */
     103           0 :                 REG_UPDATE(DOMAIN18_PG_CONFIG,
     104             :                                 DOMAIN_POWER_GATE, power_gate);
     105             : 
     106           0 :                 REG_WAIT(DOMAIN18_PG_STATUS,
     107             :                                 DOMAIN_PGFSM_PWR_STATUS, pwr_status,
     108             :                                 1, 1000);
     109           0 :                 break;
     110             :         case 3: /* DSC3 */
     111           0 :                 REG_UPDATE(DOMAIN19_PG_CONFIG,
     112             :                                 DOMAIN_POWER_GATE, power_gate);
     113             : 
     114           0 :                 REG_WAIT(DOMAIN19_PG_STATUS,
     115             :                                 DOMAIN_PGFSM_PWR_STATUS, pwr_status,
     116             :                                 1, 1000);
     117           0 :                 break;
     118             :         default:
     119           0 :                 BREAK_TO_DEBUGGER();
     120           0 :                 break;
     121             :         }
     122             : 
     123           0 :         if (org_ip_request_cntl == 0)
     124           0 :                 REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
     125             : }
     126             : 
     127             : 
     128           0 : void dcn32_enable_power_gating_plane(
     129             :         struct dce_hwseq *hws,
     130             :         bool enable)
     131             : {
     132           0 :         bool force_on = true; /* disable power gating */
     133             : 
     134           0 :         if (enable)
     135           0 :                 force_on = false;
     136             : 
     137             :         /* DCHUBP0/1/2/3 */
     138           0 :         REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
     139           0 :         REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
     140           0 :         REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
     141           0 :         REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
     142             : 
     143             :         /* DCS0/1/2/3 */
     144           0 :         REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
     145           0 :         REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
     146           0 :         REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
     147           0 :         REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
     148           0 : }
     149             : 
     150           0 : void dcn32_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on)
     151             : {
     152           0 :         uint32_t power_gate = power_on ? 0 : 1;
     153           0 :         uint32_t pwr_status = power_on ? 0 : 2;
     154             : 
     155           0 :         if (hws->ctx->dc->debug.disable_hubp_power_gate)
     156             :                 return;
     157             : 
     158           0 :         if (REG(DOMAIN0_PG_CONFIG) == 0)
     159             :                 return;
     160             : 
     161           0 :         switch (hubp_inst) {
     162             :         case 0:
     163           0 :                 REG_SET(DOMAIN0_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
     164           0 :                 REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
     165           0 :                 break;
     166             :         case 1:
     167           0 :                 REG_SET(DOMAIN1_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
     168           0 :                 REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
     169           0 :                 break;
     170             :         case 2:
     171           0 :                 REG_SET(DOMAIN2_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
     172           0 :                 REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
     173           0 :                 break;
     174             :         case 3:
     175           0 :                 REG_SET(DOMAIN3_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
     176           0 :                 REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
     177           0 :                 break;
     178             :         default:
     179           0 :                 BREAK_TO_DEBUGGER();
     180           0 :                 break;
     181             :         }
     182             : }
     183             : 
     184             : static bool dcn32_check_no_memory_request_for_cab(struct dc *dc)
     185             : {
     186             :         int i;
     187             : 
     188             :     /* First, check no-memory-request case */
     189           0 :         for (i = 0; i < dc->current_state->stream_count; i++) {
     190           0 :                 if (dc->current_state->stream_status[i].plane_count)
     191             :                         /* Fail eligibility on a visible stream */
     192             :                         break;
     193             :         }
     194             : 
     195           0 :         if (i == dc->current_state->stream_count)
     196             :                 return true;
     197             : 
     198             :         return false;
     199             : }
     200             : 
     201             : /* This function takes in the start address and surface size to be cached in CAB
     202             :  * and calculates the total number of cache lines required to store the surface.
     203             :  * The number of cache lines used for each surface is calculated independently of
     204             :  * one another. For example, if there is a primary surface(1), meta surface(2), and
     205             :  * cursor(3), this function should be called 3 times to calculate the number of cache
     206             :  * lines used for each of those surfaces.
     207             :  */
     208             : static uint32_t dcn32_cache_lines_for_surface(struct dc *dc, uint32_t surface_size, uint64_t start_address)
     209             : {
     210           0 :         uint32_t lines_used = 1;
     211           0 :         uint32_t num_cached_bytes = 0;
     212           0 :         uint32_t remaining_size = 0;
     213           0 :         uint32_t cache_line_size = dc->caps.cache_line_size;
     214           0 :         uint32_t remainder = 0;
     215             : 
     216             :         /* 1. Calculate surface size minus the number of bytes stored
     217             :          * in the first cache line (all bytes in first cache line might
     218             :          * not be fully used).
     219             :          */
     220           0 :         div_u64_rem(start_address, cache_line_size, &remainder);
     221           0 :         num_cached_bytes = cache_line_size - remainder;
     222           0 :         remaining_size = surface_size - num_cached_bytes;
     223             : 
     224             :         /* 2. Calculate number of cache lines that will be fully used with
     225             :          * the remaining number of bytes to be stored.
     226             :          */
     227           0 :         lines_used += (remaining_size / cache_line_size);
     228             : 
     229             :         /* 3. Check if we need an extra line due to the remaining size not being
     230             :          * a multiple of CACHE_LINE_SIZE.
     231             :          */
     232           0 :         if (remaining_size % cache_line_size > 0)
     233           0 :                 lines_used++;
     234             : 
     235             :         return lines_used;
     236             : }
     237             : 
     238             : /* This function loops through every surface that needs to be cached in CAB for SS,
     239             :  * and calculates the total number of ways required to store all surfaces (primary,
     240             :  * meta, cursor).
     241             :  */
     242           0 : static uint32_t dcn32_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx)
     243             : {
     244             :         uint8_t i, j;
     245           0 :         struct dc_stream_state *stream = NULL;
     246           0 :         struct dc_plane_state *plane = NULL;
     247           0 :         uint32_t surface_size = 0;
     248           0 :         uint32_t cursor_size = 0;
     249           0 :         uint32_t cache_lines_used = 0;
     250           0 :         uint32_t total_lines = 0;
     251           0 :         uint32_t lines_per_way = 0;
     252           0 :         uint32_t num_ways = 0;
     253           0 :         uint32_t prev_addr_low = 0;
     254             : 
     255           0 :         for (i = 0; i < ctx->stream_count; i++) {
     256           0 :                 stream = ctx->streams[i];
     257             : 
     258             :                 // Don't include PSR surface in the total surface size for CAB allocation
     259           0 :                 if (stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED)
     260           0 :                         continue;
     261             : 
     262           0 :                 if (ctx->stream_status[i].plane_count == 0)
     263           0 :                         continue;
     264             : 
     265             :                 // For each stream, loop through each plane to calculate the number of cache
     266             :                 // lines required to store the surface in CAB
     267           0 :                 for (j = 0; j < ctx->stream_status[i].plane_count; j++) {
     268           0 :                         plane = ctx->stream_status[i].plane_states[j];
     269             : 
     270             :                         // Calculate total surface size
     271           0 :                         if (prev_addr_low != plane->address.grph.addr.u.low_part) {
     272             :                                 /* if plane address are different from prev FB, then userspace allocated separate FBs*/
     273           0 :                                 surface_size += plane->plane_size.surface_pitch *
     274           0 :                                         plane->plane_size.surface_size.height *
     275           0 :                                         (plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4);
     276             : 
     277           0 :                                 prev_addr_low = plane->address.grph.addr.u.low_part;
     278             :                         } else {
     279             :                                 /* We have the same fb for all the planes.
     280             :                                  * Xorg always creates one giant fb that holds all surfaces,
     281             :                                  * so allocating it once is sufficient.
     282             :                                  * */
     283           0 :                                 continue;
     284             :                         }
     285             :                         // Convert surface size + starting address to number of cache lines required
     286             :                         // (alignment accounted for)
     287           0 :                         cache_lines_used += dcn32_cache_lines_for_surface(dc, surface_size,
     288           0 :                                         plane->address.grph.addr.quad_part);
     289             : 
     290           0 :                         if (plane->address.grph.meta_addr.quad_part) {
     291             :                                 // Meta surface
     292           0 :                                 cache_lines_used += dcn32_cache_lines_for_surface(dc, surface_size,
     293             :                                                 plane->address.grph.meta_addr.quad_part);
     294             :                         }
     295             :                 }
     296             : 
     297             :                 // Include cursor size for CAB allocation
     298           0 :                 for (j = 0; j < dc->res_pool->pipe_count; j++) {
     299           0 :                         struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[j];
     300           0 :                         struct hubp *hubp = pipe->plane_res.hubp;
     301             : 
     302           0 :                         if (pipe->stream && pipe->plane_state && hubp)
     303             :                                 /* Find the cursor plane and use the exact size instead of
     304             :                                  * using the max for calculation
     305             :                                  */
     306           0 :                                 if (hubp->curs_attr.width > 0) {
     307           0 :                                         cursor_size = hubp->curs_attr.width * hubp->curs_attr.height;
     308           0 :                                         break;
     309             :                                 }
     310             :                 }
     311             : 
     312           0 :                 switch (stream->cursor_attributes.color_format) {
     313             :                 case CURSOR_MODE_MONO:
     314           0 :                         cursor_size /= 2;
     315           0 :                         break;
     316             :                 case CURSOR_MODE_COLOR_1BIT_AND:
     317             :                 case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
     318             :                 case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
     319           0 :                         cursor_size *= 4;
     320           0 :                         break;
     321             : 
     322             :                 case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
     323             :                 case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
     324           0 :                         cursor_size *= 8;
     325           0 :                         break;
     326             :                 }
     327             : 
     328           0 :                 if (stream->cursor_position.enable && plane->address.grph.cursor_cache_addr.quad_part) {
     329           0 :                         cache_lines_used += dcn32_cache_lines_for_surface(dc, cursor_size,
     330             :                                         plane->address.grph.cursor_cache_addr.quad_part);
     331             :                 }
     332             :         }
     333             : 
     334             :         // Convert number of cache lines required to number of ways
     335           0 :         total_lines = dc->caps.max_cab_allocation_bytes / dc->caps.cache_line_size;
     336           0 :         lines_per_way = total_lines / dc->caps.cache_num_ways;
     337           0 :         num_ways = cache_lines_used / lines_per_way;
     338             : 
     339           0 :         if (cache_lines_used % lines_per_way > 0)
     340           0 :                 num_ways++;
     341             : 
     342           0 :         for (i = 0; i < ctx->stream_count; i++) {
     343           0 :                 stream = ctx->streams[i];
     344           0 :                 for (j = 0; j < ctx->stream_status[i].plane_count; j++) {
     345           0 :                         plane = ctx->stream_status[i].plane_states[j];
     346             : 
     347           0 :                         if (stream->cursor_position.enable && plane &&
     348           0 :                                 !plane->address.grph.cursor_cache_addr.quad_part &&
     349             :                                 cursor_size > 16384) {
     350             :                                 /* Cursor caching is not supported since it won't be on the same line.
     351             :                                  * So we need an extra line to accommodate it. With large cursors and a single 4k monitor
     352             :                                  * this case triggers corruption. If we're at the edge, then dont trigger display refresh
     353             :                                  * from MALL. We only need to cache cursor if its greater that 64x64 at 4 bpp.
     354             :                                  */
     355           0 :                                 num_ways++;
     356             :                                 /* We only expect one cursor plane */
     357           0 :                                 break;
     358             :                         }
     359             :                 }
     360             :         }
     361             : 
     362           0 :         return num_ways;
     363             : }
     364             : 
     365           0 : bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable)
     366             : {
     367             :         union dmub_rb_cmd cmd;
     368             :         uint8_t ways, i;
     369             :         int j;
     370           0 :         bool stereo_in_use = false;
     371           0 :         struct dc_plane_state *plane = NULL;
     372             : 
     373           0 :         if (!dc->ctx->dmub_srv)
     374             :                 return false;
     375             : 
     376           0 :         if (enable) {
     377           0 :                 if (dc->current_state) {
     378             : 
     379             :                         /* 1. Check no memory request case for CAB.
     380             :                          * If no memory request case, send CAB_ACTION NO_DF_REQ DMUB message
     381             :                          */
     382           0 :                         if (dcn32_check_no_memory_request_for_cab(dc)) {
     383             :                                 /* Enable no-memory-requests case */
     384           0 :                                 memset(&cmd, 0, sizeof(cmd));
     385           0 :                                 cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
     386           0 :                                 cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ;
     387           0 :                                 cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header);
     388             : 
     389           0 :                                 dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
     390           0 :                                 dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
     391             : 
     392           0 :                                 return true;
     393             :                         }
     394             : 
     395             :                         /* 2. Check if all surfaces can fit in CAB.
     396             :                          * If surfaces can fit into CAB, send CAB_ACTION_ALLOW DMUB message
     397             :                          * and configure HUBP's to fetch from MALL
     398             :                          */
     399           0 :                         ways = dcn32_calculate_cab_allocation(dc, dc->current_state);
     400             : 
     401             :                         /* MALL not supported with Stereo3D. If any plane is using stereo,
     402             :                          * don't try to enter MALL.
     403             :                          */
     404           0 :                         for (i = 0; i < dc->current_state->stream_count; i++) {
     405           0 :                                 for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
     406           0 :                                         plane = dc->current_state->stream_status[i].plane_states[j];
     407             : 
     408           0 :                                         if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO) {
     409             :                                                 stereo_in_use = true;
     410             :                                                 break;
     411             :                                         }
     412             :                                 }
     413           0 :                                 if (stereo_in_use)
     414             :                                         break;
     415             :                         }
     416           0 :                         if (ways <= dc->caps.cache_num_ways && !stereo_in_use) {
     417           0 :                                 memset(&cmd, 0, sizeof(cmd));
     418           0 :                                 cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
     419           0 :                                 cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB;
     420           0 :                                 cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header);
     421           0 :                                 cmd.cab.cab_alloc_ways = ways;
     422             : 
     423           0 :                                 dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
     424           0 :                                 dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
     425             : 
     426           0 :                                 return true;
     427             :                         }
     428             : 
     429             :                 }
     430             :                 return false;
     431             :         }
     432             : 
     433             :         /* Disable CAB */
     434           0 :         memset(&cmd, 0, sizeof(cmd));
     435           0 :         cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
     436           0 :         cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION;
     437           0 :         cmd.cab.header.payload_bytes =
     438             :                         sizeof(cmd.cab) - sizeof(cmd.cab.header);
     439             : 
     440           0 :         dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
     441           0 :         dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
     442           0 :         dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
     443             : 
     444           0 :         return true;
     445             : }
     446             : 
     447             : /* Send DMCUB message with SubVP pipe info
     448             :  * - For each pipe in context, populate payload with required SubVP information
     449             :  *   if the pipe is using SubVP for MCLK switch
     450             :  * - This function must be called while the DMUB HW lock is acquired by driver
     451             :  */
     452           0 : void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context)
     453             : {
     454             : /*
     455             :         int i;
     456             :         bool enable_subvp = false;
     457             : 
     458             :         if (!dc->ctx || !dc->ctx->dmub_srv)
     459             :                 return;
     460             : 
     461             :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     462             :                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
     463             : 
     464             :                 if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.paired_stream &&
     465             :                                 pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN) {
     466             :                         // There is at least 1 SubVP pipe, so enable SubVP
     467             :                         enable_subvp = true;
     468             :                         break;
     469             :                 }
     470             :         }
     471             :         dc_dmub_setup_subvp_dmub_command(dc, context, enable_subvp);
     472             : */
     473           0 : }
     474             : 
     475             : /* Sub-Viewport DMUB lock needs to be acquired by driver whenever SubVP is active and:
     476             :  * 1. Any full update for any SubVP main pipe
     477             :  * 2. Any immediate flip for any SubVP pipe
     478             :  * 3. Any flip for DRR pipe
     479             :  * 4. If SubVP was previously in use (i.e. in old context)
     480             :  */
     481           0 : void dcn32_subvp_pipe_control_lock(struct dc *dc,
     482             :                 struct dc_state *context,
     483             :                 bool lock,
     484             :                 bool should_lock_all_pipes,
     485             :                 struct pipe_ctx *top_pipe_to_program,
     486             :                 bool subvp_prev_use)
     487             : {
     488           0 :         unsigned int i = 0;
     489           0 :         bool subvp_immediate_flip = false;
     490           0 :         bool subvp_in_use = false;
     491             :         struct pipe_ctx *pipe;
     492             : 
     493           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     494           0 :                 pipe = &context->res_ctx.pipe_ctx[i];
     495             : 
     496           0 :                 if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
     497             :                         subvp_in_use = true;
     498             :                         break;
     499             :                 }
     500             :         }
     501             : 
     502           0 :         if (top_pipe_to_program && top_pipe_to_program->stream && top_pipe_to_program->plane_state) {
     503           0 :                 if (top_pipe_to_program->stream->mall_stream_config.type == SUBVP_MAIN &&
     504           0 :                                 top_pipe_to_program->plane_state->flip_immediate)
     505           0 :                         subvp_immediate_flip = true;
     506             :         }
     507             : 
     508             :         // Don't need to lock for DRR VSYNC flips -- FW will wait for DRR pending update cleared.
     509           0 :         if ((subvp_in_use && (should_lock_all_pipes || subvp_immediate_flip)) || (!subvp_in_use && subvp_prev_use)) {
     510           0 :                 union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
     511             : 
     512           0 :                 if (!lock) {
     513           0 :                         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     514           0 :                                 pipe = &context->res_ctx.pipe_ctx[i];
     515           0 :                                 if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN &&
     516             :                                                 should_lock_all_pipes)
     517           0 :                                         pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK);
     518             :                         }
     519             :                 }
     520             : 
     521           0 :                 hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
     522             :                 hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
     523           0 :                 hw_lock_cmd.bits.lock = lock;
     524           0 :                 hw_lock_cmd.bits.should_release = !lock;
     525           0 :                 dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
     526             :         }
     527           0 : }
     528             : 
     529             : 
     530           0 : static bool dcn32_set_mpc_shaper_3dlut(
     531             :         struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream)
     532             : {
     533           0 :         struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
     534           0 :         int mpcc_id = pipe_ctx->plane_res.hubp->inst;
     535           0 :         struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
     536           0 :         bool result = false;
     537             : 
     538           0 :         const struct pwl_params *shaper_lut = NULL;
     539             :         //get the shaper lut params
     540           0 :         if (stream->func_shaper) {
     541           0 :                 if (stream->func_shaper->type == TF_TYPE_HWPWL)
     542           0 :                         shaper_lut = &stream->func_shaper->pwl;
     543           0 :                 else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
     544           0 :                         cm_helper_translate_curve_to_hw_format(
     545             :                                         stream->func_shaper,
     546             :                                         &dpp_base->shaper_params, true);
     547           0 :                         shaper_lut = &dpp_base->shaper_params;
     548             :                 }
     549             :         }
     550             : 
     551           0 :         if (stream->lut3d_func &&
     552           0 :                 stream->lut3d_func->state.bits.initialized == 1) {
     553             : 
     554           0 :                 result = mpc->funcs->program_3dlut(mpc,
     555             :                                                                 &stream->lut3d_func->lut_3d,
     556             :                                                                 mpcc_id);
     557             : 
     558           0 :                 result = mpc->funcs->program_shaper(mpc,
     559             :                                                                 shaper_lut,
     560             :                                                                 mpcc_id);
     561             :         }
     562             : 
     563           0 :         return result;
     564             : }
     565             : 
     566           0 : bool dcn32_set_mcm_luts(
     567             :         struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
     568             : {
     569           0 :         struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
     570           0 :         int mpcc_id = pipe_ctx->plane_res.hubp->inst;
     571           0 :         struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
     572           0 :         bool result = true;
     573           0 :         struct pwl_params *lut_params = NULL;
     574             : 
     575             :         // 1D LUT
     576           0 :         if (plane_state->blend_tf) {
     577           0 :                 if (plane_state->blend_tf->type == TF_TYPE_HWPWL)
     578           0 :                         lut_params = &plane_state->blend_tf->pwl;
     579           0 :                 else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
     580           0 :                         cm_helper_translate_curve_to_hw_format(
     581             :                                         plane_state->blend_tf,
     582             :                                         &dpp_base->regamma_params, false);
     583           0 :                         lut_params = &dpp_base->regamma_params;
     584             :                 }
     585             :         }
     586           0 :         result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id);
     587             : 
     588             :         // Shaper
     589           0 :         if (plane_state->in_shaper_func) {
     590           0 :                 if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL)
     591           0 :                         lut_params = &plane_state->in_shaper_func->pwl;
     592           0 :                 else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
     593             :                         // TODO: dpp_base replace
     594           0 :                         ASSERT(false);
     595           0 :                         cm_helper_translate_curve_to_hw_format(
     596           0 :                                         plane_state->in_shaper_func,
     597             :                                         &dpp_base->shaper_params, true);
     598           0 :                         lut_params = &dpp_base->shaper_params;
     599             :                 }
     600             :         }
     601             : 
     602           0 :         result = mpc->funcs->program_shaper(mpc, lut_params, mpcc_id);
     603             : 
     604             :         // 3D
     605           0 :         if (plane_state->lut3d_func && plane_state->lut3d_func->state.bits.initialized == 1)
     606           0 :                 result = mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func->lut_3d, mpcc_id);
     607             :         else
     608           0 :                 result = mpc->funcs->program_3dlut(mpc, NULL, mpcc_id);
     609             : 
     610           0 :         return result;
     611             : }
     612             : 
     613           0 : bool dcn32_set_input_transfer_func(struct dc *dc,
     614             :                                 struct pipe_ctx *pipe_ctx,
     615             :                                 const struct dc_plane_state *plane_state)
     616             : {
     617           0 :         struct dce_hwseq *hws = dc->hwseq;
     618           0 :         struct mpc *mpc = dc->res_pool->mpc;
     619           0 :         struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
     620             : 
     621             :         enum dc_transfer_func_predefined tf;
     622           0 :         bool result = true;
     623           0 :         struct pwl_params *params = NULL;
     624             : 
     625           0 :         if (mpc == NULL || plane_state == NULL)
     626             :                 return false;
     627             : 
     628           0 :         tf = TRANSFER_FUNCTION_UNITY;
     629             : 
     630           0 :         if (plane_state->in_transfer_func &&
     631           0 :                 plane_state->in_transfer_func->type == TF_TYPE_PREDEFINED)
     632           0 :                 tf = plane_state->in_transfer_func->tf;
     633             : 
     634           0 :         dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf);
     635             : 
     636           0 :         if (plane_state->in_transfer_func) {
     637           0 :                 if (plane_state->in_transfer_func->type == TF_TYPE_HWPWL)
     638           0 :                         params = &plane_state->in_transfer_func->pwl;
     639           0 :                 else if (plane_state->in_transfer_func->type == TF_TYPE_DISTRIBUTED_POINTS &&
     640           0 :                         cm3_helper_translate_curve_to_hw_format(plane_state->in_transfer_func,
     641             :                                         &dpp_base->degamma_params, false))
     642           0 :                         params = &dpp_base->degamma_params;
     643             :         }
     644             : 
     645           0 :         result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
     646             : 
     647           0 :         if (result &&
     648           0 :                         pipe_ctx->stream_res.opp &&
     649           0 :                         pipe_ctx->stream_res.opp->ctx &&
     650           0 :                         hws->funcs.set_mcm_luts)
     651           0 :                 result = hws->funcs.set_mcm_luts(pipe_ctx, plane_state);
     652             : 
     653             :         return result;
     654             : }
     655             : 
     656           0 : bool dcn32_set_output_transfer_func(struct dc *dc,
     657             :                                 struct pipe_ctx *pipe_ctx,
     658             :                                 const struct dc_stream_state *stream)
     659             : {
     660           0 :         int mpcc_id = pipe_ctx->plane_res.hubp->inst;
     661           0 :         struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
     662           0 :         struct pwl_params *params = NULL;
     663           0 :         bool ret = false;
     664             : 
     665             :         /* program OGAM or 3DLUT only for the top pipe*/
     666           0 :         if (pipe_ctx->top_pipe == NULL) {
     667             :                 /*program shaper and 3dlut in MPC*/
     668           0 :                 ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream);
     669           0 :                 if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) {
     670           0 :                         if (stream->out_transfer_func->type == TF_TYPE_HWPWL)
     671           0 :                                 params = &stream->out_transfer_func->pwl;
     672           0 :                         else if (pipe_ctx->stream->out_transfer_func->type ==
     673           0 :                                         TF_TYPE_DISTRIBUTED_POINTS &&
     674           0 :                                         cm3_helper_translate_curve_to_hw_format(
     675             :                                         stream->out_transfer_func,
     676             :                                         &mpc->blender_params, false))
     677           0 :                                 params = &mpc->blender_params;
     678             :                         /* there are no ROM LUTs in OUTGAM */
     679           0 :                         if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED)
     680           0 :                                 BREAK_TO_DEBUGGER();
     681             :                 }
     682             :         }
     683             : 
     684           0 :         mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
     685           0 :         return ret;
     686             : }
     687             : 
     688             : /* Program P-State force value according to if pipe is using SubVP or not:
     689             :  * 1. Reset P-State force on all pipes first
     690             :  * 2. For each main pipe, force P-State disallow (P-State allow moderated by DMUB)
     691             :  */
     692           0 : void dcn32_subvp_update_force_pstate(struct dc *dc, struct dc_state *context)
     693             : {
     694             :         int i;
     695           0 :         int num_subvp = 0;
     696             :         /* Unforce p-state for each pipe
     697             :          */
     698           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     699           0 :                 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
     700           0 :                 struct hubp *hubp = pipe->plane_res.hubp;
     701             : 
     702           0 :                 if (hubp && hubp->funcs->hubp_update_force_pstate_disallow)
     703           0 :                         hubp->funcs->hubp_update_force_pstate_disallow(hubp, false);
     704           0 :                 if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_MAIN)
     705           0 :                         num_subvp++;
     706             :         }
     707             : 
     708           0 :         if (num_subvp == 0)
     709             :                 return;
     710             : 
     711             :         /* Loop through each pipe -- for each subvp main pipe force p-state allow equal to false.
     712             :          */
     713           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     714           0 :                 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
     715             : 
     716             :                 // For SubVP + DRR, also force disallow on the DRR pipe
     717             :                 // (We will force allow in the DMUB sequence -- some DRR timings by default won't allow P-State so we have
     718             :                 // to force once the vblank is stretched).
     719           0 :                 if (pipe->stream && pipe->plane_state && (pipe->stream->mall_stream_config.type == SUBVP_MAIN ||
     720           0 :                                 (pipe->stream->mall_stream_config.type == SUBVP_NONE && pipe->stream->ignore_msa_timing_param))) {
     721           0 :                         struct hubp *hubp = pipe->plane_res.hubp;
     722             : 
     723           0 :                         if (hubp && hubp->funcs->hubp_update_force_pstate_disallow)
     724           0 :                                 hubp->funcs->hubp_update_force_pstate_disallow(hubp, true);
     725             :                 }
     726             :         }
     727             : }
     728             : 
     729             : /* Update MALL_SEL register based on if pipe / plane
     730             :  * is a phantom pipe, main pipe, and if using MALL
     731             :  * for SS.
     732             :  */
     733           0 : void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context)
     734             : {
     735             :         int i;
     736           0 :         unsigned int num_ways = dcn32_calculate_cab_allocation(dc, context);
     737           0 :         bool cache_cursor = false;
     738             : 
     739           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     740           0 :                 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
     741           0 :                 struct hubp *hubp = pipe->plane_res.hubp;
     742             : 
     743           0 :                 if (pipe->stream && pipe->plane_state && hubp && hubp->funcs->hubp_update_mall_sel) {
     744           0 :                         if (hubp->curs_attr.width * hubp->curs_attr.height * 4 > 16384)
     745           0 :                                 cache_cursor = true;
     746             : 
     747           0 :                         if (pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
     748           0 :                                         hubp->funcs->hubp_update_mall_sel(hubp, 1, false);
     749             :                         } else {
     750             :                                 // MALL not supported with Stereo3D
     751           0 :                                 hubp->funcs->hubp_update_mall_sel(hubp,
     752           0 :                                         num_ways <= dc->caps.cache_num_ways &&
     753           0 :                                         pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED &&
     754           0 :                                         pipe->plane_state->address.type !=  PLN_ADDR_TYPE_GRPH_STEREO ? 2 : 0,
     755             :                                                         cache_cursor);
     756             :                         }
     757             :                 }
     758             :         }
     759           0 : }
     760             : 
     761             : /* Program the sub-viewport pipe configuration after the main / phantom pipes
     762             :  * have been programmed in hardware.
     763             :  * 1. Update force P-State for all the main pipes (disallow P-state)
     764             :  * 2. Update MALL_SEL register
     765             :  * 3. Program FORCE_ONE_ROW_FOR_FRAME for main subvp pipes
     766             :  */
     767           0 : void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context)
     768             : {
     769             :         int i;
     770           0 :         struct dce_hwseq *hws = dc->hwseq;
     771             : 
     772             :         // Don't force p-state disallow -- can't block dummy p-state
     773             : 
     774             :         // Update MALL_SEL register for each pipe
     775           0 :         if (hws && hws->funcs.update_mall_sel)
     776           0 :                 hws->funcs.update_mall_sel(dc, context);
     777             : 
     778             :         // Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes
     779           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     780           0 :                 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
     781           0 :                 struct hubp *hubp = pipe->plane_res.hubp;
     782             : 
     783           0 :                 if (pipe->stream && hubp && hubp->funcs->hubp_prepare_subvp_buffering) {
     784             :                         /* TODO - remove setting CURSOR_REQ_MODE to 0 for legacy cases
     785             :                          *      - need to investigate single pipe MPO + SubVP case to
     786             :                          *        see if CURSOR_REQ_MODE will be back to 1 for SubVP
     787             :                          *        when it should be 0 for MPO
     788             :                          */
     789           0 :                         if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
     790           0 :                                 hubp->funcs->hubp_prepare_subvp_buffering(hubp, true);
     791             :                         }
     792             :                 }
     793             :         }
     794           0 : }
     795             : 
     796           0 : void dcn32_init_hw(struct dc *dc)
     797             : {
     798           0 :         struct abm **abms = dc->res_pool->multiple_abms;
     799           0 :         struct dce_hwseq *hws = dc->hwseq;
     800           0 :         struct dc_bios *dcb = dc->ctx->dc_bios;
     801           0 :         struct resource_pool *res_pool = dc->res_pool;
     802             :         int i;
     803             :         int edp_num;
     804           0 :         uint32_t backlight = MAX_BACKLIGHT_LEVEL;
     805             : 
     806           0 :         if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
     807           0 :                 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
     808             : 
     809             :         // Initialize the dccg
     810           0 :         if (res_pool->dccg->funcs->dccg_init)
     811           0 :                 res_pool->dccg->funcs->dccg_init(res_pool->dccg);
     812             : 
     813           0 :         if (!dcb->funcs->is_accelerated_mode(dcb)) {
     814           0 :                 hws->funcs.bios_golden_init(dc);
     815           0 :                 hws->funcs.disable_vga(dc->hwseq);
     816             :         }
     817             : 
     818             :         // Set default OPTC memory power states
     819           0 :         if (dc->debug.enable_mem_low_power.bits.optc) {
     820             :                 // Shutdown when unassigned and light sleep in VBLANK
     821           0 :                 REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
     822             :         }
     823             : 
     824           0 :         if (dc->debug.enable_mem_low_power.bits.vga) {
     825             :                 // Power down VGA memory
     826           0 :                 REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
     827             :         }
     828             : 
     829           0 :         if (dc->ctx->dc_bios->fw_info_valid) {
     830           0 :                 res_pool->ref_clocks.xtalin_clock_inKhz =
     831           0 :                                 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
     832             : 
     833           0 :                 if (res_pool->dccg && res_pool->hubbub) {
     834           0 :                         (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
     835           0 :                                         dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
     836             :                                         &res_pool->ref_clocks.dccg_ref_clock_inKhz);
     837             : 
     838           0 :                         (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
     839             :                                         res_pool->ref_clocks.dccg_ref_clock_inKhz,
     840             :                                         &res_pool->ref_clocks.dchub_ref_clock_inKhz);
     841             :                 } else {
     842             :                         // Not all ASICs have DCCG sw component
     843           0 :                         res_pool->ref_clocks.dccg_ref_clock_inKhz =
     844             :                                         res_pool->ref_clocks.xtalin_clock_inKhz;
     845           0 :                         res_pool->ref_clocks.dchub_ref_clock_inKhz =
     846             :                                         res_pool->ref_clocks.xtalin_clock_inKhz;
     847             :                 }
     848             :         } else
     849           0 :                 ASSERT_CRITICAL(false);
     850             : 
     851           0 :         for (i = 0; i < dc->link_count; i++) {
     852             :                 /* Power up AND update implementation according to the
     853             :                  * required signal (which may be different from the
     854             :                  * default signal on connector).
     855             :                  */
     856           0 :                 struct dc_link *link = dc->links[i];
     857             : 
     858           0 :                 link->link_enc->funcs->hw_init(link->link_enc);
     859             : 
     860             :                 /* Check for enabled DIG to identify enabled display */
     861           0 :                 if (link->link_enc->funcs->is_dig_enabled &&
     862           0 :                         link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
     863           0 :                         link->link_status.link_active = true;
     864           0 :                         if (link->link_enc->funcs->fec_is_active &&
     865           0 :                                         link->link_enc->funcs->fec_is_active(link->link_enc))
     866           0 :                                 link->fec_state = dc_link_fec_enabled;
     867             :                 }
     868             :         }
     869             : 
     870             :         /* Power gate DSCs */
     871           0 :         for (i = 0; i < res_pool->res_cap->num_dsc; i++)
     872           0 :                 if (hws->funcs.dsc_pg_control != NULL)
     873           0 :                         hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
     874             : 
     875             :         /* we want to turn off all dp displays before doing detection */
     876           0 :         dc_link_blank_all_dp_displays(dc);
     877             : 
     878             :         /* If taking control over from VBIOS, we may want to optimize our first
     879             :          * mode set, so we need to skip powering down pipes until we know which
     880             :          * pipes we want to use.
     881             :          * Otherwise, if taking control is not possible, we need to power
     882             :          * everything down.
     883             :          */
     884           0 :         if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
     885           0 :                 hws->funcs.init_pipes(dc, dc->current_state);
     886           0 :                 if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
     887           0 :                         dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
     888           0 :                                         !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
     889             :         }
     890             : 
     891             :         /* In headless boot cases, DIG may be turned
     892             :          * on which causes HW/SW discrepancies.
     893             :          * To avoid this, power down hardware on boot
     894             :          * if DIG is turned on and seamless boot not enabled
     895             :          */
     896           0 :         if (!dc->config.seamless_boot_edp_requested) {
     897             :                 struct dc_link *edp_links[MAX_NUM_EDP];
     898             :                 struct dc_link *edp_link;
     899             : 
     900           0 :                 get_edp_links(dc, edp_links, &edp_num);
     901           0 :                 if (edp_num) {
     902           0 :                         for (i = 0; i < edp_num; i++) {
     903           0 :                                 edp_link = edp_links[i];
     904           0 :                                 if (edp_link->link_enc->funcs->is_dig_enabled &&
     905           0 :                                                 edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
     906           0 :                                                 dc->hwss.edp_backlight_control &&
     907           0 :                                                 dc->hwss.power_down &&
     908           0 :                                                 dc->hwss.edp_power_control) {
     909           0 :                                         dc->hwss.edp_backlight_control(edp_link, false);
     910           0 :                                         dc->hwss.power_down(dc);
     911           0 :                                         dc->hwss.edp_power_control(edp_link, false);
     912             :                                 }
     913             :                         }
     914             :                 } else {
     915           0 :                         for (i = 0; i < dc->link_count; i++) {
     916           0 :                                 struct dc_link *link = dc->links[i];
     917             : 
     918           0 :                                 if (link->link_enc->funcs->is_dig_enabled &&
     919           0 :                                                 link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
     920           0 :                                                 dc->hwss.power_down) {
     921           0 :                                         dc->hwss.power_down(dc);
     922           0 :                                         break;
     923             :                                 }
     924             : 
     925             :                         }
     926             :                 }
     927             :         }
     928             : 
     929           0 :         for (i = 0; i < res_pool->audio_count; i++) {
     930           0 :                 struct audio *audio = res_pool->audios[i];
     931             : 
     932           0 :                 audio->funcs->hw_init(audio);
     933             :         }
     934             : 
     935           0 :         for (i = 0; i < dc->link_count; i++) {
     936           0 :                 struct dc_link *link = dc->links[i];
     937             : 
     938           0 :                 if (link->panel_cntl)
     939           0 :                         backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
     940             :         }
     941             : 
     942           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     943           0 :                 if (abms[i] != NULL && abms[i]->funcs != NULL)
     944           0 :                         abms[i]->funcs->abm_init(abms[i], backlight);
     945             :         }
     946             : 
     947             :         /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
     948           0 :         REG_WRITE(DIO_MEM_PWR_CTRL, 0);
     949             : 
     950           0 :         if (!dc->debug.disable_clock_gate) {
     951             :                 /* enable all DCN clock gating */
     952           0 :                 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
     953             : 
     954           0 :                 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
     955             : 
     956           0 :                 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
     957             :         }
     958           0 :         if (hws->funcs.enable_power_gating_plane)
     959           0 :                 hws->funcs.enable_power_gating_plane(dc->hwseq, true);
     960             : 
     961           0 :         if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
     962           0 :                 dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
     963             : 
     964           0 :         if (dc->clk_mgr->funcs->notify_wm_ranges)
     965           0 :                 dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
     966             : 
     967           0 :         if (dc->clk_mgr->funcs->set_hard_max_memclk)
     968           0 :                 dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
     969             : 
     970           0 :         if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
     971           0 :                 dc->res_pool->hubbub->funcs->force_pstate_change_control(
     972             :                                 dc->res_pool->hubbub, false, false);
     973             : 
     974           0 :         if (dc->res_pool->hubbub->funcs->init_crb)
     975           0 :                 dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
     976             : 
     977             :         // Get DMCUB capabilities
     978           0 :         if (dc->ctx->dmub_srv) {
     979           0 :                 dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv->dmub);
     980           0 :                 dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
     981             :         }
     982           0 : }
     983             : 
     984           0 : static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
     985             :                 int opp_cnt)
     986             : {
     987           0 :         bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing);
     988             :         int flow_ctrl_cnt;
     989             : 
     990           0 :         if (opp_cnt >= 2)
     991           0 :                 hblank_halved = true;
     992             : 
     993           0 :         flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable -
     994           0 :                         stream->timing.h_border_left -
     995           0 :                         stream->timing.h_border_right;
     996             : 
     997           0 :         if (hblank_halved)
     998           0 :                 flow_ctrl_cnt /= 2;
     999             : 
    1000             :         /* ODM combine 4:1 case */
    1001           0 :         if (opp_cnt == 4)
    1002           0 :                 flow_ctrl_cnt /= 2;
    1003             : 
    1004           0 :         return flow_ctrl_cnt;
    1005             : }
    1006             : 
    1007           0 : static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
    1008             : {
    1009           0 :         struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
    1010           0 :         struct dc_stream_state *stream = pipe_ctx->stream;
    1011             :         struct pipe_ctx *odm_pipe;
    1012           0 :         int opp_cnt = 1;
    1013             : 
    1014           0 :         ASSERT(dsc);
    1015           0 :         for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
    1016           0 :                 opp_cnt++;
    1017             : 
    1018           0 :         if (enable) {
    1019             :                 struct dsc_config dsc_cfg;
    1020             :                 struct dsc_optc_config dsc_optc_cfg;
    1021             :                 enum optc_dsc_mode optc_dsc_mode;
    1022             : 
    1023             :                 /* Enable DSC hw block */
    1024           0 :                 dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
    1025           0 :                 dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
    1026           0 :                 dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
    1027           0 :                 dsc_cfg.color_depth = stream->timing.display_color_depth;
    1028           0 :                 dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
    1029           0 :                 dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
    1030           0 :                 ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
    1031           0 :                 dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
    1032             : 
    1033           0 :                 dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
    1034           0 :                 dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
    1035           0 :                 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
    1036           0 :                         struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
    1037             : 
    1038           0 :                         ASSERT(odm_dsc);
    1039           0 :                         odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
    1040           0 :                         odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
    1041             :                 }
    1042           0 :                 dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
    1043           0 :                 dsc_cfg.pic_width *= opp_cnt;
    1044             : 
    1045           0 :                 optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
    1046             : 
    1047             :                 /* Enable DSC in OPTC */
    1048           0 :                 DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
    1049           0 :                 pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
    1050             :                                                         optc_dsc_mode,
    1051             :                                                         dsc_optc_cfg.bytes_per_pixel,
    1052             :                                                         dsc_optc_cfg.slice_width);
    1053             :         } else {
    1054             :                 /* disable DSC in OPTC */
    1055           0 :                 pipe_ctx->stream_res.tg->funcs->set_dsc_config(
    1056             :                                 pipe_ctx->stream_res.tg,
    1057             :                                 OPTC_DSC_DISABLED, 0, 0);
    1058             : 
    1059             :                 /* disable DSC block */
    1060           0 :                 dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
    1061           0 :                 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
    1062           0 :                         ASSERT(odm_pipe->stream_res.dsc);
    1063           0 :                         odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
    1064             :                 }
    1065             :         }
    1066           0 : }
    1067             : 
    1068             : /*
    1069             : * Given any pipe_ctx, return the total ODM combine factor, and optionally return
    1070             : * the OPPids which are used
    1071             : * */
    1072             : static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances)
    1073             : {
    1074           0 :         unsigned int opp_count = 1;
    1075             :         struct pipe_ctx *odm_pipe;
    1076             : 
    1077             :         /* First get to the top pipe */
    1078           0 :         for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe)
    1079             :                 ;
    1080             : 
    1081             :         /* First pipe is always used */
    1082             :         if (opp_instances)
    1083           0 :                 opp_instances[0] = odm_pipe->stream_res.opp->inst;
    1084             : 
    1085             :         /* Find and count odm pipes, if any */
    1086           0 :         for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
    1087             :                 if (opp_instances)
    1088           0 :                         opp_instances[opp_count] = odm_pipe->stream_res.opp->inst;
    1089           0 :                 opp_count++;
    1090             :         }
    1091             : 
    1092             :         return opp_count;
    1093             : }
    1094             : 
    1095           0 : void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)
    1096             : {
    1097             :         struct pipe_ctx *odm_pipe;
    1098           0 :         int opp_cnt = 0;
    1099           0 :         int opp_inst[MAX_PIPES] = {0};
    1100           0 :         bool rate_control_2x_pclk = (pipe_ctx->stream->timing.flags.INTERLACE || optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing));
    1101             :         struct mpc_dwb_flow_control flow_control;
    1102           0 :         struct mpc *mpc = dc->res_pool->mpc;
    1103             :         int i;
    1104             : 
    1105           0 :         opp_cnt = get_odm_config(pipe_ctx, opp_inst);
    1106             : 
    1107           0 :         if (opp_cnt > 1)
    1108           0 :                 pipe_ctx->stream_res.tg->funcs->set_odm_combine(
    1109             :                                 pipe_ctx->stream_res.tg,
    1110             :                                 opp_inst, opp_cnt,
    1111           0 :                                 &pipe_ctx->stream->timing);
    1112             :         else
    1113           0 :                 pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
    1114           0 :                                 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
    1115             : 
    1116           0 :         rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1;
    1117           0 :         flow_control.flow_ctrl_mode = 0;
    1118           0 :         flow_control.flow_ctrl_cnt0 = 0x80;
    1119           0 :         flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(pipe_ctx->stream, opp_cnt);
    1120           0 :         if (mpc->funcs->set_out_rate_control) {
    1121           0 :                 for (i = 0; i < opp_cnt; ++i) {
    1122           0 :                         mpc->funcs->set_out_rate_control(
    1123             :                                         mpc, opp_inst[i],
    1124             :                                         true,
    1125             :                                         rate_control_2x_pclk,
    1126             :                                         &flow_control);
    1127             :                 }
    1128             :         }
    1129             : 
    1130           0 :         for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
    1131           0 :                 odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
    1132             :                                 odm_pipe->stream_res.opp,
    1133             :                                 true);
    1134             :         }
    1135             : 
    1136             :         // Don't program pixel clock after link is already enabled
    1137             : /*      if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
    1138             :                         pipe_ctx->clock_source,
    1139             :                         &pipe_ctx->stream_res.pix_clk_params,
    1140             :                         &pipe_ctx->pll_settings)) {
    1141             :                 BREAK_TO_DEBUGGER();
    1142             :         }*/
    1143             : 
    1144           0 :         if (pipe_ctx->stream_res.dsc)
    1145           0 :                 update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC);
    1146           0 : }
    1147             : 
    1148           0 : unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div)
    1149             : {
    1150           0 :         struct dc_stream_state *stream = pipe_ctx->stream;
    1151           0 :         unsigned int odm_combine_factor = 0;
    1152           0 :         struct dc *dc = pipe_ctx->stream->ctx->dc;
    1153           0 :         bool two_pix_per_container = false;
    1154             : 
    1155             :         // For phantom pipes, use the same programming as the main pipes
    1156           0 :         if (pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM) {
    1157           0 :                 stream = pipe_ctx->stream->mall_stream_config.paired_stream;
    1158             :         }
    1159           0 :         two_pix_per_container = optc2_is_two_pixels_per_containter(&stream->timing);
    1160           0 :         odm_combine_factor = get_odm_config(pipe_ctx, NULL);
    1161             : 
    1162           0 :         if (is_dp_128b_132b_signal(pipe_ctx)) {
    1163           0 :                 *k2_div = PIXEL_RATE_DIV_BY_1;
    1164           0 :         } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) {
    1165           0 :                 *k1_div = PIXEL_RATE_DIV_BY_1;
    1166           0 :                 if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
    1167           0 :                         *k2_div = PIXEL_RATE_DIV_BY_2;
    1168             :                 else
    1169           0 :                         *k2_div = PIXEL_RATE_DIV_BY_4;
    1170           0 :         } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
    1171           0 :                 if (two_pix_per_container) {
    1172           0 :                         *k1_div = PIXEL_RATE_DIV_BY_1;
    1173           0 :                         *k2_div = PIXEL_RATE_DIV_BY_2;
    1174             :                 } else {
    1175           0 :                         *k1_div = PIXEL_RATE_DIV_BY_1;
    1176           0 :                         *k2_div = PIXEL_RATE_DIV_BY_4;
    1177           0 :                         if ((odm_combine_factor == 2) || dc->debug.enable_dp_dig_pixel_rate_div_policy)
    1178           0 :                                 *k2_div = PIXEL_RATE_DIV_BY_2;
    1179             :                 }
    1180             :         }
    1181             : 
    1182           0 :         if ((*k1_div == PIXEL_RATE_DIV_NA) && (*k2_div == PIXEL_RATE_DIV_NA))
    1183           0 :                 ASSERT(false);
    1184             : 
    1185           0 :         return odm_combine_factor;
    1186             : }
    1187             : 
    1188           0 : void dcn32_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
    1189             : {
    1190           0 :         uint32_t pix_per_cycle = 1;
    1191           0 :         uint32_t odm_combine_factor = 1;
    1192             : 
    1193           0 :         if (!pipe_ctx || !pipe_ctx->stream || !pipe_ctx->stream_res.stream_enc)
    1194             :                 return;
    1195             : 
    1196           0 :         odm_combine_factor = get_odm_config(pipe_ctx, NULL);
    1197           0 :         if (optc2_is_two_pixels_per_containter(&pipe_ctx->stream->timing) || odm_combine_factor > 1
    1198           0 :                 || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx))
    1199             :                 pix_per_cycle = 2;
    1200             : 
    1201           0 :         if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode)
    1202           0 :                 pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc,
    1203             :                                 pix_per_cycle);
    1204             : }
    1205             : 
    1206           0 : void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
    1207             :                 struct dc_link_settings *link_settings)
    1208             : {
    1209           0 :         struct encoder_unblank_param params = {0};
    1210           0 :         struct dc_stream_state *stream = pipe_ctx->stream;
    1211           0 :         struct dc_link *link = stream->link;
    1212           0 :         struct dce_hwseq *hws = link->dc->hwseq;
    1213             :         struct pipe_ctx *odm_pipe;
    1214           0 :         struct dc *dc = pipe_ctx->stream->ctx->dc;
    1215           0 :         uint32_t pix_per_cycle = 1;
    1216             : 
    1217           0 :         params.opp_cnt = 1;
    1218           0 :         for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
    1219           0 :                 params.opp_cnt++;
    1220             : 
    1221             :         /* only 3 items below are used by unblank */
    1222           0 :         params.timing = pipe_ctx->stream->timing;
    1223             : 
    1224           0 :         params.link_settings.link_rate = link_settings->link_rate;
    1225             : 
    1226           0 :         if (is_dp_128b_132b_signal(pipe_ctx)) {
    1227             :                 /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
    1228           0 :                 pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
    1229             :                                 pipe_ctx->stream_res.hpo_dp_stream_enc,
    1230           0 :                                 pipe_ctx->stream_res.tg->inst);
    1231           0 :         } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
    1232           0 :                 if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1
    1233           0 :                         || dc->debug.enable_dp_dig_pixel_rate_div_policy) {
    1234           0 :                         params.timing.pix_clk_100hz /= 2;
    1235           0 :                         pix_per_cycle = 2;
    1236             :                 }
    1237           0 :                 pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
    1238             :                                 pipe_ctx->stream_res.stream_enc, pix_per_cycle > 1);
    1239           0 :                 pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
    1240             :         }
    1241             : 
    1242           0 :         if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP)
    1243           0 :                 hws->funcs.edp_backlight_control(link, true);
    1244           0 : }
    1245             : 
    1246           0 : bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx)
    1247             : {
    1248           0 :         struct dc *dc = pipe_ctx->stream->ctx->dc;
    1249             : 
    1250           0 :         if (dc_is_dp_signal(pipe_ctx->stream->signal) && !is_dp_128b_132b_signal(pipe_ctx) &&
    1251           0 :                 dc->debug.enable_dp_dig_pixel_rate_div_policy)
    1252             :                 return true;
    1253             :         return false;
    1254             : }
    1255             : 
    1256           0 : void dcn32_update_phy_state(struct dc_state *state, struct pipe_ctx *pipe_ctx,
    1257             :                 enum phy_state target_state)
    1258             : {
    1259           0 :         enum phy_state current_state = pipe_ctx->stream->link->phy_state;
    1260             : 
    1261           0 :         if (target_state == TX_OFF_SYMCLK_OFF) {
    1262           0 :                 core_link_disable_stream(pipe_ctx);
    1263           0 :                 pipe_ctx->stream->link->phy_state = TX_OFF_SYMCLK_OFF;
    1264           0 :         } else if (target_state == TX_ON_SYMCLK_ON) {
    1265           0 :                 core_link_enable_stream(state, pipe_ctx);
    1266           0 :                 pipe_ctx->stream->link->phy_state = TX_ON_SYMCLK_ON;
    1267           0 :         } else if (target_state == TX_OFF_SYMCLK_ON) {
    1268           0 :                 if (current_state == TX_ON_SYMCLK_ON) {
    1269           0 :                         core_link_disable_stream(pipe_ctx);
    1270           0 :                         pipe_ctx->stream->link->phy_state = TX_OFF_SYMCLK_OFF;
    1271             :                 }
    1272             : 
    1273           0 :                 pipe_ctx->clock_source->funcs->program_pix_clk(
    1274             :                         pipe_ctx->clock_source,
    1275             :                         &pipe_ctx->stream_res.pix_clk_params,
    1276           0 :                         dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings),
    1277             :                         &pipe_ctx->pll_settings);
    1278           0 :                 pipe_ctx->stream->link->phy_state = TX_OFF_SYMCLK_ON;
    1279             :         } else
    1280           0 :                 BREAK_TO_DEBUGGER();
    1281           0 : }

Generated by: LCOV version 1.14