1 | /* |
2 | * Copyright 2012-16 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 "core_types.h" |
27 | #include "link_encoder.h" |
28 | #include "dce_dmcu.h" |
29 | #include "dm_services.h" |
30 | #include "reg_helper.h" |
31 | #include "fixed31_32.h" |
32 | #include "dc.h" |
33 | |
34 | #define TO_DCE_DMCU(dmcu)\ |
35 | container_of(dmcu, struct dce_dmcu, base) |
36 | |
37 | #define REG(reg) \ |
38 | (dmcu_dce->regs->reg) |
39 | |
40 | #undef FN |
41 | #define FN(reg_name, field_name) \ |
42 | dmcu_dce->dmcu_shift->field_name, dmcu_dce->dmcu_mask->field_name |
43 | |
44 | #define CTX \ |
45 | dmcu_dce->base.ctx |
46 | |
47 | /* PSR related commands */ |
48 | #define PSR_ENABLE 0x20 |
49 | #define PSR_EXIT 0x21 |
50 | #define PSR_SET 0x23 |
51 | #define PSR_SET_WAITLOOP 0x31 |
52 | #define MCP_INIT_DMCU 0x88 |
53 | #define MCP_INIT_IRAM 0x89 |
54 | #define MCP_SYNC_PHY_LOCK 0x90 |
55 | #define MCP_SYNC_PHY_UNLOCK 0x91 |
56 | #define MCP_BL_SET_PWM_FRAC 0x6A /* Enable or disable Fractional PWM */ |
57 | #define CRC_WIN_NOTIFY 0x92 |
58 | #define CRC_STOP_UPDATE 0x93 |
59 | #define MCP_SEND_EDID_CEA 0xA0 |
60 | #define EDID_CEA_CMD_ACK 1 |
61 | #define EDID_CEA_CMD_NACK 2 |
62 | #define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L |
63 | |
64 | // PSP FW version |
65 | #define mmMP0_SMN_C2PMSG_58 0x1607A |
66 | |
67 | //Register access policy version |
68 | #define mmMP0_SMN_C2PMSG_91 0x1609B |
69 | |
70 | static const uint32_t abm_gain_stepsize = 0x0060; |
71 | |
72 | static bool dce_dmcu_init(struct dmcu *dmcu) |
73 | { |
74 | // Do nothing |
75 | return true; |
76 | } |
77 | |
78 | static bool dce_dmcu_load_iram(struct dmcu *dmcu, |
79 | unsigned int start_offset, |
80 | const char *src, |
81 | unsigned int bytes) |
82 | { |
83 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
84 | unsigned int count = 0; |
85 | |
86 | /* Enable write access to IRAM */ |
87 | REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, |
88 | IRAM_HOST_ACCESS_EN, 1, |
89 | IRAM_WR_ADDR_AUTO_INC, 1); |
90 | |
91 | REG_WAIT(DCI_MEM_PWR_STATUS, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10); |
92 | |
93 | REG_WRITE(DMCU_IRAM_WR_CTRL, start_offset); |
94 | |
95 | for (count = 0; count < bytes; count++) |
96 | REG_WRITE(DMCU_IRAM_WR_DATA, src[count]); |
97 | |
98 | /* Disable write access to IRAM to allow dynamic sleep state */ |
99 | REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, |
100 | IRAM_HOST_ACCESS_EN, 0, |
101 | IRAM_WR_ADDR_AUTO_INC, 0); |
102 | |
103 | return true; |
104 | } |
105 | |
106 | static void dce_get_dmcu_psr_state(struct dmcu *dmcu, enum dc_psr_state *state) |
107 | { |
108 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
109 | |
110 | uint32_t psr_state_offset = 0xf0; |
111 | |
112 | /* Enable write access to IRAM */ |
113 | REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1); |
114 | |
115 | REG_WAIT(DCI_MEM_PWR_STATUS, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10); |
116 | |
117 | /* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */ |
118 | REG_WRITE(DMCU_IRAM_RD_CTRL, psr_state_offset); |
119 | |
120 | /* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/ |
121 | *state = (enum dc_psr_state)REG_READ(DMCU_IRAM_RD_DATA); |
122 | |
123 | /* Disable write access to IRAM after finished using IRAM |
124 | * in order to allow dynamic sleep state |
125 | */ |
126 | REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0); |
127 | } |
128 | |
129 | static void dce_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait) |
130 | { |
131 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
132 | unsigned int dmcu_max_retry_on_wait_reg_ready = 801; |
133 | unsigned int dmcu_wait_reg_ready_interval = 100; |
134 | |
135 | unsigned int retryCount; |
136 | enum dc_psr_state state = PSR_STATE0; |
137 | |
138 | /* waitDMCUReadyForCmd */ |
139 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, |
140 | dmcu_wait_reg_ready_interval, |
141 | dmcu_max_retry_on_wait_reg_ready); |
142 | |
143 | /* setDMCUParam_Cmd */ |
144 | if (enable) |
145 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, |
146 | PSR_ENABLE); |
147 | else |
148 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, |
149 | PSR_EXIT); |
150 | |
151 | /* notifyDMCUMsg */ |
152 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
153 | if (wait == true) { |
154 | for (retryCount = 0; retryCount <= 100; retryCount++) { |
155 | dce_get_dmcu_psr_state(dmcu, state: &state); |
156 | if (enable) { |
157 | if (state != PSR_STATE0) |
158 | break; |
159 | } else { |
160 | if (state == PSR_STATE0) |
161 | break; |
162 | } |
163 | udelay(10); |
164 | } |
165 | } |
166 | } |
167 | |
168 | static bool dce_dmcu_setup_psr(struct dmcu *dmcu, |
169 | struct dc_link *link, |
170 | struct psr_context *psr_context) |
171 | { |
172 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
173 | |
174 | unsigned int dmcu_max_retry_on_wait_reg_ready = 801; |
175 | unsigned int dmcu_wait_reg_ready_interval = 100; |
176 | |
177 | union dce_dmcu_psr_config_data_reg1 masterCmdData1; |
178 | union dce_dmcu_psr_config_data_reg2 masterCmdData2; |
179 | union dce_dmcu_psr_config_data_reg3 masterCmdData3; |
180 | |
181 | link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc, |
182 | psr_context->psrExitLinkTrainingRequired); |
183 | |
184 | /* Enable static screen interrupts for PSR supported display */ |
185 | /* Disable the interrupt coming from other displays. */ |
186 | REG_UPDATE_4(DMCU_INTERRUPT_TO_UC_EN_MASK, |
187 | STATIC_SCREEN1_INT_TO_UC_EN, 0, |
188 | STATIC_SCREEN2_INT_TO_UC_EN, 0, |
189 | STATIC_SCREEN3_INT_TO_UC_EN, 0, |
190 | STATIC_SCREEN4_INT_TO_UC_EN, 0); |
191 | |
192 | switch (psr_context->controllerId) { |
193 | /* Driver uses case 1 for unconfigured */ |
194 | case 1: |
195 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
196 | STATIC_SCREEN1_INT_TO_UC_EN, 1); |
197 | break; |
198 | case 2: |
199 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
200 | STATIC_SCREEN2_INT_TO_UC_EN, 1); |
201 | break; |
202 | case 3: |
203 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
204 | STATIC_SCREEN3_INT_TO_UC_EN, 1); |
205 | break; |
206 | case 4: |
207 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
208 | STATIC_SCREEN4_INT_TO_UC_EN, 1); |
209 | break; |
210 | case 5: |
211 | /* CZ/NL only has 4 CRTC!! |
212 | * really valid. |
213 | * There is no interrupt enable mask for these instances. |
214 | */ |
215 | break; |
216 | case 6: |
217 | /* CZ/NL only has 4 CRTC!! |
218 | * These are here because they are defined in HW regspec, |
219 | * but not really valid. There is no interrupt enable mask |
220 | * for these instances. |
221 | */ |
222 | break; |
223 | default: |
224 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
225 | STATIC_SCREEN1_INT_TO_UC_EN, 1); |
226 | break; |
227 | } |
228 | |
229 | link->link_enc->funcs->psr_program_secondary_packet(link->link_enc, |
230 | psr_context->sdpTransmitLineNumDeadline); |
231 | |
232 | /* waitDMCUReadyForCmd */ |
233 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, |
234 | dmcu_wait_reg_ready_interval, |
235 | dmcu_max_retry_on_wait_reg_ready); |
236 | |
237 | /* setDMCUParam_PSRHostConfigData */ |
238 | masterCmdData1.u32All = 0; |
239 | masterCmdData1.bits.timehyst_frames = psr_context->timehyst_frames; |
240 | masterCmdData1.bits.hyst_lines = psr_context->hyst_lines; |
241 | masterCmdData1.bits.rfb_update_auto_en = |
242 | psr_context->rfb_update_auto_en; |
243 | masterCmdData1.bits.dp_port_num = psr_context->transmitterId; |
244 | masterCmdData1.bits.dcp_sel = psr_context->controllerId; |
245 | masterCmdData1.bits.phy_type = psr_context->phyType; |
246 | masterCmdData1.bits.frame_cap_ind = |
247 | psr_context->psrFrameCaptureIndicationReq; |
248 | masterCmdData1.bits.aux_chan = psr_context->channel; |
249 | masterCmdData1.bits.aux_repeat = psr_context->aux_repeats; |
250 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), |
251 | masterCmdData1.u32All); |
252 | |
253 | masterCmdData2.u32All = 0; |
254 | masterCmdData2.bits.dig_fe = psr_context->engineId; |
255 | masterCmdData2.bits.dig_be = psr_context->transmitterId; |
256 | masterCmdData2.bits.skip_wait_for_pll_lock = |
257 | psr_context->skipPsrWaitForPllLock; |
258 | masterCmdData2.bits.frame_delay = psr_context->frame_delay; |
259 | masterCmdData2.bits.smu_phy_id = psr_context->smuPhyId; |
260 | masterCmdData2.bits.num_of_controllers = |
261 | psr_context->numberOfControllers; |
262 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2), |
263 | masterCmdData2.u32All); |
264 | |
265 | masterCmdData3.u32All = 0; |
266 | masterCmdData3.bits.psr_level = psr_context->psr_level.u32all; |
267 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3), |
268 | masterCmdData3.u32All); |
269 | |
270 | /* setDMCUParam_Cmd */ |
271 | REG_UPDATE(MASTER_COMM_CMD_REG, |
272 | MASTER_COMM_CMD_REG_BYTE0, PSR_SET); |
273 | |
274 | /* notifyDMCUMsg */ |
275 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
276 | |
277 | return true; |
278 | } |
279 | |
280 | static bool dce_is_dmcu_initialized(struct dmcu *dmcu) |
281 | { |
282 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
283 | unsigned int dmcu_uc_reset; |
284 | |
285 | /* microcontroller is not running */ |
286 | REG_GET(DMCU_STATUS, UC_IN_RESET, &dmcu_uc_reset); |
287 | |
288 | /* DMCU is not running */ |
289 | if (dmcu_uc_reset) |
290 | return false; |
291 | |
292 | return true; |
293 | } |
294 | |
295 | static void dce_psr_wait_loop( |
296 | struct dmcu *dmcu, |
297 | unsigned int wait_loop_number) |
298 | { |
299 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
300 | union dce_dmcu_psr_config_data_wait_loop_reg1 masterCmdData1; |
301 | |
302 | if (dmcu->cached_wait_loop_number == wait_loop_number) |
303 | return; |
304 | |
305 | /* DMCU is not running */ |
306 | if (!dce_is_dmcu_initialized(dmcu)) |
307 | return; |
308 | |
309 | /* waitDMCUReadyForCmd */ |
310 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); |
311 | |
312 | masterCmdData1.u32 = 0; |
313 | masterCmdData1.bits.wait_loop = wait_loop_number; |
314 | dmcu->cached_wait_loop_number = wait_loop_number; |
315 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), masterCmdData1.u32); |
316 | |
317 | /* setDMCUParam_Cmd */ |
318 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_SET_WAITLOOP); |
319 | |
320 | /* notifyDMCUMsg */ |
321 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
322 | } |
323 | |
324 | static void dce_get_psr_wait_loop( |
325 | struct dmcu *dmcu, unsigned int *psr_wait_loop_number) |
326 | { |
327 | *psr_wait_loop_number = dmcu->cached_wait_loop_number; |
328 | return; |
329 | } |
330 | |
331 | static void dcn10_get_dmcu_version(struct dmcu *dmcu) |
332 | { |
333 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
334 | uint32_t dmcu_version_offset = 0xf1; |
335 | |
336 | /* Enable write access to IRAM */ |
337 | REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, |
338 | IRAM_HOST_ACCESS_EN, 1, |
339 | IRAM_RD_ADDR_AUTO_INC, 1); |
340 | |
341 | REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10); |
342 | |
343 | /* Write address to IRAM_RD_ADDR and read from DATA register */ |
344 | REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_version_offset); |
345 | dmcu->dmcu_version.interface_version = REG_READ(DMCU_IRAM_RD_DATA); |
346 | dmcu->dmcu_version.abm_version = REG_READ(DMCU_IRAM_RD_DATA); |
347 | dmcu->dmcu_version.psr_version = REG_READ(DMCU_IRAM_RD_DATA); |
348 | dmcu->dmcu_version.build_version = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) | |
349 | REG_READ(DMCU_IRAM_RD_DATA)); |
350 | |
351 | /* Disable write access to IRAM to allow dynamic sleep state */ |
352 | REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, |
353 | IRAM_HOST_ACCESS_EN, 0, |
354 | IRAM_RD_ADDR_AUTO_INC, 0); |
355 | } |
356 | |
357 | static void dcn10_dmcu_enable_fractional_pwm(struct dmcu *dmcu, |
358 | uint32_t fractional_pwm) |
359 | { |
360 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
361 | |
362 | /* Wait until microcontroller is ready to process interrupt */ |
363 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); |
364 | |
365 | /* Set PWM fractional enable/disable */ |
366 | REG_WRITE(MASTER_COMM_DATA_REG1, fractional_pwm); |
367 | |
368 | /* Set command to enable or disable fractional PWM microcontroller */ |
369 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, |
370 | MCP_BL_SET_PWM_FRAC); |
371 | |
372 | /* Notify microcontroller of new command */ |
373 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
374 | |
375 | /* Ensure command has been executed before continuing */ |
376 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); |
377 | } |
378 | |
379 | static bool dcn10_dmcu_init(struct dmcu *dmcu) |
380 | { |
381 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
382 | const struct dc_config *config = &dmcu->ctx->dc->config; |
383 | bool status = false; |
384 | struct dc_context *ctx = dmcu->ctx; |
385 | unsigned int i; |
386 | // 5 4 3 2 1 0 |
387 | // F E D C B A - bit 0 is A, bit 5 is F |
388 | unsigned int tx_interrupt_mask = 0; |
389 | |
390 | PERF_TRACE(); |
391 | /* Definition of DC_DMCU_SCRATCH |
392 | * 0 : firmare not loaded |
393 | * 1 : PSP load DMCU FW but not initialized |
394 | * 2 : Firmware already initialized |
395 | */ |
396 | dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH); |
397 | |
398 | for (i = 0; i < ctx->dc->link_count; i++) { |
399 | if (ctx->dc->links[i]->link_enc->features.flags.bits.DP_IS_USB_C) { |
400 | if (ctx->dc->links[i]->link_enc->transmitter >= TRANSMITTER_UNIPHY_A && |
401 | ctx->dc->links[i]->link_enc->transmitter <= TRANSMITTER_UNIPHY_F) { |
402 | tx_interrupt_mask |= 1 << ctx->dc->links[i]->link_enc->transmitter; |
403 | } |
404 | } |
405 | } |
406 | |
407 | switch (dmcu->dmcu_state) { |
408 | case DMCU_UNLOADED: |
409 | status = false; |
410 | break; |
411 | case DMCU_LOADED_UNINITIALIZED: |
412 | /* Wait until microcontroller is ready to process interrupt */ |
413 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); |
414 | |
415 | /* Set initialized ramping boundary value */ |
416 | REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF); |
417 | |
418 | /* Set backlight ramping stepsize */ |
419 | REG_WRITE(MASTER_COMM_DATA_REG2, abm_gain_stepsize); |
420 | |
421 | REG_WRITE(MASTER_COMM_DATA_REG3, tx_interrupt_mask); |
422 | |
423 | /* Set command to initialize microcontroller */ |
424 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, |
425 | MCP_INIT_DMCU); |
426 | |
427 | /* Notify microcontroller of new command */ |
428 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
429 | |
430 | /* Ensure command has been executed before continuing */ |
431 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); |
432 | |
433 | // Check state is initialized |
434 | dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH); |
435 | |
436 | // If microcontroller is not in running state, fail |
437 | if (dmcu->dmcu_state == DMCU_RUNNING) { |
438 | /* Retrieve and cache the DMCU firmware version. */ |
439 | dcn10_get_dmcu_version(dmcu); |
440 | |
441 | /* Initialize DMCU to use fractional PWM or not */ |
442 | dcn10_dmcu_enable_fractional_pwm(dmcu, |
443 | fractional_pwm: (config->disable_fractional_pwm == false) ? 1 : 0); |
444 | status = true; |
445 | } else { |
446 | status = false; |
447 | } |
448 | |
449 | break; |
450 | case DMCU_RUNNING: |
451 | status = true; |
452 | break; |
453 | default: |
454 | status = false; |
455 | break; |
456 | } |
457 | |
458 | PERF_TRACE(); |
459 | return status; |
460 | } |
461 | |
462 | static bool dcn21_dmcu_init(struct dmcu *dmcu) |
463 | { |
464 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
465 | uint32_t dmcub_psp_version = REG_READ(DMCUB_SCRATCH15); |
466 | |
467 | if (dmcu->auto_load_dmcu && dmcub_psp_version == 0) { |
468 | return false; |
469 | } |
470 | |
471 | return dcn10_dmcu_init(dmcu); |
472 | } |
473 | |
474 | static bool dcn10_dmcu_load_iram(struct dmcu *dmcu, |
475 | unsigned int start_offset, |
476 | const char *src, |
477 | unsigned int bytes) |
478 | { |
479 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
480 | unsigned int count = 0; |
481 | |
482 | /* If microcontroller is not running, do nothing */ |
483 | if (dmcu->dmcu_state != DMCU_RUNNING) |
484 | return false; |
485 | |
486 | /* Enable write access to IRAM */ |
487 | REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, |
488 | IRAM_HOST_ACCESS_EN, 1, |
489 | IRAM_WR_ADDR_AUTO_INC, 1); |
490 | |
491 | REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10); |
492 | |
493 | REG_WRITE(DMCU_IRAM_WR_CTRL, start_offset); |
494 | |
495 | for (count = 0; count < bytes; count++) |
496 | REG_WRITE(DMCU_IRAM_WR_DATA, src[count]); |
497 | |
498 | /* Disable write access to IRAM to allow dynamic sleep state */ |
499 | REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, |
500 | IRAM_HOST_ACCESS_EN, 0, |
501 | IRAM_WR_ADDR_AUTO_INC, 0); |
502 | |
503 | /* Wait until microcontroller is ready to process interrupt */ |
504 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); |
505 | |
506 | /* Set command to signal IRAM is loaded and to initialize IRAM */ |
507 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, |
508 | MCP_INIT_IRAM); |
509 | |
510 | /* Notify microcontroller of new command */ |
511 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
512 | |
513 | /* Ensure command has been executed before continuing */ |
514 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); |
515 | |
516 | return true; |
517 | } |
518 | |
519 | static void dcn10_get_dmcu_psr_state(struct dmcu *dmcu, enum dc_psr_state *state) |
520 | { |
521 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
522 | |
523 | uint32_t psr_state_offset = 0xf0; |
524 | |
525 | /* If microcontroller is not running, do nothing */ |
526 | if (dmcu->dmcu_state != DMCU_RUNNING) |
527 | return; |
528 | |
529 | /* Enable write access to IRAM */ |
530 | REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1); |
531 | |
532 | REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10); |
533 | |
534 | /* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */ |
535 | REG_WRITE(DMCU_IRAM_RD_CTRL, psr_state_offset); |
536 | |
537 | /* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/ |
538 | *state = (enum dc_psr_state)REG_READ(DMCU_IRAM_RD_DATA); |
539 | |
540 | /* Disable write access to IRAM after finished using IRAM |
541 | * in order to allow dynamic sleep state |
542 | */ |
543 | REG_UPDATE(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0); |
544 | } |
545 | |
546 | static void dcn10_dmcu_set_psr_enable(struct dmcu *dmcu, bool enable, bool wait) |
547 | { |
548 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
549 | unsigned int dmcu_max_retry_on_wait_reg_ready = 801; |
550 | unsigned int dmcu_wait_reg_ready_interval = 100; |
551 | |
552 | unsigned int retryCount; |
553 | enum dc_psr_state state = PSR_STATE0; |
554 | |
555 | /* If microcontroller is not running, do nothing */ |
556 | if (dmcu->dmcu_state != DMCU_RUNNING) |
557 | return; |
558 | |
559 | /* waitDMCUReadyForCmd */ |
560 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, |
561 | dmcu_wait_reg_ready_interval, |
562 | dmcu_max_retry_on_wait_reg_ready); |
563 | |
564 | /* setDMCUParam_Cmd */ |
565 | if (enable) |
566 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, |
567 | PSR_ENABLE); |
568 | else |
569 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, |
570 | PSR_EXIT); |
571 | |
572 | /* notifyDMCUMsg */ |
573 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
574 | |
575 | /* Below loops 1000 x 500us = 500 ms. |
576 | * Exit PSR may need to wait 1-2 frames to power up. Timeout after at |
577 | * least a few frames. Should never hit the max retry assert below. |
578 | */ |
579 | if (wait == true) { |
580 | for (retryCount = 0; retryCount <= 1000; retryCount++) { |
581 | dcn10_get_dmcu_psr_state(dmcu, state: &state); |
582 | if (enable) { |
583 | if (state != PSR_STATE0) |
584 | break; |
585 | } else { |
586 | if (state == PSR_STATE0) |
587 | break; |
588 | } |
589 | /* must *not* be fsleep - this can be called from high irq levels */ |
590 | udelay(500); |
591 | } |
592 | |
593 | /* assert if max retry hit */ |
594 | if (retryCount >= 1000) |
595 | ASSERT(0); |
596 | } |
597 | } |
598 | |
599 | static bool dcn10_dmcu_setup_psr(struct dmcu *dmcu, |
600 | struct dc_link *link, |
601 | struct psr_context *psr_context) |
602 | { |
603 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
604 | |
605 | unsigned int dmcu_max_retry_on_wait_reg_ready = 801; |
606 | unsigned int dmcu_wait_reg_ready_interval = 100; |
607 | |
608 | union dce_dmcu_psr_config_data_reg1 masterCmdData1; |
609 | union dce_dmcu_psr_config_data_reg2 masterCmdData2; |
610 | union dce_dmcu_psr_config_data_reg3 masterCmdData3; |
611 | |
612 | /* If microcontroller is not running, do nothing */ |
613 | if (dmcu->dmcu_state != DMCU_RUNNING) |
614 | return false; |
615 | |
616 | link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc, |
617 | psr_context->psrExitLinkTrainingRequired); |
618 | |
619 | /* Enable static screen interrupts for PSR supported display */ |
620 | /* Disable the interrupt coming from other displays. */ |
621 | REG_UPDATE_4(DMCU_INTERRUPT_TO_UC_EN_MASK, |
622 | STATIC_SCREEN1_INT_TO_UC_EN, 0, |
623 | STATIC_SCREEN2_INT_TO_UC_EN, 0, |
624 | STATIC_SCREEN3_INT_TO_UC_EN, 0, |
625 | STATIC_SCREEN4_INT_TO_UC_EN, 0); |
626 | |
627 | switch (psr_context->controllerId) { |
628 | /* Driver uses case 1 for unconfigured */ |
629 | case 1: |
630 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
631 | STATIC_SCREEN1_INT_TO_UC_EN, 1); |
632 | break; |
633 | case 2: |
634 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
635 | STATIC_SCREEN2_INT_TO_UC_EN, 1); |
636 | break; |
637 | case 3: |
638 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
639 | STATIC_SCREEN3_INT_TO_UC_EN, 1); |
640 | break; |
641 | case 4: |
642 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
643 | STATIC_SCREEN4_INT_TO_UC_EN, 1); |
644 | break; |
645 | case 5: |
646 | /* CZ/NL only has 4 CRTC!! |
647 | * really valid. |
648 | * There is no interrupt enable mask for these instances. |
649 | */ |
650 | break; |
651 | case 6: |
652 | /* CZ/NL only has 4 CRTC!! |
653 | * These are here because they are defined in HW regspec, |
654 | * but not really valid. There is no interrupt enable mask |
655 | * for these instances. |
656 | */ |
657 | break; |
658 | default: |
659 | REG_UPDATE(DMCU_INTERRUPT_TO_UC_EN_MASK, |
660 | STATIC_SCREEN1_INT_TO_UC_EN, 1); |
661 | break; |
662 | } |
663 | |
664 | link->link_enc->funcs->psr_program_secondary_packet(link->link_enc, |
665 | psr_context->sdpTransmitLineNumDeadline); |
666 | |
667 | if (psr_context->allow_smu_optimizations) |
668 | REG_UPDATE(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, 1); |
669 | |
670 | /* waitDMCUReadyForCmd */ |
671 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, |
672 | dmcu_wait_reg_ready_interval, |
673 | dmcu_max_retry_on_wait_reg_ready); |
674 | |
675 | /* setDMCUParam_PSRHostConfigData */ |
676 | masterCmdData1.u32All = 0; |
677 | masterCmdData1.bits.timehyst_frames = psr_context->timehyst_frames; |
678 | masterCmdData1.bits.hyst_lines = psr_context->hyst_lines; |
679 | masterCmdData1.bits.rfb_update_auto_en = |
680 | psr_context->rfb_update_auto_en; |
681 | masterCmdData1.bits.dp_port_num = psr_context->transmitterId; |
682 | masterCmdData1.bits.dcp_sel = psr_context->controllerId; |
683 | masterCmdData1.bits.phy_type = psr_context->phyType; |
684 | masterCmdData1.bits.frame_cap_ind = |
685 | psr_context->psrFrameCaptureIndicationReq; |
686 | masterCmdData1.bits.aux_chan = psr_context->channel; |
687 | masterCmdData1.bits.aux_repeat = psr_context->aux_repeats; |
688 | masterCmdData1.bits.allow_smu_optimizations = psr_context->allow_smu_optimizations; |
689 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), |
690 | masterCmdData1.u32All); |
691 | |
692 | masterCmdData2.u32All = 0; |
693 | masterCmdData2.bits.dig_fe = psr_context->engineId; |
694 | masterCmdData2.bits.dig_be = psr_context->transmitterId; |
695 | masterCmdData2.bits.skip_wait_for_pll_lock = |
696 | psr_context->skipPsrWaitForPllLock; |
697 | masterCmdData2.bits.frame_delay = psr_context->frame_delay; |
698 | masterCmdData2.bits.smu_phy_id = psr_context->smuPhyId; |
699 | masterCmdData2.bits.num_of_controllers = |
700 | psr_context->numberOfControllers; |
701 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2), |
702 | masterCmdData2.u32All); |
703 | |
704 | masterCmdData3.u32All = 0; |
705 | masterCmdData3.bits.psr_level = psr_context->psr_level.u32all; |
706 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3), |
707 | masterCmdData3.u32All); |
708 | |
709 | |
710 | /* setDMCUParam_Cmd */ |
711 | REG_UPDATE(MASTER_COMM_CMD_REG, |
712 | MASTER_COMM_CMD_REG_BYTE0, PSR_SET); |
713 | |
714 | /* notifyDMCUMsg */ |
715 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
716 | |
717 | /* waitDMCUReadyForCmd */ |
718 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); |
719 | |
720 | return true; |
721 | } |
722 | |
723 | static void dcn10_psr_wait_loop( |
724 | struct dmcu *dmcu, |
725 | unsigned int wait_loop_number) |
726 | { |
727 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
728 | union dce_dmcu_psr_config_data_wait_loop_reg1 masterCmdData1; |
729 | |
730 | /* If microcontroller is not running, do nothing */ |
731 | if (dmcu->dmcu_state != DMCU_RUNNING) |
732 | return; |
733 | |
734 | if (wait_loop_number != 0) { |
735 | /* waitDMCUReadyForCmd */ |
736 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); |
737 | |
738 | masterCmdData1.u32 = 0; |
739 | masterCmdData1.bits.wait_loop = wait_loop_number; |
740 | dmcu->cached_wait_loop_number = wait_loop_number; |
741 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), masterCmdData1.u32); |
742 | |
743 | /* setDMCUParam_Cmd */ |
744 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_SET_WAITLOOP); |
745 | |
746 | /* notifyDMCUMsg */ |
747 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
748 | } |
749 | } |
750 | |
751 | static void dcn10_get_psr_wait_loop( |
752 | struct dmcu *dmcu, unsigned int *psr_wait_loop_number) |
753 | { |
754 | *psr_wait_loop_number = dmcu->cached_wait_loop_number; |
755 | return; |
756 | } |
757 | |
758 | static bool dcn10_is_dmcu_initialized(struct dmcu *dmcu) |
759 | { |
760 | /* microcontroller is not running */ |
761 | if (dmcu->dmcu_state != DMCU_RUNNING) |
762 | return false; |
763 | return true; |
764 | } |
765 | |
766 | |
767 | |
768 | static bool dcn20_lock_phy(struct dmcu *dmcu) |
769 | { |
770 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
771 | |
772 | /* If microcontroller is not running, do nothing */ |
773 | if (dmcu->dmcu_state != DMCU_RUNNING) |
774 | return false; |
775 | |
776 | /* waitDMCUReadyForCmd */ |
777 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); |
778 | |
779 | /* setDMCUParam_Cmd */ |
780 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SYNC_PHY_LOCK); |
781 | |
782 | /* notifyDMCUMsg */ |
783 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
784 | |
785 | /* waitDMCUReadyForCmd */ |
786 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); |
787 | |
788 | return true; |
789 | } |
790 | |
791 | static bool dcn20_unlock_phy(struct dmcu *dmcu) |
792 | { |
793 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
794 | |
795 | /* If microcontroller is not running, do nothing */ |
796 | if (dmcu->dmcu_state != DMCU_RUNNING) |
797 | return false; |
798 | |
799 | /* waitDMCUReadyForCmd */ |
800 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); |
801 | |
802 | /* setDMCUParam_Cmd */ |
803 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SYNC_PHY_UNLOCK); |
804 | |
805 | /* notifyDMCUMsg */ |
806 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
807 | |
808 | /* waitDMCUReadyForCmd */ |
809 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); |
810 | |
811 | return true; |
812 | } |
813 | |
814 | static bool dcn10_send_edid_cea(struct dmcu *dmcu, |
815 | int offset, |
816 | int total_length, |
817 | uint8_t *data, |
818 | int length) |
819 | { |
820 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
821 | uint32_t , data1, data2; |
822 | |
823 | /* If microcontroller is not running, do nothing */ |
824 | if (dmcu->dmcu_state != DMCU_RUNNING) |
825 | return false; |
826 | |
827 | if (length > 8 || length <= 0) |
828 | return false; |
829 | |
830 | header = ((uint32_t)offset & 0xFFFF) << 16 | (total_length & 0xFFFF); |
831 | data1 = (((uint32_t)data[0]) << 24) | (((uint32_t)data[1]) << 16) | |
832 | (((uint32_t)data[2]) << 8) | ((uint32_t)data[3]); |
833 | data2 = (((uint32_t)data[4]) << 24) | (((uint32_t)data[5]) << 16) | |
834 | (((uint32_t)data[6]) << 8) | ((uint32_t)data[7]); |
835 | |
836 | /* waitDMCUReadyForCmd */ |
837 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); |
838 | |
839 | /* setDMCUParam_Cmd */ |
840 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SEND_EDID_CEA); |
841 | |
842 | REG_WRITE(MASTER_COMM_DATA_REG1, header); |
843 | REG_WRITE(MASTER_COMM_DATA_REG2, data1); |
844 | REG_WRITE(MASTER_COMM_DATA_REG3, data2); |
845 | |
846 | /* notifyDMCUMsg */ |
847 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
848 | |
849 | /* waitDMCUReadyForCmd */ |
850 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); |
851 | |
852 | return true; |
853 | } |
854 | |
855 | static bool dcn10_get_scp_results(struct dmcu *dmcu, |
856 | uint32_t *cmd, |
857 | uint32_t *data1, |
858 | uint32_t *data2, |
859 | uint32_t *data3) |
860 | { |
861 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
862 | |
863 | /* If microcontroller is not running, do nothing */ |
864 | if (dmcu->dmcu_state != DMCU_RUNNING) |
865 | return false; |
866 | |
867 | *cmd = REG_READ(SLAVE_COMM_CMD_REG); |
868 | *data1 = REG_READ(SLAVE_COMM_DATA_REG1); |
869 | *data2 = REG_READ(SLAVE_COMM_DATA_REG2); |
870 | *data3 = REG_READ(SLAVE_COMM_DATA_REG3); |
871 | |
872 | /* clear SCP interrupt */ |
873 | REG_UPDATE(SLAVE_COMM_CNTL_REG, SLAVE_COMM_INTERRUPT, 0); |
874 | |
875 | return true; |
876 | } |
877 | |
878 | static bool dcn10_recv_amd_vsdb(struct dmcu *dmcu, |
879 | int *version, |
880 | int *min_frame_rate, |
881 | int *max_frame_rate) |
882 | { |
883 | uint32_t data[4]; |
884 | int cmd, ack, len; |
885 | |
886 | if (!dcn10_get_scp_results(dmcu, cmd: &data[0], data1: &data[1], data2: &data[2], data3: &data[3])) |
887 | return false; |
888 | |
889 | cmd = data[0] & 0x3FF; |
890 | len = (data[0] >> 10) & 0x3F; |
891 | ack = data[1]; |
892 | |
893 | if (cmd != MCP_SEND_EDID_CEA || ack != EDID_CEA_CMD_ACK || len != 12) |
894 | return false; |
895 | |
896 | if ((data[2] & 0xFF)) { |
897 | *version = (data[2] >> 8) & 0xFF; |
898 | *min_frame_rate = (data[3] >> 16) & 0xFFFF; |
899 | *max_frame_rate = data[3] & 0xFFFF; |
900 | return true; |
901 | } |
902 | |
903 | return false; |
904 | } |
905 | |
906 | static bool dcn10_recv_edid_cea_ack(struct dmcu *dmcu, int *offset) |
907 | { |
908 | uint32_t data[4]; |
909 | int cmd, ack; |
910 | |
911 | if (!dcn10_get_scp_results(dmcu, |
912 | cmd: &data[0], data1: &data[1], data2: &data[2], data3: &data[3])) |
913 | return false; |
914 | |
915 | cmd = data[0] & 0x3FF; |
916 | ack = data[1]; |
917 | |
918 | if (cmd != MCP_SEND_EDID_CEA) |
919 | return false; |
920 | |
921 | if (ack == EDID_CEA_CMD_ACK) |
922 | return true; |
923 | |
924 | *offset = data[2]; /* nack */ |
925 | return false; |
926 | } |
927 | |
928 | |
929 | #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) |
930 | static void dcn10_forward_crc_window(struct dmcu *dmcu, |
931 | struct rect *rect, |
932 | struct otg_phy_mux *mux_mapping) |
933 | { |
934 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
935 | unsigned int dmcu_max_retry_on_wait_reg_ready = 801; |
936 | unsigned int dmcu_wait_reg_ready_interval = 100; |
937 | unsigned int crc_start = 0, crc_end = 0, otg_phy_mux = 0; |
938 | int x_start, y_start, x_end, y_end; |
939 | |
940 | /* If microcontroller is not running, do nothing */ |
941 | if (dmcu->dmcu_state != DMCU_RUNNING) |
942 | return; |
943 | |
944 | if (!rect) |
945 | return; |
946 | |
947 | /* waitDMCUReadyForCmd */ |
948 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, |
949 | dmcu_wait_reg_ready_interval, |
950 | dmcu_max_retry_on_wait_reg_ready); |
951 | |
952 | x_start = rect->x; |
953 | y_start = rect->y; |
954 | x_end = x_start + rect->width; |
955 | y_end = y_start + rect->height; |
956 | |
957 | /* build up nitification data */ |
958 | crc_start = (((unsigned int) x_start) << 16) | y_start; |
959 | crc_end = (((unsigned int) x_end) << 16) | y_end; |
960 | otg_phy_mux = |
961 | (((unsigned int) mux_mapping->otg_output_num) << 16) | mux_mapping->phy_output_num; |
962 | |
963 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), |
964 | crc_start); |
965 | |
966 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG2), |
967 | crc_end); |
968 | |
969 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3), |
970 | otg_phy_mux); |
971 | |
972 | /* setDMCUParam_Cmd */ |
973 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, |
974 | CRC_WIN_NOTIFY); |
975 | |
976 | /* notifyDMCUMsg */ |
977 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
978 | } |
979 | |
980 | static void dcn10_stop_crc_win_update(struct dmcu *dmcu, |
981 | struct otg_phy_mux *mux_mapping) |
982 | { |
983 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); |
984 | unsigned int dmcu_max_retry_on_wait_reg_ready = 801; |
985 | unsigned int dmcu_wait_reg_ready_interval = 100; |
986 | unsigned int otg_phy_mux = 0; |
987 | |
988 | /* If microcontroller is not running, do nothing */ |
989 | if (dmcu->dmcu_state != DMCU_RUNNING) |
990 | return; |
991 | |
992 | /* waitDMCUReadyForCmd */ |
993 | REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, |
994 | dmcu_wait_reg_ready_interval, |
995 | dmcu_max_retry_on_wait_reg_ready); |
996 | |
997 | /* build up nitification data */ |
998 | otg_phy_mux = |
999 | (((unsigned int) mux_mapping->otg_output_num) << 16) | mux_mapping->phy_output_num; |
1000 | |
1001 | dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), |
1002 | otg_phy_mux); |
1003 | |
1004 | /* setDMCUParam_Cmd */ |
1005 | REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, |
1006 | CRC_STOP_UPDATE); |
1007 | |
1008 | /* notifyDMCUMsg */ |
1009 | REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); |
1010 | } |
1011 | #endif |
1012 | |
1013 | static const struct dmcu_funcs dce_funcs = { |
1014 | .dmcu_init = dce_dmcu_init, |
1015 | .load_iram = dce_dmcu_load_iram, |
1016 | .set_psr_enable = dce_dmcu_set_psr_enable, |
1017 | .setup_psr = dce_dmcu_setup_psr, |
1018 | .get_psr_state = dce_get_dmcu_psr_state, |
1019 | .set_psr_wait_loop = dce_psr_wait_loop, |
1020 | .get_psr_wait_loop = dce_get_psr_wait_loop, |
1021 | .is_dmcu_initialized = dce_is_dmcu_initialized |
1022 | }; |
1023 | |
1024 | static const struct dmcu_funcs dcn10_funcs = { |
1025 | .dmcu_init = dcn10_dmcu_init, |
1026 | .load_iram = dcn10_dmcu_load_iram, |
1027 | .set_psr_enable = dcn10_dmcu_set_psr_enable, |
1028 | .setup_psr = dcn10_dmcu_setup_psr, |
1029 | .get_psr_state = dcn10_get_dmcu_psr_state, |
1030 | .set_psr_wait_loop = dcn10_psr_wait_loop, |
1031 | .get_psr_wait_loop = dcn10_get_psr_wait_loop, |
1032 | .send_edid_cea = dcn10_send_edid_cea, |
1033 | .recv_amd_vsdb = dcn10_recv_amd_vsdb, |
1034 | .recv_edid_cea_ack = dcn10_recv_edid_cea_ack, |
1035 | #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) |
1036 | .forward_crc_window = dcn10_forward_crc_window, |
1037 | .stop_crc_win_update = dcn10_stop_crc_win_update, |
1038 | #endif |
1039 | .is_dmcu_initialized = dcn10_is_dmcu_initialized |
1040 | }; |
1041 | |
1042 | static const struct dmcu_funcs dcn20_funcs = { |
1043 | .dmcu_init = dcn10_dmcu_init, |
1044 | .load_iram = dcn10_dmcu_load_iram, |
1045 | .set_psr_enable = dcn10_dmcu_set_psr_enable, |
1046 | .setup_psr = dcn10_dmcu_setup_psr, |
1047 | .get_psr_state = dcn10_get_dmcu_psr_state, |
1048 | .set_psr_wait_loop = dcn10_psr_wait_loop, |
1049 | .get_psr_wait_loop = dcn10_get_psr_wait_loop, |
1050 | .is_dmcu_initialized = dcn10_is_dmcu_initialized, |
1051 | .lock_phy = dcn20_lock_phy, |
1052 | .unlock_phy = dcn20_unlock_phy |
1053 | }; |
1054 | |
1055 | static const struct dmcu_funcs dcn21_funcs = { |
1056 | .dmcu_init = dcn21_dmcu_init, |
1057 | .load_iram = dcn10_dmcu_load_iram, |
1058 | .set_psr_enable = dcn10_dmcu_set_psr_enable, |
1059 | .setup_psr = dcn10_dmcu_setup_psr, |
1060 | .get_psr_state = dcn10_get_dmcu_psr_state, |
1061 | .set_psr_wait_loop = dcn10_psr_wait_loop, |
1062 | .get_psr_wait_loop = dcn10_get_psr_wait_loop, |
1063 | .is_dmcu_initialized = dcn10_is_dmcu_initialized, |
1064 | .lock_phy = dcn20_lock_phy, |
1065 | .unlock_phy = dcn20_unlock_phy |
1066 | }; |
1067 | |
1068 | static void dce_dmcu_construct( |
1069 | struct dce_dmcu *dmcu_dce, |
1070 | struct dc_context *ctx, |
1071 | const struct dce_dmcu_registers *regs, |
1072 | const struct dce_dmcu_shift *dmcu_shift, |
1073 | const struct dce_dmcu_mask *dmcu_mask) |
1074 | { |
1075 | struct dmcu *base = &dmcu_dce->base; |
1076 | |
1077 | base->ctx = ctx; |
1078 | base->funcs = &dce_funcs; |
1079 | base->cached_wait_loop_number = 0; |
1080 | |
1081 | dmcu_dce->regs = regs; |
1082 | dmcu_dce->dmcu_shift = dmcu_shift; |
1083 | dmcu_dce->dmcu_mask = dmcu_mask; |
1084 | } |
1085 | |
1086 | static void dcn21_dmcu_construct( |
1087 | struct dce_dmcu *dmcu_dce, |
1088 | struct dc_context *ctx, |
1089 | const struct dce_dmcu_registers *regs, |
1090 | const struct dce_dmcu_shift *dmcu_shift, |
1091 | const struct dce_dmcu_mask *dmcu_mask) |
1092 | { |
1093 | uint32_t psp_version = 0; |
1094 | |
1095 | dce_dmcu_construct(dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); |
1096 | |
1097 | psp_version = dm_read_reg(ctx, mmMP0_SMN_C2PMSG_58); |
1098 | dmcu_dce->base.auto_load_dmcu = ((psp_version & 0x00FF00FF) > 0x00110029); |
1099 | dmcu_dce->base.psp_version = psp_version; |
1100 | } |
1101 | |
1102 | struct dmcu *dce_dmcu_create( |
1103 | struct dc_context *ctx, |
1104 | const struct dce_dmcu_registers *regs, |
1105 | const struct dce_dmcu_shift *dmcu_shift, |
1106 | const struct dce_dmcu_mask *dmcu_mask) |
1107 | { |
1108 | struct dce_dmcu *dmcu_dce = kzalloc(size: sizeof(*dmcu_dce), GFP_KERNEL); |
1109 | |
1110 | if (dmcu_dce == NULL) { |
1111 | BREAK_TO_DEBUGGER(); |
1112 | return NULL; |
1113 | } |
1114 | |
1115 | dce_dmcu_construct( |
1116 | dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); |
1117 | |
1118 | dmcu_dce->base.funcs = &dce_funcs; |
1119 | |
1120 | return &dmcu_dce->base; |
1121 | } |
1122 | |
1123 | struct dmcu *dcn10_dmcu_create( |
1124 | struct dc_context *ctx, |
1125 | const struct dce_dmcu_registers *regs, |
1126 | const struct dce_dmcu_shift *dmcu_shift, |
1127 | const struct dce_dmcu_mask *dmcu_mask) |
1128 | { |
1129 | struct dce_dmcu *dmcu_dce = kzalloc(size: sizeof(*dmcu_dce), GFP_ATOMIC); |
1130 | |
1131 | if (dmcu_dce == NULL) { |
1132 | BREAK_TO_DEBUGGER(); |
1133 | return NULL; |
1134 | } |
1135 | |
1136 | dce_dmcu_construct( |
1137 | dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); |
1138 | |
1139 | dmcu_dce->base.funcs = &dcn10_funcs; |
1140 | |
1141 | return &dmcu_dce->base; |
1142 | } |
1143 | |
1144 | struct dmcu *dcn20_dmcu_create( |
1145 | struct dc_context *ctx, |
1146 | const struct dce_dmcu_registers *regs, |
1147 | const struct dce_dmcu_shift *dmcu_shift, |
1148 | const struct dce_dmcu_mask *dmcu_mask) |
1149 | { |
1150 | struct dce_dmcu *dmcu_dce = kzalloc(size: sizeof(*dmcu_dce), GFP_ATOMIC); |
1151 | |
1152 | if (dmcu_dce == NULL) { |
1153 | BREAK_TO_DEBUGGER(); |
1154 | return NULL; |
1155 | } |
1156 | |
1157 | dce_dmcu_construct( |
1158 | dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); |
1159 | |
1160 | dmcu_dce->base.funcs = &dcn20_funcs; |
1161 | |
1162 | return &dmcu_dce->base; |
1163 | } |
1164 | |
1165 | struct dmcu *dcn21_dmcu_create( |
1166 | struct dc_context *ctx, |
1167 | const struct dce_dmcu_registers *regs, |
1168 | const struct dce_dmcu_shift *dmcu_shift, |
1169 | const struct dce_dmcu_mask *dmcu_mask) |
1170 | { |
1171 | struct dce_dmcu *dmcu_dce = kzalloc(size: sizeof(*dmcu_dce), GFP_ATOMIC); |
1172 | |
1173 | if (dmcu_dce == NULL) { |
1174 | BREAK_TO_DEBUGGER(); |
1175 | return NULL; |
1176 | } |
1177 | |
1178 | dcn21_dmcu_construct( |
1179 | dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); |
1180 | |
1181 | dmcu_dce->base.funcs = &dcn21_funcs; |
1182 | |
1183 | return &dmcu_dce->base; |
1184 | } |
1185 | |
1186 | void dce_dmcu_destroy(struct dmcu **dmcu) |
1187 | { |
1188 | struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(*dmcu); |
1189 | |
1190 | kfree(objp: dmcu_dce); |
1191 | *dmcu = NULL; |
1192 | } |
1193 | |