1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright 2021 Advanced Micro Devices, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 * OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: AMD 24 * 25 */ 26 27 #include "amdgpu_dm_psr.h" 28 #include "amdgpu.h" 29 #include "dc_dmub_srv.h" 30 #include "dc.h" 31 #include "amdgpu_dm.h" 32 #include "modules/power/power_helpers.h" 33 #include "amdgpu_dm_kunit_helpers.h" 34 35 36 static bool link_supports_psrsu(struct dc_link *link) 37 { 38 struct dc *dc = link->ctx->dc; 39 40 if (!dc->caps.dmcub_support) 41 return false; 42 43 if (dc->ctx->dce_version < DCN_VERSION_3_1) 44 return false; 45 46 if (!is_psr_su_specific_panel(link)) 47 return false; 48 49 if (!link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP || 50 !link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED) 51 return false; 52 53 if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.SU_GRANULARITY_REQUIRED && 54 !link->dpcd_caps.psr_info.psr2_su_y_granularity_cap) 55 return false; 56 57 if (amdgpu_dc_debug_mask & DC_DISABLE_PSR_SU) 58 return false; 59 60 /* Temporarily disable PSR-SU to avoid glitches */ 61 return false; 62 } 63 64 STATIC_IFN_KUNIT 65 void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps) 66 { 67 struct dpcd_caps *dpcd_caps = &link->dpcd_caps; 68 unsigned int power_opts = 0; 69 70 if (amdgpu_dc_feature_mask & DC_PSR_ALLOW_SMU_OPT) 71 power_opts |= psr_power_opt_smu_opt_static_screen; 72 power_opts |= psr_power_opt_z10_static_screen; 73 74 if (link->psr_settings.psr_version == DC_PSR_VERSION_1) 75 caps->psr_version = 1; 76 else if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) 77 caps->psr_version = 2; 78 79 caps->psr_rfb_setup_time = (6 - dpcd_caps->psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME) * 55; 80 caps->psr_exit_link_training_required = 81 !dpcd_caps->psr_info.psr_dpcd_caps.bits.LINK_TRAINING_ON_EXIT_NOT_REQUIRED; 82 caps->edp_revision = dpcd_caps->edp_rev; 83 caps->support_ver = dpcd_caps->psr_info.psr_version; 84 caps->su_granularity_required = 85 dpcd_caps->psr_info.psr_dpcd_caps.bits.SU_GRANULARITY_REQUIRED; 86 caps->y_coordinate_required = dpcd_caps->psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED; 87 caps->su_y_granularity = dpcd_caps->psr_info.psr2_su_y_granularity_cap; 88 caps->alpm_cap = dpcd_caps->alpm_caps.bits.AUX_WAKE_ALPM_CAP; 89 caps->standby_support = dpcd_caps->alpm_caps.bits.PM_STATE_2A_SUPPORT; 90 caps->rate_control_caps = 0; /* TODO: read in rc caps from aux */ 91 caps->psr_power_opt_flag = power_opts; 92 } 93 EXPORT_IF_KUNIT(amdgpu_dm_psr_fill_caps); 94 95 /* 96 * amdgpu_dm_set_psr_caps() - set link psr capabilities 97 * @link: link 98 * @aconnector: amdgpu_dm_connector 99 */ 100 bool amdgpu_dm_set_psr_caps(struct dc_link *link, struct amdgpu_dm_connector *aconnector) 101 { 102 struct dc *dc; 103 unsigned int panel_inst = 0; 104 105 if (!link || !aconnector) 106 return false; 107 108 dc = link->ctx->dc; 109 110 /* Reset psr version first */ 111 link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; 112 113 if (!dc->caps.dmub_caps.psr) 114 return false; 115 116 if (!(link->connector_signal & SIGNAL_TYPE_EDP)) 117 return false; 118 119 if (link->type == dc_connection_none) 120 return false; 121 122 if (link->dpcd_caps.psr_info.psr_version == 0) 123 return false; 124 125 /*disable allow psr/psrsu/replay on eDP1*/ 126 if (dc_get_edp_link_panel_inst(dc, link, &panel_inst) && panel_inst == 1) 127 return false; 128 129 if (link_supports_psrsu(link)) 130 link->psr_settings.psr_version = DC_PSR_VERSION_SU_1; 131 else 132 link->psr_settings.psr_version = DC_PSR_VERSION_1; 133 134 amdgpu_dm_psr_fill_caps(link, &aconnector->psr_caps); 135 return true; 136 } 137 138 /* 139 * amdgpu_dm_psr_is_active_allowed() - check if psr is allowed on any stream 140 * @dm: pointer to amdgpu_display_manager 141 * 142 * Return: true if allowed 143 */ 144 145 bool amdgpu_dm_psr_is_active_allowed(struct amdgpu_display_manager *dm) 146 { 147 unsigned int i; 148 149 for (i = 0; i < dm->dc->current_state->stream_count; i++) { 150 const struct dc_link *link = dm->dc->current_state->streams[i]->link; 151 152 if (!link) 153 continue; 154 155 if (link->psr_settings.psr_feature_enabled && link->psr_settings.psr_allow_active) 156 return true; 157 } 158 return false; 159 } 160 161 /* 162 * amdgpu_dm_psr_set_event() - set or clear PSR event for stream 163 * @dm: pointer to amdgpu_display_manager 164 * @stream: pointer to dc_stream_state 165 * @set_event: true to set event, false to clear event 166 * @event: PSR event type 167 * @wait_for_disable: whether to wait for PSR to be disabled 168 * 169 * Return: true if successful, false otherwise 170 */ 171 bool amdgpu_dm_psr_set_event(struct amdgpu_display_manager *dm, struct dc_stream_state *stream, 172 bool set_event, enum psr_event event, bool wait_for_disable) 173 { 174 unsigned int psr_events; 175 176 /* Validate all required parameters */ 177 if (!stream || !stream->link || 178 !stream->link->psr_settings.psr_feature_enabled) 179 return false; 180 181 /* Get current psr events */ 182 if (!mod_power_get_psr_event(dm->power_module, stream, &psr_events)) 183 return false; 184 185 /* If all events already in desired state, return true. */ 186 if ((psr_events & event) == (set_event ? event : 0)) 187 return true; 188 189 return mod_power_set_psr_event(dm->power_module, stream, 190 set_event, event, wait_for_disable); 191 } 192 EXPORT_IF_KUNIT(amdgpu_dm_psr_set_event); 193