linux/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c

// SPDX-License-Identifier: MIT
/*
 * Copyright 2022 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 "dcn32_fpu.h"
#include "dcn32/dcn32_resource.h"
#include "dcn20/dcn20_resource.h"
#include "display_mode_vba_util_32.h"
#include "dml/dcn32/display_mode_vba_32.h"
// We need this includes for WATERMARKS_* defines
#include "clk_mgr/dcn32/dcn32_smu13_driver_if.h"
#include "dcn30/dcn30_resource.h"
#include "link.h"
#include "dc_state_priv.h"

#define DC_LOGGER_INIT(logger)

static const struct subvp_high_refresh_list subvp_high_refresh_list =;

static const struct subvp_active_margin_list subvp_active_margin_list =;

struct _vcs_dpi_ip_params_st dcn3_2_ip =;

struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc =;

static bool dcn32_apply_merge_split_flags_helper(struct dc *dc, struct dc_state *context,
	bool *repopulate_pipes, int *split, bool *merge);

void dcn32_build_wm_range_table_fpu(struct clk_mgr_internal *clk_mgr)
{}

/*
 * Finds dummy_latency_index when MCLK switching using firmware based
 * vblank stretch is enabled. This function will iterate through the
 * table of dummy pstate latencies until the lowest value that allows
 * dm_allow_self_refresh_and_mclk_switch to happen is found
 */
int dcn32_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc,
							    struct dc_state *context,
							    display_e2e_pipe_params_st *pipes,
							    int pipe_cnt,
							    int vlevel)
{}

/**
 * dcn32_helper_populate_phantom_dlg_params - Get DLG params for phantom pipes
 * and populate pipe_ctx with those params.
 * @dc: [in] current dc state
 * @context: [in] new dc state
 * @pipes: [in] DML pipe params array
 * @pipe_cnt: [in] DML pipe count
 *
 * This function must be called AFTER the phantom pipes are added to context
 * and run through DML (so that the DLG params for the phantom pipes can be
 * populated), and BEFORE we program the timing for the phantom pipes.
 */
void dcn32_helper_populate_phantom_dlg_params(struct dc *dc,
					      struct dc_state *context,
					      display_e2e_pipe_params_st *pipes,
					      int pipe_cnt)
{}

static float calculate_net_bw_in_kbytes_sec(struct _vcs_dpi_voltage_scaling_st *entry)
{}

static void get_optimal_ntuple(struct _vcs_dpi_voltage_scaling_st *entry)
{}

static void insert_entry_into_table_sorted(struct _vcs_dpi_voltage_scaling_st *table,
				    unsigned int *num_entries,
				    struct _vcs_dpi_voltage_scaling_st *entry)
{}

/**
 * dcn32_set_phantom_stream_timing - Set timing params for the phantom stream
 * @dc: current dc state
 * @context: new dc state
 * @ref_pipe: Main pipe for the phantom stream
 * @phantom_stream: target phantom stream state
 * @pipes: DML pipe params
 * @pipe_cnt: number of DML pipes
 * @dc_pipe_idx: DC pipe index for the main pipe (i.e. ref_pipe)
 *
 * Set timing params of the phantom stream based on calculated output from DML.
 * This function first gets the DML pipe index using the DC pipe index, then
 * calls into DML (get_subviewport_lines_needed_in_mall) to get the number of
 * lines required for SubVP MCLK switching and assigns to the phantom stream
 * accordingly.
 *
 * - The number of SubVP lines calculated in DML does not take into account
 * FW processing delays and required pstate allow width, so we must include
 * that separately.
 *
 * - Set phantom backporch = vstartup of main pipe
 */
void dcn32_set_phantom_stream_timing(struct dc *dc,
				     struct dc_state *context,
				     struct pipe_ctx *ref_pipe,
				     struct dc_stream_state *phantom_stream,
				     display_e2e_pipe_params_st *pipes,
				     unsigned int pipe_cnt,
				     unsigned int dc_pipe_idx)
{}

/**
 * dcn32_get_num_free_pipes - Calculate number of free pipes
 * @dc: current dc state
 * @context: new dc state
 *
 * This function assumes that a "used" pipe is a pipe that has
 * both a stream and a plane assigned to it.
 *
 * Return: Number of free pipes available in the context
 */
static unsigned int dcn32_get_num_free_pipes(struct dc *dc, struct dc_state *context)
{}

/**
 * dcn32_assign_subvp_pipe - Function to decide which pipe will use Sub-VP.
 * @dc: current dc state
 * @context: new dc state
 * @index: [out] dc pipe index for the pipe chosen to have phantom pipes assigned
 *
 * We enter this function if we are Sub-VP capable (i.e. enough pipes available)
 * and regular P-State switching (i.e. VACTIVE/VBLANK) is not supported, or if
 * we are forcing SubVP P-State switching on the current config.
 *
 * The number of pipes used for the chosen surface must be less than or equal to the
 * number of free pipes available.
 *
 * In general we choose surfaces with the longest frame time first (better for SubVP + VBLANK).
 * For multi-display cases the ActiveDRAMClockChangeMargin doesn't provide enough info on its own
 * for determining which should be the SubVP pipe (need a way to determine if a pipe / plane doesn't
 * support MCLK switching naturally [i.e. ACTIVE or VBLANK]).
 *
 * Return: True if a valid pipe assignment was found for Sub-VP. Otherwise false.
 */
static bool dcn32_assign_subvp_pipe(struct dc *dc,
				    struct dc_state *context,
				    unsigned int *index)
{}

/**
 * dcn32_enough_pipes_for_subvp - Function to check if there are "enough" pipes for SubVP.
 * @dc: current dc state
 * @context: new dc state
 *
 * This function returns true if there are enough free pipes
 * to create the required phantom pipes for any given stream
 * (that does not already have phantom pipe assigned).
 *
 * e.g. For a 2 stream config where the first stream uses one
 * pipe and the second stream uses 2 pipes (i.e. pipe split),
 * this function will return true because there is 1 remaining
 * pipe which can be used as the phantom pipe for the non pipe
 * split pipe.
 *
 * Return:
 * True if there are enough free pipes to assign phantom pipes to at least one
 * stream that does not already have phantom pipes assigned. Otherwise false.
 */
static bool dcn32_enough_pipes_for_subvp(struct dc *dc, struct dc_state *context)
{}

/**
 * subvp_subvp_schedulable - Determine if SubVP + SubVP config is schedulable
 * @dc: current dc state
 * @context: new dc state
 *
 * High level algorithm:
 * 1. Find longest microschedule length (in us) between the two SubVP pipes
 * 2. Check if the worst case overlap (VBLANK in middle of ACTIVE) for both
 * pipes still allows for the maximum microschedule to fit in the active
 * region for both pipes.
 *
 * Return: True if the SubVP + SubVP config is schedulable, false otherwise
 */
static bool subvp_subvp_schedulable(struct dc *dc, struct dc_state *context)
{}

/**
 * subvp_drr_schedulable() - Determine if SubVP + DRR config is schedulable
 * @dc: current dc state
 * @context: new dc state
 *
 * High level algorithm:
 * 1. Get timing for SubVP pipe, phantom pipe, and DRR pipe
 * 2. Determine the frame time for the DRR display when adding required margin for MCLK switching
 * (the margin is equal to the MALL region + DRR margin (500us))
 * 3.If (SubVP Active - Prefetch > Stretched DRR frame + max(MALL region, Stretched DRR frame))
 * then report the configuration as supported
 *
 * Return: True if the SubVP + DRR config is schedulable, false otherwise
 */
static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context)
{}


/**
 * subvp_vblank_schedulable - Determine if SubVP + VBLANK config is schedulable
 * @dc: current dc state
 * @context: new dc state
 *
 * High level algorithm:
 * 1. Get timing for SubVP pipe, phantom pipe, and VBLANK pipe
 * 2. If (SubVP Active - Prefetch > Vblank Frame Time + max(MALL region, Vblank blanking time))
 * then report the configuration as supported
 * 3. If the VBLANK display is DRR, then take the DRR static schedulability path
 *
 * Return: True if the SubVP + VBLANK/DRR config is schedulable, false otherwise
 */
static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
{}

/**
 * subvp_subvp_admissable() - Determine if subvp + subvp config is admissible
 *
 * @dc: Current DC state
 * @context: New DC state to be programmed
 *
 * SubVP + SubVP is admissible under the following conditions:
 * - All SubVP pipes are < 120Hz OR
 * - All SubVP pipes are >= 120hz
 *
 * Return: True if admissible, false otherwise
 */
static bool subvp_subvp_admissable(struct dc *dc,
				struct dc_state *context)
{}

/**
 * subvp_validate_static_schedulability - Check which SubVP case is calculated
 * and handle static analysis based on the case.
 * @dc: current dc state
 * @context: new dc state
 * @vlevel: Voltage level calculated by DML
 *
 * Three cases:
 * 1. SubVP + SubVP
 * 2. SubVP + VBLANK (DRR checked internally)
 * 3. SubVP + VACTIVE (currently unsupported)
 *
 * Return: True if statically schedulable, false otherwise
 */
static bool subvp_validate_static_schedulability(struct dc *dc,
				struct dc_state *context,
				int vlevel)
{}

static void assign_subvp_index(struct dc *dc, struct dc_state *context)
{}

struct pipe_slice_table {};


static void update_slice_table_for_stream(struct pipe_slice_table *table,
		struct dc_stream_state *stream, int diff)
{}

static void update_slice_table_for_plane(struct pipe_slice_table *table,
		struct pipe_ctx *dpp_pipe, struct dc_plane_state *plane, int diff)
{}

static void init_pipe_slice_table_from_context(
		struct pipe_slice_table *table,
		struct dc_state *context)
{}

static bool update_pipe_slice_table_with_split_flags(
		struct pipe_slice_table *table,
		struct dc *dc,
		struct dc_state *context,
		struct vba_vars_st *vba,
		int split[MAX_PIPES],
		bool merge[MAX_PIPES])
{}

static void update_pipes_with_slice_table(struct dc *dc, struct dc_state *context,
		struct pipe_slice_table *table)
{}

static bool update_pipes_with_split_flags(struct dc *dc, struct dc_state *context,
		struct vba_vars_st *vba, int split[MAX_PIPES],
		bool merge[MAX_PIPES])
{}

static bool should_apply_odm_power_optimization(struct dc *dc,
		struct dc_state *context, struct vba_vars_st *v, int *split,
		bool *merge)
{}

static void try_odm_power_optimization_and_revalidate(
		struct dc *dc,
		struct dc_state *context,
		display_e2e_pipe_params_st *pipes,
		int *split,
		bool *merge,
		unsigned int *vlevel,
		int pipe_cnt)
{}

static bool is_test_pattern_enabled(
		struct dc_state *context)
{}

static bool dcn32_full_validate_bw_helper(struct dc *dc,
				   struct dc_state *context,
				   display_e2e_pipe_params_st *pipes,
				   int *vlevel,
				   int *split,
				   bool *merge,
				   int *pipe_cnt,
				   bool *repopulate_pipes)
{}

static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
{}

static void dcn20_adjust_freesync_v_startup(const struct dc_crtc_timing *dc_crtc_timing, int *vstartup_start)
{}

static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context,
				       display_e2e_pipe_params_st *pipes,
				       int pipe_cnt, int vlevel)
{}

static struct pipe_ctx *dcn32_find_split_pipe(
		struct dc *dc,
		struct dc_state *context,
		int old_index)
{}

static bool dcn32_split_stream_for_mpc_or_odm(
		const struct dc *dc,
		struct resource_context *res_ctx,
		struct pipe_ctx *pri_pipe,
		struct pipe_ctx *sec_pipe,
		bool odm)
{}

static bool dcn32_apply_merge_split_flags_helper(
		struct dc *dc,
		struct dc_state *context,
		bool *repopulate_pipes,
		int *split,
		bool *merge)
{}

bool dcn32_internal_validate_bw(struct dc *dc,
				struct dc_state *context,
				display_e2e_pipe_params_st *pipes,
				int *pipe_cnt_out,
				int *vlevel_out,
				bool fast_validate)
{}


void dcn32_calculate_wm_and_dlg_fpu(struct dc *dc, struct dc_state *context,
				display_e2e_pipe_params_st *pipes,
				int pipe_cnt,
				int vlevel)
{}

static void dcn32_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
		unsigned int *optimal_dcfclk,
		unsigned int *optimal_fclk)
{}

static void remove_entry_from_table_at_index(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries,
		unsigned int index)
{}

void dcn32_patch_dpm_table(struct clk_bw_params *bw_params)
{}

static void swap_table_entries(struct _vcs_dpi_voltage_scaling_st *first_entry,
		struct _vcs_dpi_voltage_scaling_st *second_entry)
{}

/*
 * sort_entries_with_same_bw - Sort entries sharing the same bandwidth by DCFCLK
 */
static void sort_entries_with_same_bw(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries)
{}

/*
 * remove_inconsistent_entries - Ensure entries with the same bandwidth have MEMCLK and FCLK monotonically increasing
 *                               and remove entries that do not
 */
static void remove_inconsistent_entries(struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries)
{}

/*
 * override_max_clk_values - Overwrite the max clock frequencies with the max DC mode timings
 * Input:
 *	max_clk_limit - struct containing the desired clock timings
 * Output:
 *	curr_clk_limit  - struct containing the timings that need to be overwritten
 * Return: 0 upon success, non-zero for failure
 */
static int override_max_clk_values(struct clk_limit_table_entry *max_clk_limit,
		struct clk_limit_table_entry *curr_clk_limit)
{}

static int build_synthetic_soc_states(bool disable_dc_mode_overwrite, struct clk_bw_params *bw_params,
		struct _vcs_dpi_voltage_scaling_st *table, unsigned int *num_entries)
{}

/*
 * dcn32_update_bw_bounding_box
 *
 * This would override some dcn3_2 ip_or_soc initial parameters hardcoded from
 * spreadsheet with actual values as per dGPU SKU:
 * - with passed few options from dc->config
 * - with dentist_vco_frequency from Clk Mgr (currently hardcoded, but might
 *   need to get it from PM FW)
 * - with passed latency values (passed in ns units) in dc-> bb override for
 *   debugging purposes
 * - with passed latencies from VBIOS (in 100_ns units) if available for
 *   certain dGPU SKU
 * - with number of DRAM channels from VBIOS (which differ for certain dGPU SKU
 *   of the same ASIC)
 * - clocks levels with passed clk_table entries from Clk Mgr as reported by PM
 *   FW for different clocks (which might differ for certain dGPU SKU of the
 *   same ASIC)
 */
void dcn32_update_bw_bounding_box_fpu(struct dc *dc, struct clk_bw_params *bw_params)
{}

void dcn32_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes,
				  int pipe_cnt)
{}

bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe)
{}

/**
 * dcn32_allow_subvp_high_refresh_rate: Determine if the high refresh rate config will allow subvp
 *
 * @dc: Current DC state
 * @context: New DC state to be programmed
 * @pipe: Pipe to be considered for use in subvp
 *
 * On high refresh rate display configs, we will allow subvp under the following conditions:
 * 1. Resolution is 3840x2160, 3440x1440, or 2560x1440
 * 2. Refresh rate is between 120hz - 165hz
 * 3. No scaling
 * 4. Freesync is inactive
 * 5. For single display cases, freesync must be disabled
 *
 * Return: True if pipe can be used for subvp, false otherwise
 */
bool dcn32_allow_subvp_high_refresh_rate(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe)
{}

/**
 * dcn32_determine_max_vratio_prefetch: Determine max Vratio for prefetch by driver policy
 *
 * @dc: Current DC state
 * @context: New DC state to be programmed
 *
 * Return: Max vratio for prefetch
 */
double dcn32_determine_max_vratio_prefetch(struct dc *dc, struct dc_state *context)
{}

/**
 * dcn32_assign_fpo_vactive_candidate - Assign the FPO stream candidate for FPO + VActive case
 *
 * This function chooses the FPO candidate stream for FPO + VActive cases (2 stream config).
 * For FPO + VAtive cases, the assumption is that one display has ActiveMargin > 0, and the
 * other display has ActiveMargin <= 0. This function will choose the pipe/stream that has
 * ActiveMargin <= 0 to be the FPO stream candidate if found.
 *
 *
 * @dc: current dc state
 * @context: new dc state
 * @fpo_candidate_stream: pointer to FPO stream candidate if one is found
 *
 * Return: void
 */
void dcn32_assign_fpo_vactive_candidate(struct dc *dc, const struct dc_state *context, struct dc_stream_state **fpo_candidate_stream)
{}

/**
 * dcn32_find_vactive_pipe - Determines if the config has a pipe that can switch in VACTIVE
 *
 * @dc: current dc state
 * @context: new dc state
 * @fpo_candidate_stream: candidate stream to be chosen for FPO
 * @vactive_margin_req_us: The vactive marign required for a vactive pipe to be considered "found"
 *
 * Return: True if VACTIVE display is found, false otherwise
 */
bool dcn32_find_vactive_pipe(struct dc *dc, const struct dc_state *context, struct dc_stream_state *fpo_candidate_stream, uint32_t vactive_margin_req_us)
{}

void dcn32_set_clock_limits(const struct _vcs_dpi_soc_bounding_box_st *soc_bb)
{}

void dcn32_override_min_req_memclk(struct dc *dc, struct dc_state *context)
{}