1 | /* |
2 | * Copyright 2012-15 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 "dm_services.h" |
27 | #include "amdgpu.h" |
28 | #include "atom.h" |
29 | |
30 | #include "include/bios_parser_interface.h" |
31 | |
32 | #include "command_table.h" |
33 | #include "command_table_helper.h" |
34 | #include "bios_parser_helper.h" |
35 | #include "bios_parser_types_internal.h" |
36 | |
37 | #define EXEC_BIOS_CMD_TABLE(command, params)\ |
38 | (amdgpu_atom_execute_table(((struct amdgpu_device *)bp->base.ctx->driver_context)->mode_info.atom_context, \ |
39 | GetIndexIntoMasterTable(COMMAND, command), \ |
40 | (uint32_t *)¶ms, sizeof(params)) == 0) |
41 | |
42 | #define BIOS_CMD_TABLE_REVISION(command, frev, crev)\ |
43 | amdgpu_atom_parse_cmd_header(((struct amdgpu_device *)bp->base.ctx->driver_context)->mode_info.atom_context, \ |
44 | GetIndexIntoMasterTable(COMMAND, command), &frev, &crev) |
45 | |
46 | #define BIOS_CMD_TABLE_PARA_REVISION(command)\ |
47 | bios_cmd_table_para_revision(bp->base.ctx->driver_context, \ |
48 | GetIndexIntoMasterTable(COMMAND, command)) |
49 | |
50 | static void init_dig_encoder_control(struct bios_parser *bp); |
51 | static void init_transmitter_control(struct bios_parser *bp); |
52 | static void init_set_pixel_clock(struct bios_parser *bp); |
53 | static void init_enable_spread_spectrum_on_ppll(struct bios_parser *bp); |
54 | static void init_adjust_display_pll(struct bios_parser *bp); |
55 | static void init_dac_encoder_control(struct bios_parser *bp); |
56 | static void init_dac_output_control(struct bios_parser *bp); |
57 | static void init_set_crtc_timing(struct bios_parser *bp); |
58 | static void init_enable_crtc(struct bios_parser *bp); |
59 | static void init_enable_crtc_mem_req(struct bios_parser *bp); |
60 | static void init_external_encoder_control(struct bios_parser *bp); |
61 | static void init_enable_disp_power_gating(struct bios_parser *bp); |
62 | static void init_program_clock(struct bios_parser *bp); |
63 | static void init_set_dce_clock(struct bios_parser *bp); |
64 | |
65 | void dal_bios_parser_init_cmd_tbl(struct bios_parser *bp) |
66 | { |
67 | init_dig_encoder_control(bp); |
68 | init_transmitter_control(bp); |
69 | init_set_pixel_clock(bp); |
70 | init_enable_spread_spectrum_on_ppll(bp); |
71 | init_adjust_display_pll(bp); |
72 | init_dac_encoder_control(bp); |
73 | init_dac_output_control(bp); |
74 | init_set_crtc_timing(bp); |
75 | init_enable_crtc(bp); |
76 | init_enable_crtc_mem_req(bp); |
77 | init_program_clock(bp); |
78 | init_external_encoder_control(bp); |
79 | init_enable_disp_power_gating(bp); |
80 | init_set_dce_clock(bp); |
81 | } |
82 | |
83 | static uint32_t bios_cmd_table_para_revision(void *dev, |
84 | uint32_t index) |
85 | { |
86 | struct amdgpu_device *adev = dev; |
87 | uint8_t frev, crev; |
88 | |
89 | if (amdgpu_atom_parse_cmd_header(ctx: adev->mode_info.atom_context, |
90 | index, |
91 | frev: &frev, crev: &crev)) |
92 | return crev; |
93 | else |
94 | return 0; |
95 | } |
96 | |
97 | /******************************************************************************* |
98 | ******************************************************************************** |
99 | ** |
100 | ** D I G E N C O D E R C O N T R O L |
101 | ** |
102 | ******************************************************************************** |
103 | *******************************************************************************/ |
104 | static enum bp_result encoder_control_digx_v3( |
105 | struct bios_parser *bp, |
106 | struct bp_encoder_control *cntl); |
107 | |
108 | static enum bp_result encoder_control_digx_v4( |
109 | struct bios_parser *bp, |
110 | struct bp_encoder_control *cntl); |
111 | |
112 | static enum bp_result encoder_control_digx_v5( |
113 | struct bios_parser *bp, |
114 | struct bp_encoder_control *cntl); |
115 | |
116 | static void init_encoder_control_dig_v1(struct bios_parser *bp); |
117 | |
118 | static void init_dig_encoder_control(struct bios_parser *bp) |
119 | { |
120 | uint32_t version = |
121 | BIOS_CMD_TABLE_PARA_REVISION(DIGxEncoderControl); |
122 | |
123 | switch (version) { |
124 | case 2: |
125 | bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v3; |
126 | break; |
127 | case 4: |
128 | bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v4; |
129 | break; |
130 | |
131 | case 5: |
132 | bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v5; |
133 | break; |
134 | |
135 | default: |
136 | init_encoder_control_dig_v1(bp); |
137 | break; |
138 | } |
139 | } |
140 | |
141 | static enum bp_result encoder_control_dig_v1( |
142 | struct bios_parser *bp, |
143 | struct bp_encoder_control *cntl); |
144 | static enum bp_result encoder_control_dig1_v1( |
145 | struct bios_parser *bp, |
146 | struct bp_encoder_control *cntl); |
147 | static enum bp_result encoder_control_dig2_v1( |
148 | struct bios_parser *bp, |
149 | struct bp_encoder_control *cntl); |
150 | |
151 | static void init_encoder_control_dig_v1(struct bios_parser *bp) |
152 | { |
153 | struct cmd_tbl *cmd_tbl = &bp->cmd_tbl; |
154 | |
155 | if (1 == BIOS_CMD_TABLE_PARA_REVISION(DIG1EncoderControl)) |
156 | cmd_tbl->encoder_control_dig1 = encoder_control_dig1_v1; |
157 | else |
158 | cmd_tbl->encoder_control_dig1 = NULL; |
159 | |
160 | if (1 == BIOS_CMD_TABLE_PARA_REVISION(DIG2EncoderControl)) |
161 | cmd_tbl->encoder_control_dig2 = encoder_control_dig2_v1; |
162 | else |
163 | cmd_tbl->encoder_control_dig2 = NULL; |
164 | |
165 | cmd_tbl->dig_encoder_control = encoder_control_dig_v1; |
166 | } |
167 | |
168 | static enum bp_result encoder_control_dig_v1( |
169 | struct bios_parser *bp, |
170 | struct bp_encoder_control *cntl) |
171 | { |
172 | enum bp_result result = BP_RESULT_FAILURE; |
173 | struct cmd_tbl *cmd_tbl = &bp->cmd_tbl; |
174 | |
175 | if (cntl != NULL) |
176 | switch (cntl->engine_id) { |
177 | case ENGINE_ID_DIGA: |
178 | if (cmd_tbl->encoder_control_dig1 != NULL) |
179 | result = |
180 | cmd_tbl->encoder_control_dig1(bp, cntl); |
181 | break; |
182 | case ENGINE_ID_DIGB: |
183 | if (cmd_tbl->encoder_control_dig2 != NULL) |
184 | result = |
185 | cmd_tbl->encoder_control_dig2(bp, cntl); |
186 | break; |
187 | |
188 | default: |
189 | break; |
190 | } |
191 | |
192 | return result; |
193 | } |
194 | |
195 | static enum bp_result encoder_control_dig1_v1( |
196 | struct bios_parser *bp, |
197 | struct bp_encoder_control *cntl) |
198 | { |
199 | enum bp_result result = BP_RESULT_FAILURE; |
200 | DIG_ENCODER_CONTROL_PARAMETERS_V2 params = {0}; |
201 | |
202 | bp->cmd_helper->assign_control_parameter(bp->cmd_helper, cntl, ¶ms); |
203 | |
204 | if (EXEC_BIOS_CMD_TABLE(DIG1EncoderControl, params)) |
205 | result = BP_RESULT_OK; |
206 | |
207 | return result; |
208 | } |
209 | |
210 | static enum bp_result encoder_control_dig2_v1( |
211 | struct bios_parser *bp, |
212 | struct bp_encoder_control *cntl) |
213 | { |
214 | enum bp_result result = BP_RESULT_FAILURE; |
215 | DIG_ENCODER_CONTROL_PARAMETERS_V2 params = {0}; |
216 | |
217 | bp->cmd_helper->assign_control_parameter(bp->cmd_helper, cntl, ¶ms); |
218 | |
219 | if (EXEC_BIOS_CMD_TABLE(DIG2EncoderControl, params)) |
220 | result = BP_RESULT_OK; |
221 | |
222 | return result; |
223 | } |
224 | |
225 | static enum bp_result encoder_control_digx_v3( |
226 | struct bios_parser *bp, |
227 | struct bp_encoder_control *cntl) |
228 | { |
229 | enum bp_result result = BP_RESULT_FAILURE; |
230 | DIG_ENCODER_CONTROL_PARAMETERS_V3 params = {0}; |
231 | |
232 | if (LANE_COUNT_FOUR < cntl->lanes_number) |
233 | params.acConfig.ucDPLinkRate = 1; /* dual link 2.7GHz */ |
234 | else |
235 | params.acConfig.ucDPLinkRate = 0; /* single link 1.62GHz */ |
236 | |
237 | params.acConfig.ucDigSel = (uint8_t)(cntl->engine_id); |
238 | |
239 | /* We need to convert from KHz units into 10KHz units */ |
240 | params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action); |
241 | params.usPixelClock = cpu_to_le16((uint16_t)(cntl->pixel_clock / 10)); |
242 | params.ucEncoderMode = |
243 | (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom( |
244 | cntl->signal, |
245 | cntl->enable_dp_audio); |
246 | params.ucLaneNum = (uint8_t)(cntl->lanes_number); |
247 | |
248 | switch (cntl->color_depth) { |
249 | case COLOR_DEPTH_888: |
250 | params.ucBitPerColor = PANEL_8BIT_PER_COLOR; |
251 | break; |
252 | case COLOR_DEPTH_101010: |
253 | params.ucBitPerColor = PANEL_10BIT_PER_COLOR; |
254 | break; |
255 | case COLOR_DEPTH_121212: |
256 | params.ucBitPerColor = PANEL_12BIT_PER_COLOR; |
257 | break; |
258 | case COLOR_DEPTH_161616: |
259 | params.ucBitPerColor = PANEL_16BIT_PER_COLOR; |
260 | break; |
261 | default: |
262 | break; |
263 | } |
264 | |
265 | if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params)) |
266 | result = BP_RESULT_OK; |
267 | |
268 | return result; |
269 | } |
270 | |
271 | static enum bp_result encoder_control_digx_v4( |
272 | struct bios_parser *bp, |
273 | struct bp_encoder_control *cntl) |
274 | { |
275 | enum bp_result result = BP_RESULT_FAILURE; |
276 | DIG_ENCODER_CONTROL_PARAMETERS_V4 params = {0}; |
277 | |
278 | if (LANE_COUNT_FOUR < cntl->lanes_number) |
279 | params.acConfig.ucDPLinkRate = 1; /* dual link 2.7GHz */ |
280 | else |
281 | params.acConfig.ucDPLinkRate = 0; /* single link 1.62GHz */ |
282 | |
283 | params.acConfig.ucDigSel = (uint8_t)(cntl->engine_id); |
284 | |
285 | /* We need to convert from KHz units into 10KHz units */ |
286 | params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action); |
287 | params.usPixelClock = cpu_to_le16((uint16_t)(cntl->pixel_clock / 10)); |
288 | params.ucEncoderMode = |
289 | (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom( |
290 | cntl->signal, |
291 | cntl->enable_dp_audio)); |
292 | params.ucLaneNum = (uint8_t)(cntl->lanes_number); |
293 | |
294 | switch (cntl->color_depth) { |
295 | case COLOR_DEPTH_888: |
296 | params.ucBitPerColor = PANEL_8BIT_PER_COLOR; |
297 | break; |
298 | case COLOR_DEPTH_101010: |
299 | params.ucBitPerColor = PANEL_10BIT_PER_COLOR; |
300 | break; |
301 | case COLOR_DEPTH_121212: |
302 | params.ucBitPerColor = PANEL_12BIT_PER_COLOR; |
303 | break; |
304 | case COLOR_DEPTH_161616: |
305 | params.ucBitPerColor = PANEL_16BIT_PER_COLOR; |
306 | break; |
307 | default: |
308 | break; |
309 | } |
310 | |
311 | if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params)) |
312 | result = BP_RESULT_OK; |
313 | |
314 | return result; |
315 | } |
316 | |
317 | static enum bp_result encoder_control_digx_v5( |
318 | struct bios_parser *bp, |
319 | struct bp_encoder_control *cntl) |
320 | { |
321 | enum bp_result result = BP_RESULT_FAILURE; |
322 | ENCODER_STREAM_SETUP_PARAMETERS_V5 params = {0}; |
323 | |
324 | params.ucDigId = (uint8_t)(cntl->engine_id); |
325 | params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action); |
326 | |
327 | params.ulPixelClock = cntl->pixel_clock / 10; |
328 | params.ucDigMode = |
329 | (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom( |
330 | cntl->signal, |
331 | cntl->enable_dp_audio)); |
332 | params.ucLaneNum = (uint8_t)(cntl->lanes_number); |
333 | |
334 | switch (cntl->color_depth) { |
335 | case COLOR_DEPTH_888: |
336 | params.ucBitPerColor = PANEL_8BIT_PER_COLOR; |
337 | break; |
338 | case COLOR_DEPTH_101010: |
339 | params.ucBitPerColor = PANEL_10BIT_PER_COLOR; |
340 | break; |
341 | case COLOR_DEPTH_121212: |
342 | params.ucBitPerColor = PANEL_12BIT_PER_COLOR; |
343 | break; |
344 | case COLOR_DEPTH_161616: |
345 | params.ucBitPerColor = PANEL_16BIT_PER_COLOR; |
346 | break; |
347 | default: |
348 | break; |
349 | } |
350 | |
351 | if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A) |
352 | switch (cntl->color_depth) { |
353 | case COLOR_DEPTH_101010: |
354 | params.ulPixelClock = |
355 | (params.ulPixelClock * 30) / 24; |
356 | break; |
357 | case COLOR_DEPTH_121212: |
358 | params.ulPixelClock = |
359 | (params.ulPixelClock * 36) / 24; |
360 | break; |
361 | case COLOR_DEPTH_161616: |
362 | params.ulPixelClock = |
363 | (params.ulPixelClock * 48) / 24; |
364 | break; |
365 | default: |
366 | break; |
367 | } |
368 | |
369 | if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params)) |
370 | result = BP_RESULT_OK; |
371 | |
372 | return result; |
373 | } |
374 | |
375 | /******************************************************************************* |
376 | ******************************************************************************** |
377 | ** |
378 | ** TRANSMITTER CONTROL |
379 | ** |
380 | ******************************************************************************** |
381 | *******************************************************************************/ |
382 | |
383 | static enum bp_result transmitter_control_v2( |
384 | struct bios_parser *bp, |
385 | struct bp_transmitter_control *cntl); |
386 | static enum bp_result transmitter_control_v3( |
387 | struct bios_parser *bp, |
388 | struct bp_transmitter_control *cntl); |
389 | static enum bp_result transmitter_control_v4( |
390 | struct bios_parser *bp, |
391 | struct bp_transmitter_control *cntl); |
392 | static enum bp_result transmitter_control_v1_5( |
393 | struct bios_parser *bp, |
394 | struct bp_transmitter_control *cntl); |
395 | static enum bp_result transmitter_control_v1_6( |
396 | struct bios_parser *bp, |
397 | struct bp_transmitter_control *cntl); |
398 | |
399 | static void init_transmitter_control(struct bios_parser *bp) |
400 | { |
401 | uint8_t frev; |
402 | uint8_t crev; |
403 | |
404 | if (BIOS_CMD_TABLE_REVISION(UNIPHYTransmitterControl, |
405 | frev, crev) == false) |
406 | BREAK_TO_DEBUGGER(); |
407 | switch (crev) { |
408 | case 2: |
409 | bp->cmd_tbl.transmitter_control = transmitter_control_v2; |
410 | break; |
411 | case 3: |
412 | bp->cmd_tbl.transmitter_control = transmitter_control_v3; |
413 | break; |
414 | case 4: |
415 | bp->cmd_tbl.transmitter_control = transmitter_control_v4; |
416 | break; |
417 | case 5: |
418 | bp->cmd_tbl.transmitter_control = transmitter_control_v1_5; |
419 | break; |
420 | case 6: |
421 | bp->cmd_tbl.transmitter_control = transmitter_control_v1_6; |
422 | break; |
423 | default: |
424 | dm_output_to_console("Don't have transmitter_control for v%d\n" , crev); |
425 | bp->cmd_tbl.transmitter_control = NULL; |
426 | break; |
427 | } |
428 | } |
429 | |
430 | static enum bp_result transmitter_control_v2( |
431 | struct bios_parser *bp, |
432 | struct bp_transmitter_control *cntl) |
433 | { |
434 | enum bp_result result = BP_RESULT_FAILURE; |
435 | DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 params; |
436 | enum connector_id connector_id = |
437 | dal_graphics_object_id_get_connector_id(id: cntl->connector_obj_id); |
438 | |
439 | memset(¶ms, 0, sizeof(params)); |
440 | |
441 | switch (cntl->transmitter) { |
442 | case TRANSMITTER_UNIPHY_A: |
443 | case TRANSMITTER_UNIPHY_B: |
444 | case TRANSMITTER_UNIPHY_C: |
445 | case TRANSMITTER_UNIPHY_D: |
446 | case TRANSMITTER_UNIPHY_E: |
447 | case TRANSMITTER_UNIPHY_F: |
448 | case TRANSMITTER_TRAVIS_LCD: |
449 | break; |
450 | default: |
451 | return BP_RESULT_BADINPUT; |
452 | } |
453 | |
454 | switch (cntl->action) { |
455 | case TRANSMITTER_CONTROL_INIT: |
456 | if ((CONNECTOR_ID_DUAL_LINK_DVII == connector_id) || |
457 | (CONNECTOR_ID_DUAL_LINK_DVID == connector_id)) |
458 | /* on INIT this bit should be set according to the |
459 | * physical connector |
460 | * Bit0: dual link connector flag |
461 | * =0 connector is single link connector |
462 | * =1 connector is dual link connector |
463 | */ |
464 | params.acConfig.fDualLinkConnector = 1; |
465 | |
466 | /* connector object id */ |
467 | params.usInitInfo = |
468 | cpu_to_le16((uint8_t)cntl->connector_obj_id.id); |
469 | break; |
470 | case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS: |
471 | /* voltage swing and pre-emphsis */ |
472 | params.asMode.ucLaneSel = (uint8_t)cntl->lane_select; |
473 | params.asMode.ucLaneSet = (uint8_t)cntl->lane_settings; |
474 | break; |
475 | default: |
476 | /* if dual-link */ |
477 | if (LANE_COUNT_FOUR < cntl->lanes_number) { |
478 | /* on ENABLE/DISABLE this bit should be set according to |
479 | * actual timing (number of lanes) |
480 | * Bit0: dual link connector flag |
481 | * =0 connector is single link connector |
482 | * =1 connector is dual link connector |
483 | */ |
484 | params.acConfig.fDualLinkConnector = 1; |
485 | |
486 | /* link rate, half for dual link |
487 | * We need to convert from KHz units into 20KHz units |
488 | */ |
489 | params.usPixelClock = |
490 | cpu_to_le16((uint16_t)(cntl->pixel_clock / 20)); |
491 | } else |
492 | /* link rate, half for dual link |
493 | * We need to convert from KHz units into 10KHz units |
494 | */ |
495 | params.usPixelClock = |
496 | cpu_to_le16((uint16_t)(cntl->pixel_clock / 10)); |
497 | break; |
498 | } |
499 | |
500 | /* 00 - coherent mode |
501 | * 01 - incoherent mode |
502 | */ |
503 | |
504 | params.acConfig.fCoherentMode = cntl->coherent; |
505 | |
506 | if ((TRANSMITTER_UNIPHY_B == cntl->transmitter) |
507 | || (TRANSMITTER_UNIPHY_D == cntl->transmitter) |
508 | || (TRANSMITTER_UNIPHY_F == cntl->transmitter)) |
509 | /* Bit2: Transmitter Link selection |
510 | * =0 when bit0=0, single link A/C/E, when bit0=1, |
511 | * master link A/C/E |
512 | * =1 when bit0=0, single link B/D/F, when bit0=1, |
513 | * master link B/D/F |
514 | */ |
515 | params.acConfig.ucLinkSel = 1; |
516 | |
517 | if (ENGINE_ID_DIGB == cntl->engine_id) |
518 | /* Bit3: Transmitter data source selection |
519 | * =0 DIGA is data source. |
520 | * =1 DIGB is data source. |
521 | * This bit is only useful when ucAction= ATOM_ENABLE |
522 | */ |
523 | params.acConfig.ucEncoderSel = 1; |
524 | |
525 | if (CONNECTOR_ID_DISPLAY_PORT == connector_id || |
526 | CONNECTOR_ID_USBC == connector_id) |
527 | /* Bit4: DP connector flag |
528 | * =0 connector is none-DP connector |
529 | * =1 connector is DP connector |
530 | */ |
531 | params.acConfig.fDPConnector = 1; |
532 | |
533 | /* Bit[7:6]: Transmitter selection |
534 | * =0 UNIPHY_ENCODER: UNIPHYA/B |
535 | * =1 UNIPHY1_ENCODER: UNIPHYC/D |
536 | * =2 UNIPHY2_ENCODER: UNIPHYE/F |
537 | * =3 reserved |
538 | */ |
539 | params.acConfig.ucTransmitterSel = |
540 | (uint8_t)bp->cmd_helper->transmitter_bp_to_atom( |
541 | cntl->transmitter); |
542 | |
543 | params.ucAction = (uint8_t)cntl->action; |
544 | |
545 | if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params)) |
546 | result = BP_RESULT_OK; |
547 | |
548 | return result; |
549 | } |
550 | |
551 | static enum bp_result transmitter_control_v3( |
552 | struct bios_parser *bp, |
553 | struct bp_transmitter_control *cntl) |
554 | { |
555 | enum bp_result result = BP_RESULT_FAILURE; |
556 | DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 params; |
557 | uint32_t pll_id; |
558 | enum connector_id conn_id = |
559 | dal_graphics_object_id_get_connector_id(id: cntl->connector_obj_id); |
560 | const struct command_table_helper *cmd = bp->cmd_helper; |
561 | bool dual_link_conn = (CONNECTOR_ID_DUAL_LINK_DVII == conn_id) |
562 | || (CONNECTOR_ID_DUAL_LINK_DVID == conn_id); |
563 | |
564 | memset(¶ms, 0, sizeof(params)); |
565 | |
566 | switch (cntl->transmitter) { |
567 | case TRANSMITTER_UNIPHY_A: |
568 | case TRANSMITTER_UNIPHY_B: |
569 | case TRANSMITTER_UNIPHY_C: |
570 | case TRANSMITTER_UNIPHY_D: |
571 | case TRANSMITTER_UNIPHY_E: |
572 | case TRANSMITTER_UNIPHY_F: |
573 | case TRANSMITTER_TRAVIS_LCD: |
574 | break; |
575 | default: |
576 | return BP_RESULT_BADINPUT; |
577 | } |
578 | |
579 | if (!cmd->clock_source_id_to_atom(cntl->pll_id, &pll_id)) |
580 | return BP_RESULT_BADINPUT; |
581 | |
582 | /* fill information based on the action */ |
583 | switch (cntl->action) { |
584 | case TRANSMITTER_CONTROL_INIT: |
585 | if (dual_link_conn) { |
586 | /* on INIT this bit should be set according to the |
587 | * phisycal connector |
588 | * Bit0: dual link connector flag |
589 | * =0 connector is single link connector |
590 | * =1 connector is dual link connector |
591 | */ |
592 | params.acConfig.fDualLinkConnector = 1; |
593 | } |
594 | |
595 | /* connector object id */ |
596 | params.usInitInfo = |
597 | cpu_to_le16((uint8_t)(cntl->connector_obj_id.id)); |
598 | break; |
599 | case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS: |
600 | /* votage swing and pre-emphsis */ |
601 | params.asMode.ucLaneSel = (uint8_t)cntl->lane_select; |
602 | params.asMode.ucLaneSet = (uint8_t)cntl->lane_settings; |
603 | break; |
604 | default: |
605 | if (dual_link_conn && cntl->multi_path) |
606 | /* on ENABLE/DISABLE this bit should be set according to |
607 | * actual timing (number of lanes) |
608 | * Bit0: dual link connector flag |
609 | * =0 connector is single link connector |
610 | * =1 connector is dual link connector |
611 | */ |
612 | params.acConfig.fDualLinkConnector = 1; |
613 | |
614 | /* if dual-link */ |
615 | if (LANE_COUNT_FOUR < cntl->lanes_number) { |
616 | /* on ENABLE/DISABLE this bit should be set according to |
617 | * actual timing (number of lanes) |
618 | * Bit0: dual link connector flag |
619 | * =0 connector is single link connector |
620 | * =1 connector is dual link connector |
621 | */ |
622 | params.acConfig.fDualLinkConnector = 1; |
623 | |
624 | /* link rate, half for dual link |
625 | * We need to convert from KHz units into 20KHz units |
626 | */ |
627 | params.usPixelClock = |
628 | cpu_to_le16((uint16_t)(cntl->pixel_clock / 20)); |
629 | } else { |
630 | /* link rate, half for dual link |
631 | * We need to convert from KHz units into 10KHz units |
632 | */ |
633 | params.usPixelClock = |
634 | cpu_to_le16((uint16_t)(cntl->pixel_clock / 10)); |
635 | } |
636 | break; |
637 | } |
638 | |
639 | /* 00 - coherent mode |
640 | * 01 - incoherent mode |
641 | */ |
642 | |
643 | params.acConfig.fCoherentMode = cntl->coherent; |
644 | |
645 | if ((TRANSMITTER_UNIPHY_B == cntl->transmitter) |
646 | || (TRANSMITTER_UNIPHY_D == cntl->transmitter) |
647 | || (TRANSMITTER_UNIPHY_F == cntl->transmitter)) |
648 | /* Bit2: Transmitter Link selection |
649 | * =0 when bit0=0, single link A/C/E, when bit0=1, |
650 | * master link A/C/E |
651 | * =1 when bit0=0, single link B/D/F, when bit0=1, |
652 | * master link B/D/F |
653 | */ |
654 | params.acConfig.ucLinkSel = 1; |
655 | |
656 | if (ENGINE_ID_DIGB == cntl->engine_id) |
657 | /* Bit3: Transmitter data source selection |
658 | * =0 DIGA is data source. |
659 | * =1 DIGB is data source. |
660 | * This bit is only useful when ucAction= ATOM_ENABLE |
661 | */ |
662 | params.acConfig.ucEncoderSel = 1; |
663 | |
664 | /* Bit[7:6]: Transmitter selection |
665 | * =0 UNIPHY_ENCODER: UNIPHYA/B |
666 | * =1 UNIPHY1_ENCODER: UNIPHYC/D |
667 | * =2 UNIPHY2_ENCODER: UNIPHYE/F |
668 | * =3 reserved |
669 | */ |
670 | params.acConfig.ucTransmitterSel = |
671 | (uint8_t)cmd->transmitter_bp_to_atom(cntl->transmitter); |
672 | |
673 | params.ucLaneNum = (uint8_t)cntl->lanes_number; |
674 | |
675 | params.acConfig.ucRefClkSource = (uint8_t)pll_id; |
676 | |
677 | params.ucAction = (uint8_t)cntl->action; |
678 | |
679 | if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params)) |
680 | result = BP_RESULT_OK; |
681 | |
682 | return result; |
683 | } |
684 | |
685 | static enum bp_result transmitter_control_v4( |
686 | struct bios_parser *bp, |
687 | struct bp_transmitter_control *cntl) |
688 | { |
689 | enum bp_result result = BP_RESULT_FAILURE; |
690 | DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 params; |
691 | uint32_t ref_clk_src_id; |
692 | enum connector_id conn_id = |
693 | dal_graphics_object_id_get_connector_id(id: cntl->connector_obj_id); |
694 | const struct command_table_helper *cmd = bp->cmd_helper; |
695 | |
696 | memset(¶ms, 0, sizeof(params)); |
697 | |
698 | switch (cntl->transmitter) { |
699 | case TRANSMITTER_UNIPHY_A: |
700 | case TRANSMITTER_UNIPHY_B: |
701 | case TRANSMITTER_UNIPHY_C: |
702 | case TRANSMITTER_UNIPHY_D: |
703 | case TRANSMITTER_UNIPHY_E: |
704 | case TRANSMITTER_UNIPHY_F: |
705 | case TRANSMITTER_TRAVIS_LCD: |
706 | break; |
707 | default: |
708 | return BP_RESULT_BADINPUT; |
709 | } |
710 | |
711 | if (!cmd->clock_source_id_to_ref_clk_src(cntl->pll_id, &ref_clk_src_id)) |
712 | return BP_RESULT_BADINPUT; |
713 | |
714 | switch (cntl->action) { |
715 | case TRANSMITTER_CONTROL_INIT: |
716 | { |
717 | if ((CONNECTOR_ID_DUAL_LINK_DVII == conn_id) || |
718 | (CONNECTOR_ID_DUAL_LINK_DVID == conn_id)) |
719 | /* on INIT this bit should be set according to the |
720 | * phisycal connector |
721 | * Bit0: dual link connector flag |
722 | * =0 connector is single link connector |
723 | * =1 connector is dual link connector |
724 | */ |
725 | params.acConfig.fDualLinkConnector = 1; |
726 | |
727 | /* connector object id */ |
728 | params.usInitInfo = |
729 | cpu_to_le16((uint8_t)(cntl->connector_obj_id.id)); |
730 | } |
731 | break; |
732 | case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS: |
733 | /* votage swing and pre-emphsis */ |
734 | params.asMode.ucLaneSel = (uint8_t)(cntl->lane_select); |
735 | params.asMode.ucLaneSet = (uint8_t)(cntl->lane_settings); |
736 | break; |
737 | default: |
738 | if ((CONNECTOR_ID_DUAL_LINK_DVII == conn_id) || |
739 | (CONNECTOR_ID_DUAL_LINK_DVID == conn_id)) |
740 | /* on ENABLE/DISABLE this bit should be set according to |
741 | * actual timing (number of lanes) |
742 | * Bit0: dual link connector flag |
743 | * =0 connector is single link connector |
744 | * =1 connector is dual link connector |
745 | */ |
746 | params.acConfig.fDualLinkConnector = 1; |
747 | |
748 | /* if dual-link */ |
749 | if (LANE_COUNT_FOUR < cntl->lanes_number) |
750 | /* link rate, half for dual link |
751 | * We need to convert from KHz units into 20KHz units |
752 | */ |
753 | params.usPixelClock = |
754 | cpu_to_le16((uint16_t)(cntl->pixel_clock / 20)); |
755 | else { |
756 | /* link rate, half for dual link |
757 | * We need to convert from KHz units into 10KHz units |
758 | */ |
759 | params.usPixelClock = |
760 | cpu_to_le16((uint16_t)(cntl->pixel_clock / 10)); |
761 | } |
762 | break; |
763 | } |
764 | |
765 | /* 00 - coherent mode |
766 | * 01 - incoherent mode |
767 | */ |
768 | |
769 | params.acConfig.fCoherentMode = cntl->coherent; |
770 | |
771 | if ((TRANSMITTER_UNIPHY_B == cntl->transmitter) |
772 | || (TRANSMITTER_UNIPHY_D == cntl->transmitter) |
773 | || (TRANSMITTER_UNIPHY_F == cntl->transmitter)) |
774 | /* Bit2: Transmitter Link selection |
775 | * =0 when bit0=0, single link A/C/E, when bit0=1, |
776 | * master link A/C/E |
777 | * =1 when bit0=0, single link B/D/F, when bit0=1, |
778 | * master link B/D/F |
779 | */ |
780 | params.acConfig.ucLinkSel = 1; |
781 | |
782 | if (ENGINE_ID_DIGB == cntl->engine_id) |
783 | /* Bit3: Transmitter data source selection |
784 | * =0 DIGA is data source. |
785 | * =1 DIGB is data source. |
786 | * This bit is only useful when ucAction= ATOM_ENABLE |
787 | */ |
788 | params.acConfig.ucEncoderSel = 1; |
789 | |
790 | /* Bit[7:6]: Transmitter selection |
791 | * =0 UNIPHY_ENCODER: UNIPHYA/B |
792 | * =1 UNIPHY1_ENCODER: UNIPHYC/D |
793 | * =2 UNIPHY2_ENCODER: UNIPHYE/F |
794 | * =3 reserved |
795 | */ |
796 | params.acConfig.ucTransmitterSel = |
797 | (uint8_t)(cmd->transmitter_bp_to_atom(cntl->transmitter)); |
798 | params.ucLaneNum = (uint8_t)(cntl->lanes_number); |
799 | params.acConfig.ucRefClkSource = (uint8_t)(ref_clk_src_id); |
800 | params.ucAction = (uint8_t)(cntl->action); |
801 | |
802 | if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params)) |
803 | result = BP_RESULT_OK; |
804 | |
805 | return result; |
806 | } |
807 | |
808 | static enum bp_result transmitter_control_v1_5( |
809 | struct bios_parser *bp, |
810 | struct bp_transmitter_control *cntl) |
811 | { |
812 | enum bp_result result = BP_RESULT_FAILURE; |
813 | const struct command_table_helper *cmd = bp->cmd_helper; |
814 | DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 params; |
815 | |
816 | memset(¶ms, 0, sizeof(params)); |
817 | params.ucPhyId = cmd->phy_id_to_atom(cntl->transmitter); |
818 | params.ucAction = (uint8_t)cntl->action; |
819 | params.ucLaneNum = (uint8_t)cntl->lanes_number; |
820 | params.ucConnObjId = (uint8_t)cntl->connector_obj_id.id; |
821 | |
822 | params.ucDigMode = |
823 | cmd->signal_type_to_atom_dig_mode(cntl->signal); |
824 | params.asConfig.ucPhyClkSrcId = |
825 | cmd->clock_source_id_to_atom_phy_clk_src_id(cntl->pll_id); |
826 | /* 00 - coherent mode */ |
827 | params.asConfig.ucCoherentMode = cntl->coherent; |
828 | params.asConfig.ucHPDSel = |
829 | cmd->hpd_sel_to_atom(cntl->hpd_sel); |
830 | params.ucDigEncoderSel = |
831 | cmd->dig_encoder_sel_to_atom(cntl->engine_id); |
832 | params.ucDPLaneSet = (uint8_t) cntl->lane_settings; |
833 | params.usSymClock = cpu_to_le16((uint16_t) (cntl->pixel_clock / 10)); |
834 | /* |
835 | * In SI/TN case, caller have to set usPixelClock as following: |
836 | * DP mode: usPixelClock = DP_LINK_CLOCK/10 |
837 | * (DP_LINK_CLOCK = 1.62GHz, 2.7GHz, 5.4GHz) |
838 | * DVI single link mode: usPixelClock = pixel clock |
839 | * DVI dual link mode: usPixelClock = pixel clock |
840 | * HDMI mode: usPixelClock = pixel clock * deep_color_ratio |
841 | * (=1: 8bpp, =1.25: 10bpp, =1.5:12bpp, =2: 16bpp) |
842 | * LVDS mode: usPixelClock = pixel clock |
843 | */ |
844 | if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A) { |
845 | switch (cntl->color_depth) { |
846 | case COLOR_DEPTH_101010: |
847 | params.usSymClock = |
848 | cpu_to_le16((le16_to_cpu(params.usSymClock) * 30) / 24); |
849 | break; |
850 | case COLOR_DEPTH_121212: |
851 | params.usSymClock = |
852 | cpu_to_le16((le16_to_cpu(params.usSymClock) * 36) / 24); |
853 | break; |
854 | case COLOR_DEPTH_161616: |
855 | params.usSymClock = |
856 | cpu_to_le16((le16_to_cpu(params.usSymClock) * 48) / 24); |
857 | break; |
858 | default: |
859 | break; |
860 | } |
861 | } |
862 | |
863 | if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params)) |
864 | result = BP_RESULT_OK; |
865 | |
866 | return result; |
867 | } |
868 | |
869 | static enum bp_result transmitter_control_v1_6( |
870 | struct bios_parser *bp, |
871 | struct bp_transmitter_control *cntl) |
872 | { |
873 | enum bp_result result = BP_RESULT_FAILURE; |
874 | const struct command_table_helper *cmd = bp->cmd_helper; |
875 | DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_6 params; |
876 | |
877 | memset(¶ms, 0, sizeof(params)); |
878 | params.ucPhyId = cmd->phy_id_to_atom(cntl->transmitter); |
879 | params.ucAction = (uint8_t)cntl->action; |
880 | |
881 | if (cntl->action == TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS) |
882 | params.ucDPLaneSet = (uint8_t)cntl->lane_settings; |
883 | else |
884 | params.ucDigMode = cmd->signal_type_to_atom_dig_mode(cntl->signal); |
885 | |
886 | params.ucLaneNum = (uint8_t)cntl->lanes_number; |
887 | params.ucHPDSel = cmd->hpd_sel_to_atom(cntl->hpd_sel); |
888 | params.ucDigEncoderSel = cmd->dig_encoder_sel_to_atom(cntl->engine_id); |
889 | params.ucConnObjId = (uint8_t)cntl->connector_obj_id.id; |
890 | params.ulSymClock = cntl->pixel_clock/10; |
891 | |
892 | /* |
893 | * In SI/TN case, caller have to set usPixelClock as following: |
894 | * DP mode: usPixelClock = DP_LINK_CLOCK/10 |
895 | * (DP_LINK_CLOCK = 1.62GHz, 2.7GHz, 5.4GHz) |
896 | * DVI single link mode: usPixelClock = pixel clock |
897 | * DVI dual link mode: usPixelClock = pixel clock |
898 | * HDMI mode: usPixelClock = pixel clock * deep_color_ratio |
899 | * (=1: 8bpp, =1.25: 10bpp, =1.5:12bpp, =2: 16bpp) |
900 | * LVDS mode: usPixelClock = pixel clock |
901 | */ |
902 | switch (cntl->signal) { |
903 | case SIGNAL_TYPE_HDMI_TYPE_A: |
904 | switch (cntl->color_depth) { |
905 | case COLOR_DEPTH_101010: |
906 | params.ulSymClock = |
907 | cpu_to_le16((le16_to_cpu(params.ulSymClock) * 30) / 24); |
908 | break; |
909 | case COLOR_DEPTH_121212: |
910 | params.ulSymClock = |
911 | cpu_to_le16((le16_to_cpu(params.ulSymClock) * 36) / 24); |
912 | break; |
913 | case COLOR_DEPTH_161616: |
914 | params.ulSymClock = |
915 | cpu_to_le16((le16_to_cpu(params.ulSymClock) * 48) / 24); |
916 | break; |
917 | default: |
918 | break; |
919 | } |
920 | break; |
921 | default: |
922 | break; |
923 | } |
924 | |
925 | if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params)) |
926 | result = BP_RESULT_OK; |
927 | return result; |
928 | } |
929 | |
930 | /******************************************************************************* |
931 | ******************************************************************************** |
932 | ** |
933 | ** SET PIXEL CLOCK |
934 | ** |
935 | ******************************************************************************** |
936 | *******************************************************************************/ |
937 | |
938 | static enum bp_result set_pixel_clock_v3( |
939 | struct bios_parser *bp, |
940 | struct bp_pixel_clock_parameters *bp_params); |
941 | static enum bp_result set_pixel_clock_v5( |
942 | struct bios_parser *bp, |
943 | struct bp_pixel_clock_parameters *bp_params); |
944 | static enum bp_result set_pixel_clock_v6( |
945 | struct bios_parser *bp, |
946 | struct bp_pixel_clock_parameters *bp_params); |
947 | static enum bp_result set_pixel_clock_v7( |
948 | struct bios_parser *bp, |
949 | struct bp_pixel_clock_parameters *bp_params); |
950 | |
951 | static void init_set_pixel_clock(struct bios_parser *bp) |
952 | { |
953 | switch (BIOS_CMD_TABLE_PARA_REVISION(SetPixelClock)) { |
954 | case 3: |
955 | bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v3; |
956 | break; |
957 | case 5: |
958 | bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v5; |
959 | break; |
960 | case 6: |
961 | bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v6; |
962 | break; |
963 | case 7: |
964 | bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v7; |
965 | break; |
966 | default: |
967 | dm_output_to_console("Don't have set_pixel_clock for v%d\n" , |
968 | BIOS_CMD_TABLE_PARA_REVISION(SetPixelClock)); |
969 | bp->cmd_tbl.set_pixel_clock = NULL; |
970 | break; |
971 | } |
972 | } |
973 | |
974 | static enum bp_result set_pixel_clock_v3( |
975 | struct bios_parser *bp, |
976 | struct bp_pixel_clock_parameters *bp_params) |
977 | { |
978 | enum bp_result result = BP_RESULT_FAILURE; |
979 | PIXEL_CLOCK_PARAMETERS_V3 *params; |
980 | SET_PIXEL_CLOCK_PS_ALLOCATION allocation; |
981 | |
982 | memset(&allocation, 0, sizeof(allocation)); |
983 | |
984 | if (CLOCK_SOURCE_ID_PLL1 == bp_params->pll_id) |
985 | allocation.sPCLKInput.ucPpll = ATOM_PPLL1; |
986 | else if (CLOCK_SOURCE_ID_PLL2 == bp_params->pll_id) |
987 | allocation.sPCLKInput.ucPpll = ATOM_PPLL2; |
988 | else |
989 | return BP_RESULT_BADINPUT; |
990 | |
991 | allocation.sPCLKInput.usRefDiv = |
992 | cpu_to_le16((uint16_t)bp_params->reference_divider); |
993 | allocation.sPCLKInput.usFbDiv = |
994 | cpu_to_le16((uint16_t)bp_params->feedback_divider); |
995 | allocation.sPCLKInput.ucFracFbDiv = |
996 | (uint8_t)bp_params->fractional_feedback_divider; |
997 | allocation.sPCLKInput.ucPostDiv = |
998 | (uint8_t)bp_params->pixel_clock_post_divider; |
999 | |
1000 | /* We need to convert from 100Hz units into 10KHz units */ |
1001 | allocation.sPCLKInput.usPixelClock = |
1002 | cpu_to_le16((uint16_t)(bp_params->target_pixel_clock_100hz / 100)); |
1003 | |
1004 | params = (PIXEL_CLOCK_PARAMETERS_V3 *)&allocation.sPCLKInput; |
1005 | params->ucTransmitterId = |
1006 | bp->cmd_helper->encoder_id_to_atom( |
1007 | dal_graphics_object_id_get_encoder_id( |
1008 | id: bp_params->encoder_object_id)); |
1009 | params->ucEncoderMode = |
1010 | (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom( |
1011 | bp_params->signal_type, false)); |
1012 | |
1013 | if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) |
1014 | params->ucMiscInfo |= PIXEL_CLOCK_MISC_FORCE_PROG_PPLL; |
1015 | |
1016 | if (bp_params->flags.USE_E_CLOCK_AS_SOURCE_FOR_D_CLOCK) |
1017 | params->ucMiscInfo |= PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK; |
1018 | |
1019 | if (CONTROLLER_ID_D1 != bp_params->controller_id) |
1020 | params->ucMiscInfo |= PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2; |
1021 | |
1022 | if (EXEC_BIOS_CMD_TABLE(SetPixelClock, allocation)) |
1023 | result = BP_RESULT_OK; |
1024 | |
1025 | return result; |
1026 | } |
1027 | |
1028 | #ifndef SET_PIXEL_CLOCK_PS_ALLOCATION_V5 |
1029 | /* video bios did not define this: */ |
1030 | typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION_V5 { |
1031 | PIXEL_CLOCK_PARAMETERS_V5 sPCLKInput; |
1032 | /* Caller doesn't need to init this portion */ |
1033 | ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved; |
1034 | } SET_PIXEL_CLOCK_PS_ALLOCATION_V5; |
1035 | #endif |
1036 | |
1037 | #ifndef SET_PIXEL_CLOCK_PS_ALLOCATION_V6 |
1038 | /* video bios did not define this: */ |
1039 | typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION_V6 { |
1040 | PIXEL_CLOCK_PARAMETERS_V6 sPCLKInput; |
1041 | /* Caller doesn't need to init this portion */ |
1042 | ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved; |
1043 | } SET_PIXEL_CLOCK_PS_ALLOCATION_V6; |
1044 | #endif |
1045 | |
1046 | static enum bp_result set_pixel_clock_v5( |
1047 | struct bios_parser *bp, |
1048 | struct bp_pixel_clock_parameters *bp_params) |
1049 | { |
1050 | enum bp_result result = BP_RESULT_FAILURE; |
1051 | SET_PIXEL_CLOCK_PS_ALLOCATION_V5 clk; |
1052 | uint8_t controller_id; |
1053 | uint32_t pll_id; |
1054 | |
1055 | memset(&clk, 0, sizeof(clk)); |
1056 | |
1057 | if (bp->cmd_helper->clock_source_id_to_atom(bp_params->pll_id, &pll_id) |
1058 | && bp->cmd_helper->controller_id_to_atom( |
1059 | bp_params->controller_id, &controller_id)) { |
1060 | clk.sPCLKInput.ucCRTC = controller_id; |
1061 | clk.sPCLKInput.ucPpll = (uint8_t)pll_id; |
1062 | clk.sPCLKInput.ucRefDiv = |
1063 | (uint8_t)(bp_params->reference_divider); |
1064 | clk.sPCLKInput.usFbDiv = |
1065 | cpu_to_le16((uint16_t)(bp_params->feedback_divider)); |
1066 | clk.sPCLKInput.ulFbDivDecFrac = |
1067 | cpu_to_le32(bp_params->fractional_feedback_divider); |
1068 | clk.sPCLKInput.ucPostDiv = |
1069 | (uint8_t)(bp_params->pixel_clock_post_divider); |
1070 | clk.sPCLKInput.ucTransmitterID = |
1071 | bp->cmd_helper->encoder_id_to_atom( |
1072 | dal_graphics_object_id_get_encoder_id( |
1073 | id: bp_params->encoder_object_id)); |
1074 | clk.sPCLKInput.ucEncoderMode = |
1075 | (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom( |
1076 | bp_params->signal_type, false); |
1077 | |
1078 | /* We need to convert from 100Hz units into 10KHz units */ |
1079 | clk.sPCLKInput.usPixelClock = |
1080 | cpu_to_le16((uint16_t)(bp_params->target_pixel_clock_100hz / 100)); |
1081 | |
1082 | if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) |
1083 | clk.sPCLKInput.ucMiscInfo |= |
1084 | PIXEL_CLOCK_MISC_FORCE_PROG_PPLL; |
1085 | |
1086 | if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC) |
1087 | clk.sPCLKInput.ucMiscInfo |= |
1088 | PIXEL_CLOCK_MISC_REF_DIV_SRC; |
1089 | |
1090 | /* clkV5.ucMiscInfo bit[3:2]= HDMI panel bit depth: =0: 24bpp |
1091 | * =1:30bpp, =2:32bpp |
1092 | * driver choose program it itself, i.e. here we program it |
1093 | * to 888 by default. |
1094 | */ |
1095 | if (bp_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) |
1096 | switch (bp_params->color_depth) { |
1097 | case TRANSMITTER_COLOR_DEPTH_30: |
1098 | /* yes this is correct, the atom define is wrong */ |
1099 | clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP; |
1100 | break; |
1101 | case TRANSMITTER_COLOR_DEPTH_36: |
1102 | /* yes this is correct, the atom define is wrong */ |
1103 | clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; |
1104 | break; |
1105 | default: |
1106 | break; |
1107 | } |
1108 | |
1109 | if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk)) |
1110 | result = BP_RESULT_OK; |
1111 | } |
1112 | |
1113 | return result; |
1114 | } |
1115 | |
1116 | static enum bp_result set_pixel_clock_v6( |
1117 | struct bios_parser *bp, |
1118 | struct bp_pixel_clock_parameters *bp_params) |
1119 | { |
1120 | enum bp_result result = BP_RESULT_FAILURE; |
1121 | SET_PIXEL_CLOCK_PS_ALLOCATION_V6 clk; |
1122 | uint8_t controller_id; |
1123 | uint32_t pll_id; |
1124 | |
1125 | memset(&clk, 0, sizeof(clk)); |
1126 | |
1127 | if (bp->cmd_helper->clock_source_id_to_atom(bp_params->pll_id, &pll_id) |
1128 | && bp->cmd_helper->controller_id_to_atom( |
1129 | bp_params->controller_id, &controller_id)) { |
1130 | /* Note: VBIOS still wants to use ucCRTC name which is now |
1131 | * 1 byte in ULONG |
1132 | *typedef struct _CRTC_PIXEL_CLOCK_FREQ |
1133 | *{ |
1134 | * target the pixel clock to drive the CRTC timing. |
1135 | * ULONG ulPixelClock:24; |
1136 | * 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to |
1137 | * previous version. |
1138 | * ATOM_CRTC1~6, indicate the CRTC controller to |
1139 | * ULONG ucCRTC:8; |
1140 | * drive the pixel clock. not used for DCPLL case. |
1141 | *}CRTC_PIXEL_CLOCK_FREQ; |
1142 | *union |
1143 | *{ |
1144 | * pixel clock and CRTC id frequency |
1145 | * CRTC_PIXEL_CLOCK_FREQ ulCrtcPclkFreq; |
1146 | * ULONG ulDispEngClkFreq; dispclk frequency |
1147 | *}; |
1148 | */ |
1149 | clk.sPCLKInput.ulCrtcPclkFreq.ucCRTC = controller_id; |
1150 | clk.sPCLKInput.ucPpll = (uint8_t) pll_id; |
1151 | clk.sPCLKInput.ucRefDiv = |
1152 | (uint8_t) bp_params->reference_divider; |
1153 | clk.sPCLKInput.usFbDiv = |
1154 | cpu_to_le16((uint16_t) bp_params->feedback_divider); |
1155 | clk.sPCLKInput.ulFbDivDecFrac = |
1156 | cpu_to_le32(bp_params->fractional_feedback_divider); |
1157 | clk.sPCLKInput.ucPostDiv = |
1158 | (uint8_t) bp_params->pixel_clock_post_divider; |
1159 | clk.sPCLKInput.ucTransmitterID = |
1160 | bp->cmd_helper->encoder_id_to_atom( |
1161 | dal_graphics_object_id_get_encoder_id( |
1162 | id: bp_params->encoder_object_id)); |
1163 | clk.sPCLKInput.ucEncoderMode = |
1164 | (uint8_t) bp->cmd_helper->encoder_mode_bp_to_atom( |
1165 | bp_params->signal_type, false); |
1166 | |
1167 | /* We need to convert from 100 Hz units into 10KHz units */ |
1168 | clk.sPCLKInput.ulCrtcPclkFreq.ulPixelClock = |
1169 | cpu_to_le32(bp_params->target_pixel_clock_100hz / 100); |
1170 | |
1171 | if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) { |
1172 | clk.sPCLKInput.ucMiscInfo |= |
1173 | PIXEL_CLOCK_V6_MISC_FORCE_PROG_PPLL; |
1174 | } |
1175 | |
1176 | if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC) { |
1177 | clk.sPCLKInput.ucMiscInfo |= |
1178 | PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; |
1179 | } |
1180 | |
1181 | /* clkV6.ucMiscInfo bit[3:2]= HDMI panel bit depth: =0: |
1182 | * 24bpp =1:30bpp, =2:32bpp |
1183 | * driver choose program it itself, i.e. here we pass required |
1184 | * target rate that includes deep color. |
1185 | */ |
1186 | if (bp_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) |
1187 | switch (bp_params->color_depth) { |
1188 | case TRANSMITTER_COLOR_DEPTH_30: |
1189 | clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6; |
1190 | break; |
1191 | case TRANSMITTER_COLOR_DEPTH_36: |
1192 | clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6; |
1193 | break; |
1194 | case TRANSMITTER_COLOR_DEPTH_48: |
1195 | clk.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; |
1196 | break; |
1197 | default: |
1198 | break; |
1199 | } |
1200 | |
1201 | if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk)) |
1202 | result = BP_RESULT_OK; |
1203 | } |
1204 | |
1205 | return result; |
1206 | } |
1207 | |
1208 | static enum bp_result set_pixel_clock_v7( |
1209 | struct bios_parser *bp, |
1210 | struct bp_pixel_clock_parameters *bp_params) |
1211 | { |
1212 | enum bp_result result = BP_RESULT_FAILURE; |
1213 | PIXEL_CLOCK_PARAMETERS_V7 clk; |
1214 | uint8_t controller_id; |
1215 | uint32_t pll_id; |
1216 | |
1217 | memset(&clk, 0, sizeof(clk)); |
1218 | |
1219 | if (bp->cmd_helper->clock_source_id_to_atom(bp_params->pll_id, &pll_id) |
1220 | && bp->cmd_helper->controller_id_to_atom(bp_params->controller_id, &controller_id)) { |
1221 | /* Note: VBIOS still wants to use ucCRTC name which is now |
1222 | * 1 byte in ULONG |
1223 | *typedef struct _CRTC_PIXEL_CLOCK_FREQ |
1224 | *{ |
1225 | * target the pixel clock to drive the CRTC timing. |
1226 | * ULONG ulPixelClock:24; |
1227 | * 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to |
1228 | * previous version. |
1229 | * ATOM_CRTC1~6, indicate the CRTC controller to |
1230 | * ULONG ucCRTC:8; |
1231 | * drive the pixel clock. not used for DCPLL case. |
1232 | *}CRTC_PIXEL_CLOCK_FREQ; |
1233 | *union |
1234 | *{ |
1235 | * pixel clock and CRTC id frequency |
1236 | * CRTC_PIXEL_CLOCK_FREQ ulCrtcPclkFreq; |
1237 | * ULONG ulDispEngClkFreq; dispclk frequency |
1238 | *}; |
1239 | */ |
1240 | clk.ucCRTC = controller_id; |
1241 | clk.ucPpll = (uint8_t) pll_id; |
1242 | clk.ucTransmitterID = bp->cmd_helper->encoder_id_to_atom(dal_graphics_object_id_get_encoder_id(id: bp_params->encoder_object_id)); |
1243 | clk.ucEncoderMode = (uint8_t) bp->cmd_helper->encoder_mode_bp_to_atom(bp_params->signal_type, false); |
1244 | |
1245 | clk.ulPixelClock = cpu_to_le32(bp_params->target_pixel_clock_100hz); |
1246 | |
1247 | clk.ucDeepColorRatio = (uint8_t) bp->cmd_helper->transmitter_color_depth_to_atom(bp_params->color_depth); |
1248 | |
1249 | if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) |
1250 | clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_FORCE_PROG_PPLL; |
1251 | |
1252 | if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC) |
1253 | clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_REF_DIV_SRC; |
1254 | |
1255 | if (bp_params->flags.PROGRAM_PHY_PLL_ONLY) |
1256 | clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_PROG_PHYPLL; |
1257 | |
1258 | if (bp_params->flags.SUPPORT_YUV_420) |
1259 | clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_YUV420_MODE; |
1260 | |
1261 | if (bp_params->flags.SET_XTALIN_REF_SRC) |
1262 | clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_REF_DIV_SRC_XTALIN; |
1263 | |
1264 | if (bp_params->flags.SET_GENLOCK_REF_DIV_SRC) |
1265 | clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_REF_DIV_SRC_GENLK; |
1266 | |
1267 | if (bp_params->signal_type == SIGNAL_TYPE_DVI_DUAL_LINK) |
1268 | clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN; |
1269 | |
1270 | if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk)) |
1271 | result = BP_RESULT_OK; |
1272 | } |
1273 | return result; |
1274 | } |
1275 | |
1276 | /******************************************************************************* |
1277 | ******************************************************************************** |
1278 | ** |
1279 | ** ENABLE PIXEL CLOCK SS |
1280 | ** |
1281 | ******************************************************************************** |
1282 | *******************************************************************************/ |
1283 | static enum bp_result enable_spread_spectrum_on_ppll_v1( |
1284 | struct bios_parser *bp, |
1285 | struct bp_spread_spectrum_parameters *bp_params, |
1286 | bool enable); |
1287 | static enum bp_result enable_spread_spectrum_on_ppll_v2( |
1288 | struct bios_parser *bp, |
1289 | struct bp_spread_spectrum_parameters *bp_params, |
1290 | bool enable); |
1291 | static enum bp_result enable_spread_spectrum_on_ppll_v3( |
1292 | struct bios_parser *bp, |
1293 | struct bp_spread_spectrum_parameters *bp_params, |
1294 | bool enable); |
1295 | |
1296 | static void init_enable_spread_spectrum_on_ppll(struct bios_parser *bp) |
1297 | { |
1298 | switch (BIOS_CMD_TABLE_PARA_REVISION(EnableSpreadSpectrumOnPPLL)) { |
1299 | case 1: |
1300 | bp->cmd_tbl.enable_spread_spectrum_on_ppll = |
1301 | enable_spread_spectrum_on_ppll_v1; |
1302 | break; |
1303 | case 2: |
1304 | bp->cmd_tbl.enable_spread_spectrum_on_ppll = |
1305 | enable_spread_spectrum_on_ppll_v2; |
1306 | break; |
1307 | case 3: |
1308 | bp->cmd_tbl.enable_spread_spectrum_on_ppll = |
1309 | enable_spread_spectrum_on_ppll_v3; |
1310 | break; |
1311 | default: |
1312 | dm_output_to_console("Don't have enable_spread_spectrum_on_ppll for v%d\n" , |
1313 | BIOS_CMD_TABLE_PARA_REVISION(EnableSpreadSpectrumOnPPLL)); |
1314 | bp->cmd_tbl.enable_spread_spectrum_on_ppll = NULL; |
1315 | break; |
1316 | } |
1317 | } |
1318 | |
1319 | static enum bp_result enable_spread_spectrum_on_ppll_v1( |
1320 | struct bios_parser *bp, |
1321 | struct bp_spread_spectrum_parameters *bp_params, |
1322 | bool enable) |
1323 | { |
1324 | enum bp_result result = BP_RESULT_FAILURE; |
1325 | ENABLE_SPREAD_SPECTRUM_ON_PPLL params; |
1326 | |
1327 | memset(¶ms, 0, sizeof(params)); |
1328 | |
1329 | if ((enable == true) && (bp_params->percentage > 0)) |
1330 | params.ucEnable = ATOM_ENABLE; |
1331 | else |
1332 | params.ucEnable = ATOM_DISABLE; |
1333 | |
1334 | params.usSpreadSpectrumPercentage = |
1335 | cpu_to_le16((uint16_t)bp_params->percentage); |
1336 | params.ucSpreadSpectrumStep = |
1337 | (uint8_t)bp_params->ver1.step; |
1338 | params.ucSpreadSpectrumDelay = |
1339 | (uint8_t)bp_params->ver1.delay; |
1340 | /* convert back to unit of 10KHz */ |
1341 | params.ucSpreadSpectrumRange = |
1342 | (uint8_t)(bp_params->ver1.range / 10000); |
1343 | |
1344 | if (bp_params->flags.EXTERNAL_SS) |
1345 | params.ucSpreadSpectrumType |= ATOM_EXTERNAL_SS_MASK; |
1346 | |
1347 | if (bp_params->flags.CENTER_SPREAD) |
1348 | params.ucSpreadSpectrumType |= ATOM_SS_CENTRE_SPREAD_MODE; |
1349 | |
1350 | if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL1) |
1351 | params.ucPpll = ATOM_PPLL1; |
1352 | else if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL2) |
1353 | params.ucPpll = ATOM_PPLL2; |
1354 | else |
1355 | BREAK_TO_DEBUGGER(); /* Unexpected PLL value!! */ |
1356 | |
1357 | if (EXEC_BIOS_CMD_TABLE(EnableSpreadSpectrumOnPPLL, params)) |
1358 | result = BP_RESULT_OK; |
1359 | |
1360 | return result; |
1361 | } |
1362 | |
1363 | static enum bp_result enable_spread_spectrum_on_ppll_v2( |
1364 | struct bios_parser *bp, |
1365 | struct bp_spread_spectrum_parameters *bp_params, |
1366 | bool enable) |
1367 | { |
1368 | enum bp_result result = BP_RESULT_FAILURE; |
1369 | ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 params; |
1370 | |
1371 | memset(¶ms, 0, sizeof(params)); |
1372 | |
1373 | if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL1) |
1374 | params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V2_P1PLL; |
1375 | else if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL2) |
1376 | params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V2_P2PLL; |
1377 | else |
1378 | BREAK_TO_DEBUGGER(); /* Unexpected PLL value!! */ |
1379 | |
1380 | if ((enable == true) && (bp_params->percentage > 0)) { |
1381 | params.ucEnable = ATOM_ENABLE; |
1382 | |
1383 | params.usSpreadSpectrumPercentage = |
1384 | cpu_to_le16((uint16_t)(bp_params->percentage)); |
1385 | params.usSpreadSpectrumStep = |
1386 | cpu_to_le16((uint16_t)(bp_params->ds.ds_frac_size)); |
1387 | |
1388 | if (bp_params->flags.EXTERNAL_SS) |
1389 | params.ucSpreadSpectrumType |= |
1390 | ATOM_PPLL_SS_TYPE_V2_EXT_SPREAD; |
1391 | |
1392 | if (bp_params->flags.CENTER_SPREAD) |
1393 | params.ucSpreadSpectrumType |= |
1394 | ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD; |
1395 | |
1396 | /* Both amounts need to be left shifted first before bit |
1397 | * comparison. Otherwise, the result will always be zero here |
1398 | */ |
1399 | params.usSpreadSpectrumAmount = cpu_to_le16((uint16_t)( |
1400 | ((bp_params->ds.feedback_amount << |
1401 | ATOM_PPLL_SS_AMOUNT_V2_FBDIV_SHIFT) & |
1402 | ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK) | |
1403 | ((bp_params->ds.nfrac_amount << |
1404 | ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) & |
1405 | ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK))); |
1406 | } else |
1407 | params.ucEnable = ATOM_DISABLE; |
1408 | |
1409 | if (EXEC_BIOS_CMD_TABLE(EnableSpreadSpectrumOnPPLL, params)) |
1410 | result = BP_RESULT_OK; |
1411 | |
1412 | return result; |
1413 | } |
1414 | |
1415 | static enum bp_result enable_spread_spectrum_on_ppll_v3( |
1416 | struct bios_parser *bp, |
1417 | struct bp_spread_spectrum_parameters *bp_params, |
1418 | bool enable) |
1419 | { |
1420 | enum bp_result result = BP_RESULT_FAILURE; |
1421 | ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 params; |
1422 | |
1423 | memset(¶ms, 0, sizeof(params)); |
1424 | |
1425 | switch (bp_params->pll_id) { |
1426 | case CLOCK_SOURCE_ID_PLL0: |
1427 | /* ATOM_PPLL_SS_TYPE_V3_P0PLL; this is pixel clock only, |
1428 | * not for SI display clock. |
1429 | */ |
1430 | params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_DCPLL; |
1431 | break; |
1432 | case CLOCK_SOURCE_ID_PLL1: |
1433 | params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_P1PLL; |
1434 | break; |
1435 | |
1436 | case CLOCK_SOURCE_ID_PLL2: |
1437 | params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_P2PLL; |
1438 | break; |
1439 | |
1440 | case CLOCK_SOURCE_ID_DCPLL: |
1441 | params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_DCPLL; |
1442 | break; |
1443 | |
1444 | default: |
1445 | BREAK_TO_DEBUGGER(); |
1446 | /* Unexpected PLL value!! */ |
1447 | return result; |
1448 | } |
1449 | |
1450 | if (enable == true) { |
1451 | params.ucEnable = ATOM_ENABLE; |
1452 | |
1453 | params.usSpreadSpectrumAmountFrac = |
1454 | cpu_to_le16((uint16_t)(bp_params->ds_frac_amount)); |
1455 | params.usSpreadSpectrumStep = |
1456 | cpu_to_le16((uint16_t)(bp_params->ds.ds_frac_size)); |
1457 | |
1458 | if (bp_params->flags.EXTERNAL_SS) |
1459 | params.ucSpreadSpectrumType |= |
1460 | ATOM_PPLL_SS_TYPE_V3_EXT_SPREAD; |
1461 | if (bp_params->flags.CENTER_SPREAD) |
1462 | params.ucSpreadSpectrumType |= |
1463 | ATOM_PPLL_SS_TYPE_V3_CENTRE_SPREAD; |
1464 | |
1465 | /* Both amounts need to be left shifted first before bit |
1466 | * comparison. Otherwise, the result will always be zero here |
1467 | */ |
1468 | params.usSpreadSpectrumAmount = cpu_to_le16((uint16_t)( |
1469 | ((bp_params->ds.feedback_amount << |
1470 | ATOM_PPLL_SS_AMOUNT_V3_FBDIV_SHIFT) & |
1471 | ATOM_PPLL_SS_AMOUNT_V3_FBDIV_MASK) | |
1472 | ((bp_params->ds.nfrac_amount << |
1473 | ATOM_PPLL_SS_AMOUNT_V3_NFRAC_SHIFT) & |
1474 | ATOM_PPLL_SS_AMOUNT_V3_NFRAC_MASK))); |
1475 | } else |
1476 | params.ucEnable = ATOM_DISABLE; |
1477 | |
1478 | if (EXEC_BIOS_CMD_TABLE(EnableSpreadSpectrumOnPPLL, params)) |
1479 | result = BP_RESULT_OK; |
1480 | |
1481 | return result; |
1482 | } |
1483 | |
1484 | /******************************************************************************* |
1485 | ******************************************************************************** |
1486 | ** |
1487 | ** ADJUST DISPLAY PLL |
1488 | ** |
1489 | ******************************************************************************** |
1490 | *******************************************************************************/ |
1491 | |
1492 | static enum bp_result adjust_display_pll_v2( |
1493 | struct bios_parser *bp, |
1494 | struct bp_adjust_pixel_clock_parameters *bp_params); |
1495 | static enum bp_result adjust_display_pll_v3( |
1496 | struct bios_parser *bp, |
1497 | struct bp_adjust_pixel_clock_parameters *bp_params); |
1498 | |
1499 | static void init_adjust_display_pll(struct bios_parser *bp) |
1500 | { |
1501 | switch (BIOS_CMD_TABLE_PARA_REVISION(AdjustDisplayPll)) { |
1502 | case 2: |
1503 | bp->cmd_tbl.adjust_display_pll = adjust_display_pll_v2; |
1504 | break; |
1505 | case 3: |
1506 | bp->cmd_tbl.adjust_display_pll = adjust_display_pll_v3; |
1507 | break; |
1508 | default: |
1509 | dm_output_to_console("Don't have adjust_display_pll for v%d\n" , |
1510 | BIOS_CMD_TABLE_PARA_REVISION(AdjustDisplayPll)); |
1511 | bp->cmd_tbl.adjust_display_pll = NULL; |
1512 | break; |
1513 | } |
1514 | } |
1515 | |
1516 | static enum bp_result adjust_display_pll_v2( |
1517 | struct bios_parser *bp, |
1518 | struct bp_adjust_pixel_clock_parameters *bp_params) |
1519 | { |
1520 | enum bp_result result = BP_RESULT_FAILURE; |
1521 | ADJUST_DISPLAY_PLL_PS_ALLOCATION params = { 0 }; |
1522 | |
1523 | /* We need to convert from KHz units into 10KHz units and then convert |
1524 | * output pixel clock back 10KHz-->KHz */ |
1525 | uint32_t pixel_clock_10KHz_in = bp_params->pixel_clock / 10; |
1526 | |
1527 | params.usPixelClock = cpu_to_le16((uint16_t)(pixel_clock_10KHz_in)); |
1528 | params.ucTransmitterID = |
1529 | bp->cmd_helper->encoder_id_to_atom( |
1530 | dal_graphics_object_id_get_encoder_id( |
1531 | id: bp_params->encoder_object_id)); |
1532 | params.ucEncodeMode = |
1533 | (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom( |
1534 | bp_params->signal_type, false); |
1535 | |
1536 | if (EXEC_BIOS_CMD_TABLE(AdjustDisplayPll, params)) { |
1537 | /* Convert output pixel clock back 10KHz-->KHz: multiply |
1538 | * original pixel clock in KHz by ratio |
1539 | * [output pxlClk/input pxlClk] */ |
1540 | uint64_t pixel_clk_10_khz_out = |
1541 | (uint64_t)le16_to_cpu(params.usPixelClock); |
1542 | uint64_t pixel_clk = (uint64_t)bp_params->pixel_clock; |
1543 | |
1544 | if (pixel_clock_10KHz_in != 0) { |
1545 | bp_params->adjusted_pixel_clock = |
1546 | div_u64(dividend: pixel_clk * pixel_clk_10_khz_out, |
1547 | divisor: pixel_clock_10KHz_in); |
1548 | } else { |
1549 | bp_params->adjusted_pixel_clock = 0; |
1550 | BREAK_TO_DEBUGGER(); |
1551 | } |
1552 | |
1553 | result = BP_RESULT_OK; |
1554 | } |
1555 | |
1556 | return result; |
1557 | } |
1558 | |
1559 | static enum bp_result adjust_display_pll_v3( |
1560 | struct bios_parser *bp, |
1561 | struct bp_adjust_pixel_clock_parameters *bp_params) |
1562 | { |
1563 | enum bp_result result = BP_RESULT_FAILURE; |
1564 | ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 params; |
1565 | uint32_t pixel_clk_10_kHz_in = bp_params->pixel_clock / 10; |
1566 | |
1567 | memset(¶ms, 0, sizeof(params)); |
1568 | |
1569 | /* We need to convert from KHz units into 10KHz units and then convert |
1570 | * output pixel clock back 10KHz-->KHz */ |
1571 | params.sInput.usPixelClock = cpu_to_le16((uint16_t)pixel_clk_10_kHz_in); |
1572 | params.sInput.ucTransmitterID = |
1573 | bp->cmd_helper->encoder_id_to_atom( |
1574 | dal_graphics_object_id_get_encoder_id( |
1575 | id: bp_params->encoder_object_id)); |
1576 | params.sInput.ucEncodeMode = |
1577 | (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom( |
1578 | bp_params->signal_type, false); |
1579 | |
1580 | if (bp_params->ss_enable == true) |
1581 | params.sInput.ucDispPllConfig |= DISPPLL_CONFIG_SS_ENABLE; |
1582 | |
1583 | if (bp_params->signal_type == SIGNAL_TYPE_DVI_DUAL_LINK) |
1584 | params.sInput.ucDispPllConfig |= DISPPLL_CONFIG_DUAL_LINK; |
1585 | |
1586 | if (EXEC_BIOS_CMD_TABLE(AdjustDisplayPll, params)) { |
1587 | /* Convert output pixel clock back 10KHz-->KHz: multiply |
1588 | * original pixel clock in KHz by ratio |
1589 | * [output pxlClk/input pxlClk] */ |
1590 | uint64_t pixel_clk_10_khz_out = |
1591 | (uint64_t)le32_to_cpu(params.sOutput.ulDispPllFreq); |
1592 | uint64_t pixel_clk = (uint64_t)bp_params->pixel_clock; |
1593 | |
1594 | if (pixel_clk_10_kHz_in != 0) { |
1595 | bp_params->adjusted_pixel_clock = |
1596 | div_u64(dividend: pixel_clk * pixel_clk_10_khz_out, |
1597 | divisor: pixel_clk_10_kHz_in); |
1598 | } else { |
1599 | bp_params->adjusted_pixel_clock = 0; |
1600 | BREAK_TO_DEBUGGER(); |
1601 | } |
1602 | |
1603 | bp_params->reference_divider = params.sOutput.ucRefDiv; |
1604 | bp_params->pixel_clock_post_divider = params.sOutput.ucPostDiv; |
1605 | |
1606 | result = BP_RESULT_OK; |
1607 | } |
1608 | |
1609 | return result; |
1610 | } |
1611 | |
1612 | /******************************************************************************* |
1613 | ******************************************************************************** |
1614 | ** |
1615 | ** DAC ENCODER CONTROL |
1616 | ** |
1617 | ******************************************************************************** |
1618 | *******************************************************************************/ |
1619 | |
1620 | static enum bp_result dac1_encoder_control_v1( |
1621 | struct bios_parser *bp, |
1622 | bool enable, |
1623 | uint32_t pixel_clock, |
1624 | uint8_t dac_standard); |
1625 | static enum bp_result dac2_encoder_control_v1( |
1626 | struct bios_parser *bp, |
1627 | bool enable, |
1628 | uint32_t pixel_clock, |
1629 | uint8_t dac_standard); |
1630 | |
1631 | static void init_dac_encoder_control(struct bios_parser *bp) |
1632 | { |
1633 | switch (BIOS_CMD_TABLE_PARA_REVISION(DAC1EncoderControl)) { |
1634 | case 1: |
1635 | bp->cmd_tbl.dac1_encoder_control = dac1_encoder_control_v1; |
1636 | break; |
1637 | default: |
1638 | bp->cmd_tbl.dac1_encoder_control = NULL; |
1639 | break; |
1640 | } |
1641 | switch (BIOS_CMD_TABLE_PARA_REVISION(DAC2EncoderControl)) { |
1642 | case 1: |
1643 | bp->cmd_tbl.dac2_encoder_control = dac2_encoder_control_v1; |
1644 | break; |
1645 | default: |
1646 | bp->cmd_tbl.dac2_encoder_control = NULL; |
1647 | break; |
1648 | } |
1649 | } |
1650 | |
1651 | static void dac_encoder_control_prepare_params( |
1652 | DAC_ENCODER_CONTROL_PS_ALLOCATION *params, |
1653 | bool enable, |
1654 | uint32_t pixel_clock, |
1655 | uint8_t dac_standard) |
1656 | { |
1657 | params->ucDacStandard = dac_standard; |
1658 | if (enable) |
1659 | params->ucAction = ATOM_ENABLE; |
1660 | else |
1661 | params->ucAction = ATOM_DISABLE; |
1662 | |
1663 | /* We need to convert from KHz units into 10KHz units |
1664 | * it looks as if the TvControl do not care about pixel clock |
1665 | */ |
1666 | params->usPixelClock = cpu_to_le16((uint16_t)(pixel_clock / 10)); |
1667 | } |
1668 | |
1669 | static enum bp_result dac1_encoder_control_v1( |
1670 | struct bios_parser *bp, |
1671 | bool enable, |
1672 | uint32_t pixel_clock, |
1673 | uint8_t dac_standard) |
1674 | { |
1675 | enum bp_result result = BP_RESULT_FAILURE; |
1676 | DAC_ENCODER_CONTROL_PS_ALLOCATION params; |
1677 | |
1678 | dac_encoder_control_prepare_params( |
1679 | params: ¶ms, |
1680 | enable, |
1681 | pixel_clock, |
1682 | dac_standard); |
1683 | |
1684 | if (EXEC_BIOS_CMD_TABLE(DAC1EncoderControl, params)) |
1685 | result = BP_RESULT_OK; |
1686 | |
1687 | return result; |
1688 | } |
1689 | |
1690 | static enum bp_result dac2_encoder_control_v1( |
1691 | struct bios_parser *bp, |
1692 | bool enable, |
1693 | uint32_t pixel_clock, |
1694 | uint8_t dac_standard) |
1695 | { |
1696 | enum bp_result result = BP_RESULT_FAILURE; |
1697 | DAC_ENCODER_CONTROL_PS_ALLOCATION params; |
1698 | |
1699 | dac_encoder_control_prepare_params( |
1700 | params: ¶ms, |
1701 | enable, |
1702 | pixel_clock, |
1703 | dac_standard); |
1704 | |
1705 | if (EXEC_BIOS_CMD_TABLE(DAC2EncoderControl, params)) |
1706 | result = BP_RESULT_OK; |
1707 | |
1708 | return result; |
1709 | } |
1710 | |
1711 | /******************************************************************************* |
1712 | ******************************************************************************** |
1713 | ** |
1714 | ** DAC OUTPUT CONTROL |
1715 | ** |
1716 | ******************************************************************************** |
1717 | *******************************************************************************/ |
1718 | static enum bp_result dac1_output_control_v1( |
1719 | struct bios_parser *bp, |
1720 | bool enable); |
1721 | static enum bp_result dac2_output_control_v1( |
1722 | struct bios_parser *bp, |
1723 | bool enable); |
1724 | |
1725 | static void init_dac_output_control(struct bios_parser *bp) |
1726 | { |
1727 | switch (BIOS_CMD_TABLE_PARA_REVISION(DAC1OutputControl)) { |
1728 | case 1: |
1729 | bp->cmd_tbl.dac1_output_control = dac1_output_control_v1; |
1730 | break; |
1731 | default: |
1732 | bp->cmd_tbl.dac1_output_control = NULL; |
1733 | break; |
1734 | } |
1735 | switch (BIOS_CMD_TABLE_PARA_REVISION(DAC2OutputControl)) { |
1736 | case 1: |
1737 | bp->cmd_tbl.dac2_output_control = dac2_output_control_v1; |
1738 | break; |
1739 | default: |
1740 | bp->cmd_tbl.dac2_output_control = NULL; |
1741 | break; |
1742 | } |
1743 | } |
1744 | |
1745 | static enum bp_result dac1_output_control_v1( |
1746 | struct bios_parser *bp, bool enable) |
1747 | { |
1748 | enum bp_result result = BP_RESULT_FAILURE; |
1749 | DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION params; |
1750 | |
1751 | if (enable) |
1752 | params.ucAction = ATOM_ENABLE; |
1753 | else |
1754 | params.ucAction = ATOM_DISABLE; |
1755 | |
1756 | if (EXEC_BIOS_CMD_TABLE(DAC1OutputControl, params)) |
1757 | result = BP_RESULT_OK; |
1758 | |
1759 | return result; |
1760 | } |
1761 | |
1762 | static enum bp_result dac2_output_control_v1( |
1763 | struct bios_parser *bp, bool enable) |
1764 | { |
1765 | enum bp_result result = BP_RESULT_FAILURE; |
1766 | DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION params; |
1767 | |
1768 | if (enable) |
1769 | params.ucAction = ATOM_ENABLE; |
1770 | else |
1771 | params.ucAction = ATOM_DISABLE; |
1772 | |
1773 | if (EXEC_BIOS_CMD_TABLE(DAC2OutputControl, params)) |
1774 | result = BP_RESULT_OK; |
1775 | |
1776 | return result; |
1777 | } |
1778 | |
1779 | /******************************************************************************* |
1780 | ******************************************************************************** |
1781 | ** |
1782 | ** SET CRTC TIMING |
1783 | ** |
1784 | ******************************************************************************** |
1785 | *******************************************************************************/ |
1786 | |
1787 | static enum bp_result set_crtc_using_dtd_timing_v3( |
1788 | struct bios_parser *bp, |
1789 | struct bp_hw_crtc_timing_parameters *bp_params); |
1790 | static enum bp_result set_crtc_timing_v1( |
1791 | struct bios_parser *bp, |
1792 | struct bp_hw_crtc_timing_parameters *bp_params); |
1793 | |
1794 | static void init_set_crtc_timing(struct bios_parser *bp) |
1795 | { |
1796 | uint32_t dtd_version = |
1797 | BIOS_CMD_TABLE_PARA_REVISION(SetCRTC_UsingDTDTiming); |
1798 | if (dtd_version > 2) |
1799 | switch (dtd_version) { |
1800 | case 3: |
1801 | bp->cmd_tbl.set_crtc_timing = |
1802 | set_crtc_using_dtd_timing_v3; |
1803 | break; |
1804 | default: |
1805 | dm_output_to_console("Don't have set_crtc_timing for dtd v%d\n" , |
1806 | dtd_version); |
1807 | bp->cmd_tbl.set_crtc_timing = NULL; |
1808 | break; |
1809 | } |
1810 | else |
1811 | switch (BIOS_CMD_TABLE_PARA_REVISION(SetCRTC_Timing)) { |
1812 | case 1: |
1813 | bp->cmd_tbl.set_crtc_timing = set_crtc_timing_v1; |
1814 | break; |
1815 | default: |
1816 | dm_output_to_console("Don't have set_crtc_timing for v%d\n" , |
1817 | BIOS_CMD_TABLE_PARA_REVISION(SetCRTC_Timing)); |
1818 | bp->cmd_tbl.set_crtc_timing = NULL; |
1819 | break; |
1820 | } |
1821 | } |
1822 | |
1823 | static enum bp_result set_crtc_timing_v1( |
1824 | struct bios_parser *bp, |
1825 | struct bp_hw_crtc_timing_parameters *bp_params) |
1826 | { |
1827 | enum bp_result result = BP_RESULT_FAILURE; |
1828 | SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION params = {0}; |
1829 | uint8_t atom_controller_id; |
1830 | |
1831 | if (bp->cmd_helper->controller_id_to_atom( |
1832 | bp_params->controller_id, &atom_controller_id)) |
1833 | params.ucCRTC = atom_controller_id; |
1834 | |
1835 | params.usH_Total = cpu_to_le16((uint16_t)(bp_params->h_total)); |
1836 | params.usH_Disp = cpu_to_le16((uint16_t)(bp_params->h_addressable)); |
1837 | params.usH_SyncStart = cpu_to_le16((uint16_t)(bp_params->h_sync_start)); |
1838 | params.usH_SyncWidth = cpu_to_le16((uint16_t)(bp_params->h_sync_width)); |
1839 | params.usV_Total = cpu_to_le16((uint16_t)(bp_params->v_total)); |
1840 | params.usV_Disp = cpu_to_le16((uint16_t)(bp_params->v_addressable)); |
1841 | params.usV_SyncStart = |
1842 | cpu_to_le16((uint16_t)(bp_params->v_sync_start)); |
1843 | params.usV_SyncWidth = |
1844 | cpu_to_le16((uint16_t)(bp_params->v_sync_width)); |
1845 | |
1846 | /* VBIOS does not expect any value except zero into this call, for |
1847 | * underscan use another entry ProgramOverscan call but when mode |
1848 | * 1776x1000 with the overscan 72x44 .e.i. 1920x1080 @30 DAL2 is ok, |
1849 | * but when same ,but 60 Hz there is corruption |
1850 | * DAL1 does not allow the mode 1776x1000@60 |
1851 | */ |
1852 | params.ucOverscanRight = (uint8_t)bp_params->h_overscan_right; |
1853 | params.ucOverscanLeft = (uint8_t)bp_params->h_overscan_left; |
1854 | params.ucOverscanBottom = (uint8_t)bp_params->v_overscan_bottom; |
1855 | params.ucOverscanTop = (uint8_t)bp_params->v_overscan_top; |
1856 | |
1857 | if (0 == bp_params->flags.HSYNC_POSITIVE_POLARITY) |
1858 | params.susModeMiscInfo.usAccess = |
1859 | cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_HSYNC_POLARITY); |
1860 | |
1861 | if (0 == bp_params->flags.VSYNC_POSITIVE_POLARITY) |
1862 | params.susModeMiscInfo.usAccess = |
1863 | cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_VSYNC_POLARITY); |
1864 | |
1865 | if (bp_params->flags.INTERLACE) { |
1866 | params.susModeMiscInfo.usAccess = |
1867 | cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_INTERLACE); |
1868 | |
1869 | /* original DAL code has this condition to apply tis for |
1870 | * non-TV/CV only due to complex MV testing for possible |
1871 | * impact |
1872 | * if (pACParameters->signal != SignalType_YPbPr && |
1873 | * pACParameters->signal != SignalType_Composite && |
1874 | * pACParameters->signal != SignalType_SVideo) |
1875 | */ |
1876 | /* HW will deduct 0.5 line from 2nd feild. |
1877 | * i.e. for 1080i, it is 2 lines for 1st field, 2.5 |
1878 | * lines for the 2nd feild. we need input as 5 instead |
1879 | * of 4, but it is 4 either from Edid data |
1880 | * (spec CEA 861) or CEA timing table. |
1881 | */ |
1882 | params.usV_SyncStart = |
1883 | cpu_to_le16((uint16_t)(bp_params->v_sync_start + 1)); |
1884 | } |
1885 | |
1886 | if (bp_params->flags.HORZ_COUNT_BY_TWO) |
1887 | params.susModeMiscInfo.usAccess = |
1888 | cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_DOUBLE_CLOCK_MODE); |
1889 | |
1890 | if (EXEC_BIOS_CMD_TABLE(SetCRTC_Timing, params)) |
1891 | result = BP_RESULT_OK; |
1892 | |
1893 | return result; |
1894 | } |
1895 | |
1896 | static enum bp_result set_crtc_using_dtd_timing_v3( |
1897 | struct bios_parser *bp, |
1898 | struct bp_hw_crtc_timing_parameters *bp_params) |
1899 | { |
1900 | enum bp_result result = BP_RESULT_FAILURE; |
1901 | SET_CRTC_USING_DTD_TIMING_PARAMETERS params = {0}; |
1902 | uint8_t atom_controller_id; |
1903 | |
1904 | if (bp->cmd_helper->controller_id_to_atom( |
1905 | bp_params->controller_id, &atom_controller_id)) |
1906 | params.ucCRTC = atom_controller_id; |
1907 | |
1908 | /* bios usH_Size wants h addressable size */ |
1909 | params.usH_Size = cpu_to_le16((uint16_t)bp_params->h_addressable); |
1910 | /* bios usH_Blanking_Time wants borders included in blanking */ |
1911 | params.usH_Blanking_Time = |
1912 | cpu_to_le16((uint16_t)(bp_params->h_total - bp_params->h_addressable)); |
1913 | /* bios usV_Size wants v addressable size */ |
1914 | params.usV_Size = cpu_to_le16((uint16_t)bp_params->v_addressable); |
1915 | /* bios usV_Blanking_Time wants borders included in blanking */ |
1916 | params.usV_Blanking_Time = |
1917 | cpu_to_le16((uint16_t)(bp_params->v_total - bp_params->v_addressable)); |
1918 | /* bios usHSyncOffset is the offset from the end of h addressable, |
1919 | * our horizontalSyncStart is the offset from the beginning |
1920 | * of h addressable */ |
1921 | params.usH_SyncOffset = |
1922 | cpu_to_le16((uint16_t)(bp_params->h_sync_start - bp_params->h_addressable)); |
1923 | params.usH_SyncWidth = cpu_to_le16((uint16_t)bp_params->h_sync_width); |
1924 | /* bios usHSyncOffset is the offset from the end of v addressable, |
1925 | * our verticalSyncStart is the offset from the beginning of |
1926 | * v addressable */ |
1927 | params.usV_SyncOffset = |
1928 | cpu_to_le16((uint16_t)(bp_params->v_sync_start - bp_params->v_addressable)); |
1929 | params.usV_SyncWidth = cpu_to_le16((uint16_t)bp_params->v_sync_width); |
1930 | |
1931 | /* we assume that overscan from original timing does not get bigger |
1932 | * than 255 |
1933 | * we will program all the borders in the Set CRTC Overscan call below |
1934 | */ |
1935 | |
1936 | if (0 == bp_params->flags.HSYNC_POSITIVE_POLARITY) |
1937 | params.susModeMiscInfo.usAccess = |
1938 | cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_HSYNC_POLARITY); |
1939 | |
1940 | if (0 == bp_params->flags.VSYNC_POSITIVE_POLARITY) |
1941 | params.susModeMiscInfo.usAccess = |
1942 | cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_VSYNC_POLARITY); |
1943 | |
1944 | if (bp_params->flags.INTERLACE) { |
1945 | params.susModeMiscInfo.usAccess = |
1946 | cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_INTERLACE); |
1947 | |
1948 | /* original DAL code has this condition to apply this |
1949 | * for non-TV/CV only |
1950 | * due to complex MV testing for possible impact |
1951 | * if ( pACParameters->signal != SignalType_YPbPr && |
1952 | * pACParameters->signal != SignalType_Composite && |
1953 | * pACParameters->signal != SignalType_SVideo) |
1954 | */ |
1955 | { |
1956 | /* HW will deduct 0.5 line from 2nd feild. |
1957 | * i.e. for 1080i, it is 2 lines for 1st field, |
1958 | * 2.5 lines for the 2nd feild. we need input as 5 |
1959 | * instead of 4. |
1960 | * but it is 4 either from Edid data (spec CEA 861) |
1961 | * or CEA timing table. |
1962 | */ |
1963 | le16_add_cpu(var: ¶ms.usV_SyncOffset, val: 1); |
1964 | } |
1965 | } |
1966 | |
1967 | if (bp_params->flags.HORZ_COUNT_BY_TWO) |
1968 | params.susModeMiscInfo.usAccess = |
1969 | cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_DOUBLE_CLOCK_MODE); |
1970 | |
1971 | if (EXEC_BIOS_CMD_TABLE(SetCRTC_UsingDTDTiming, params)) |
1972 | result = BP_RESULT_OK; |
1973 | |
1974 | return result; |
1975 | } |
1976 | |
1977 | /******************************************************************************* |
1978 | ******************************************************************************** |
1979 | ** |
1980 | ** ENABLE CRTC |
1981 | ** |
1982 | ******************************************************************************** |
1983 | *******************************************************************************/ |
1984 | |
1985 | static enum bp_result enable_crtc_v1( |
1986 | struct bios_parser *bp, |
1987 | enum controller_id controller_id, |
1988 | bool enable); |
1989 | |
1990 | static void init_enable_crtc(struct bios_parser *bp) |
1991 | { |
1992 | switch (BIOS_CMD_TABLE_PARA_REVISION(EnableCRTC)) { |
1993 | case 1: |
1994 | bp->cmd_tbl.enable_crtc = enable_crtc_v1; |
1995 | break; |
1996 | default: |
1997 | dm_output_to_console("Don't have enable_crtc for v%d\n" , |
1998 | BIOS_CMD_TABLE_PARA_REVISION(EnableCRTC)); |
1999 | bp->cmd_tbl.enable_crtc = NULL; |
2000 | break; |
2001 | } |
2002 | } |
2003 | |
2004 | static enum bp_result enable_crtc_v1( |
2005 | struct bios_parser *bp, |
2006 | enum controller_id controller_id, |
2007 | bool enable) |
2008 | { |
2009 | bool result = BP_RESULT_FAILURE; |
2010 | ENABLE_CRTC_PARAMETERS params = {0}; |
2011 | uint8_t id; |
2012 | |
2013 | if (bp->cmd_helper->controller_id_to_atom(controller_id, &id)) |
2014 | params.ucCRTC = id; |
2015 | else |
2016 | return BP_RESULT_BADINPUT; |
2017 | |
2018 | if (enable) |
2019 | params.ucEnable = ATOM_ENABLE; |
2020 | else |
2021 | params.ucEnable = ATOM_DISABLE; |
2022 | |
2023 | if (EXEC_BIOS_CMD_TABLE(EnableCRTC, params)) |
2024 | result = BP_RESULT_OK; |
2025 | |
2026 | return result; |
2027 | } |
2028 | |
2029 | /******************************************************************************* |
2030 | ******************************************************************************** |
2031 | ** |
2032 | ** ENABLE CRTC MEM REQ |
2033 | ** |
2034 | ******************************************************************************** |
2035 | *******************************************************************************/ |
2036 | |
2037 | static enum bp_result enable_crtc_mem_req_v1( |
2038 | struct bios_parser *bp, |
2039 | enum controller_id controller_id, |
2040 | bool enable); |
2041 | |
2042 | static void init_enable_crtc_mem_req(struct bios_parser *bp) |
2043 | { |
2044 | switch (BIOS_CMD_TABLE_PARA_REVISION(EnableCRTCMemReq)) { |
2045 | case 1: |
2046 | bp->cmd_tbl.enable_crtc_mem_req = enable_crtc_mem_req_v1; |
2047 | break; |
2048 | default: |
2049 | bp->cmd_tbl.enable_crtc_mem_req = NULL; |
2050 | break; |
2051 | } |
2052 | } |
2053 | |
2054 | static enum bp_result enable_crtc_mem_req_v1( |
2055 | struct bios_parser *bp, |
2056 | enum controller_id controller_id, |
2057 | bool enable) |
2058 | { |
2059 | bool result = BP_RESULT_BADINPUT; |
2060 | ENABLE_CRTC_PARAMETERS params = {0}; |
2061 | uint8_t id; |
2062 | |
2063 | if (bp->cmd_helper->controller_id_to_atom(controller_id, &id)) { |
2064 | params.ucCRTC = id; |
2065 | |
2066 | if (enable) |
2067 | params.ucEnable = ATOM_ENABLE; |
2068 | else |
2069 | params.ucEnable = ATOM_DISABLE; |
2070 | |
2071 | if (EXEC_BIOS_CMD_TABLE(EnableCRTCMemReq, params)) |
2072 | result = BP_RESULT_OK; |
2073 | else |
2074 | result = BP_RESULT_FAILURE; |
2075 | } |
2076 | |
2077 | return result; |
2078 | } |
2079 | |
2080 | /******************************************************************************* |
2081 | ******************************************************************************** |
2082 | ** |
2083 | ** DISPLAY PLL |
2084 | ** |
2085 | ******************************************************************************** |
2086 | *******************************************************************************/ |
2087 | |
2088 | static enum bp_result program_clock_v5( |
2089 | struct bios_parser *bp, |
2090 | struct bp_pixel_clock_parameters *bp_params); |
2091 | static enum bp_result program_clock_v6( |
2092 | struct bios_parser *bp, |
2093 | struct bp_pixel_clock_parameters *bp_params); |
2094 | |
2095 | static void init_program_clock(struct bios_parser *bp) |
2096 | { |
2097 | switch (BIOS_CMD_TABLE_PARA_REVISION(SetPixelClock)) { |
2098 | case 5: |
2099 | bp->cmd_tbl.program_clock = program_clock_v5; |
2100 | break; |
2101 | case 6: |
2102 | bp->cmd_tbl.program_clock = program_clock_v6; |
2103 | break; |
2104 | default: |
2105 | dm_output_to_console("Don't have program_clock for v%d\n" , |
2106 | BIOS_CMD_TABLE_PARA_REVISION(SetPixelClock)); |
2107 | bp->cmd_tbl.program_clock = NULL; |
2108 | break; |
2109 | } |
2110 | } |
2111 | |
2112 | static enum bp_result program_clock_v5( |
2113 | struct bios_parser *bp, |
2114 | struct bp_pixel_clock_parameters *bp_params) |
2115 | { |
2116 | enum bp_result result = BP_RESULT_FAILURE; |
2117 | |
2118 | SET_PIXEL_CLOCK_PS_ALLOCATION_V5 params; |
2119 | uint32_t atom_pll_id; |
2120 | |
2121 | memset(¶ms, 0, sizeof(params)); |
2122 | if (!bp->cmd_helper->clock_source_id_to_atom( |
2123 | bp_params->pll_id, &atom_pll_id)) { |
2124 | BREAK_TO_DEBUGGER(); /* Invalid Input!! */ |
2125 | return BP_RESULT_BADINPUT; |
2126 | } |
2127 | |
2128 | /* We need to convert from KHz units into 10KHz units */ |
2129 | params.sPCLKInput.ucPpll = (uint8_t) atom_pll_id; |
2130 | params.sPCLKInput.usPixelClock = |
2131 | cpu_to_le16((uint16_t) (bp_params->target_pixel_clock_100hz / 100)); |
2132 | params.sPCLKInput.ucCRTC = (uint8_t) ATOM_CRTC_INVALID; |
2133 | |
2134 | if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC) |
2135 | params.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; |
2136 | |
2137 | if (EXEC_BIOS_CMD_TABLE(SetPixelClock, params)) |
2138 | result = BP_RESULT_OK; |
2139 | |
2140 | return result; |
2141 | } |
2142 | |
2143 | static enum bp_result program_clock_v6( |
2144 | struct bios_parser *bp, |
2145 | struct bp_pixel_clock_parameters *bp_params) |
2146 | { |
2147 | enum bp_result result = BP_RESULT_FAILURE; |
2148 | |
2149 | SET_PIXEL_CLOCK_PS_ALLOCATION_V6 params; |
2150 | uint32_t atom_pll_id; |
2151 | |
2152 | memset(¶ms, 0, sizeof(params)); |
2153 | |
2154 | if (!bp->cmd_helper->clock_source_id_to_atom( |
2155 | bp_params->pll_id, &atom_pll_id)) { |
2156 | BREAK_TO_DEBUGGER(); /*Invalid Input!!*/ |
2157 | return BP_RESULT_BADINPUT; |
2158 | } |
2159 | |
2160 | /* We need to convert from KHz units into 10KHz units */ |
2161 | params.sPCLKInput.ucPpll = (uint8_t)atom_pll_id; |
2162 | params.sPCLKInput.ulDispEngClkFreq = |
2163 | cpu_to_le32(bp_params->target_pixel_clock_100hz / 100); |
2164 | |
2165 | if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC) |
2166 | params.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; |
2167 | |
2168 | if (bp_params->flags.SET_DISPCLK_DFS_BYPASS) |
2169 | params.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_DPREFCLK_BYPASS; |
2170 | |
2171 | if (EXEC_BIOS_CMD_TABLE(SetPixelClock, params)) { |
2172 | /* True display clock is returned by VBIOS if DFS bypass |
2173 | * is enabled. */ |
2174 | bp_params->dfs_bypass_display_clock = |
2175 | (uint32_t)(le32_to_cpu(params.sPCLKInput.ulDispEngClkFreq) * 10); |
2176 | result = BP_RESULT_OK; |
2177 | } |
2178 | |
2179 | return result; |
2180 | } |
2181 | |
2182 | /******************************************************************************* |
2183 | ******************************************************************************** |
2184 | ** |
2185 | ** EXTERNAL ENCODER CONTROL |
2186 | ** |
2187 | ******************************************************************************** |
2188 | *******************************************************************************/ |
2189 | |
2190 | static enum bp_result external_encoder_control_v3( |
2191 | struct bios_parser *bp, |
2192 | struct bp_external_encoder_control *cntl); |
2193 | |
2194 | static void init_external_encoder_control( |
2195 | struct bios_parser *bp) |
2196 | { |
2197 | switch (BIOS_CMD_TABLE_PARA_REVISION(ExternalEncoderControl)) { |
2198 | case 3: |
2199 | bp->cmd_tbl.external_encoder_control = |
2200 | external_encoder_control_v3; |
2201 | break; |
2202 | default: |
2203 | bp->cmd_tbl.external_encoder_control = NULL; |
2204 | break; |
2205 | } |
2206 | } |
2207 | |
2208 | static enum bp_result external_encoder_control_v3( |
2209 | struct bios_parser *bp, |
2210 | struct bp_external_encoder_control *cntl) |
2211 | { |
2212 | enum bp_result result = BP_RESULT_FAILURE; |
2213 | |
2214 | /* we need use _PS_Alloc struct */ |
2215 | EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 params; |
2216 | EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 *cntl_params; |
2217 | struct graphics_object_id encoder; |
2218 | bool is_input_signal_dp = false; |
2219 | |
2220 | memset(¶ms, 0, sizeof(params)); |
2221 | |
2222 | cntl_params = ¶ms.sExtEncoder; |
2223 | |
2224 | encoder = cntl->encoder_id; |
2225 | |
2226 | /* check if encoder supports external encoder control table */ |
2227 | switch (dal_graphics_object_id_get_encoder_id(id: encoder)) { |
2228 | case ENCODER_ID_EXTERNAL_NUTMEG: |
2229 | case ENCODER_ID_EXTERNAL_TRAVIS: |
2230 | is_input_signal_dp = true; |
2231 | break; |
2232 | |
2233 | default: |
2234 | BREAK_TO_DEBUGGER(); |
2235 | return BP_RESULT_BADINPUT; |
2236 | } |
2237 | |
2238 | /* Fill information based on the action |
2239 | * |
2240 | * Bit[6:4]: indicate external encoder, applied to all functions. |
2241 | * =0: external encoder1, mapped to external encoder enum id1 |
2242 | * =1: external encoder2, mapped to external encoder enum id2 |
2243 | * |
2244 | * enum ObjectEnumId |
2245 | * { |
2246 | * EnumId_Unknown = 0, |
2247 | * EnumId_1, |
2248 | * EnumId_2, |
2249 | * }; |
2250 | */ |
2251 | cntl_params->ucConfig = (uint8_t)((encoder.enum_id - 1) << 4); |
2252 | |
2253 | switch (cntl->action) { |
2254 | case EXTERNAL_ENCODER_CONTROL_INIT: |
2255 | /* output display connector type. Only valid in encoder |
2256 | * initialization */ |
2257 | cntl_params->usConnectorId = |
2258 | cpu_to_le16((uint16_t)cntl->connector_obj_id.id); |
2259 | break; |
2260 | case EXTERNAL_ENCODER_CONTROL_SETUP: |
2261 | /* EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 pixel clock unit in |
2262 | * 10KHz |
2263 | * output display device pixel clock frequency in unit of 10KHz. |
2264 | * Only valid in setup and enableoutput |
2265 | */ |
2266 | cntl_params->usPixelClock = |
2267 | cpu_to_le16((uint16_t)(cntl->pixel_clock / 10)); |
2268 | /* Indicate display output signal type drive by external |
2269 | * encoder, only valid in setup and enableoutput */ |
2270 | cntl_params->ucEncoderMode = |
2271 | (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom( |
2272 | cntl->signal, false); |
2273 | |
2274 | if (is_input_signal_dp) { |
2275 | /* Bit[0]: indicate link rate, =1: 2.7Ghz, =0: 1.62Ghz, |
2276 | * only valid in encoder setup with DP mode. */ |
2277 | if (LINK_RATE_HIGH == cntl->link_rate) |
2278 | cntl_params->ucConfig |= 1; |
2279 | /* output color depth Indicate encoder data bpc format |
2280 | * in DP mode, only valid in encoder setup in DP mode. |
2281 | */ |
2282 | cntl_params->ucBitPerColor = |
2283 | (uint8_t)(cntl->color_depth); |
2284 | } |
2285 | /* Indicate how many lanes used by external encoder, only valid |
2286 | * in encoder setup and enableoutput. */ |
2287 | cntl_params->ucLaneNum = (uint8_t)(cntl->lanes_number); |
2288 | break; |
2289 | case EXTERNAL_ENCODER_CONTROL_ENABLE: |
2290 | cntl_params->usPixelClock = |
2291 | cpu_to_le16((uint16_t)(cntl->pixel_clock / 10)); |
2292 | cntl_params->ucEncoderMode = |
2293 | (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom( |
2294 | cntl->signal, false); |
2295 | cntl_params->ucLaneNum = (uint8_t)cntl->lanes_number; |
2296 | break; |
2297 | default: |
2298 | break; |
2299 | } |
2300 | |
2301 | cntl_params->ucAction = (uint8_t)cntl->action; |
2302 | |
2303 | if (EXEC_BIOS_CMD_TABLE(ExternalEncoderControl, params)) |
2304 | result = BP_RESULT_OK; |
2305 | |
2306 | return result; |
2307 | } |
2308 | |
2309 | /******************************************************************************* |
2310 | ******************************************************************************** |
2311 | ** |
2312 | ** ENABLE DISPLAY POWER GATING |
2313 | ** |
2314 | ******************************************************************************** |
2315 | *******************************************************************************/ |
2316 | |
2317 | static enum bp_result enable_disp_power_gating_v2_1( |
2318 | struct bios_parser *bp, |
2319 | enum controller_id crtc_id, |
2320 | enum bp_pipe_control_action action); |
2321 | |
2322 | static void init_enable_disp_power_gating( |
2323 | struct bios_parser *bp) |
2324 | { |
2325 | switch (BIOS_CMD_TABLE_PARA_REVISION(EnableDispPowerGating)) { |
2326 | case 1: |
2327 | bp->cmd_tbl.enable_disp_power_gating = |
2328 | enable_disp_power_gating_v2_1; |
2329 | break; |
2330 | default: |
2331 | dm_output_to_console("Don't enable_disp_power_gating enable_crtc for v%d\n" , |
2332 | BIOS_CMD_TABLE_PARA_REVISION(EnableDispPowerGating)); |
2333 | bp->cmd_tbl.enable_disp_power_gating = NULL; |
2334 | break; |
2335 | } |
2336 | } |
2337 | |
2338 | static enum bp_result enable_disp_power_gating_v2_1( |
2339 | struct bios_parser *bp, |
2340 | enum controller_id crtc_id, |
2341 | enum bp_pipe_control_action action) |
2342 | { |
2343 | enum bp_result result = BP_RESULT_FAILURE; |
2344 | |
2345 | ENABLE_DISP_POWER_GATING_PS_ALLOCATION params = {0}; |
2346 | uint8_t atom_crtc_id; |
2347 | |
2348 | if (bp->cmd_helper->controller_id_to_atom(crtc_id, &atom_crtc_id)) |
2349 | params.ucDispPipeId = atom_crtc_id; |
2350 | else |
2351 | return BP_RESULT_BADINPUT; |
2352 | |
2353 | params.ucEnable = |
2354 | bp->cmd_helper->disp_power_gating_action_to_atom(action); |
2355 | |
2356 | if (EXEC_BIOS_CMD_TABLE(EnableDispPowerGating, params)) |
2357 | result = BP_RESULT_OK; |
2358 | |
2359 | return result; |
2360 | } |
2361 | |
2362 | /******************************************************************************* |
2363 | ******************************************************************************** |
2364 | ** |
2365 | ** SET DCE CLOCK |
2366 | ** |
2367 | ******************************************************************************** |
2368 | *******************************************************************************/ |
2369 | static enum bp_result set_dce_clock_v2_1( |
2370 | struct bios_parser *bp, |
2371 | struct bp_set_dce_clock_parameters *bp_params); |
2372 | |
2373 | static void init_set_dce_clock(struct bios_parser *bp) |
2374 | { |
2375 | switch (BIOS_CMD_TABLE_PARA_REVISION(SetDCEClock)) { |
2376 | case 1: |
2377 | bp->cmd_tbl.set_dce_clock = set_dce_clock_v2_1; |
2378 | break; |
2379 | default: |
2380 | dm_output_to_console("Don't have set_dce_clock for v%d\n" , |
2381 | BIOS_CMD_TABLE_PARA_REVISION(SetDCEClock)); |
2382 | bp->cmd_tbl.set_dce_clock = NULL; |
2383 | break; |
2384 | } |
2385 | } |
2386 | |
2387 | static enum bp_result set_dce_clock_v2_1( |
2388 | struct bios_parser *bp, |
2389 | struct bp_set_dce_clock_parameters *bp_params) |
2390 | { |
2391 | enum bp_result result = BP_RESULT_FAILURE; |
2392 | |
2393 | SET_DCE_CLOCK_PS_ALLOCATION_V2_1 params; |
2394 | uint32_t atom_pll_id; |
2395 | uint32_t atom_clock_type; |
2396 | const struct command_table_helper *cmd = bp->cmd_helper; |
2397 | |
2398 | memset(¶ms, 0, sizeof(params)); |
2399 | |
2400 | if (!cmd->clock_source_id_to_atom(bp_params->pll_id, &atom_pll_id) || |
2401 | !cmd->dc_clock_type_to_atom(bp_params->clock_type, &atom_clock_type)) |
2402 | return BP_RESULT_BADINPUT; |
2403 | |
2404 | params.asParam.ucDCEClkSrc = atom_pll_id; |
2405 | params.asParam.ucDCEClkType = atom_clock_type; |
2406 | |
2407 | if (bp_params->clock_type == DCECLOCK_TYPE_DPREFCLK) { |
2408 | if (bp_params->flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK) |
2409 | params.asParam.ucDCEClkFlag |= DCE_CLOCK_FLAG_PLL_REFCLK_SRC_GENLK; |
2410 | |
2411 | if (bp_params->flags.USE_PCIE_AS_SOURCE_FOR_DPREFCLK) |
2412 | params.asParam.ucDCEClkFlag |= DCE_CLOCK_FLAG_PLL_REFCLK_SRC_PCIE; |
2413 | |
2414 | if (bp_params->flags.USE_XTALIN_AS_SOURCE_FOR_DPREFCLK) |
2415 | params.asParam.ucDCEClkFlag |= DCE_CLOCK_FLAG_PLL_REFCLK_SRC_XTALIN; |
2416 | |
2417 | if (bp_params->flags.USE_GENERICA_AS_SOURCE_FOR_DPREFCLK) |
2418 | params.asParam.ucDCEClkFlag |= DCE_CLOCK_FLAG_PLL_REFCLK_SRC_GENERICA; |
2419 | } |
2420 | else |
2421 | /* only program clock frequency if display clock is used; VBIOS will program DPREFCLK */ |
2422 | /* We need to convert from KHz units into 10KHz units */ |
2423 | params.asParam.ulDCEClkFreq = cpu_to_le32(bp_params->target_clock_frequency / 10); |
2424 | |
2425 | if (EXEC_BIOS_CMD_TABLE(SetDCEClock, params)) { |
2426 | /* Convert from 10KHz units back to KHz */ |
2427 | bp_params->target_clock_frequency = le32_to_cpu(params.asParam.ulDCEClkFreq) * 10; |
2428 | result = BP_RESULT_OK; |
2429 | } |
2430 | |
2431 | return result; |
2432 | } |
2433 | |