Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/*
2 * Copyright 2021 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_psr.h"
27#include "dc.h"
28#include "dm_helpers.h"
29#include "amdgpu_dm.h"
30
31static bool link_get_psr_caps(struct dc_link *link)
32{
33 uint8_t psr_dpcd_data[EDP_PSR_RECEIVER_CAP_SIZE];
34 uint8_t edp_rev_dpcd_data;
35
36
37
38 if (!dm_helpers_dp_read_dpcd(NULL, link, DP_PSR_SUPPORT,
39 psr_dpcd_data, sizeof(psr_dpcd_data)))
40 return false;
41
42 if (!dm_helpers_dp_read_dpcd(NULL, link, DP_EDP_DPCD_REV,
43 &edp_rev_dpcd_data, sizeof(edp_rev_dpcd_data)))
44 return false;
45
46 link->dpcd_caps.psr_caps.psr_version = psr_dpcd_data[0];
47 link->dpcd_caps.psr_caps.edp_revision = edp_rev_dpcd_data;
48
49#ifdef CONFIG_DRM_AMD_DC_DCN
50 if (link->dpcd_caps.psr_caps.psr_version > 0x1) {
51 uint8_t alpm_dpcd_data;
52 uint8_t su_granularity_dpcd_data;
53
54 if (!dm_helpers_dp_read_dpcd(NULL, link, DP_RECEIVER_ALPM_CAP,
55 &alpm_dpcd_data, sizeof(alpm_dpcd_data)))
56 return false;
57
58 if (!dm_helpers_dp_read_dpcd(NULL, link, DP_PSR2_SU_Y_GRANULARITY,
59 &su_granularity_dpcd_data, sizeof(su_granularity_dpcd_data)))
60 return false;
61
62 link->dpcd_caps.psr_caps.y_coordinate_required = psr_dpcd_data[1] & DP_PSR2_SU_Y_COORDINATE_REQUIRED;
63 link->dpcd_caps.psr_caps.su_granularity_required = psr_dpcd_data[1] & DP_PSR2_SU_GRANULARITY_REQUIRED;
64
65 link->dpcd_caps.psr_caps.alpm_cap = alpm_dpcd_data & DP_ALPM_CAP;
66 link->dpcd_caps.psr_caps.standby_support = alpm_dpcd_data & (1 << 1);
67
68 link->dpcd_caps.psr_caps.su_y_granularity = su_granularity_dpcd_data;
69 }
70#endif
71 return true;
72}
73
74#ifdef CONFIG_DRM_AMD_DC_DCN
75static bool link_supports_psrsu(struct dc_link *link)
76{
77 struct dc *dc = link->ctx->dc;
78
79 if (!dc->caps.dmcub_support)
80 return false;
81
82 if (dc->ctx->dce_version < DCN_VERSION_3_1)
83 return false;
84
85 if (!link->dpcd_caps.psr_caps.alpm_cap ||
86 !link->dpcd_caps.psr_caps.y_coordinate_required)
87 return false;
88
89 if (link->dpcd_caps.psr_caps.su_granularity_required &&
90 !link->dpcd_caps.psr_caps.su_y_granularity)
91 return false;
92
93 return true;
94}
95#endif
96
97/*
98 * amdgpu_dm_set_psr_caps() - set link psr capabilities
99 * @link: link
100 *
101 */
102void amdgpu_dm_set_psr_caps(struct dc_link *link)
103{
104 if (!(link->connector_signal & SIGNAL_TYPE_EDP))
105 return;
106
107 if (link->type == dc_connection_none)
108 return;
109
110 if (!link_get_psr_caps(link)) {
111 DRM_ERROR("amdgpu: Failed to read PSR Caps!\n");
112 return;
113 }
114
115 if (link->dpcd_caps.psr_caps.psr_version == 0) {
116 link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
117 link->psr_settings.psr_feature_enabled = false;
118
119 } else {
120#ifdef CONFIG_DRM_AMD_DC_DCN
121 if (link_supports_psrsu(link))
122 link->psr_settings.psr_version = DC_PSR_VERSION_SU_1;
123 else
124#endif
125 link->psr_settings.psr_version = DC_PSR_VERSION_1;
126
127 link->psr_settings.psr_feature_enabled = true;
128 }
129
130 DRM_INFO("PSR support:%d\n", link->psr_settings.psr_feature_enabled);
131
132}
133
134/*
135 * amdgpu_dm_link_setup_psr() - configure psr link
136 * @stream: stream state
137 *
138 * Return: true if success
139 */
140bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream)
141{
142 struct dc_link *link = NULL;
143 struct psr_config psr_config = {0};
144 struct psr_context psr_context = {0};
145 bool ret = false;
146
147 if (stream == NULL)
148 return false;
149
150 link = stream->link;
151
152 psr_config.psr_version = link->dpcd_caps.psr_caps.psr_version;
153
154 if (psr_config.psr_version > 0) {
155 psr_config.psr_exit_link_training_required = 0x1;
156 psr_config.psr_frame_capture_indication_req = 0;
157 psr_config.psr_rfb_setup_time = 0x37;
158 psr_config.psr_sdp_transmit_line_num_deadline = 0x20;
159 psr_config.allow_smu_optimizations = 0x0;
160
161 ret = dc_link_setup_psr(link, stream, &psr_config, &psr_context);
162
163 }
164 DRM_DEBUG_DRIVER("PSR link: %d\n", link->psr_settings.psr_feature_enabled);
165
166 return ret;
167}
168
169/*
170 * amdgpu_dm_psr_enable() - enable psr f/w
171 * @stream: stream state
172 *
173 * Return: true if success
174 */
175bool amdgpu_dm_psr_enable(struct dc_stream_state *stream)
176{
177 struct dc_link *link = stream->link;
178 unsigned int vsync_rate_hz = 0;
179 struct dc_static_screen_params params = {0};
180 /* Calculate number of static frames before generating interrupt to
181 * enter PSR.
182 */
183 // Init fail safe of 2 frames static
184 unsigned int num_frames_static = 2;
185 unsigned int power_opt = 0;
186 bool psr_enable = true;
187
188 DRM_DEBUG_DRIVER("Enabling psr...\n");
189
190 vsync_rate_hz = div64_u64(div64_u64((
191 stream->timing.pix_clk_100hz * 100),
192 stream->timing.v_total),
193 stream->timing.h_total);
194
195 /* Round up
196 * Calculate number of frames such that at least 30 ms of time has
197 * passed.
198 */
199 if (vsync_rate_hz != 0) {
200 unsigned int frame_time_microsec = 1000000 / vsync_rate_hz;
201 num_frames_static = (30000 / frame_time_microsec) + 1;
202 }
203
204 params.triggers.cursor_update = true;
205 params.triggers.overlay_update = true;
206 params.triggers.surface_update = true;
207 params.num_frames = num_frames_static;
208
209 dc_stream_set_static_screen_params(link->ctx->dc,
210 &stream, 1,
211 ¶ms);
212
213 power_opt |= psr_power_opt_z10_static_screen;
214
215 return dc_link_set_psr_allow_active(link, &psr_enable, false, false, &power_opt);
216}
217
218/*
219 * amdgpu_dm_psr_disable() - disable psr f/w
220 * @stream: stream state
221 *
222 * Return: true if success
223 */
224bool amdgpu_dm_psr_disable(struct dc_stream_state *stream)
225{
226 unsigned int power_opt = 0;
227 bool psr_enable = false;
228
229 DRM_DEBUG_DRIVER("Disabling psr...\n");
230
231 return dc_link_set_psr_allow_active(stream->link, &psr_enable, true, false, &power_opt);
232}
233
234/*
235 * amdgpu_dm_psr_disable() - disable psr f/w
236 * if psr is enabled on any stream
237 *
238 * Return: true if success
239 */
240bool amdgpu_dm_psr_disable_all(struct amdgpu_display_manager *dm)
241{
242 DRM_DEBUG_DRIVER("Disabling psr if psr is enabled on any stream\n");
243 return dc_set_psr_allow_active(dm->dc, false);
244}
245