/* SPDX-License-Identifier: MIT */ /* * Copyright 2023 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 "dml2_dc_types.h" #include "dml2_internal_types.h" #include "dml2_utils.h" #include "dml2_mall_phantom.h" unsigned int dml2_helper_calculate_num_ways_for_subvp(struct dml2_context *ctx, struct dc_state *context) { … } static void merge_pipes_for_subvp(struct dml2_context *ctx, struct dc_state *context) { … } static bool all_pipes_have_stream_and_plane(struct dml2_context *ctx, const struct dc_state *context) { … } static bool mpo_in_use(const struct dc_state *context) { … } /* * dcn32_get_num_free_pipes: Calculate number of free pipes * * This function assumes that a "used" pipe is a pipe that has * both a stream and a plane assigned to it. * * @dc: current dc state * @context: new dc state * * Return: * Number of free pipes available in the context */ static unsigned int get_num_free_pipes(struct dml2_context *ctx, struct dc_state *state) { … } /* * dcn32_assign_subvp_pipe: Function to decide which pipe will use Sub-VP. * * 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]). * * @param dc: current dc state * @param context: new dc state * @param index: [out] dc pipe index for the pipe chosen to have phantom pipes assigned * * Return: * True if a valid pipe assignment was found for Sub-VP. Otherwise false. */ static bool assign_subvp_pipe(struct dml2_context *ctx, struct dc_state *context, unsigned int *index) { … } /* * enough_pipes_for_subvp: Function to check if there are "enough" pipes for SubVP. * * 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. * * @dc: current dc state * @context: new dc state * * 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 enough_pipes_for_subvp(struct dml2_context *ctx, struct dc_state *state) { … } /* * subvp_subvp_schedulable: Determine if SubVP + SubVP config is schedulable * * 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. * * @dc: current dc state * @context: new dc state * * Return: * bool - True if the SubVP + SubVP config is schedulable, false otherwise */ static bool subvp_subvp_schedulable(struct dml2_context *ctx, struct dc_state *context) { … } /* * dml2_svp_drr_schedulable: Determine if SubVP + DRR config is schedulable * * 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 * * @dc: current dc state * @context: new dc state * @drr_pipe: DRR pipe_ctx for the SubVP + DRR config * * Return: * bool - True if the SubVP + DRR config is schedulable, false otherwise */ bool dml2_svp_drr_schedulable(struct dml2_context *ctx, struct dc_state *context, struct dc_crtc_timing *drr_timing) { … } /* * subvp_vblank_schedulable: Determine if SubVP + VBLANK config is schedulable * * 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 * * @dc: current dc state * @context: new dc state * * Return: * bool - True if the SubVP + VBLANK/DRR config is schedulable, false otherwise */ static bool subvp_vblank_schedulable(struct dml2_context *ctx, struct dc_state *context) { … } /* * subvp_validate_static_schedulability: Check which SubVP case is calculated and handle * static analysis based on the case. * * Three cases: * 1. SubVP + SubVP * 2. SubVP + VBLANK (DRR checked internally) * 3. SubVP + VACTIVE (currently unsupported) * * @dc: current dc state * @context: new dc state * @vlevel: Voltage level calculated by DML * * Return: * bool - True if statically schedulable, false otherwise */ bool dml2_svp_validate_static_schedulability(struct dml2_context *ctx, struct dc_state *context, enum dml_dram_clock_change_support pstate_change_type) { … } static void set_phantom_stream_timing(struct dml2_context *ctx, struct dc_state *state, struct pipe_ctx *ref_pipe, struct dc_stream_state *phantom_stream, unsigned int dc_pipe_idx, unsigned int svp_height, unsigned int svp_vstartup) { … } static struct dc_stream_state *enable_phantom_stream(struct dml2_context *ctx, struct dc_state *state, unsigned int dc_pipe_idx, unsigned int svp_height, unsigned int vstartup) { … } static void enable_phantom_plane(struct dml2_context *ctx, struct dc_state *state, struct dc_stream_state *phantom_stream, unsigned int dc_pipe_idx) { … } static void add_phantom_pipes_for_main_pipe(struct dml2_context *ctx, struct dc_state *state, unsigned int main_pipe_idx, unsigned int svp_height, unsigned int vstartup) { … } static bool remove_all_phantom_planes_for_stream(struct dml2_context *ctx, struct dc_stream_state *stream, struct dc_state *context) { … } bool dml2_svp_remove_all_phantom_pipes(struct dml2_context *ctx, struct dc_state *state) { … } /* Conditions for setting up phantom pipes for SubVP: * 1. Not force disable SubVP * 2. Full update (i.e. !fast_validate) * 3. Enough pipes are available to support SubVP (TODO: Which pipes will use VACTIVE / VBLANK / SUBVP?) * 4. Display configuration passes validation * 5. (Config doesn't support MCLK in VACTIVE/VBLANK || dc->debug.force_subvp_mclk_switch) */ bool dml2_svp_add_phantom_pipe_to_dc_state(struct dml2_context *ctx, struct dc_state *state, struct dml_mode_support_info_st *mode_support_info) { … }