Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/gpu/drm/amd/display/dc/core/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 174 kB image not shown  

Quelle  dc_resource.c   Sprache: C

 
/*
 * Copyright 2012-15 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: AMD
 *
 */


#include "dm_services.h"

#include "resource.h"
#include "include/irq_service_interface.h"
#include "link_encoder.h"
#include "stream_encoder.h"
#include "opp.h"
#include "timing_generator.h"
#include "transform.h"
#include "dccg.h"
#include "dchubbub.h"
#include "dpp.h"
#include "core_types.h"
#include "set_mode_types.h"
#include "virtual/virtual_stream_encoder.h"
#include "dpcd_defs.h"
#include "link_enc_cfg.h"
#include "link.h"
#include "clk_mgr.h"
#include "dc_state_priv.h"
#include "dc_stream_priv.h"

#include "virtual/virtual_link_hwss.h"
#include "link/hwss/link_hwss_dio.h"
#include "link/hwss/link_hwss_dpia.h"
#include "link/hwss/link_hwss_hpo_dp.h"
#include "link/hwss/link_hwss_dio_fixed_vs_pe_retimer.h"
#include "link/hwss/link_hwss_hpo_fixed_vs_pe_retimer_dp.h"

#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/dce60_resource.h"
#endif
#include "dce80/dce80_resource.h"
#include "dce100/dce100_resource.h"
#include "dce110/dce110_resource.h"
#include "dce112/dce112_resource.h"
#include "dce120/dce120_resource.h"
#include "dcn10/dcn10_resource.h"
#include "dcn20/dcn20_resource.h"
#include "dcn21/dcn21_resource.h"
#include "dcn201/dcn201_resource.h"
#include "dcn30/dcn30_resource.h"
#include "dcn301/dcn301_resource.h"
#include "dcn302/dcn302_resource.h"
#include "dcn303/dcn303_resource.h"
#include "dcn31/dcn31_resource.h"
#include "dcn314/dcn314_resource.h"
#include "dcn315/dcn315_resource.h"
#include "dcn316/dcn316_resource.h"
#include "dcn32/dcn32_resource.h"
#include "dcn321/dcn321_resource.h"
#include "dcn35/dcn35_resource.h"
#include "dcn351/dcn351_resource.h"
#include "dcn36/dcn36_resource.h"
#include "dcn401/dcn401_resource.h"
#if defined(CONFIG_DRM_AMD_DC_FP)
#include "dc_spl_translate.h"
#endif

#define VISUAL_CONFIRM_BASE_DEFAULT 3
#define VISUAL_CONFIRM_BASE_MIN 1
#define VISUAL_CONFIRM_BASE_MAX 10
/* we choose 240 because it is a common denominator of common v addressable
 * such as 2160, 1440, 1200, 960. So we take 1/240 portion of v addressable as
 * the visual confirm dpp offset height. So visual confirm height can stay
 * relatively the same independent from timing used.
 */

#define VISUAL_CONFIRM_DPP_OFFSET_DENO 240

#define DC_LOGGER \
 dc->ctx->logger
#define DC_LOGGER_INIT(logger)

#include "dml2/dml2_wrapper.h"

#define UNABLE_TO_SPLIT -1

enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
{
 enum dce_version dc_version = DCE_VERSION_UNKNOWN;

 switch (asic_id.chip_family) {

#if defined(CONFIG_DRM_AMD_DC_SI)
 case FAMILY_SI:
  if (ASIC_REV_IS_TAHITI_P(asic_id.hw_internal_rev) ||
      ASIC_REV_IS_PITCAIRN_PM(asic_id.hw_internal_rev) ||
      ASIC_REV_IS_CAPEVERDE_M(asic_id.hw_internal_rev))
   dc_version = DCE_VERSION_6_0;
  else if (ASIC_REV_IS_OLAND_M(asic_id.hw_internal_rev))
   dc_version = DCE_VERSION_6_4;
  else
   dc_version = DCE_VERSION_6_1;
  break;
#endif
 case FAMILY_CI:
  dc_version = DCE_VERSION_8_0;
  break;
 case FAMILY_KV:
  if (ASIC_REV_IS_KALINDI(asic_id.hw_internal_rev) ||
      ASIC_REV_IS_BHAVANI(asic_id.hw_internal_rev) ||
      ASIC_REV_IS_GODAVARI(asic_id.hw_internal_rev))
   dc_version = DCE_VERSION_8_3;
  else
   dc_version = DCE_VERSION_8_1;
  break;
 case FAMILY_CZ:
  dc_version = DCE_VERSION_11_0;
  break;

 case FAMILY_VI:
  if (ASIC_REV_IS_TONGA_P(asic_id.hw_internal_rev) ||
    ASIC_REV_IS_FIJI_P(asic_id.hw_internal_rev)) {
   dc_version = DCE_VERSION_10_0;
   break;
  }
  if (ASIC_REV_IS_POLARIS10_P(asic_id.hw_internal_rev) ||
    ASIC_REV_IS_POLARIS11_M(asic_id.hw_internal_rev) ||
    ASIC_REV_IS_POLARIS12_V(asic_id.hw_internal_rev)) {
   dc_version = DCE_VERSION_11_2;
  }
  if (ASIC_REV_IS_VEGAM(asic_id.hw_internal_rev))
   dc_version = DCE_VERSION_11_22;
  break;
 case FAMILY_AI:
  if (ASICREV_IS_VEGA20_P(asic_id.hw_internal_rev))
   dc_version = DCE_VERSION_12_1;
  else
   dc_version = DCE_VERSION_12_0;
  break;
 case FAMILY_RV:
  dc_version = DCN_VERSION_1_0;
  if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_1_01;
  if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_2_1;
  if (ASICREV_IS_GREEN_SARDINE(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_2_1;
  break;

 case FAMILY_NV:
  dc_version = DCN_VERSION_2_0;
  if (asic_id.chip_id == DEVICE_ID_NV_13FE ||
      asic_id.chip_id == DEVICE_ID_NV_143F ||
      asic_id.chip_id == DEVICE_ID_NV_13F9 ||
      asic_id.chip_id == DEVICE_ID_NV_13FA ||
      asic_id.chip_id == DEVICE_ID_NV_13FB ||
      asic_id.chip_id == DEVICE_ID_NV_13FC ||
      asic_id.chip_id == DEVICE_ID_NV_13DB) {
   dc_version = DCN_VERSION_2_01;
   break;
  }
  if (ASICREV_IS_SIENNA_CICHLID_P(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_3_0;
  if (ASICREV_IS_DIMGREY_CAVEFISH_P(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_3_02;
  if (ASICREV_IS_BEIGE_GOBY_P(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_3_03;
  break;

 case FAMILY_VGH:
  dc_version = DCN_VERSION_3_01;
  break;

 case FAMILY_YELLOW_CARP:
  if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_3_1;
  break;
 case AMDGPU_FAMILY_GC_10_3_6:
  if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_3_15;
  break;
 case AMDGPU_FAMILY_GC_10_3_7:
  if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_3_16;
  break;
 case AMDGPU_FAMILY_GC_11_0_0:
  dc_version = DCN_VERSION_3_2;
  if (ASICREV_IS_GC_11_0_2(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_3_21;
  break;
 case AMDGPU_FAMILY_GC_11_0_1:
  dc_version = DCN_VERSION_3_14;
  break;
 case AMDGPU_FAMILY_GC_11_5_0:
  dc_version = DCN_VERSION_3_5;
  if (ASICREV_IS_GC_11_0_4(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_3_51;
  if (ASICREV_IS_DCN36(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_3_6;
  break;
 case AMDGPU_FAMILY_GC_12_0_0:
  if (ASICREV_IS_GC_12_0_1_A0(asic_id.hw_internal_rev) ||
   ASICREV_IS_GC_12_0_0_A0(asic_id.hw_internal_rev))
   dc_version = DCN_VERSION_4_01;
  break;
 default:
  dc_version = DCE_VERSION_UNKNOWN;
  break;
 }
 return dc_version;
}

struct resource_pool *dc_create_resource_pool(struct dc  *dc,
           const struct dc_init_data *init_data,
           enum dce_version dc_version)
{
 struct resource_pool *res_pool = NULL;

 switch (dc_version) {
#if defined(CONFIG_DRM_AMD_DC_SI)
 case DCE_VERSION_6_0:
  res_pool = dce60_create_resource_pool(
   init_data->num_virtual_links, dc);
  break;
 case DCE_VERSION_6_1:
  res_pool = dce61_create_resource_pool(
   init_data->num_virtual_links, dc);
  break;
 case DCE_VERSION_6_4:
  res_pool = dce64_create_resource_pool(
   init_data->num_virtual_links, dc);
  break;
#endif
 case DCE_VERSION_8_0:
  res_pool = dce80_create_resource_pool(
    init_data->num_virtual_links, dc);
  break;
 case DCE_VERSION_8_1:
  res_pool = dce81_create_resource_pool(
    init_data->num_virtual_links, dc);
  break;
 case DCE_VERSION_8_3:
  res_pool = dce83_create_resource_pool(
    init_data->num_virtual_links, dc);
  break;
 case DCE_VERSION_10_0:
  res_pool = dce100_create_resource_pool(
    init_data->num_virtual_links, dc);
  break;
 case DCE_VERSION_11_0:
  res_pool = dce110_create_resource_pool(
    init_data->num_virtual_links, dc,
    init_data->asic_id);
  break;
 case DCE_VERSION_11_2:
 case DCE_VERSION_11_22:
  res_pool = dce112_create_resource_pool(
    init_data->num_virtual_links, dc);
  break;
 case DCE_VERSION_12_0:
 case DCE_VERSION_12_1:
  res_pool = dce120_create_resource_pool(
    init_data->num_virtual_links, dc);
  break;

#if defined(CONFIG_DRM_AMD_DC_FP)
 case DCN_VERSION_1_0:
 case DCN_VERSION_1_01:
  res_pool = dcn10_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_2_0:
  res_pool = dcn20_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_2_1:
  res_pool = dcn21_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_2_01:
  res_pool = dcn201_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_0:
  res_pool = dcn30_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_01:
  res_pool = dcn301_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_02:
  res_pool = dcn302_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_03:
  res_pool = dcn303_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_1:
  res_pool = dcn31_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_14:
  res_pool = dcn314_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_15:
  res_pool = dcn315_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_16:
  res_pool = dcn316_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_2:
  res_pool = dcn32_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_21:
  res_pool = dcn321_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_5:
  res_pool = dcn35_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_51:
  res_pool = dcn351_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_3_6:
  res_pool = dcn36_create_resource_pool(init_data, dc);
  break;
 case DCN_VERSION_4_01:
  res_pool = dcn401_create_resource_pool(init_data, dc);
  break;
#endif /* CONFIG_DRM_AMD_DC_FP */
 default:
  break;
 }

 if (res_pool != NULL) {
  if (dc->ctx->dc_bios->fw_info_valid) {
   res_pool->ref_clocks.xtalin_clock_inKhz =
    dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
   /* initialize with firmware data first, no all
 * ASIC have DCCG SW component. FPGA or
 * simulation need initialization of
 * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz
 * with xtalin_clock_inKhz
 */

   res_pool->ref_clocks.dccg_ref_clock_inKhz =
    res_pool->ref_clocks.xtalin_clock_inKhz;
   res_pool->ref_clocks.dchub_ref_clock_inKhz =
    res_pool->ref_clocks.xtalin_clock_inKhz;
  } else
   ASSERT_CRITICAL(false);
 }

 return res_pool;
}

void dc_destroy_resource_pool(struct dc *dc)
{
 if (dc) {
  if (dc->res_pool)
   dc->res_pool->funcs->destroy(&dc->res_pool);

  kfree(dc->hwseq);
 }
}

static void update_num_audio(
 const struct resource_straps *straps,
 unsigned int *num_audio,
 struct audio_support *aud_support)
{
 aud_support->dp_audio = true;
 aud_support->hdmi_audio_native = false;
 aud_support->hdmi_audio_on_dongle = false;

 if (straps->hdmi_disable == 0) {
  if (straps->dc_pinstraps_audio & 0x2) {
   aud_support->hdmi_audio_on_dongle = true;
   aud_support->hdmi_audio_native = true;
  }
 }

 switch (straps->audio_stream_number) {
 case 0: /* multi streams supported */
  break;
 case 1: /* multi streams not supported */
  *num_audio = 1;
  break;
 default:
  DC_ERR("DC: unexpected audio fuse!\n");
 }
}

bool resource_construct(
 unsigned int num_virtual_links,
 struct dc  *dc,
 struct resource_pool *pool,
 const struct resource_create_funcs *create_funcs)
{
 struct dc_context *ctx = dc->ctx;
 const struct resource_caps *caps = pool->res_cap;
 int i;
 unsigned int num_audio = caps->num_audio;
 struct resource_straps straps = {0};

 if (create_funcs->read_dce_straps)
  create_funcs->read_dce_straps(dc->ctx, &straps);

 pool->audio_count = 0;
 if (create_funcs->create_audio) {
  /* find the total number of streams available via the
 * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
 * registers (one for each pin) starting from pin 1
 * up to the max number of audio pins.
 * We stop on the first pin where
 * PORT_CONNECTIVITY == 1 (as instructed by HW team).
 */

  update_num_audio(&straps, &num_audio, &pool->audio_support);
  for (i = 0; i < caps->num_audio; i++) {
   struct audio *aud = create_funcs->create_audio(ctx, i);

   if (aud == NULL) {
    DC_ERR("DC: failed to create audio!\n");
    return false;
   }
   if (!aud->funcs->endpoint_valid(aud)) {
    aud->funcs->destroy(&aud);
    break;
   }
   pool->audios[i] = aud;
   pool->audio_count++;
  }
 }

 pool->stream_enc_count = 0;
 if (create_funcs->create_stream_encoder) {
  for (i = 0; i < caps->num_stream_encoder; i++) {
   pool->stream_enc[i] = create_funcs->create_stream_encoder(i, ctx);
   if (pool->stream_enc[i] == NULL)
    DC_ERR("DC: failed to create stream_encoder!\n");
   pool->stream_enc_count++;
  }
 }

 pool->hpo_dp_stream_enc_count = 0;
 if (create_funcs->create_hpo_dp_stream_encoder) {
  for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) {
   pool->hpo_dp_stream_enc[i] = create_funcs->create_hpo_dp_stream_encoder(i+ENGINE_ID_HPO_DP_0, ctx);
   if (pool->hpo_dp_stream_enc[i] == NULL)
    DC_ERR("DC: failed to create HPO DP stream encoder!\n");
   pool->hpo_dp_stream_enc_count++;

  }
 }

 pool->hpo_dp_link_enc_count = 0;
 if (create_funcs->create_hpo_dp_link_encoder) {
  for (i = 0; i < caps->num_hpo_dp_link_encoder; i++) {
   pool->hpo_dp_link_enc[i] = create_funcs->create_hpo_dp_link_encoder(i, ctx);
   if (pool->hpo_dp_link_enc[i] == NULL)
    DC_ERR("DC: failed to create HPO DP link encoder!\n");
   pool->hpo_dp_link_enc_count++;
  }
 }

 for (i = 0; i < caps->num_mpc_3dlut; i++) {
  pool->mpc_lut[i] = dc_create_3dlut_func();
  if (pool->mpc_lut[i] == NULL)
   DC_ERR("DC: failed to create MPC 3dlut!\n");
  pool->mpc_shaper[i] = dc_create_transfer_func();
  if (pool->mpc_shaper[i] == NULL)
   DC_ERR("DC: failed to create MPC shaper!\n");
 }

 dc->caps.dynamic_audio = false;
 if (pool->audio_count < pool->stream_enc_count) {
  dc->caps.dynamic_audio = true;
 }
 for (i = 0; i < num_virtual_links; i++) {
  pool->stream_enc[pool->stream_enc_count] =
   virtual_stream_encoder_create(
     ctx, ctx->dc_bios);
  if (pool->stream_enc[pool->stream_enc_count] == NULL) {
   DC_ERR("DC: failed to create stream_encoder!\n");
   return false;
  }
  pool->stream_enc_count++;
 }

 dc->hwseq = create_funcs->create_hwseq(ctx);

 return true;
}
static int find_matching_clock_source(
  const struct resource_pool *pool,
  struct clock_source *clock_source)
{

 int i;

 for (i = 0; i < pool->clk_src_count; i++) {
  if (pool->clock_sources[i] == clock_source)
   return i;
 }
 return -1;
}

void resource_unreference_clock_source(
  struct resource_context *res_ctx,
  const struct resource_pool *pool,
  struct clock_source *clock_source)
{
 int i = find_matching_clock_source(pool, clock_source);

 if (i > -1)
  res_ctx->clock_source_ref_count[i]--;

 if (pool->dp_clock_source == clock_source)
  res_ctx->dp_clock_source_ref_count--;
}

void resource_reference_clock_source(
  struct resource_context *res_ctx,
  const struct resource_pool *pool,
  struct clock_source *clock_source)
{
 int i = find_matching_clock_source(pool, clock_source);

 if (i > -1)
  res_ctx->clock_source_ref_count[i]++;

 if (pool->dp_clock_source == clock_source)
  res_ctx->dp_clock_source_ref_count++;
}

int resource_get_clock_source_reference(
  struct resource_context *res_ctx,
  const struct resource_pool *pool,
  struct clock_source *clock_source)
{
 int i = find_matching_clock_source(pool, clock_source);

 if (i > -1)
  return res_ctx->clock_source_ref_count[i];

 if (pool->dp_clock_source == clock_source)
  return res_ctx->dp_clock_source_ref_count;

 return -1;
}

bool resource_are_vblanks_synchronizable(
 struct dc_stream_state *stream1,
 struct dc_stream_state *stream2)
{
 uint32_t base60_refresh_rates[] = {10, 20, 5};
 uint8_t i;
 uint8_t rr_count = ARRAY_SIZE(base60_refresh_rates);
 uint64_t frame_time_diff;

 if (stream1->ctx->dc->config.vblank_alignment_dto_params &&
  stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff > 0 &&
  dc_is_dp_signal(stream1->signal) &&
  dc_is_dp_signal(stream2->signal) &&
  false == stream1->has_non_synchronizable_pclk &&
  false == stream2->has_non_synchronizable_pclk &&
  stream1->timing.flags.VBLANK_SYNCHRONIZABLE &&
  stream2->timing.flags.VBLANK_SYNCHRONIZABLE) {
  /* disable refresh rates higher than 60Hz for now */
  if (stream1->timing.pix_clk_100hz*100/stream1->timing.h_total/
    stream1->timing.v_total > 60)
   return false;
  if (stream2->timing.pix_clk_100hz*100/stream2->timing.h_total/
    stream2->timing.v_total > 60)
   return false;
  frame_time_diff = (uint64_t)10000 *
   stream1->timing.h_total *
   stream1->timing.v_total *
   stream2->timing.pix_clk_100hz;
  frame_time_diff = div_u64(frame_time_diff, stream1->timing.pix_clk_100hz);
  frame_time_diff = div_u64(frame_time_diff, stream2->timing.h_total);
  frame_time_diff = div_u64(frame_time_diff, stream2->timing.v_total);
  for (i = 0; i < rr_count; i++) {
   int64_t diff = (int64_t)div_u64(frame_time_diff * base60_refresh_rates[i], 10) - 10000;

   if (diff < 0)
    diff = -diff;
   if (diff < stream1->ctx->dc->config.vblank_alignment_max_frame_time_diff)
    return true;
  }
 }
 return false;
}

bool resource_are_streams_timing_synchronizable(
 struct dc_stream_state *stream1,
 struct dc_stream_state *stream2)
{
 if (stream1->timing.h_total != stream2->timing.h_total)
  return false;

 if (stream1->timing.v_total != stream2->timing.v_total)
  return false;

 if (stream1->timing.h_addressable
    != stream2->timing.h_addressable)
  return false;

 if (stream1->timing.v_addressable
    != stream2->timing.v_addressable)
  return false;

 if (stream1->timing.v_front_porch
    != stream2->timing.v_front_porch)
  return false;

 if (stream1->timing.pix_clk_100hz
    != stream2->timing.pix_clk_100hz)
  return false;

 if (stream1->clamping.c_depth != stream2->clamping.c_depth)
  return false;

 if (stream1->phy_pix_clk != stream2->phy_pix_clk
   && (!dc_is_dp_signal(stream1->signal)
   || !dc_is_dp_signal(stream2->signal)))
  return false;

 if (stream1->view_format != stream2->view_format)
  return false;

 if (stream1->ignore_msa_timing_param || stream2->ignore_msa_timing_param)
  return false;

 return true;
}
static bool is_dp_and_hdmi_sharable(
  struct dc_stream_state *stream1,
  struct dc_stream_state *stream2)
{
 if (stream1->ctx->dc->caps.disable_dp_clk_share)
  return false;

 if (stream1->clamping.c_depth != COLOR_DEPTH_888 ||
  stream2->clamping.c_depth != COLOR_DEPTH_888)
  return false;

 return true;

}

static bool is_sharable_clk_src(
 const struct pipe_ctx *pipe_with_clk_src,
 const struct pipe_ctx *pipe)
{
 if (pipe_with_clk_src->clock_source == NULL)
  return false;

 if (pipe_with_clk_src->stream->signal == SIGNAL_TYPE_VIRTUAL)
  return false;

 if (dc_is_dp_signal(pipe_with_clk_src->stream->signal) ||
  (dc_is_dp_signal(pipe->stream->signal) &&
  !is_dp_and_hdmi_sharable(pipe_with_clk_src->stream,
         pipe->stream)))
  return false;

 if (dc_is_hdmi_signal(pipe_with_clk_src->stream->signal)
   && dc_is_dual_link_signal(pipe->stream->signal))
  return false;

 if (dc_is_hdmi_signal(pipe->stream->signal)
   && dc_is_dual_link_signal(pipe_with_clk_src->stream->signal))
  return false;

 if (!resource_are_streams_timing_synchronizable(
   pipe_with_clk_src->stream, pipe->stream))
  return false;

 return true;
}

struct clock_source *resource_find_used_clk_src_for_sharing(
     struct resource_context *res_ctx,
     struct pipe_ctx *pipe_ctx)
{
 int i;

 for (i = 0; i < MAX_PIPES; i++) {
  if (is_sharable_clk_src(&res_ctx->pipe_ctx[i], pipe_ctx))
   return res_ctx->pipe_ctx[i].clock_source;
 }

 return NULL;
}

static enum pixel_format convert_pixel_format_to_dalsurface(
  enum surface_pixel_format surface_pixel_format)
{
 enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;

 switch (surface_pixel_format) {
 case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
  dal_pixel_format = PIXEL_FORMAT_INDEX8;
  break;
 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
  dal_pixel_format = PIXEL_FORMAT_RGB565;
  break;
 case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
  dal_pixel_format = PIXEL_FORMAT_RGB565;
  break;
 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
  dal_pixel_format = PIXEL_FORMAT_ARGB8888;
  break;
 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
  dal_pixel_format = PIXEL_FORMAT_ARGB8888;
  break;
 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
  dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
  break;
 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
  dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
  break;
 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
  dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
  break;
 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
  dal_pixel_format = PIXEL_FORMAT_FP16;
  break;
 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
  dal_pixel_format = PIXEL_FORMAT_420BPP8;
  break;
 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
  dal_pixel_format = PIXEL_FORMAT_420BPP10;
  break;
 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
 default:
  dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
  break;
 }
 return dal_pixel_format;
}

static inline void get_vp_scan_direction(
 enum dc_rotation_angle rotation,
 bool horizontal_mirror,
 bool *orthogonal_rotation,
 bool *flip_vert_scan_dir,
 bool *flip_horz_scan_dir)
{
 *orthogonal_rotation = false;
 *flip_vert_scan_dir = false;
 *flip_horz_scan_dir = false;
 if (rotation == ROTATION_ANGLE_180) {
  *flip_vert_scan_dir = true;
  *flip_horz_scan_dir = true;
 } else if (rotation == ROTATION_ANGLE_90) {
  *orthogonal_rotation = true;
  *flip_horz_scan_dir = true;
 } else if (rotation == ROTATION_ANGLE_270) {
  *orthogonal_rotation = true;
  *flip_vert_scan_dir = true;
 }

 if (horizontal_mirror)
  *flip_horz_scan_dir = !*flip_horz_scan_dir;
}

static struct rect intersect_rec(const struct rect *r0, const struct rect *r1)
{
 struct rect rec;
 int r0_x_end = r0->x + r0->width;
 int r1_x_end = r1->x + r1->width;
 int r0_y_end = r0->y + r0->height;
 int r1_y_end = r1->y + r1->height;

 rec.x = r0->x > r1->x ? r0->x : r1->x;
 rec.width = r0_x_end > r1_x_end ? r1_x_end - rec.x : r0_x_end - rec.x;
 rec.y = r0->y > r1->y ? r0->y : r1->y;
 rec.height = r0_y_end > r1_y_end ? r1_y_end - rec.y : r0_y_end - rec.y;

 /* in case that there is no intersection */
 if (rec.width < 0 || rec.height < 0)
  memset(&rec, 0, sizeof(rec));

 return rec;
}

static struct rect shift_rec(const struct rect *rec_in, int x, int y)
{
 struct rect rec_out = *rec_in;

 rec_out.x += x;
 rec_out.y += y;

 return rec_out;
}

static struct rect calculate_plane_rec_in_timing_active(
  struct pipe_ctx *pipe_ctx,
  const struct rect *rec_in)
{
 /*
 * The following diagram shows an example where we map a 1920x1200
 * desktop to a 2560x1440 timing with a plane rect in the middle
 * of the screen. To map a plane rect from Stream Source to Timing
 * Active space, we first multiply stream scaling ratios (i.e 2304/1920
 * horizontal and 1440/1200 vertical) to the plane's x and y, then
 * we add stream destination offsets (i.e 128 horizontal, 0 vertical).
 * This will give us a plane rect's position in Timing Active. However
 * we have to remove the fractional. The rule is that we find left/right
 * and top/bottom positions and round the value to the adjacent integer.
 *
 * Stream Source Space
 * ------------
 *        __________________________________________________
 *       |Stream Source (1920 x 1200) ^                     |
 *       |                            y                     |
 *       |         <------- w --------|>                    |
 *       |          __________________V                     |
 *       |<-- x -->|Plane//////////////| ^                  |
 *       |         |(pre scale)////////| |                  |
 *       |         |///////////////////| |                  |
 *       |         |///////////////////| h                  |
 *       |         |///////////////////| |                  |
 *       |         |///////////////////| |                  |
 *       |         |///////////////////| V                  |
 *       |                                                  |
 *       |                                                  |
 *       |__________________________________________________|
 *
 *
 * Timing Active Space
 * ---------------------------------
 *
 *       Timing Active (2560 x 1440)
 *        __________________________________________________
 *       |*****|  Stteam Destination (2304 x 1440)    |*****|
 *       |*****|                                      |*****|
 *       |<128>|                                      |*****|
 *       |*****|     __________________               |*****|
 *       |*****|    |Plane/////////////|              |*****|
 *       |*****|    |(post scale)//////|              |*****|
 *       |*****|    |//////////////////|              |*****|
 *       |*****|    |//////////////////|              |*****|
 *       |*****|    |//////////////////|              |*****|
 *       |*****|    |//////////////////|              |*****|
 *       |*****|                                      |*****|
 *       |*****|                                      |*****|
 *       |*****|                                      |*****|
 *       |*****|______________________________________|*****|
 *
 * So the resulting formulas are shown below:
 *
 * recout_x = 128 + round(plane_x * 2304 / 1920)
 * recout_w = 128 + round((plane_x + plane_w) * 2304 / 1920) - recout_x
 * recout_y = 0 + round(plane_y * 1440 / 1280)
 * recout_h = 0 + round((plane_y + plane_h) * 1440 / 1200) - recout_y
 *
 * NOTE: fixed point division is not error free. To reduce errors
 * introduced by fixed point division, we divide only after
 * multiplication is complete.
 */

 const struct dc_stream_state *stream = pipe_ctx->stream;
 struct rect rec_out = {0};
 struct fixed31_32 temp;

 temp = dc_fixpt_from_fraction(rec_in->x * (long long)stream->dst.width,
   stream->src.width);
 rec_out.x = stream->dst.x + dc_fixpt_round(temp);

 temp = dc_fixpt_from_fraction(
   (rec_in->x + rec_in->width) * (long long)stream->dst.width,
   stream->src.width);
 rec_out.width = stream->dst.x + dc_fixpt_round(temp) - rec_out.x;

 temp = dc_fixpt_from_fraction(rec_in->y * (long long)stream->dst.height,
   stream->src.height);
 rec_out.y = stream->dst.y + dc_fixpt_round(temp);

 temp = dc_fixpt_from_fraction(
   (rec_in->y + rec_in->height) * (long long)stream->dst.height,
   stream->src.height);
 rec_out.height = stream->dst.y + dc_fixpt_round(temp) - rec_out.y;

 return rec_out;
}

static struct rect calculate_mpc_slice_in_timing_active(
  struct pipe_ctx *pipe_ctx,
  struct rect *plane_clip_rec)
{
 const struct dc_stream_state *stream = pipe_ctx->stream;
 int mpc_slice_count = resource_get_mpc_slice_count(pipe_ctx);
 int mpc_slice_idx = resource_get_mpc_slice_index(pipe_ctx);
 int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;
 struct rect mpc_rec;

 mpc_rec.width = plane_clip_rec->width / mpc_slice_count;
 mpc_rec.x = plane_clip_rec->x + mpc_rec.width * mpc_slice_idx;
 mpc_rec.height = plane_clip_rec->height;
 mpc_rec.y = plane_clip_rec->y;
 ASSERT(mpc_slice_count == 1 ||
   stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE ||
   mpc_rec.width % 2 == 0);

 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
  mpc_rec.x -= (mpc_rec.width * mpc_slice_idx);

 /* extra pixels in the division remainder need to go to pipes after
 * the extra pixel index minus one(epimo) defined here as:
 */

 if (mpc_slice_idx > epimo) {
  mpc_rec.x += mpc_slice_idx - epimo - 1;
  mpc_rec.width += 1;
 }

 if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM) {
  ASSERT(mpc_rec.height % 2 == 0);
  mpc_rec.height /= 2;
 }
 return mpc_rec;
}

static void calculate_adjust_recout_for_visual_confirm(struct pipe_ctx *pipe_ctx,
 int *base_offset, int *dpp_offset)
{
 struct dc *dc = pipe_ctx->stream->ctx->dc;
 *base_offset = 0;
 *dpp_offset = 0;

 if (dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE || !pipe_ctx->plane_res.dpp)
  return;

 *dpp_offset = pipe_ctx->stream->timing.v_addressable / VISUAL_CONFIRM_DPP_OFFSET_DENO;
 *dpp_offset *= pipe_ctx->plane_res.dpp->inst;

 if ((dc->debug.visual_confirm_rect_height >= VISUAL_CONFIRM_BASE_MIN) &&
   dc->debug.visual_confirm_rect_height <= VISUAL_CONFIRM_BASE_MAX)
  *base_offset = dc->debug.visual_confirm_rect_height;
 else
  *base_offset = VISUAL_CONFIRM_BASE_DEFAULT;
}

static void reverse_adjust_recout_for_visual_confirm(struct rect *recout,
  struct pipe_ctx *pipe_ctx)
{
 int dpp_offset, base_offset;

 calculate_adjust_recout_for_visual_confirm(pipe_ctx, &base_offset,
  &dpp_offset);
 recout->height += base_offset;
 recout->height += dpp_offset;
}

static void adjust_recout_for_visual_confirm(struct rect *recout,
  struct pipe_ctx *pipe_ctx)
{
 int dpp_offset, base_offset;

 calculate_adjust_recout_for_visual_confirm(pipe_ctx, &base_offset,
  &dpp_offset);
 recout->height -= base_offset;
 recout->height -= dpp_offset;
}

/*
 * The function maps a plane clip from Stream Source Space to ODM Slice Space
 * and calculates the rec of the overlapping area of MPC slice of the plane
 * clip, ODM slice associated with the pipe context and stream destination rec.
 */

static void calculate_recout(struct pipe_ctx *pipe_ctx)
{
 /*
 * A plane clip represents the desired plane size and position in Stream
 * Source Space. Stream Source is the destination where all planes are
 * blended (i.e. positioned, scaled and overlaid). It is a canvas where
 * all planes associated with the current stream are drawn together.
 * After Stream Source is completed, we will further scale and
 * reposition the entire canvas of the stream source to Stream
 * Destination in Timing Active Space. This could be due to display
 * overscan adjustment where we will need to rescale and reposition all
 * the planes so they can fit into a TV with overscan or downscale
 * upscale features such as GPU scaling or VSR.
 *
 * This two step blending is a virtual procedure in software. In
 * hardware there is no such thing as Stream Source. all planes are
 * blended once in Timing Active Space. Software virtualizes a Stream
 * Source space to decouple the math complicity so scaling param
 * calculation focuses on one step at a time.
 *
 * In the following two diagrams, user applied 10% overscan adjustment
 * so the Stream Source needs to be scaled down a little before mapping
 * to Timing Active Space. As a result the Plane Clip is also scaled
 * down by the same ratio, Plane Clip position (i.e. x and y) with
 * respect to Stream Source is also scaled down. To map it in Timing
 * Active Space additional x and y offsets from Stream Destination are
 * added to Plane Clip as well.
 *
 * Stream Source Space
 * ------------
 *        __________________________________________________
 *       |Stream Source (3840 x 2160) ^                     |
 *       |                            y                     |
 *       |                            |                     |
 *       |          __________________V                     |
 *       |<-- x -->|Plane Clip/////////|                    |
 *       |         |(pre scale)////////|                    |
 *       |         |///////////////////|                    |
 *       |         |///////////////////|                    |
 *       |         |///////////////////|                    |
 *       |         |///////////////////|                    |
 *       |         |///////////////////|                    |
 *       |                                                  |
 *       |                                                  |
 *       |__________________________________________________|
 *
 *
 * Timing Active Space (3840 x 2160)
 * ---------------------------------
 *
 *       Timing Active
 *        __________________________________________________
 *       | y_____________________________________________   |
 *       |x |Stream Destination (3456 x 1944)            |  |
 *       |  |                                            |  |
 *       |  |        __________________                  |  |
 *       |  |       |Plane Clip////////|                 |  |
 *       |  |       |(post scale)//////|                 |  |
 *       |  |       |//////////////////|                 |  |
 *       |  |       |//////////////////|                 |  |
 *       |  |       |//////////////////|                 |  |
 *       |  |       |//////////////////|                 |  |
 *       |  |                                            |  |
 *       |  |                                            |  |
 *       |  |____________________________________________|  |
 *       |__________________________________________________|
 *
 *
 * In Timing Active Space a plane clip could be further sliced into
 * pieces called MPC slices. Each Pipe Context is responsible for
 * processing only one MPC slice so the plane processing workload can be
 * distributed to multiple DPP Pipes. MPC slices could be blended
 * together to a single ODM slice. Each ODM slice is responsible for
 * processing a portion of Timing Active divided horizontally so the
 * output pixel processing workload can be distributed to multiple OPP
 * pipes. All ODM slices are mapped together in ODM block so all MPC
 * slices belong to different ODM slices could be pieced together to
 * form a single image in Timing Active. MPC slices must belong to
 * single ODM slice. If an MPC slice goes across ODM slice boundary, it
 * needs to be divided into two MPC slices one for each ODM slice.
 *
 * In the following diagram the output pixel processing workload is
 * divided horizontally into two ODM slices one for each OPP blend tree.
 * OPP0 blend tree is responsible for processing left half of Timing
 * Active, while OPP2 blend tree is responsible for processing right
 * half.
 *
 * The plane has two MPC slices. However since the right MPC slice goes
 * across ODM boundary, two DPP pipes are needed one for each OPP blend
 * tree. (i.e. DPP1 for OPP0 blend tree and DPP2 for OPP2 blend tree).
 *
 * Assuming that we have a Pipe Context associated with OPP0 and DPP1
 * working on processing the plane in the diagram. We want to know the
 * width and height of the shaded rectangle and its relative position
 * with respect to the ODM slice0. This is called the recout of the pipe
 * context.
 *
 * Planes can be at arbitrary size and position and there could be an
 * arbitrary number of MPC and ODM slices. The algorithm needs to take
 * all scenarios into account.
 *
 * Timing Active Space (3840 x 2160)
 * ---------------------------------
 *
 *       Timing Active
 *        __________________________________________________
 *       |OPP0(ODM slice0)^        |OPP2(ODM slice1)        |
 *       |                y        |                        |
 *       |                |  <- w ->                        |
 *       |           _____V________|____                    |
 *       |          |DPP0 ^  |DPP1 |DPP2|                   |
 *       |<------ x |-----|->|/////|    |                   |
 *       |          |     |  |/////|    |                   |
 *       |          |     h  |/////|    |                   |
 *       |          |     |  |/////|    |                   |
 *       |          |_____V__|/////|____|                   |
 *       |                         |                        |
 *       |                         |                        |
 *       |                         |                        |
 *       |_________________________|________________________|
 *
 *
 */

 struct rect plane_clip;
 struct rect mpc_slice_of_plane_clip;
 struct rect odm_slice_src;
 struct rect overlapping_area;

 plane_clip = calculate_plane_rec_in_timing_active(pipe_ctx,
   &pipe_ctx->plane_state->clip_rect);
 /* guard plane clip from drawing beyond stream dst here */
 plane_clip = intersect_rec(&plane_clip,
    &pipe_ctx->stream->dst);
 mpc_slice_of_plane_clip = calculate_mpc_slice_in_timing_active(
   pipe_ctx, &plane_clip);
 odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx);
 overlapping_area = intersect_rec(&mpc_slice_of_plane_clip, &odm_slice_src);
 if (overlapping_area.height > 0 &&
   overlapping_area.width > 0) {
  /* shift the overlapping area so it is with respect to current
 * ODM slice source's position
 */

  pipe_ctx->plane_res.scl_data.recout = shift_rec(
    &overlapping_area,
    -odm_slice_src.x, -odm_slice_src.y);
  adjust_recout_for_visual_confirm(
    &pipe_ctx->plane_res.scl_data.recout,
    pipe_ctx);
 } else {
  /* if there is no overlap, zero recout */
  memset(&pipe_ctx->plane_res.scl_data.recout, 0,
    sizeof(struct rect));
 }

}

static void calculate_scaling_ratios(struct pipe_ctx *pipe_ctx)
{
 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
 const struct dc_stream_state *stream = pipe_ctx->stream;
 struct rect surf_src = plane_state->src_rect;
 const int in_w = stream->src.width;
 const int in_h = stream->src.height;
 const int out_w = stream->dst.width;
 const int out_h = stream->dst.height;

 /*Swap surf_src height and width since scaling ratios are in recout rotation*/
 if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 ||
   pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270)
  swap(surf_src.height, surf_src.width);

 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_from_fraction(
     surf_src.width,
     plane_state->dst_rect.width);
 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_from_fraction(
     surf_src.height,
     plane_state->dst_rect.height);

 if (stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
  pipe_ctx->plane_res.scl_data.ratios.horz.value *= 2;
 else if (stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
  pipe_ctx->plane_res.scl_data.ratios.vert.value *= 2;

 pipe_ctx->plane_res.scl_data.ratios.vert.value = div64_s64(
  pipe_ctx->plane_res.scl_data.ratios.vert.value * in_h, out_h);
 pipe_ctx->plane_res.scl_data.ratios.horz.value = div64_s64(
  pipe_ctx->plane_res.scl_data.ratios.horz.value * in_w, out_w);

 pipe_ctx->plane_res.scl_data.ratios.horz_c = pipe_ctx->plane_res.scl_data.ratios.horz;
 pipe_ctx->plane_res.scl_data.ratios.vert_c = pipe_ctx->plane_res.scl_data.ratios.vert;

 if (pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP8
   || pipe_ctx->plane_res.scl_data.format == PIXEL_FORMAT_420BPP10) {
  pipe_ctx->plane_res.scl_data.ratios.horz_c.value /= 2;
  pipe_ctx->plane_res.scl_data.ratios.vert_c.value /= 2;
 }
 pipe_ctx->plane_res.scl_data.ratios.horz = dc_fixpt_truncate(
   pipe_ctx->plane_res.scl_data.ratios.horz, 19);
 pipe_ctx->plane_res.scl_data.ratios.vert = dc_fixpt_truncate(
   pipe_ctx->plane_res.scl_data.ratios.vert, 19);
 pipe_ctx->plane_res.scl_data.ratios.horz_c = dc_fixpt_truncate(
   pipe_ctx->plane_res.scl_data.ratios.horz_c, 19);
 pipe_ctx->plane_res.scl_data.ratios.vert_c = dc_fixpt_truncate(
   pipe_ctx->plane_res.scl_data.ratios.vert_c, 19);
}


/*
 * We completely calculate vp offset, size and inits here based entirely on scaling
 * ratios and recout for pixel perfect pipe combine.
 */

static void calculate_init_and_vp(
  bool flip_scan_dir,
  int recout_offset_within_recout_full,
  int recout_size,
  int src_size,
  int taps,
  struct fixed31_32 ratio,
  struct fixed31_32 *init,
  int *vp_offset,
  int *vp_size)
{
 struct fixed31_32 temp;
 int int_part;

 /*
 * First of the taps starts sampling pixel number <init_int_part> corresponding to recout
 * pixel 1. Next recout pixel samples int part of <init + scaling ratio> and so on.
 * All following calculations are based on this logic.
 *
 * Init calculated according to formula:
 *  init = (scaling_ratio + number_of_taps + 1) / 2
 *  init_bot = init + scaling_ratio
 *  to get pixel perfect combine add the fraction from calculating vp offset
 */

 temp = dc_fixpt_mul_int(ratio, recout_offset_within_recout_full);
 *vp_offset = dc_fixpt_floor(temp);
 temp.value &= 0xffffffff;
 *init = dc_fixpt_truncate(dc_fixpt_add(dc_fixpt_div_int(
   dc_fixpt_add_int(ratio, taps + 1), 2), temp), 19);
 /*
 * If viewport has non 0 offset and there are more taps than covered by init then
 * we should decrease the offset and increase init so we are never sampling
 * outside of viewport.
 */

 int_part = dc_fixpt_floor(*init);
 if (int_part < taps) {
  int_part = taps - int_part;
  if (int_part > *vp_offset)
   int_part = *vp_offset;
  *vp_offset -= int_part;
  *init = dc_fixpt_add_int(*init, int_part);
 }
 /*
 * If taps are sampling outside of viewport at end of recout and there are more pixels
 * available in the surface we should increase the viewport size, regardless set vp to
 * only what is used.
 */

 temp = dc_fixpt_add(*init, dc_fixpt_mul_int(ratio, recout_size - 1));
 *vp_size = dc_fixpt_floor(temp);
 if (*vp_size + *vp_offset > src_size)
  *vp_size = src_size - *vp_offset;

 /* We did all the math assuming we are scanning same direction as display does,
 * however mirror/rotation changes how vp scans vs how it is offset. If scan direction
 * is flipped we simply need to calculate offset from the other side of plane.
 * Note that outside of viewport all scaling hardware works in recout space.
 */

 if (flip_scan_dir)
  *vp_offset = src_size - *vp_offset - *vp_size;
}

static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx)
{
 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
 struct scaler_data *data = &pipe_ctx->plane_res.scl_data;
 struct rect src = plane_state->src_rect;
 struct rect recout_dst_in_active_timing;
 struct rect recout_clip_in_active_timing;
 struct rect recout_clip_in_recout_dst;
 struct rect overlap_in_active_timing;
 struct rect odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx);
 int vpc_div = (data->format == PIXEL_FORMAT_420BPP8
    || data->format == PIXEL_FORMAT_420BPP10) ? 2 : 1;
 bool orthogonal_rotation, flip_vert_scan_dir, flip_horz_scan_dir;

 recout_clip_in_active_timing = shift_rec(
   &data->recout, odm_slice_src.x, odm_slice_src.y);
 recout_dst_in_active_timing = calculate_plane_rec_in_timing_active(
   pipe_ctx, &plane_state->dst_rect);
 overlap_in_active_timing = intersect_rec(&recout_clip_in_active_timing,
   &recout_dst_in_active_timing);
 if (overlap_in_active_timing.width > 0 &&
   overlap_in_active_timing.height > 0)
  recout_clip_in_recout_dst = shift_rec(&overlap_in_active_timing,
    -recout_dst_in_active_timing.x,
    -recout_dst_in_active_timing.y);
 else
  memset(&recout_clip_in_recout_dst, 0, sizeof(struct rect));

 /*
 * Work in recout rotation since that requires less transformations
 */

 get_vp_scan_direction(
   plane_state->rotation,
   plane_state->horizontal_mirror,
   &orthogonal_rotation,
   &flip_vert_scan_dir,
   &flip_horz_scan_dir);

 if (orthogonal_rotation) {
  swap(src.width, src.height);
  swap(flip_vert_scan_dir, flip_horz_scan_dir);
 }

 calculate_init_and_vp(
   flip_horz_scan_dir,
   recout_clip_in_recout_dst.x,
   data->recout.width,
   src.width,
   data->taps.h_taps,
   data->ratios.horz,
   &data->inits.h,
   &data->viewport.x,
   &data->viewport.width);
 calculate_init_and_vp(
   flip_horz_scan_dir,
   recout_clip_in_recout_dst.x,
   data->recout.width,
   src.width / vpc_div,
   data->taps.h_taps_c,
   data->ratios.horz_c,
   &data->inits.h_c,
   &data->viewport_c.x,
   &data->viewport_c.width);
 calculate_init_and_vp(
   flip_vert_scan_dir,
   recout_clip_in_recout_dst.y,
   data->recout.height,
   src.height,
   data->taps.v_taps,
   data->ratios.vert,
   &data->inits.v,
   &data->viewport.y,
   &data->viewport.height);
 calculate_init_and_vp(
   flip_vert_scan_dir,
   recout_clip_in_recout_dst.y,
   data->recout.height,
   src.height / vpc_div,
   data->taps.v_taps_c,
   data->ratios.vert_c,
   &data->inits.v_c,
   &data->viewport_c.y,
   &data->viewport_c.height);
 if (orthogonal_rotation) {
  swap(data->viewport.x, data->viewport.y);
  swap(data->viewport.width, data->viewport.height);
  swap(data->viewport_c.x, data->viewport_c.y);
  swap(data->viewport_c.width, data->viewport_c.height);
 }
 data->viewport.x += src.x;
 data->viewport.y += src.y;
 ASSERT(src.x % vpc_div == 0 && src.y % vpc_div == 0);
 data->viewport_c.x += src.x / vpc_div;
 data->viewport_c.y += src.y / vpc_div;
}

static enum controller_dp_test_pattern convert_dp_to_controller_test_pattern(
    enum dp_test_pattern test_pattern)
{
 enum controller_dp_test_pattern controller_test_pattern;

 switch (test_pattern) {
 case DP_TEST_PATTERN_COLOR_SQUARES:
  controller_test_pattern =
    CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
 break;
 case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
  controller_test_pattern =
    CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA;
 break;
 case DP_TEST_PATTERN_VERTICAL_BARS:
  controller_test_pattern =
    CONTROLLER_DP_TEST_PATTERN_VERTICALBARS;
 break;
 case DP_TEST_PATTERN_HORIZONTAL_BARS:
  controller_test_pattern =
    CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS;
 break;
 case DP_TEST_PATTERN_COLOR_RAMP:
  controller_test_pattern =
    CONTROLLER_DP_TEST_PATTERN_COLORRAMP;
 break;
 default:
  controller_test_pattern =
    CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
 break;
 }

 return controller_test_pattern;
}

static enum controller_dp_color_space convert_dp_to_controller_color_space(
  enum dp_test_pattern_color_space color_space)
{
 enum controller_dp_color_space controller_color_space;

 switch (color_space) {
 case DP_TEST_PATTERN_COLOR_SPACE_RGB:
  controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
  break;
 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
  controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601;
  break;
 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
  controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709;
  break;
 case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED:
 default:
  controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
  break;
 }

 return controller_color_space;
}

void resource_build_test_pattern_params(struct resource_context *res_ctx,
    struct pipe_ctx *otg_master)
{
 struct pipe_ctx *opp_heads[MAX_PIPES];
 struct test_pattern_params *params;
 int odm_cnt;
 enum controller_dp_test_pattern controller_test_pattern;
 enum controller_dp_color_space controller_color_space;
 enum dc_color_depth color_depth = otg_master->stream->timing.display_color_depth;
 struct rect odm_slice_src;
 int i;

 controller_test_pattern = convert_dp_to_controller_test_pattern(
   otg_master->stream->test_pattern.type);
 controller_color_space = convert_dp_to_controller_color_space(
   otg_master->stream->test_pattern.color_space);

 if (controller_test_pattern == CONTROLLER_DP_TEST_PATTERN_VIDEOMODE)
  return;

 odm_cnt = resource_get_opp_heads_for_otg_master(otg_master, res_ctx, opp_heads);

 for (i = 0; i < odm_cnt; i++) {
  odm_slice_src = resource_get_odm_slice_src_rect(opp_heads[i]);
  params = &opp_heads[i]->stream_res.test_pattern_params;
  params->test_pattern = controller_test_pattern;
  params->color_space = controller_color_space;
  params->color_depth = color_depth;
  params->height = odm_slice_src.height;
  params->offset = odm_slice_src.x;
  params->width = odm_slice_src.width;
 }
}

bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
{
 const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
 struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
 const struct rect odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx);
 struct scaling_taps temp = {0};
 bool res = false;

 DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);

 /* Invalid input */
 if (!plane_state ||
   !plane_state->dst_rect.width ||
   !plane_state->dst_rect.height ||
   !plane_state->src_rect.width ||
   !plane_state->src_rect.height) {
  ASSERT(0);
  return false;
 }

 /* Timing borders are part of vactive that we are also supposed to skip in addition
 * to any stream dst offset. Since dm logic assumes dst is in addressable
 * space we need to add the left and top borders to dst offsets temporarily.
 * TODO: fix in DM, stream dst is supposed to be in vactive
 */

 pipe_ctx->stream->dst.x += timing->h_border_left;
 pipe_ctx->stream->dst.y += timing->v_border_top;

 /* Calculate H and V active size */
 pipe_ctx->plane_res.scl_data.h_active = odm_slice_src.width;
 pipe_ctx->plane_res.scl_data.v_active = odm_slice_src.height;
 pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
   pipe_ctx->plane_state->format);

#if defined(CONFIG_DRM_AMD_DC_FP)
 if ((pipe_ctx->stream->ctx->dc->config.use_spl) && (!pipe_ctx->stream->ctx->dc->debug.disable_spl)) {
  struct spl_in *spl_in = &pipe_ctx->plane_res.spl_in;
  struct spl_out *spl_out = &pipe_ctx->plane_res.spl_out;

  if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
   pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
  else
   pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;

  pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;

  // Convert pipe_ctx to respective input params for SPL
  translate_SPL_in_params_from_pipe_ctx(pipe_ctx, spl_in);
  /* Pass visual confirm debug information */
  calculate_adjust_recout_for_visual_confirm(pipe_ctx,
   &spl_in->debug.visual_confirm_base_offset,
   &spl_in->debug.visual_confirm_dpp_offset);
  // Set SPL output parameters to dscl_prog_data to be used for hw registers
  spl_out->dscl_prog_data = resource_get_dscl_prog_data(pipe_ctx);
  // Calculate scaler parameters from SPL
  res = spl_calculate_scaler_params(spl_in, spl_out);
  // Convert respective out params from SPL to scaler data
  translate_SPL_out_params_to_pipe_ctx(pipe_ctx, spl_out);

  /* Ignore scaler failure if pipe context plane is phantom plane */
  if (!res && plane_state->is_phantom)
   res = true;
 } else {
#endif
 /* depends on h_active */
 calculate_recout(pipe_ctx);
 /* depends on pixel format */
 calculate_scaling_ratios(pipe_ctx);

 /*
 * LB calculations depend on vp size, h/v_active and scaling ratios
 * Setting line buffer pixel depth to 24bpp yields banding
 * on certain displays, such as the Sharp 4k. 36bpp is needed
 * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
 * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
 * precision on DCN display engines, but apparently not for DCE, as
 * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have
 * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
 * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel
 * passthrough). Therefore only use 36 bpp on DCN where it is actually needed.
 */

 if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
  pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
 else
  pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;

 pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;

 // get TAP value with 100x100 dummy data for max scaling qualify, override
 // if a new scaling quality required
 pipe_ctx->plane_res.scl_data.viewport.width = 100;
 pipe_ctx->plane_res.scl_data.viewport.height = 100;
 pipe_ctx->plane_res.scl_data.viewport_c.width = 100;
 pipe_ctx->plane_res.scl_data.viewport_c.height = 100;
 if (pipe_ctx->plane_res.xfm != NULL)
  res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
    pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);

 if (pipe_ctx->plane_res.dpp != NULL)
  res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
    pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);

 temp = pipe_ctx->plane_res.scl_data.taps;

 calculate_inits_and_viewports(pipe_ctx);

 if (pipe_ctx->plane_res.xfm != NULL)
  res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
    pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);

 if (pipe_ctx->plane_res.dpp != NULL)
  res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
    pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);


 if (!res) {
  /* Try 24 bpp linebuffer */
  pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP;

  if (pipe_ctx->plane_res.xfm != NULL)
   res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
     pipe_ctx->plane_res.xfm,
     &pipe_ctx->plane_res.scl_data,
     &plane_state->scaling_quality);

  if (pipe_ctx->plane_res.dpp != NULL)
   res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps(
     pipe_ctx->plane_res.dpp,
     &pipe_ctx->plane_res.scl_data,
     &plane_state->scaling_quality);
 }

 /* Ignore scaler failure if pipe context plane is phantom plane */
 if (!res && plane_state->is_phantom)
  res = true;

 if (res && (pipe_ctx->plane_res.scl_data.taps.v_taps != temp.v_taps ||
  pipe_ctx->plane_res.scl_data.taps.h_taps != temp.h_taps ||
  pipe_ctx->plane_res.scl_data.taps.v_taps_c != temp.v_taps_c ||
  pipe_ctx->plane_res.scl_data.taps.h_taps_c != temp.h_taps_c))
  calculate_inits_and_viewports(pipe_ctx);

 /*
 * Handle side by side and top bottom 3d recout offsets after vp calculation
 * since 3d is special and needs to calculate vp as if there is no recout offset
 * This may break with rotation, good thing we aren't mixing hw rotation and 3d
 */

 if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->plane_state == plane_state) {
  ASSERT(plane_state->rotation == ROTATION_ANGLE_0 ||
   (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_TOP_AND_BOTTOM &&
    pipe_ctx->stream->view_format != VIEW_3D_FORMAT_SIDE_BY_SIDE));
  if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_TOP_AND_BOTTOM)
   pipe_ctx->plane_res.scl_data.recout.y += pipe_ctx->plane_res.scl_data.recout.height;
  else if (pipe_ctx->stream->view_format == VIEW_3D_FORMAT_SIDE_BY_SIDE)
   pipe_ctx->plane_res.scl_data.recout.x += pipe_ctx->plane_res.scl_data.recout.width;
 }

 /* Clamp minimum viewport size */
 if (pipe_ctx->plane_res.scl_data.viewport.height < MIN_VIEWPORT_SIZE)
  pipe_ctx->plane_res.scl_data.viewport.height = MIN_VIEWPORT_SIZE;
 if (pipe_ctx->plane_res.scl_data.viewport.width < MIN_VIEWPORT_SIZE)
  pipe_ctx->plane_res.scl_data.viewport.width = MIN_VIEWPORT_SIZE;
#ifdef CONFIG_DRM_AMD_DC_FP
 }
#endif
 DC_LOG_SCALER("%s pipe %d:\nViewport: height:%d width:%d x:%d y:%d Recout: height:%d width:%d x:%d y:%d HACTIVE:%d VACTIVE:%d\n"
   "src_rect: height:%d width:%d x:%d y:%d dst_rect: height:%d width:%d x:%d y:%d clip_rect: height:%d width:%d x:%d y:%d\n",
   __func__,
   pipe_ctx->pipe_idx,
   pipe_ctx->plane_res.scl_data.viewport.height,
   pipe_ctx->plane_res.scl_data.viewport.width,
   pipe_ctx->plane_res.scl_data.viewport.x,
   pipe_ctx->plane_res.scl_data.viewport.y,
   pipe_ctx->plane_res.scl_data.recout.height,
   pipe_ctx->plane_res.scl_data.recout.width,
   pipe_ctx->plane_res.scl_data.recout.x,
   pipe_ctx->plane_res.scl_data.recout.y,
   pipe_ctx->plane_res.scl_data.h_active,
   pipe_ctx->plane_res.scl_data.v_active,
   plane_state->src_rect.height,
   plane_state->src_rect.width,
   plane_state->src_rect.x,
   plane_state->src_rect.y,
   plane_state->dst_rect.height,
   plane_state->dst_rect.width,
   plane_state->dst_rect.x,
   plane_state->dst_rect.y,
   plane_state->clip_rect.height,
   plane_state->clip_rect.width,
   plane_state->clip_rect.x,
   plane_state->clip_rect.y);

 pipe_ctx->stream->dst.x -= timing->h_border_left;
 pipe_ctx->stream->dst.y -= timing->v_border_top;

 return res;
}

bool resource_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
{
 struct pipe_ctx *test_pipe, *split_pipe;
 struct rect r1 = pipe_ctx->plane_res.scl_data.recout;
 int r1_right, r1_bottom;
 int cur_layer = pipe_ctx->plane_state->layer_index;

 reverse_adjust_recout_for_visual_confirm(&r1, pipe_ctx);
 r1_right = r1.x + r1.width;
 r1_bottom = r1.y + r1.height;

 /**
 * Disable the cursor if there's another pipe above this with a
 * plane that contains this pipe's viewport to prevent double cursor
 * and incorrect scaling artifacts.
 */

 for (test_pipe = pipe_ctx->top_pipe; test_pipe;
      test_pipe = test_pipe->top_pipe) {
  struct rect r2;
  int r2_right, r2_bottom;
  // Skip invisible layer and pipe-split plane on same layer
  if (!test_pipe->plane_state ||
      !test_pipe->plane_state->visible ||
      test_pipe->plane_state->layer_index == cur_layer)
   continue;

  r2 = test_pipe->plane_res.scl_data.recout;
  reverse_adjust_recout_for_visual_confirm(&r2, test_pipe);
  r2_right = r2.x + r2.width;
  r2_bottom = r2.y + r2.height;

  /**
 * There is another half plane on same layer because of
 * pipe-split, merge together per same height.
 */

  for (split_pipe = pipe_ctx->top_pipe; split_pipe;
       split_pipe = split_pipe->top_pipe)
   if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) {
    struct rect r2_half;

    r2_half = split_pipe->plane_res.scl_data.recout;
    reverse_adjust_recout_for_visual_confirm(&r2_half, split_pipe);
    r2.x = min(r2_half.x, r2.x);
    r2.width = r2.width + r2_half.width;
    r2_right = r2.x + r2.width;
    r2_bottom = min(r2_bottom, r2_half.y + r2_half.height);
    break;
   }

  if (r1.x >= r2.x && r1.y >= r2.y && r1_right <= r2_right && r1_bottom <= r2_bottom)
   return true;
 }

 return false;
}


enum dc_status resource_build_scaling_params_for_context(
 const struct dc  *dc,
 struct dc_state *context)
{
 int i;

 for (i = 0; i < MAX_PIPES; i++) {
  if (context->res_ctx.pipe_ctx[i].plane_state != NULL &&
    context->res_ctx.pipe_ctx[i].stream != NULL)
   if (!resource_build_scaling_params(&context->res_ctx.pipe_ctx[i]))
    return DC_FAIL_SCALING;
 }

 return DC_OK;
}

struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
  struct resource_context *res_ctx,
  const struct resource_pool *pool,
  const struct pipe_ctx *primary_pipe)
{
 int i;
 struct pipe_ctx *secondary_pipe = NULL;

 /*
 * We add a preferred pipe mapping to avoid the chance that
 * MPCCs already in use will need to be reassigned to other trees.
 * For example, if we went with the strict, assign backwards logic:
 *
 * (State 1)
 * Display A on, no surface, top pipe = 0
 * Display B on, no surface, top pipe = 1
 *
 * (State 2)
 * Display A on, no surface, top pipe = 0
 * Display B on, surface enable, top pipe = 1, bottom pipe = 5
 *
 * (State 3)
 * Display A on, surface enable, top pipe = 0, bottom pipe = 5
 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
 *
 * The state 2->3 transition requires remapping MPCC 5 from display B
 * to display A.
 *
 * However, with the preferred pipe logic, state 2 would look like:
 *
 * (State 2)
 * Display A on, no surface, top pipe = 0
 * Display B on, surface enable, top pipe = 1, bottom pipe = 4
 *
 * This would then cause 2->3 to not require remapping any MPCCs.
 */

 if (primary_pipe) {
  int preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx;
  if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
   secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
   secondary_pipe->pipe_idx = preferred_pipe_idx;
  }
 }

 /*
 * search backwards for the second pipe to keep pipe
 * assignment more consistent
 */

 if (!secondary_pipe)
  for (i = pool->pipe_count - 1; i >= 0; i--) {
   if (res_ctx->pipe_ctx[i].stream == NULL) {
    secondary_pipe = &res_ctx->pipe_ctx[i];
    secondary_pipe->pipe_idx = i;
    break;
   }
  }

 return secondary_pipe;
}

int resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master(
  const struct resource_context *cur_res_ctx,
  struct resource_context *new_res_ctx,
  const struct pipe_ctx *cur_otg_master)
{
 const struct pipe_ctx *cur_sec_opp_head = cur_otg_master->next_odm_pipe;
 struct pipe_ctx *new_pipe;
 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;

 while (cur_sec_opp_head) {
  new_pipe = &new_res_ctx->pipe_ctx[cur_sec_opp_head->pipe_idx];
  if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
   free_pipe_idx = cur_sec_opp_head->pipe_idx;
   break;
  }
  cur_sec_opp_head = cur_sec_opp_head->next_odm_pipe;
 }

 return free_pipe_idx;
}

int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
  const struct resource_context *cur_res_ctx,
  struct resource_context *new_res_ctx,
  const struct pipe_ctx *cur_opp_head)
{
 const struct pipe_ctx *cur_sec_dpp = cur_opp_head->bottom_pipe;
 struct pipe_ctx *new_pipe;
 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;

 while (cur_sec_dpp) {
  /* find a free pipe used in current opp blend tree,
 * this is to avoid MPO pipe switching to different opp blending
 * tree
 */

  new_pipe = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx];
  if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
   free_pipe_idx = cur_sec_dpp->pipe_idx;
   break;
  }
  cur_sec_dpp = cur_sec_dpp->bottom_pipe;
 }

 return free_pipe_idx;
}

int recource_find_free_pipe_not_used_in_cur_res_ctx(
  const struct resource_context *cur_res_ctx,
  struct resource_context *new_res_ctx,
  const struct resource_pool *pool)
{
 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
 const struct pipe_ctx *new_pipe, *cur_pipe;
 int i;

 for (i = 0; i < pool->pipe_count; i++) {
  cur_pipe = &cur_res_ctx->pipe_ctx[i];
  new_pipe = &new_res_ctx->pipe_ctx[i];

  if (resource_is_pipe_type(cur_pipe, FREE_PIPE) &&
    resource_is_pipe_type(new_pipe, FREE_PIPE)) {
   free_pipe_idx = i;
   break;
  }
 }

 return free_pipe_idx;
}

int recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx(
  const struct resource_context *cur_res_ctx,
  struct resource_context *new_res_ctx,
  const struct resource_pool *pool)
{
 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
 const struct pipe_ctx *new_pipe, *cur_pipe;
 int i;

 for (i = 0; i < pool->pipe_count; i++) {
  cur_pipe = &cur_res_ctx->pipe_ctx[i];
  new_pipe = &new_res_ctx->pipe_ctx[i];

  if (resource_is_pipe_type(cur_pipe, OTG_MASTER) &&
    resource_is_pipe_type(new_pipe, FREE_PIPE)) {
   free_pipe_idx = i;
   break;
  }
 }

 return free_pipe_idx;
}

int resource_find_free_pipe_used_as_cur_sec_dpp(
  const struct resource_context *cur_res_ctx,
  struct resource_context *new_res_ctx,
  const struct resource_pool *pool)
{
 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
 const struct pipe_ctx *new_pipe, *cur_pipe;
 int i;

 for (i = 0; i < pool->pipe_count; i++) {
  cur_pipe = &cur_res_ctx->pipe_ctx[i];
  new_pipe = &new_res_ctx->pipe_ctx[i];

  if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
    !resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
    resource_is_pipe_type(new_pipe, FREE_PIPE)) {
   free_pipe_idx = i;
   break;
  }
 }

 return free_pipe_idx;
}

int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(
  const struct resource_context *cur_res_ctx,
  struct resource_context *new_res_ctx,
  const struct resource_pool *pool)
{
 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
 const struct pipe_ctx *new_pipe, *cur_pipe;
 int i;

 for (i = 0; i < pool->pipe_count; i++) {
  cur_pipe = &cur_res_ctx->pipe_ctx[i];
  new_pipe = &new_res_ctx->pipe_ctx[i];

  if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
    !resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
    resource_get_mpc_slice_index(cur_pipe) > 0 &&
    resource_is_pipe_type(new_pipe, FREE_PIPE)) {
   free_pipe_idx = i;
   break;
  }
 }

 return free_pipe_idx;
}

int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
  const struct resource_pool *pool)
{
 int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
 const struct pipe_ctx *new_pipe;
 int i;

 for (i = 0; i < pool->pipe_count; i++) {
  new_pipe = &new_res_ctx->pipe_ctx[i];

  if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
   free_pipe_idx = i;
   break;
  }
 }

 return free_pipe_idx;
}

bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type)
{
 switch (type) {
 case OTG_MASTER:
  return !pipe_ctx->prev_odm_pipe &&
    !pipe_ctx->top_pipe &&
    pipe_ctx->stream;
 case OPP_HEAD:
  return !pipe_ctx->top_pipe && pipe_ctx->stream;
 case DPP_PIPE:
  return pipe_ctx->plane_state && pipe_ctx->stream;
 case FREE_PIPE:
  return !pipe_ctx->plane_state && !pipe_ctx->stream;
 default:
  return false;
 }
}

struct pipe_ctx *resource_get_otg_master_for_stream(
  struct resource_context *res_ctx,
  const struct dc_stream_state *stream)
{
 int i;

 for (i = 0; i < MAX_PIPES; i++) {
  if (res_ctx->pipe_ctx[i].stream == stream &&
    resource_is_pipe_type(&res_ctx->pipe_ctx[i], OTG_MASTER))
   return &res_ctx->pipe_ctx[i];
 }
 return NULL;
}

int resource_get_opp_heads_for_otg_master(const struct pipe_ctx *otg_master,
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=92 G=93

¤ Dauer der Verarbeitung: 0.20 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.