1 | /* |
2 | * Copyright 2023 Advanced Micro Devices, Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
22 | * Authors: AMD |
23 | * |
24 | */ |
25 | |
26 | #include "amdgpu_dm_replay.h" |
27 | #include "dc.h" |
28 | #include "dm_helpers.h" |
29 | #include "amdgpu_dm.h" |
30 | #include "modules/power/power_helpers.h" |
31 | #include "dmub/inc/dmub_cmd.h" |
32 | #include "dc/inc/link.h" |
33 | |
34 | /* |
35 | * link_supports_replay() - check if the link supports replay |
36 | * @link: link |
37 | * @aconnector: aconnector |
38 | * |
39 | */ |
40 | static bool link_supports_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector) |
41 | { |
42 | struct dm_connector_state *state = to_dm_connector_state(aconnector->base.state); |
43 | struct dpcd_caps *dpcd_caps = &link->dpcd_caps; |
44 | struct adaptive_sync_caps *as_caps = &link->dpcd_caps.adaptive_sync_caps; |
45 | |
46 | if (!state->freesync_capable) |
47 | return false; |
48 | |
49 | if (!aconnector->vsdb_info.replay_mode) |
50 | return false; |
51 | |
52 | // Check the eDP version |
53 | if (dpcd_caps->edp_rev < EDP_REVISION_13) |
54 | return false; |
55 | |
56 | if (!dpcd_caps->alpm_caps.bits.AUX_WAKE_ALPM_CAP) |
57 | return false; |
58 | |
59 | // Check adaptive sync support cap |
60 | if (!as_caps->dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT) |
61 | return false; |
62 | |
63 | // Sink shall populate line deviation information |
64 | if (dpcd_caps->pr_info.pixel_deviation_per_line == 0 || |
65 | dpcd_caps->pr_info.max_deviation_line == 0) |
66 | return false; |
67 | |
68 | return true; |
69 | } |
70 | |
71 | /* |
72 | * amdgpu_dm_set_replay_caps() - setup Replay capabilities |
73 | * @link: link |
74 | * @aconnector: aconnector |
75 | * |
76 | */ |
77 | bool amdgpu_dm_set_replay_caps(struct dc_link *link, struct amdgpu_dm_connector *aconnector) |
78 | { |
79 | struct replay_config pr_config = { 0 }; |
80 | union replay_debug_flags *debug_flags = NULL; |
81 | |
82 | // If Replay is already set to support, return true to skip checks |
83 | if (link->replay_settings.config.replay_supported) |
84 | return true; |
85 | |
86 | if (!dc_is_embedded_signal(signal: link->connector_signal)) |
87 | return false; |
88 | |
89 | if (link->panel_config.psr.disallow_replay) |
90 | return false; |
91 | |
92 | if (!link_supports_replay(link, aconnector)) |
93 | return false; |
94 | |
95 | // Mark Replay is supported in pr_config |
96 | pr_config.replay_supported = true; |
97 | |
98 | debug_flags = (union replay_debug_flags *)&pr_config.debug_flags; |
99 | debug_flags->u32All = 0; |
100 | debug_flags->bitfields.visual_confirm = |
101 | link->ctx->dc->debug.visual_confirm == VISUAL_CONFIRM_REPLAY; |
102 | |
103 | init_replay_config(link, pr_config: &pr_config); |
104 | |
105 | return true; |
106 | } |
107 | |
108 | /* |
109 | * amdgpu_dm_link_setup_replay() - configure replay link |
110 | * @link: link |
111 | * @aconnector: aconnector |
112 | * |
113 | */ |
114 | bool amdgpu_dm_link_setup_replay(struct dc_link *link, struct amdgpu_dm_connector *aconnector) |
115 | { |
116 | struct replay_config *pr_config; |
117 | |
118 | if (link == NULL || aconnector == NULL) |
119 | return false; |
120 | |
121 | pr_config = &link->replay_settings.config; |
122 | |
123 | if (!pr_config->replay_supported) |
124 | return false; |
125 | |
126 | pr_config->replay_power_opt_supported = 0x11; |
127 | pr_config->replay_smu_opt_supported = false; |
128 | pr_config->replay_enable_option |= pr_enable_option_static_screen; |
129 | pr_config->replay_support_fast_resync_in_ultra_sleep_mode = aconnector->max_vfreq >= 2 * aconnector->min_vfreq; |
130 | pr_config->replay_timing_sync_supported = false; |
131 | |
132 | if (!pr_config->replay_timing_sync_supported) |
133 | pr_config->replay_enable_option &= ~pr_enable_option_general_ui; |
134 | |
135 | link->replay_settings.replay_feature_enabled = true; |
136 | |
137 | return true; |
138 | } |
139 | |
140 | /* |
141 | * amdgpu_dm_replay_enable() - enable replay f/w |
142 | * @stream: stream state |
143 | * |
144 | * Return: true if success |
145 | */ |
146 | bool amdgpu_dm_replay_enable(struct dc_stream_state *stream, bool wait) |
147 | { |
148 | bool replay_active = true; |
149 | struct dc_link *link = NULL; |
150 | |
151 | if (stream == NULL) |
152 | return false; |
153 | |
154 | link = stream->link; |
155 | |
156 | if (link) { |
157 | link->dc->link_srv->edp_setup_replay(link, stream); |
158 | link->dc->link_srv->edp_set_coasting_vtotal(link, stream->timing.v_total); |
159 | DRM_DEBUG_DRIVER("Enabling replay...\n" ); |
160 | link->dc->link_srv->edp_set_replay_allow_active(link, &replay_active, wait, false, NULL); |
161 | return true; |
162 | } |
163 | |
164 | return false; |
165 | } |
166 | |
167 | /* |
168 | * amdgpu_dm_replay_disable() - disable replay f/w |
169 | * @stream: stream state |
170 | * |
171 | * Return: true if success |
172 | */ |
173 | bool amdgpu_dm_replay_disable(struct dc_stream_state *stream) |
174 | { |
175 | bool replay_active = false; |
176 | struct dc_link *link = NULL; |
177 | |
178 | if (stream == NULL) |
179 | return false; |
180 | |
181 | link = stream->link; |
182 | |
183 | if (link) { |
184 | DRM_DEBUG_DRIVER("Disabling replay...\n" ); |
185 | link->dc->link_srv->edp_set_replay_allow_active(stream->link, &replay_active, true, false, NULL); |
186 | return true; |
187 | } |
188 | |
189 | return false; |
190 | } |
191 | |
192 | /* |
193 | * amdgpu_dm_replay_disable_all() - disable replay f/w |
194 | * if replay is enabled on any stream |
195 | * |
196 | * Return: true if success |
197 | */ |
198 | bool amdgpu_dm_replay_disable_all(struct amdgpu_display_manager *dm) |
199 | { |
200 | DRM_DEBUG_DRIVER("Disabling replay if replay is enabled on any stream\n" ); |
201 | return dc_set_replay_allow_active(dc: dm->dc, active: false); |
202 | } |
203 | |