Commit | Line | Data |
---|---|---|
4c1a1335 WW |
1 | /* |
2 | * Copyright 2019 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 "dmub_psr.h" | |
27 | #include "dc.h" | |
28 | #include "dc_dmub_srv.h" | |
cdca3f21 | 29 | #include "dmub/dmub_srv.h" |
4c1a1335 | 30 | #include "core_types.h" |
4c1a1335 | 31 | |
f59a66c1 | 32 | #define DC_TRACE_LEVEL_MESSAGE(...) do {} while (0) /* do nothing */ |
b30eda8d | 33 | |
4c1a1335 WW |
34 | #define MAX_PIPES 6 |
35 | ||
bc517825 LJ |
36 | static const uint8_t DP_SINK_DEVICE_STR_ID_1[] = {7, 1, 8, 7, 3}; |
37 | static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5}; | |
fae058b4 | 38 | static const uint8_t DP_SINK_DEVICE_STR_ID_3[] = {0x42, 0x61, 0x6c, 0x73, 0x61}; |
bc517825 | 39 | |
bc4cf4d4 | 40 | /* |
bccbf13d WW |
41 | * Convert dmcub psr state to dmcu psr state. |
42 | */ | |
1d496907 | 43 | static enum dc_psr_state convert_psr_state(uint32_t raw_state) |
bccbf13d | 44 | { |
1d496907 KK |
45 | enum dc_psr_state state = PSR_STATE0; |
46 | ||
47 | if (raw_state == 0) | |
48 | state = PSR_STATE0; | |
49 | else if (raw_state == 0x10) | |
50 | state = PSR_STATE1; | |
51 | else if (raw_state == 0x11) | |
52 | state = PSR_STATE1a; | |
53 | else if (raw_state == 0x20) | |
54 | state = PSR_STATE2; | |
55 | else if (raw_state == 0x21) | |
56 | state = PSR_STATE2a; | |
a35e5c5b ML |
57 | else if (raw_state == 0x22) |
58 | state = PSR_STATE2b; | |
1d496907 KK |
59 | else if (raw_state == 0x30) |
60 | state = PSR_STATE3; | |
61 | else if (raw_state == 0x31) | |
62 | state = PSR_STATE3Init; | |
63 | else if (raw_state == 0x40) | |
64 | state = PSR_STATE4; | |
65 | else if (raw_state == 0x41) | |
66 | state = PSR_STATE4a; | |
67 | else if (raw_state == 0x42) | |
68 | state = PSR_STATE4b; | |
69 | else if (raw_state == 0x43) | |
70 | state = PSR_STATE4c; | |
71 | else if (raw_state == 0x44) | |
72 | state = PSR_STATE4d; | |
73 | else if (raw_state == 0x50) | |
74 | state = PSR_STATE5; | |
75 | else if (raw_state == 0x51) | |
76 | state = PSR_STATE5a; | |
77 | else if (raw_state == 0x52) | |
78 | state = PSR_STATE5b; | |
79 | else if (raw_state == 0x53) | |
80 | state = PSR_STATE5c; | |
6cc5c773 DZ |
81 | else if (raw_state == 0x4A) |
82 | state = PSR_STATE4_FULL_FRAME; | |
83 | else if (raw_state == 0x4B) | |
84 | state = PSR_STATE4a_FULL_FRAME; | |
85 | else if (raw_state == 0x4C) | |
86 | state = PSR_STATE4b_FULL_FRAME; | |
87 | else if (raw_state == 0x4D) | |
88 | state = PSR_STATE4c_FULL_FRAME; | |
89 | else if (raw_state == 0x4E) | |
90 | state = PSR_STATE4_FULL_FRAME_POWERUP; | |
e8c49e9e TC |
91 | else if (raw_state == 0x4F) |
92 | state = PSR_STATE4_FULL_FRAME_HW_LOCK; | |
6cc5c773 DZ |
93 | else if (raw_state == 0x60) |
94 | state = PSR_STATE_HWLOCK_MGR; | |
95 | else if (raw_state == 0x61) | |
96 | state = PSR_STATE_POLLVUPDATE; | |
97 | else | |
98 | state = PSR_STATE_INVALID; | |
1d496907 KK |
99 | |
100 | return state; | |
bccbf13d WW |
101 | } |
102 | ||
bc4cf4d4 | 103 | /* |
4c1a1335 WW |
104 | * Get PSR state from firmware. |
105 | */ | |
f56c837a | 106 | static void dmub_psr_get_state(struct dmub_psr *dmub, enum dc_psr_state *state, uint8_t panel_inst) |
4c1a1335 | 107 | { |
115c7e7f | 108 | struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub; |
04f3c88f WW |
109 | uint32_t raw_state = 0; |
110 | uint32_t retry_count = 0; | |
d0c04856 | 111 | enum dmub_status status; |
115c7e7f | 112 | |
04f3c88f WW |
113 | do { |
114 | // Send gpint command and wait for ack | |
f56c837a | 115 | status = dmub_srv_send_gpint_command(srv, DMUB_GPINT__GET_PSR_STATE, panel_inst, 30); |
115c7e7f | 116 | |
04f3c88f WW |
117 | if (status == DMUB_STATUS_OK) { |
118 | // GPINT was executed, get response | |
119 | dmub_srv_get_gpint_response(srv, &raw_state); | |
120 | *state = convert_psr_state(raw_state); | |
121 | } else | |
122 | // Return invalid state when GPINT times out | |
123 | *state = PSR_STATE_INVALID; | |
124 | ||
04f3c88f | 125 | } while (++retry_count <= 1000 && *state == PSR_STATE_INVALID); |
b30eda8d WW |
126 | |
127 | // Assert if max retry hit | |
128 | if (retry_count >= 1000 && *state == PSR_STATE_INVALID) { | |
129 | ASSERT(0); | |
130 | DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR, | |
131 | WPP_BIT_FLAG_Firmware_PsrState, | |
132 | "Unable to get PSR state from FW."); | |
133 | } else | |
134 | DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_VERBOSE, | |
135 | WPP_BIT_FLAG_Firmware_PsrState, | |
136 | "Got PSR state from FW. PSR state: %d, Retry count: %d", | |
137 | *state, retry_count); | |
4c1a1335 WW |
138 | } |
139 | ||
bc4cf4d4 | 140 | /* |
8eb85cb5 WW |
141 | * Set PSR version. |
142 | */ | |
f56c837a | 143 | static bool dmub_psr_set_version(struct dmub_psr *dmub, struct dc_stream_state *stream, uint8_t panel_inst) |
d4b8573e | 144 | { |
d4b8573e WW |
145 | union dmub_rb_cmd cmd; |
146 | struct dc_context *dc = dmub->ctx; | |
147 | ||
1cfbbdde | 148 | if (stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED) |
d1ebfdd8 WW |
149 | return false; |
150 | ||
148816f9 | 151 | memset(&cmd, 0, sizeof(cmd)); |
d4b8573e WW |
152 | cmd.psr_set_version.header.type = DMUB_CMD__PSR; |
153 | cmd.psr_set_version.header.sub_type = DMUB_CMD__PSR_SET_VERSION; | |
1cfbbdde AK |
154 | switch (stream->link->psr_settings.psr_version) { |
155 | case DC_PSR_VERSION_1: | |
156 | cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_1; | |
157 | break; | |
b3d0c0f2 DZ |
158 | case DC_PSR_VERSION_SU_1: |
159 | cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_SU_1; | |
160 | break; | |
1cfbbdde AK |
161 | case DC_PSR_VERSION_UNSUPPORTED: |
162 | default: | |
163 | cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_UNSUPPORTED; | |
164 | break; | |
165 | } | |
1210b17d NK |
166 | |
167 | if (cmd.psr_set_version.psr_set_version_data.version == PSR_VERSION_UNSUPPORTED) | |
168 | return false; | |
169 | ||
f56c837a ML |
170 | cmd.psr_set_version.psr_set_version_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; |
171 | cmd.psr_set_version.psr_set_version_data.panel_inst = panel_inst; | |
d1ebfdd8 | 172 | cmd.psr_set_version.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_version_data); |
d4b8573e | 173 | |
88927808 | 174 | dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); |
8eb85cb5 WW |
175 | |
176 | return true; | |
d4b8573e WW |
177 | } |
178 | ||
bc4cf4d4 | 179 | /* |
4c1a1335 WW |
180 | * Enable/Disable PSR. |
181 | */ | |
f56c837a | 182 | static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait, uint8_t panel_inst) |
4c1a1335 WW |
183 | { |
184 | union dmub_rb_cmd cmd; | |
185 | struct dc_context *dc = dmub->ctx; | |
1d496907 KK |
186 | uint32_t retry_count; |
187 | enum dc_psr_state state = PSR_STATE0; | |
188 | ||
148816f9 | 189 | memset(&cmd, 0, sizeof(cmd)); |
4c1a1335 WW |
190 | cmd.psr_enable.header.type = DMUB_CMD__PSR; |
191 | ||
f56c837a ML |
192 | cmd.psr_enable.data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; |
193 | cmd.psr_enable.data.panel_inst = panel_inst; | |
194 | ||
4c1a1335 WW |
195 | if (enable) |
196 | cmd.psr_enable.header.sub_type = DMUB_CMD__PSR_ENABLE; | |
197 | else | |
198 | cmd.psr_enable.header.sub_type = DMUB_CMD__PSR_DISABLE; | |
199 | ||
200 | cmd.psr_enable.header.payload_bytes = 0; // Send header only | |
201 | ||
88927808 | 202 | dc_wake_and_execute_dmub_cmd(dc->dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); |
a9edc815 WW |
203 | |
204 | /* Below loops 1000 x 500us = 500 ms. | |
205 | * Exit PSR may need to wait 1-2 frames to power up. Timeout after at | |
206 | * least a few frames. Should never hit the max retry assert below. | |
207 | */ | |
208 | if (wait) { | |
209 | for (retry_count = 0; retry_count <= 1000; retry_count++) { | |
f56c837a | 210 | dmub_psr_get_state(dmub, &state, panel_inst); |
a9edc815 WW |
211 | |
212 | if (enable) { | |
1d496907 | 213 | if (state != PSR_STATE0) |
a9edc815 WW |
214 | break; |
215 | } else { | |
1d496907 | 216 | if (state == PSR_STATE0) |
a9edc815 WW |
217 | break; |
218 | } | |
219 | ||
79df45dc NK |
220 | /* must *not* be fsleep - this can be called from high irq levels */ |
221 | udelay(500); | |
a9edc815 WW |
222 | } |
223 | ||
224 | /* assert if max retry hit */ | |
225 | if (retry_count >= 1000) | |
226 | ASSERT(0); | |
227 | } | |
4c1a1335 WW |
228 | } |
229 | ||
bc4cf4d4 | 230 | /* |
4c1a1335 WW |
231 | * Set PSR level. |
232 | */ | |
f56c837a | 233 | static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level, uint8_t panel_inst) |
4c1a1335 WW |
234 | { |
235 | union dmub_rb_cmd cmd; | |
1d496907 | 236 | enum dc_psr_state state = PSR_STATE0; |
4c1a1335 WW |
237 | struct dc_context *dc = dmub->ctx; |
238 | ||
f56c837a | 239 | dmub_psr_get_state(dmub, &state, panel_inst); |
4c1a1335 | 240 | |
1d496907 | 241 | if (state == PSR_STATE0) |
4c1a1335 WW |
242 | return; |
243 | ||
148816f9 | 244 | memset(&cmd, 0, sizeof(cmd)); |
4c1a1335 WW |
245 | cmd.psr_set_level.header.type = DMUB_CMD__PSR; |
246 | cmd.psr_set_level.header.sub_type = DMUB_CMD__PSR_SET_LEVEL; | |
247 | cmd.psr_set_level.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_level_data); | |
248 | cmd.psr_set_level.psr_set_level_data.psr_level = psr_level; | |
af1f2b19 | 249 | cmd.psr_set_level.psr_set_level_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; |
f56c837a | 250 | cmd.psr_set_level.psr_set_level_data.panel_inst = panel_inst; |
88927808 | 251 | dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); |
4c1a1335 WW |
252 | } |
253 | ||
b8c6b225 | 254 | /* |
6651875a DZ |
255 | * Set PSR vtotal requirement for FreeSync PSR. |
256 | */ | |
257 | static void dmub_psr_set_sink_vtotal_in_psr_active(struct dmub_psr *dmub, | |
258 | uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su) | |
259 | { | |
260 | union dmub_rb_cmd cmd; | |
261 | struct dc_context *dc = dmub->ctx; | |
262 | ||
263 | memset(&cmd, 0, sizeof(cmd)); | |
264 | cmd.psr_set_vtotal.header.type = DMUB_CMD__PSR; | |
265 | cmd.psr_set_vtotal.header.sub_type = DMUB_CMD__SET_SINK_VTOTAL_IN_PSR_ACTIVE; | |
266 | cmd.psr_set_vtotal.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_vtotal_data); | |
267 | cmd.psr_set_vtotal.psr_set_vtotal_data.psr_vtotal_idle = psr_vtotal_idle; | |
268 | cmd.psr_set_vtotal.psr_set_vtotal_data.psr_vtotal_su = psr_vtotal_su; | |
269 | ||
88927808 | 270 | dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); |
6651875a DZ |
271 | } |
272 | ||
4ae182de | 273 | /* |
e5dfcd27 RC |
274 | * Set PSR power optimization flags. |
275 | */ | |
f0d0c391 | 276 | static void dmub_psr_set_power_opt(struct dmub_psr *dmub, unsigned int power_opt, uint8_t panel_inst) |
e5dfcd27 RC |
277 | { |
278 | union dmub_rb_cmd cmd; | |
279 | struct dc_context *dc = dmub->ctx; | |
280 | ||
281 | memset(&cmd, 0, sizeof(cmd)); | |
282 | cmd.psr_set_power_opt.header.type = DMUB_CMD__PSR; | |
283 | cmd.psr_set_power_opt.header.sub_type = DMUB_CMD__SET_PSR_POWER_OPT; | |
284 | cmd.psr_set_power_opt.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_power_opt_data); | |
f0d0c391 | 285 | cmd.psr_set_power_opt.psr_set_power_opt_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; |
e5dfcd27 | 286 | cmd.psr_set_power_opt.psr_set_power_opt_data.power_opt = power_opt; |
f0d0c391 | 287 | cmd.psr_set_power_opt.psr_set_power_opt_data.panel_inst = panel_inst; |
e5dfcd27 | 288 | |
88927808 | 289 | dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); |
e5dfcd27 RC |
290 | } |
291 | ||
bc4cf4d4 | 292 | /* |
4c1a1335 WW |
293 | * Setup PSR by programming phy registers and sending psr hw context values to firmware. |
294 | */ | |
d4b8573e | 295 | static bool dmub_psr_copy_settings(struct dmub_psr *dmub, |
4c1a1335 | 296 | struct dc_link *link, |
f56c837a ML |
297 | struct psr_context *psr_context, |
298 | uint8_t panel_inst) | |
4c1a1335 | 299 | { |
fae058b4 | 300 | union dmub_rb_cmd cmd = { 0 }; |
4c1a1335 WW |
301 | struct dc_context *dc = dmub->ctx; |
302 | struct dmub_cmd_psr_copy_settings_data *copy_settings_data | |
303 | = &cmd.psr_copy_settings.psr_copy_settings_data; | |
304 | struct pipe_ctx *pipe_ctx = NULL; | |
305 | struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx; | |
9dac88d8 | 306 | int i = 0; |
4c1a1335 | 307 | |
9dac88d8 | 308 | for (i = 0; i < MAX_PIPES; i++) { |
a5437e0b DC |
309 | if (res_ctx->pipe_ctx[i].stream && |
310 | res_ctx->pipe_ctx[i].stream->link == link && | |
311 | res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) { | |
4c1a1335 | 312 | pipe_ctx = &res_ctx->pipe_ctx[i]; |
45a1261b | 313 | //TODO: refactor for multi edp support |
4c1a1335 WW |
314 | break; |
315 | } | |
316 | } | |
317 | ||
67a4addd | 318 | if (!pipe_ctx) |
4c1a1335 WW |
319 | return false; |
320 | ||
8eb85cb5 | 321 | // First, set the psr version |
f56c837a | 322 | if (!dmub_psr_set_version(dmub, pipe_ctx->stream, panel_inst)) |
8eb85cb5 WW |
323 | return false; |
324 | ||
4c1a1335 WW |
325 | // Program DP DPHY fast training registers |
326 | link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc, | |
327 | psr_context->psrExitLinkTrainingRequired); | |
328 | ||
329 | // Program DP_SEC_CNTL1 register to set transmission GPS0 line num and priority to high | |
330 | link->link_enc->funcs->psr_program_secondary_packet(link->link_enc, | |
331 | psr_context->sdpTransmitLineNumDeadline); | |
332 | ||
148816f9 | 333 | memset(&cmd, 0, sizeof(cmd)); |
4c1a1335 WW |
334 | cmd.psr_copy_settings.header.type = DMUB_CMD__PSR; |
335 | cmd.psr_copy_settings.header.sub_type = DMUB_CMD__PSR_COPY_SETTINGS; | |
336 | cmd.psr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_psr_copy_settings_data); | |
337 | ||
338 | // Hw insts | |
bccbf13d | 339 | copy_settings_data->dpphy_inst = psr_context->transmitterId; |
4c1a1335 WW |
340 | copy_settings_data->aux_inst = psr_context->channel; |
341 | copy_settings_data->digfe_inst = psr_context->engineId; | |
342 | copy_settings_data->digbe_inst = psr_context->transmitterId; | |
343 | ||
344 | copy_settings_data->mpcc_inst = pipe_ctx->plane_res.mpcc_inst; | |
345 | ||
4c1a1335 WW |
346 | if (pipe_ctx->plane_res.dpp) |
347 | copy_settings_data->dpp_inst = pipe_ctx->plane_res.dpp->inst; | |
348 | else | |
349 | copy_settings_data->dpp_inst = 0; | |
350 | if (pipe_ctx->stream_res.opp) | |
351 | copy_settings_data->opp_inst = pipe_ctx->stream_res.opp->inst; | |
352 | else | |
353 | copy_settings_data->opp_inst = 0; | |
354 | if (pipe_ctx->stream_res.tg) | |
355 | copy_settings_data->otg_inst = pipe_ctx->stream_res.tg->inst; | |
356 | else | |
357 | copy_settings_data->otg_inst = 0; | |
358 | ||
359 | // Misc | |
b5175966 | 360 | copy_settings_data->use_phy_fsm = link->ctx->dc->debug.psr_power_use_phy_fsm; |
4c1a1335 | 361 | copy_settings_data->psr_level = psr_context->psr_level.u32all; |
d4b8573e | 362 | copy_settings_data->smu_optimizations_en = psr_context->allow_smu_optimizations; |
175f0971 | 363 | copy_settings_data->multi_disp_optimizations_en = psr_context->allow_multi_disp_optimizations; |
4c1a1335 | 364 | copy_settings_data->frame_delay = psr_context->frame_delay; |
4c1a1335 | 365 | copy_settings_data->frame_cap_ind = psr_context->psrFrameCaptureIndicationReq; |
89b151ad WW |
366 | copy_settings_data->init_sdp_deadline = psr_context->sdpTransmitLineNumDeadline; |
367 | copy_settings_data->debug.u32All = 0; | |
dce38c8b | 368 | copy_settings_data->debug.bitfields.visual_confirm = dc->dc->debug.visual_confirm == VISUAL_CONFIRM_PSR; |
89b151ad | 369 | copy_settings_data->debug.bitfields.use_hw_lock_mgr = 1; |
e61a048e | 370 | copy_settings_data->debug.bitfields.force_full_frame_update = 0; |
a35806b3 DZ |
371 | |
372 | if (psr_context->su_granularity_required == 0) | |
373 | copy_settings_data->su_y_granularity = 0; | |
374 | else | |
375 | copy_settings_data->su_y_granularity = psr_context->su_y_granularity; | |
376 | ||
65657d98 | 377 | copy_settings_data->line_capture_indication = 0; |
32c453f1 | 378 | copy_settings_data->line_time_in_us = psr_context->line_time_in_us; |
6651875a | 379 | copy_settings_data->rate_control_caps = psr_context->rate_control_caps; |
8cf9575d MH |
380 | copy_settings_data->fec_enable_status = (link->fec_state == dc_link_fec_enabled); |
381 | copy_settings_data->fec_enable_delay_in100us = link->dc->debug.fec_enable_delay_in100us; | |
af1f2b19 | 382 | copy_settings_data->cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; |
f56c837a | 383 | copy_settings_data->panel_inst = panel_inst; |
2665f63a | 384 | copy_settings_data->dsc_enable_status = (pipe_ctx->stream->timing.flags.DSC == 1); |
4c1a1335 | 385 | |
e61a048e DZ |
386 | /** |
387 | * WA for PSRSU+DSC on specific TCON, if DSC is enabled, force PSRSU as ffu mode(full frame update) | |
388 | * Note that PSRSU+DSC is still under development. | |
389 | */ | |
390 | if (copy_settings_data->dsc_enable_status && | |
391 | link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 && | |
392 | !memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1, | |
8bc14183 | 393 | sizeof(DP_SINK_DEVICE_STR_ID_1))) |
e61a048e DZ |
394 | link->psr_settings.force_ffu_mode = 1; |
395 | else | |
396 | link->psr_settings.force_ffu_mode = 0; | |
397 | copy_settings_data->force_ffu_mode = link->psr_settings.force_ffu_mode; | |
398 | ||
361edc61 IN |
399 | if (((link->dpcd_caps.fec_cap.bits.FEC_CAPABLE && |
400 | !link->dc->debug.disable_fec) && | |
401 | (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT && | |
402 | !link->panel_config.dsc.disable_dsc_edp && | |
403 | link->dc->caps.edp_dsc_support)) && | |
8bc14183 | 404 | link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_38EC11 && |
548f2125 | 405 | (!memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_1, |
8bc14183 | 406 | sizeof(DP_SINK_DEVICE_STR_ID_1)) || |
548f2125 | 407 | !memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_2, |
8bc14183 | 408 | sizeof(DP_SINK_DEVICE_STR_ID_2)))) |
548f2125 RC |
409 | copy_settings_data->debug.bitfields.force_wakeup_by_tps3 = 1; |
410 | else | |
411 | copy_settings_data->debug.bitfields.force_wakeup_by_tps3 = 0; | |
412 | ||
fae058b4 PH |
413 | if (link->psr_settings.psr_version == DC_PSR_VERSION_1 && |
414 | link->dpcd_caps.sink_dev_id == DP_DEVICE_ID_0022B9 && | |
415 | !memcmp(link->dpcd_caps.sink_dev_id_str, DP_SINK_DEVICE_STR_ID_3, | |
416 | sizeof(DP_SINK_DEVICE_STR_ID_3))) { | |
417 | copy_settings_data->poweroff_before_vertical_line = 16; | |
418 | } | |
419 | ||
1a2b886b RL |
420 | //WA for PSR1 on specific TCON, require frame delay for frame re-lock |
421 | copy_settings_data->relock_delay_frame_cnt = 0; | |
422 | if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8) | |
423 | copy_settings_data->relock_delay_frame_cnt = 2; | |
c84ff24a | 424 | copy_settings_data->dsc_slice_height = psr_context->dsc_slice_height; |
1a2b886b | 425 | |
88927808 | 426 | dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); |
4c1a1335 WW |
427 | |
428 | return true; | |
429 | } | |
430 | ||
bc4cf4d4 | 431 | /* |
1d496907 KK |
432 | * Send command to PSR to force static ENTER and ignore all state changes until exit |
433 | */ | |
f56c837a | 434 | static void dmub_psr_force_static(struct dmub_psr *dmub, uint8_t panel_inst) |
1d496907 KK |
435 | { |
436 | union dmub_rb_cmd cmd; | |
437 | struct dc_context *dc = dmub->ctx; | |
438 | ||
148816f9 | 439 | memset(&cmd, 0, sizeof(cmd)); |
f56c837a ML |
440 | |
441 | cmd.psr_force_static.psr_force_static_data.panel_inst = panel_inst; | |
442 | cmd.psr_force_static.psr_force_static_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; | |
1d496907 KK |
443 | cmd.psr_force_static.header.type = DMUB_CMD__PSR; |
444 | cmd.psr_force_static.header.sub_type = DMUB_CMD__PSR_FORCE_STATIC; | |
445 | cmd.psr_enable.header.payload_bytes = 0; | |
446 | ||
88927808 | 447 | dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); |
1d496907 KK |
448 | } |
449 | ||
bc4cf4d4 | 450 | /* |
b8e0b3d6 WW |
451 | * Get PSR residency from firmware. |
452 | */ | |
74b4afad | 453 | static void dmub_psr_get_residency(struct dmub_psr *dmub, uint32_t *residency, uint8_t panel_inst) |
b8e0b3d6 WW |
454 | { |
455 | struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub; | |
74b4afad | 456 | uint16_t param = (uint16_t)(panel_inst << 8); |
b8e0b3d6 | 457 | |
74b4afad ML |
458 | /* Send gpint command and wait for ack */ |
459 | dmub_srv_send_gpint_command(srv, DMUB_GPINT__PSR_RESIDENCY, param, 30); | |
b8e0b3d6 WW |
460 | |
461 | dmub_srv_get_gpint_response(srv, residency); | |
462 | } | |
463 | ||
4c1a1335 | 464 | static const struct dmub_psr_funcs psr_funcs = { |
d4b8573e WW |
465 | .psr_copy_settings = dmub_psr_copy_settings, |
466 | .psr_enable = dmub_psr_enable, | |
467 | .psr_get_state = dmub_psr_get_state, | |
468 | .psr_set_level = dmub_psr_set_level, | |
1d496907 | 469 | .psr_force_static = dmub_psr_force_static, |
b8e0b3d6 | 470 | .psr_get_residency = dmub_psr_get_residency, |
6651875a | 471 | .psr_set_sink_vtotal_in_psr_active = dmub_psr_set_sink_vtotal_in_psr_active, |
e5dfcd27 | 472 | .psr_set_power_opt = dmub_psr_set_power_opt, |
4c1a1335 WW |
473 | }; |
474 | ||
bc4cf4d4 | 475 | /* |
4c1a1335 WW |
476 | * Construct PSR object. |
477 | */ | |
478 | static void dmub_psr_construct(struct dmub_psr *psr, struct dc_context *ctx) | |
479 | { | |
480 | psr->ctx = ctx; | |
481 | psr->funcs = &psr_funcs; | |
482 | } | |
483 | ||
bc4cf4d4 | 484 | /* |
4c1a1335 WW |
485 | * Allocate and initialize PSR object. |
486 | */ | |
487 | struct dmub_psr *dmub_psr_create(struct dc_context *ctx) | |
488 | { | |
489 | struct dmub_psr *psr = kzalloc(sizeof(struct dmub_psr), GFP_KERNEL); | |
490 | ||
491 | if (psr == NULL) { | |
492 | BREAK_TO_DEBUGGER(); | |
493 | return NULL; | |
494 | } | |
495 | ||
496 | dmub_psr_construct(psr, ctx); | |
497 | ||
498 | return psr; | |
499 | } | |
500 | ||
bc4cf4d4 | 501 | /* |
4c1a1335 WW |
502 | * Deallocate PSR object. |
503 | */ | |
504 | void dmub_psr_destroy(struct dmub_psr **dmub) | |
505 | { | |
e599f01f | 506 | kfree(*dmub); |
4c1a1335 WW |
507 | *dmub = NULL; |
508 | } |