Line data Source code
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 <linux/slab.h>
27 :
28 : #include "dm_services.h"
29 :
30 : #include "atom.h"
31 :
32 : #include "dc_bios_types.h"
33 : #include "include/gpio_service_interface.h"
34 : #include "include/grph_object_ctrl_defs.h"
35 : #include "include/bios_parser_interface.h"
36 : #include "include/i2caux_interface.h"
37 : #include "include/logger_interface.h"
38 :
39 : #include "command_table.h"
40 : #include "bios_parser_helper.h"
41 : #include "command_table_helper.h"
42 : #include "bios_parser.h"
43 : #include "bios_parser_types_internal.h"
44 : #include "bios_parser_interface.h"
45 :
46 : #include "bios_parser_common.h"
47 :
48 : #include "dc.h"
49 :
50 : #define THREE_PERCENT_OF_10000 300
51 :
52 : #define LAST_RECORD_TYPE 0xff
53 :
54 : #define DC_LOGGER \
55 : bp->base.ctx->logger
56 :
57 : #define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
58 :
59 : static void get_atom_data_table_revision(
60 : ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
61 : struct atom_data_revision *tbl_revision);
62 : static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
63 : uint16_t **id_list);
64 : static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
65 : struct graphics_object_id id);
66 : static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
67 : ATOM_I2C_RECORD *record,
68 : struct graphics_object_i2c_info *info);
69 : static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
70 : ATOM_OBJECT *object);
71 : static struct device_id device_type_from_device_id(uint16_t device_id);
72 : static uint32_t signal_to_ss_id(enum as_signal_type signal);
73 : static uint32_t get_support_mask_for_device_id(struct device_id device_id);
74 : static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
75 : struct bios_parser *bp,
76 : ATOM_OBJECT *object);
77 :
78 : #define BIOS_IMAGE_SIZE_OFFSET 2
79 : #define BIOS_IMAGE_SIZE_UNIT 512
80 :
81 : /*****************************************************************************/
82 : static bool bios_parser_construct(
83 : struct bios_parser *bp,
84 : struct bp_init_data *init,
85 : enum dce_version dce_version);
86 :
87 : static uint8_t bios_parser_get_connectors_number(
88 : struct dc_bios *dcb);
89 :
90 : static enum bp_result bios_parser_get_embedded_panel_info(
91 : struct dc_bios *dcb,
92 : struct embedded_panel_info *info);
93 :
94 : /*****************************************************************************/
95 :
96 0 : struct dc_bios *bios_parser_create(
97 : struct bp_init_data *init,
98 : enum dce_version dce_version)
99 : {
100 0 : struct bios_parser *bp = NULL;
101 :
102 0 : bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
103 0 : if (!bp)
104 : return NULL;
105 :
106 0 : if (bios_parser_construct(bp, init, dce_version))
107 0 : return &bp->base;
108 :
109 0 : kfree(bp);
110 0 : BREAK_TO_DEBUGGER();
111 0 : return NULL;
112 : }
113 :
114 : static void bios_parser_destruct(struct bios_parser *bp)
115 : {
116 0 : kfree(bp->base.bios_local_image);
117 0 : kfree(bp->base.integrated_info);
118 : }
119 :
120 0 : static void bios_parser_destroy(struct dc_bios **dcb)
121 : {
122 0 : struct bios_parser *bp = BP_FROM_DCB(*dcb);
123 :
124 0 : if (!bp) {
125 0 : BREAK_TO_DEBUGGER();
126 0 : return;
127 : }
128 :
129 0 : bios_parser_destruct(bp);
130 :
131 0 : kfree(bp);
132 0 : *dcb = NULL;
133 : }
134 :
135 : static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
136 : {
137 : ATOM_OBJECT_TABLE *table;
138 :
139 0 : uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
140 :
141 0 : table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
142 :
143 0 : if (!table)
144 : return 0;
145 : else
146 0 : return table->ucNumberOfObjects;
147 : }
148 :
149 0 : static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb)
150 : {
151 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
152 :
153 0 : return get_number_of_objects(bp,
154 0 : le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
155 : }
156 :
157 0 : static struct graphics_object_id bios_parser_get_connector_id(
158 : struct dc_bios *dcb,
159 : uint8_t i)
160 : {
161 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
162 0 : struct graphics_object_id object_id = dal_graphics_object_id_init(
163 : 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
164 : uint16_t id;
165 :
166 0 : uint32_t connector_table_offset = bp->object_info_tbl_offset
167 0 : + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
168 :
169 0 : ATOM_OBJECT_TABLE *tbl =
170 0 : GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
171 :
172 0 : if (!tbl) {
173 0 : dm_error("Can't get connector table from atom bios.\n");
174 0 : return object_id;
175 : }
176 :
177 0 : if (tbl->ucNumberOfObjects <= i) {
178 0 : dm_error("Can't find connector id %d in connector table of size %d.\n",
179 : i, tbl->ucNumberOfObjects);
180 0 : return object_id;
181 : }
182 :
183 0 : id = le16_to_cpu(tbl->asObjects[i].usObjectID);
184 0 : object_id = object_id_from_bios_object_id(id);
185 0 : return object_id;
186 : }
187 :
188 0 : static enum bp_result bios_parser_get_src_obj(struct dc_bios *dcb,
189 : struct graphics_object_id object_id, uint32_t index,
190 : struct graphics_object_id *src_object_id)
191 : {
192 : uint32_t number;
193 : uint16_t *id;
194 : ATOM_OBJECT *object;
195 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
196 :
197 0 : if (!src_object_id)
198 : return BP_RESULT_BADINPUT;
199 :
200 0 : object = get_bios_object(bp, object_id);
201 :
202 0 : if (!object) {
203 0 : BREAK_TO_DEBUGGER(); /* Invalid object id */
204 0 : return BP_RESULT_BADINPUT;
205 : }
206 :
207 0 : number = get_src_obj_list(bp, object, &id);
208 :
209 0 : if (number <= index)
210 : return BP_RESULT_BADINPUT;
211 :
212 0 : *src_object_id = object_id_from_bios_object_id(id[index]);
213 :
214 0 : return BP_RESULT_OK;
215 : }
216 :
217 0 : static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
218 : struct graphics_object_id id,
219 : struct graphics_object_i2c_info *info)
220 : {
221 : uint32_t offset;
222 : ATOM_OBJECT *object;
223 : ATOM_COMMON_RECORD_HEADER *header;
224 : ATOM_I2C_RECORD *record;
225 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
226 :
227 0 : if (!info)
228 : return BP_RESULT_BADINPUT;
229 :
230 0 : object = get_bios_object(bp, id);
231 :
232 0 : if (!object)
233 : return BP_RESULT_BADINPUT;
234 :
235 0 : offset = le16_to_cpu(object->usRecordOffset)
236 0 : + bp->object_info_tbl_offset;
237 :
238 : for (;;) {
239 0 : header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
240 :
241 0 : if (!header)
242 : return BP_RESULT_BADBIOSTABLE;
243 :
244 0 : if (LAST_RECORD_TYPE == header->ucRecordType ||
245 0 : !header->ucRecordSize)
246 : break;
247 :
248 0 : if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
249 0 : && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
250 : /* get the I2C info */
251 0 : record = (ATOM_I2C_RECORD *) header;
252 :
253 0 : if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
254 : return BP_RESULT_OK;
255 : }
256 :
257 0 : offset += header->ucRecordSize;
258 : }
259 :
260 : return BP_RESULT_NORECORD;
261 : }
262 :
263 0 : static enum bp_result bios_parser_get_hpd_info(struct dc_bios *dcb,
264 : struct graphics_object_id id,
265 : struct graphics_object_hpd_info *info)
266 : {
267 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
268 : ATOM_OBJECT *object;
269 0 : ATOM_HPD_INT_RECORD *record = NULL;
270 :
271 0 : if (!info)
272 : return BP_RESULT_BADINPUT;
273 :
274 0 : object = get_bios_object(bp, id);
275 :
276 0 : if (!object)
277 : return BP_RESULT_BADINPUT;
278 :
279 0 : record = get_hpd_record(bp, object);
280 :
281 0 : if (record != NULL) {
282 0 : info->hpd_int_gpio_uid = record->ucHPDIntGPIOID;
283 0 : info->hpd_active = record->ucPlugged_PinState;
284 0 : return BP_RESULT_OK;
285 : }
286 :
287 : return BP_RESULT_NORECORD;
288 : }
289 :
290 0 : static enum bp_result bios_parser_get_device_tag_record(
291 : struct bios_parser *bp,
292 : ATOM_OBJECT *object,
293 : ATOM_CONNECTOR_DEVICE_TAG_RECORD **record)
294 : {
295 : ATOM_COMMON_RECORD_HEADER *header;
296 : uint32_t offset;
297 :
298 0 : offset = le16_to_cpu(object->usRecordOffset)
299 0 : + bp->object_info_tbl_offset;
300 :
301 : for (;;) {
302 0 : header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
303 :
304 0 : if (!header)
305 : return BP_RESULT_BADBIOSTABLE;
306 :
307 0 : offset += header->ucRecordSize;
308 :
309 0 : if (LAST_RECORD_TYPE == header->ucRecordType ||
310 : !header->ucRecordSize)
311 : break;
312 :
313 0 : if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
314 : header->ucRecordType)
315 0 : continue;
316 :
317 0 : if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
318 0 : continue;
319 :
320 0 : *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
321 0 : return BP_RESULT_OK;
322 : }
323 :
324 : return BP_RESULT_NORECORD;
325 : }
326 :
327 0 : static enum bp_result bios_parser_get_device_tag(
328 : struct dc_bios *dcb,
329 : struct graphics_object_id connector_object_id,
330 : uint32_t device_tag_index,
331 : struct connector_device_tag_info *info)
332 : {
333 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
334 : ATOM_OBJECT *object;
335 0 : ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
336 : ATOM_CONNECTOR_DEVICE_TAG *device_tag;
337 :
338 0 : if (!info)
339 : return BP_RESULT_BADINPUT;
340 :
341 : /* getBiosObject will return MXM object */
342 0 : object = get_bios_object(bp, connector_object_id);
343 :
344 0 : if (!object) {
345 0 : BREAK_TO_DEBUGGER(); /* Invalid object id */
346 0 : return BP_RESULT_BADINPUT;
347 : }
348 :
349 0 : if (bios_parser_get_device_tag_record(bp, object, &record)
350 : != BP_RESULT_OK)
351 : return BP_RESULT_NORECORD;
352 :
353 0 : if (device_tag_index >= record->ucNumberOfDevice)
354 : return BP_RESULT_NORECORD;
355 :
356 0 : device_tag = &record->asDeviceTag[device_tag_index];
357 :
358 0 : info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
359 0 : info->dev_id =
360 0 : device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
361 :
362 0 : return BP_RESULT_OK;
363 : }
364 :
365 : static enum bp_result get_firmware_info_v1_4(
366 : struct bios_parser *bp,
367 : struct dc_firmware_info *info);
368 : static enum bp_result get_firmware_info_v2_1(
369 : struct bios_parser *bp,
370 : struct dc_firmware_info *info);
371 : static enum bp_result get_firmware_info_v2_2(
372 : struct bios_parser *bp,
373 : struct dc_firmware_info *info);
374 :
375 0 : static enum bp_result bios_parser_get_firmware_info(
376 : struct dc_bios *dcb,
377 : struct dc_firmware_info *info)
378 : {
379 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
380 0 : enum bp_result result = BP_RESULT_BADBIOSTABLE;
381 : ATOM_COMMON_TABLE_HEADER *header;
382 : struct atom_data_revision revision;
383 :
384 0 : if (info && DATA_TABLES(FirmwareInfo)) {
385 0 : header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
386 : DATA_TABLES(FirmwareInfo));
387 0 : get_atom_data_table_revision(header, &revision);
388 0 : switch (revision.major) {
389 : case 1:
390 0 : switch (revision.minor) {
391 : case 4:
392 0 : result = get_firmware_info_v1_4(bp, info);
393 0 : break;
394 : default:
395 : break;
396 : }
397 : break;
398 :
399 : case 2:
400 0 : switch (revision.minor) {
401 : case 1:
402 0 : result = get_firmware_info_v2_1(bp, info);
403 0 : break;
404 : case 2:
405 0 : result = get_firmware_info_v2_2(bp, info);
406 0 : break;
407 : default:
408 : break;
409 : }
410 : break;
411 : default:
412 : break;
413 : }
414 : }
415 :
416 0 : return result;
417 : }
418 :
419 0 : static enum bp_result get_firmware_info_v1_4(
420 : struct bios_parser *bp,
421 : struct dc_firmware_info *info)
422 : {
423 0 : ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
424 0 : GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
425 : DATA_TABLES(FirmwareInfo));
426 :
427 0 : if (!info)
428 : return BP_RESULT_BADINPUT;
429 :
430 0 : if (!firmware_info)
431 : return BP_RESULT_BADBIOSTABLE;
432 :
433 0 : memset(info, 0, sizeof(*info));
434 :
435 : /* Pixel clock pll information. We need to convert from 10KHz units into
436 : * KHz units */
437 0 : info->pll_info.crystal_frequency =
438 0 : le16_to_cpu(firmware_info->usReferenceClock) * 10;
439 0 : info->pll_info.min_input_pxl_clk_pll_frequency =
440 0 : le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
441 0 : info->pll_info.max_input_pxl_clk_pll_frequency =
442 0 : le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
443 0 : info->pll_info.min_output_pxl_clk_pll_frequency =
444 0 : le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
445 0 : info->pll_info.max_output_pxl_clk_pll_frequency =
446 0 : le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
447 :
448 0 : if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
449 : /* Since there is no information on the SS, report conservative
450 : * value 3% for bandwidth calculation */
451 : /* unit of 0.01% */
452 0 : info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
453 :
454 0 : if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
455 : /* Since there is no information on the SS,report conservative
456 : * value 3% for bandwidth calculation */
457 : /* unit of 0.01% */
458 0 : info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
459 :
460 : return BP_RESULT_OK;
461 : }
462 :
463 : static enum bp_result get_ss_info_v3_1(
464 : struct bios_parser *bp,
465 : uint32_t id,
466 : uint32_t index,
467 : struct spread_spectrum_info *ss_info);
468 :
469 0 : static enum bp_result get_firmware_info_v2_1(
470 : struct bios_parser *bp,
471 : struct dc_firmware_info *info)
472 : {
473 0 : ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
474 0 : GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
475 : struct spread_spectrum_info internalSS;
476 : uint32_t index;
477 :
478 0 : if (!info)
479 : return BP_RESULT_BADINPUT;
480 :
481 0 : if (!firmwareInfo)
482 : return BP_RESULT_BADBIOSTABLE;
483 :
484 0 : memset(info, 0, sizeof(*info));
485 :
486 : /* Pixel clock pll information. We need to convert from 10KHz units into
487 : * KHz units */
488 0 : info->pll_info.crystal_frequency =
489 0 : le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
490 0 : info->pll_info.min_input_pxl_clk_pll_frequency =
491 0 : le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
492 0 : info->pll_info.max_input_pxl_clk_pll_frequency =
493 0 : le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
494 0 : info->pll_info.min_output_pxl_clk_pll_frequency =
495 0 : le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
496 0 : info->pll_info.max_output_pxl_clk_pll_frequency =
497 0 : le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
498 0 : info->default_display_engine_pll_frequency =
499 0 : le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
500 0 : info->external_clock_source_frequency_for_dp =
501 0 : le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
502 0 : info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
503 :
504 : /* There should be only one entry in the SS info table for Memory Clock
505 : */
506 0 : index = 0;
507 0 : if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
508 : /* Since there is no information for external SS, report
509 : * conservative value 3% for bandwidth calculation */
510 : /* unit of 0.01% */
511 0 : info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
512 0 : else if (get_ss_info_v3_1(bp,
513 : ASIC_INTERNAL_MEMORY_SS, index, &internalSS) == BP_RESULT_OK) {
514 0 : if (internalSS.spread_spectrum_percentage) {
515 0 : info->feature.memory_clk_ss_percentage =
516 : internalSS.spread_spectrum_percentage;
517 0 : if (internalSS.type.CENTER_MODE) {
518 : /* if it is centermode, the exact SS Percentage
519 : * will be round up of half of the percentage
520 : * reported in the SS table */
521 0 : ++info->feature.memory_clk_ss_percentage;
522 0 : info->feature.memory_clk_ss_percentage /= 2;
523 : }
524 : }
525 : }
526 :
527 : /* There should be only one entry in the SS info table for Engine Clock
528 : */
529 0 : index = 1;
530 0 : if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
531 : /* Since there is no information for external SS, report
532 : * conservative value 3% for bandwidth calculation */
533 : /* unit of 0.01% */
534 0 : info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
535 0 : else if (get_ss_info_v3_1(bp,
536 : ASIC_INTERNAL_ENGINE_SS, index, &internalSS) == BP_RESULT_OK) {
537 0 : if (internalSS.spread_spectrum_percentage) {
538 0 : info->feature.engine_clk_ss_percentage =
539 : internalSS.spread_spectrum_percentage;
540 0 : if (internalSS.type.CENTER_MODE) {
541 : /* if it is centermode, the exact SS Percentage
542 : * will be round up of half of the percentage
543 : * reported in the SS table */
544 0 : ++info->feature.engine_clk_ss_percentage;
545 0 : info->feature.engine_clk_ss_percentage /= 2;
546 : }
547 : }
548 : }
549 :
550 : return BP_RESULT_OK;
551 : }
552 :
553 0 : static enum bp_result get_firmware_info_v2_2(
554 : struct bios_parser *bp,
555 : struct dc_firmware_info *info)
556 : {
557 : ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
558 : struct spread_spectrum_info internal_ss;
559 : uint32_t index;
560 :
561 0 : if (!info)
562 : return BP_RESULT_BADINPUT;
563 :
564 0 : firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
565 : DATA_TABLES(FirmwareInfo));
566 :
567 0 : if (!firmware_info)
568 : return BP_RESULT_BADBIOSTABLE;
569 :
570 0 : memset(info, 0, sizeof(*info));
571 :
572 : /* Pixel clock pll information. We need to convert from 10KHz units into
573 : * KHz units */
574 0 : info->pll_info.crystal_frequency =
575 0 : le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
576 0 : info->pll_info.min_input_pxl_clk_pll_frequency =
577 0 : le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
578 0 : info->pll_info.max_input_pxl_clk_pll_frequency =
579 0 : le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
580 0 : info->pll_info.min_output_pxl_clk_pll_frequency =
581 0 : le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
582 0 : info->pll_info.max_output_pxl_clk_pll_frequency =
583 0 : le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
584 0 : info->default_display_engine_pll_frequency =
585 0 : le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
586 0 : info->external_clock_source_frequency_for_dp =
587 0 : le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
588 :
589 : /* There should be only one entry in the SS info table for Memory Clock
590 : */
591 0 : index = 0;
592 0 : if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
593 : /* Since there is no information for external SS, report
594 : * conservative value 3% for bandwidth calculation */
595 : /* unit of 0.01% */
596 0 : info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
597 0 : else if (get_ss_info_v3_1(bp,
598 : ASIC_INTERNAL_MEMORY_SS, index, &internal_ss) == BP_RESULT_OK) {
599 0 : if (internal_ss.spread_spectrum_percentage) {
600 0 : info->feature.memory_clk_ss_percentage =
601 : internal_ss.spread_spectrum_percentage;
602 0 : if (internal_ss.type.CENTER_MODE) {
603 : /* if it is centermode, the exact SS Percentage
604 : * will be round up of half of the percentage
605 : * reported in the SS table */
606 0 : ++info->feature.memory_clk_ss_percentage;
607 0 : info->feature.memory_clk_ss_percentage /= 2;
608 : }
609 : }
610 : }
611 :
612 : /* There should be only one entry in the SS info table for Engine Clock
613 : */
614 0 : index = 1;
615 0 : if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
616 : /* Since there is no information for external SS, report
617 : * conservative value 3% for bandwidth calculation */
618 : /* unit of 0.01% */
619 0 : info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
620 0 : else if (get_ss_info_v3_1(bp,
621 : ASIC_INTERNAL_ENGINE_SS, index, &internal_ss) == BP_RESULT_OK) {
622 0 : if (internal_ss.spread_spectrum_percentage) {
623 0 : info->feature.engine_clk_ss_percentage =
624 : internal_ss.spread_spectrum_percentage;
625 0 : if (internal_ss.type.CENTER_MODE) {
626 : /* if it is centermode, the exact SS Percentage
627 : * will be round up of half of the percentage
628 : * reported in the SS table */
629 0 : ++info->feature.engine_clk_ss_percentage;
630 0 : info->feature.engine_clk_ss_percentage /= 2;
631 : }
632 : }
633 : }
634 :
635 : /* Remote Display */
636 0 : info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
637 :
638 : /* Is allowed minimum BL level */
639 0 : info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
640 : /* Used starting from CI */
641 0 : info->smu_gpu_pll_output_freq =
642 0 : (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
643 :
644 0 : return BP_RESULT_OK;
645 : }
646 :
647 0 : static enum bp_result get_ss_info_v3_1(
648 : struct bios_parser *bp,
649 : uint32_t id,
650 : uint32_t index,
651 : struct spread_spectrum_info *ss_info)
652 : {
653 : ATOM_ASIC_INTERNAL_SS_INFO_V3 *ss_table_header_include;
654 : ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
655 : uint32_t table_size;
656 : uint32_t i;
657 0 : uint32_t table_index = 0;
658 :
659 0 : if (!ss_info)
660 : return BP_RESULT_BADINPUT;
661 :
662 0 : if (!DATA_TABLES(ASIC_InternalSS_Info))
663 : return BP_RESULT_UNSUPPORTED;
664 :
665 0 : ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
666 : DATA_TABLES(ASIC_InternalSS_Info));
667 0 : table_size =
668 0 : (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
669 0 : - sizeof(ATOM_COMMON_TABLE_HEADER))
670 0 : / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
671 :
672 0 : tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
673 : &ss_table_header_include->asSpreadSpectrum[0];
674 :
675 0 : memset(ss_info, 0, sizeof(struct spread_spectrum_info));
676 :
677 0 : for (i = 0; i < table_size; i++) {
678 0 : if (tbl[i].ucClockIndication != (uint8_t) id)
679 0 : continue;
680 :
681 0 : if (table_index != index) {
682 0 : table_index++;
683 0 : continue;
684 : }
685 : /* VBIOS introduced new defines for Version 3, same values as
686 : * before, so now use these new ones for Version 3.
687 : * Shouldn't affect field VBIOS's V3 as define values are still
688 : * same.
689 : * #define SS_MODE_V3_CENTRE_SPREAD_MASK 0x01
690 : * #define SS_MODE_V3_EXTERNAL_SS_MASK 0x02
691 :
692 : * Old VBIOS defines:
693 : * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
694 : * #define ATOM_EXTERNAL_SS_MASK 0x00000002
695 : */
696 :
697 0 : if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
698 0 : ss_info->type.EXTERNAL = true;
699 :
700 0 : if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
701 0 : ss_info->type.CENTER_MODE = true;
702 :
703 : /* Older VBIOS (in field) always provides SS percentage in 0.01%
704 : * units set Divider to 100 */
705 0 : ss_info->spread_percentage_divider = 100;
706 :
707 : /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
708 0 : if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
709 0 : & tbl[i].ucSpreadSpectrumMode)
710 0 : ss_info->spread_percentage_divider = 1000;
711 :
712 0 : ss_info->type.STEP_AND_DELAY_INFO = false;
713 : /* convert [10KHz] into [KHz] */
714 0 : ss_info->target_clock_range =
715 0 : le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
716 0 : ss_info->spread_spectrum_percentage =
717 0 : (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
718 0 : ss_info->spread_spectrum_range =
719 0 : (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
720 :
721 0 : return BP_RESULT_OK;
722 : }
723 : return BP_RESULT_NORECORD;
724 : }
725 :
726 0 : static enum bp_result bios_parser_transmitter_control(
727 : struct dc_bios *dcb,
728 : struct bp_transmitter_control *cntl)
729 : {
730 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
731 :
732 0 : if (!bp->cmd_tbl.transmitter_control)
733 : return BP_RESULT_FAILURE;
734 :
735 0 : return bp->cmd_tbl.transmitter_control(bp, cntl);
736 : }
737 :
738 0 : static enum bp_result bios_parser_encoder_control(
739 : struct dc_bios *dcb,
740 : struct bp_encoder_control *cntl)
741 : {
742 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
743 :
744 0 : if (!bp->cmd_tbl.dig_encoder_control)
745 : return BP_RESULT_FAILURE;
746 :
747 0 : return bp->cmd_tbl.dig_encoder_control(bp, cntl);
748 : }
749 :
750 0 : static enum bp_result bios_parser_adjust_pixel_clock(
751 : struct dc_bios *dcb,
752 : struct bp_adjust_pixel_clock_parameters *bp_params)
753 : {
754 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
755 :
756 0 : if (!bp->cmd_tbl.adjust_display_pll)
757 : return BP_RESULT_FAILURE;
758 :
759 0 : return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
760 : }
761 :
762 0 : static enum bp_result bios_parser_set_pixel_clock(
763 : struct dc_bios *dcb,
764 : struct bp_pixel_clock_parameters *bp_params)
765 : {
766 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
767 :
768 0 : if (!bp->cmd_tbl.set_pixel_clock)
769 : return BP_RESULT_FAILURE;
770 :
771 0 : return bp->cmd_tbl.set_pixel_clock(bp, bp_params);
772 : }
773 :
774 0 : static enum bp_result bios_parser_set_dce_clock(
775 : struct dc_bios *dcb,
776 : struct bp_set_dce_clock_parameters *bp_params)
777 : {
778 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
779 :
780 0 : if (!bp->cmd_tbl.set_dce_clock)
781 : return BP_RESULT_FAILURE;
782 :
783 0 : return bp->cmd_tbl.set_dce_clock(bp, bp_params);
784 : }
785 :
786 0 : static enum bp_result bios_parser_enable_spread_spectrum_on_ppll(
787 : struct dc_bios *dcb,
788 : struct bp_spread_spectrum_parameters *bp_params,
789 : bool enable)
790 : {
791 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
792 :
793 0 : if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
794 : return BP_RESULT_FAILURE;
795 :
796 0 : return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
797 : bp, bp_params, enable);
798 :
799 : }
800 :
801 0 : static enum bp_result bios_parser_program_crtc_timing(
802 : struct dc_bios *dcb,
803 : struct bp_hw_crtc_timing_parameters *bp_params)
804 : {
805 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
806 :
807 0 : if (!bp->cmd_tbl.set_crtc_timing)
808 : return BP_RESULT_FAILURE;
809 :
810 0 : return bp->cmd_tbl.set_crtc_timing(bp, bp_params);
811 : }
812 :
813 0 : static enum bp_result bios_parser_program_display_engine_pll(
814 : struct dc_bios *dcb,
815 : struct bp_pixel_clock_parameters *bp_params)
816 : {
817 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
818 :
819 0 : if (!bp->cmd_tbl.program_clock)
820 : return BP_RESULT_FAILURE;
821 :
822 0 : return bp->cmd_tbl.program_clock(bp, bp_params);
823 :
824 : }
825 :
826 :
827 0 : static enum bp_result bios_parser_enable_crtc(
828 : struct dc_bios *dcb,
829 : enum controller_id id,
830 : bool enable)
831 : {
832 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
833 :
834 0 : if (!bp->cmd_tbl.enable_crtc)
835 : return BP_RESULT_FAILURE;
836 :
837 0 : return bp->cmd_tbl.enable_crtc(bp, id, enable);
838 : }
839 :
840 0 : static enum bp_result bios_parser_enable_disp_power_gating(
841 : struct dc_bios *dcb,
842 : enum controller_id controller_id,
843 : enum bp_pipe_control_action action)
844 : {
845 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
846 :
847 0 : if (!bp->cmd_tbl.enable_disp_power_gating)
848 : return BP_RESULT_FAILURE;
849 :
850 0 : return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id,
851 : action);
852 : }
853 :
854 0 : static bool bios_parser_is_device_id_supported(
855 : struct dc_bios *dcb,
856 : struct device_id id)
857 : {
858 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
859 :
860 0 : uint32_t mask = get_support_mask_for_device_id(id);
861 :
862 0 : return (le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport) & mask) != 0;
863 : }
864 :
865 0 : static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
866 : ATOM_OBJECT *object)
867 : {
868 : ATOM_COMMON_RECORD_HEADER *header;
869 : uint32_t offset;
870 :
871 0 : if (!object) {
872 0 : BREAK_TO_DEBUGGER(); /* Invalid object */
873 0 : return NULL;
874 : }
875 :
876 0 : offset = le16_to_cpu(object->usRecordOffset)
877 0 : + bp->object_info_tbl_offset;
878 :
879 : for (;;) {
880 0 : header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
881 :
882 0 : if (!header)
883 : return NULL;
884 :
885 0 : if (LAST_RECORD_TYPE == header->ucRecordType ||
886 0 : !header->ucRecordSize)
887 : break;
888 :
889 0 : if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
890 0 : && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
891 : return (ATOM_HPD_INT_RECORD *) header;
892 :
893 0 : offset += header->ucRecordSize;
894 : }
895 :
896 : return NULL;
897 : }
898 :
899 : static enum bp_result get_ss_info_from_ss_info_table(
900 : struct bios_parser *bp,
901 : uint32_t id,
902 : struct spread_spectrum_info *ss_info);
903 : static enum bp_result get_ss_info_from_tbl(
904 : struct bios_parser *bp,
905 : uint32_t id,
906 : struct spread_spectrum_info *ss_info);
907 : /**
908 : * bios_parser_get_spread_spectrum_info
909 : * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or
910 : * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info
911 : * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ver 3.1,
912 : * there is only one entry for each signal /ss id. However, there is
913 : * no planning of supporting multiple spread Sprectum entry for EverGreen
914 : * @dcb: pointer to the DC BIOS
915 : * @signal: ASSignalType to be converted to info index
916 : * @index: number of entries that match the converted info index
917 : * @ss_info: sprectrum information structure,
918 : * return: Bios parser result code
919 : */
920 0 : static enum bp_result bios_parser_get_spread_spectrum_info(
921 : struct dc_bios *dcb,
922 : enum as_signal_type signal,
923 : uint32_t index,
924 : struct spread_spectrum_info *ss_info)
925 : {
926 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
927 0 : enum bp_result result = BP_RESULT_UNSUPPORTED;
928 0 : uint32_t clk_id_ss = 0;
929 : ATOM_COMMON_TABLE_HEADER *header;
930 : struct atom_data_revision tbl_revision;
931 :
932 0 : if (!ss_info) /* check for bad input */
933 : return BP_RESULT_BADINPUT;
934 : /* signal translation */
935 0 : clk_id_ss = signal_to_ss_id(signal);
936 :
937 0 : if (!DATA_TABLES(ASIC_InternalSS_Info))
938 0 : if (!index)
939 0 : return get_ss_info_from_ss_info_table(bp, clk_id_ss,
940 : ss_info);
941 :
942 0 : header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
943 : DATA_TABLES(ASIC_InternalSS_Info));
944 0 : get_atom_data_table_revision(header, &tbl_revision);
945 :
946 0 : switch (tbl_revision.major) {
947 : case 2:
948 0 : switch (tbl_revision.minor) {
949 : case 1:
950 : /* there can not be more then one entry for Internal
951 : * SS Info table version 2.1 */
952 0 : if (!index)
953 0 : return get_ss_info_from_tbl(bp, clk_id_ss,
954 : ss_info);
955 : break;
956 : default:
957 : break;
958 : }
959 : break;
960 :
961 : case 3:
962 0 : switch (tbl_revision.minor) {
963 : case 1:
964 0 : return get_ss_info_v3_1(bp, clk_id_ss, index, ss_info);
965 : default:
966 : break;
967 : }
968 : break;
969 : default:
970 : break;
971 : }
972 : /* there can not be more then one entry for SS Info table */
973 : return result;
974 : }
975 :
976 : static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
977 : struct bios_parser *bp,
978 : uint32_t id,
979 : struct spread_spectrum_info *info);
980 :
981 : /**
982 : * get_ss_info_from_tbl
983 : * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
984 : * SS_Info table from the VBIOS
985 : * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
986 : * SS_Info.
987 : *
988 : * @bp: pointer to the BIOS parser
989 : * @id: spread sprectrum info index
990 : * @ss_info: sprectrum information structure,
991 : * return: BIOS parser result code
992 : */
993 0 : static enum bp_result get_ss_info_from_tbl(
994 : struct bios_parser *bp,
995 : uint32_t id,
996 : struct spread_spectrum_info *ss_info)
997 : {
998 0 : if (!ss_info) /* check for bad input, if ss_info is not NULL */
999 : return BP_RESULT_BADINPUT;
1000 : /* for SS_Info table only support DP and LVDS */
1001 0 : if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1002 0 : return get_ss_info_from_ss_info_table(bp, id, ss_info);
1003 : else
1004 0 : return get_ss_info_from_internal_ss_info_tbl_V2_1(bp, id,
1005 : ss_info);
1006 : }
1007 :
1008 : /**
1009 : * get_ss_info_from_internal_ss_info_tbl_V2_1
1010 : * Get spread sprectrum information from the ASIC_InternalSS_Info table Ver 2.1
1011 : * from the VBIOS
1012 : * There will not be multiple entry for Ver 2.1
1013 : *
1014 : * @bp: pointer to the Bios parser
1015 : * @id: spread sprectrum info index
1016 : * @info: sprectrum information structure,
1017 : * return: Bios parser result code
1018 : */
1019 0 : static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1020 : struct bios_parser *bp,
1021 : uint32_t id,
1022 : struct spread_spectrum_info *info)
1023 : {
1024 0 : enum bp_result result = BP_RESULT_UNSUPPORTED;
1025 : ATOM_ASIC_INTERNAL_SS_INFO_V2 *header;
1026 : ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1027 : uint32_t tbl_size, i;
1028 :
1029 0 : if (!DATA_TABLES(ASIC_InternalSS_Info))
1030 : return result;
1031 :
1032 0 : header = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
1033 : DATA_TABLES(ASIC_InternalSS_Info));
1034 :
1035 0 : memset(info, 0, sizeof(struct spread_spectrum_info));
1036 :
1037 0 : tbl_size = (le16_to_cpu(header->sHeader.usStructureSize)
1038 0 : - sizeof(ATOM_COMMON_TABLE_HEADER))
1039 0 : / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1040 :
1041 0 : tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1042 : &(header->asSpreadSpectrum[0]);
1043 0 : for (i = 0; i < tbl_size; i++) {
1044 0 : result = BP_RESULT_NORECORD;
1045 :
1046 0 : if (tbl[i].ucClockIndication != (uint8_t)id)
1047 0 : continue;
1048 :
1049 0 : if (ATOM_EXTERNAL_SS_MASK
1050 0 : & tbl[i].ucSpreadSpectrumMode) {
1051 0 : info->type.EXTERNAL = true;
1052 : }
1053 0 : if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
1054 0 : & tbl[i].ucSpreadSpectrumMode) {
1055 0 : info->type.CENTER_MODE = true;
1056 : }
1057 0 : info->type.STEP_AND_DELAY_INFO = false;
1058 : /* convert [10KHz] into [KHz] */
1059 0 : info->target_clock_range =
1060 0 : le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
1061 0 : info->spread_spectrum_percentage =
1062 0 : (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
1063 0 : info->spread_spectrum_range =
1064 0 : (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
1065 0 : result = BP_RESULT_OK;
1066 0 : break;
1067 : }
1068 :
1069 : return result;
1070 :
1071 : }
1072 :
1073 : /**
1074 : * get_ss_info_from_ss_info_table
1075 : * Get spread sprectrum information from the SS_Info table from the VBIOS
1076 : * if the pointer to info is NULL, indicate the caller what to know the number
1077 : * of entries that matches the id
1078 : * for, the SS_Info table, there should not be more than 1 entry match.
1079 : *
1080 : * @bp: pointer to the Bios parser
1081 : * @id: spread sprectrum id
1082 : * @ss_info: sprectrum information structure,
1083 : * return: Bios parser result code
1084 : */
1085 0 : static enum bp_result get_ss_info_from_ss_info_table(
1086 : struct bios_parser *bp,
1087 : uint32_t id,
1088 : struct spread_spectrum_info *ss_info)
1089 : {
1090 0 : enum bp_result result = BP_RESULT_UNSUPPORTED;
1091 : ATOM_SPREAD_SPECTRUM_INFO *tbl;
1092 : ATOM_COMMON_TABLE_HEADER *header;
1093 : uint32_t table_size;
1094 : uint32_t i;
1095 0 : uint32_t id_local = SS_ID_UNKNOWN;
1096 : struct atom_data_revision revision;
1097 :
1098 : /* exist of the SS_Info table */
1099 : /* check for bad input, pSSinfo can not be NULL */
1100 0 : if (!DATA_TABLES(SS_Info) || !ss_info)
1101 : return result;
1102 :
1103 0 : header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(SS_Info));
1104 0 : get_atom_data_table_revision(header, &revision);
1105 :
1106 0 : tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info));
1107 :
1108 0 : if (1 != revision.major || 2 > revision.minor)
1109 : return result;
1110 :
1111 : /* have to convert from Internal_SS format to SS_Info format */
1112 0 : switch (id) {
1113 : case ASIC_INTERNAL_SS_ON_DP:
1114 0 : id_local = SS_ID_DP1;
1115 0 : break;
1116 : case ASIC_INTERNAL_SS_ON_LVDS:
1117 : {
1118 : struct embedded_panel_info panel_info;
1119 :
1120 0 : if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
1121 : == BP_RESULT_OK)
1122 0 : id_local = panel_info.ss_id;
1123 : break;
1124 : }
1125 : default:
1126 : break;
1127 : }
1128 :
1129 0 : if (id_local == SS_ID_UNKNOWN)
1130 : return result;
1131 :
1132 0 : table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1133 0 : sizeof(ATOM_COMMON_TABLE_HEADER)) /
1134 : sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1135 :
1136 0 : for (i = 0; i < table_size; i++) {
1137 0 : if (id_local != (uint32_t)tbl->asSS_Info[i].ucSS_Id)
1138 0 : continue;
1139 :
1140 0 : memset(ss_info, 0, sizeof(struct spread_spectrum_info));
1141 :
1142 0 : if (ATOM_EXTERNAL_SS_MASK &
1143 0 : tbl->asSS_Info[i].ucSpreadSpectrumType)
1144 0 : ss_info->type.EXTERNAL = true;
1145 :
1146 0 : if (ATOM_SS_CENTRE_SPREAD_MODE_MASK &
1147 0 : tbl->asSS_Info[i].ucSpreadSpectrumType)
1148 0 : ss_info->type.CENTER_MODE = true;
1149 :
1150 0 : ss_info->type.STEP_AND_DELAY_INFO = true;
1151 0 : ss_info->spread_spectrum_percentage =
1152 0 : (uint32_t)le16_to_cpu(tbl->asSS_Info[i].usSpreadSpectrumPercentage);
1153 0 : ss_info->step_and_delay_info.step = tbl->asSS_Info[i].ucSS_Step;
1154 0 : ss_info->step_and_delay_info.delay =
1155 0 : tbl->asSS_Info[i].ucSS_Delay;
1156 0 : ss_info->step_and_delay_info.recommended_ref_div =
1157 0 : tbl->asSS_Info[i].ucRecommendedRef_Div;
1158 0 : ss_info->spread_spectrum_range =
1159 0 : (uint32_t)tbl->asSS_Info[i].ucSS_Range * 10000;
1160 :
1161 : /* there will be only one entry for each display type in SS_info
1162 : * table */
1163 0 : result = BP_RESULT_OK;
1164 0 : break;
1165 : }
1166 :
1167 : return result;
1168 : }
1169 : static enum bp_result get_embedded_panel_info_v1_2(
1170 : struct bios_parser *bp,
1171 : struct embedded_panel_info *info);
1172 : static enum bp_result get_embedded_panel_info_v1_3(
1173 : struct bios_parser *bp,
1174 : struct embedded_panel_info *info);
1175 :
1176 0 : static enum bp_result bios_parser_get_embedded_panel_info(
1177 : struct dc_bios *dcb,
1178 : struct embedded_panel_info *info)
1179 : {
1180 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
1181 : ATOM_COMMON_TABLE_HEADER *hdr;
1182 :
1183 0 : if (!DATA_TABLES(LCD_Info))
1184 : return BP_RESULT_FAILURE;
1185 :
1186 0 : hdr = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(LCD_Info));
1187 :
1188 0 : if (!hdr)
1189 : return BP_RESULT_BADBIOSTABLE;
1190 :
1191 0 : switch (hdr->ucTableFormatRevision) {
1192 : case 1:
1193 0 : switch (hdr->ucTableContentRevision) {
1194 : case 0:
1195 : case 1:
1196 : case 2:
1197 0 : return get_embedded_panel_info_v1_2(bp, info);
1198 : case 3:
1199 0 : return get_embedded_panel_info_v1_3(bp, info);
1200 : default:
1201 : break;
1202 : }
1203 : break;
1204 : default:
1205 : break;
1206 : }
1207 :
1208 : return BP_RESULT_FAILURE;
1209 : }
1210 :
1211 0 : static enum bp_result get_embedded_panel_info_v1_2(
1212 : struct bios_parser *bp,
1213 : struct embedded_panel_info *info)
1214 : {
1215 : ATOM_LVDS_INFO_V12 *lvds;
1216 :
1217 0 : if (!info)
1218 : return BP_RESULT_BADINPUT;
1219 :
1220 0 : if (!DATA_TABLES(LVDS_Info))
1221 : return BP_RESULT_UNSUPPORTED;
1222 :
1223 0 : lvds =
1224 0 : GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
1225 :
1226 0 : if (!lvds)
1227 : return BP_RESULT_BADBIOSTABLE;
1228 :
1229 0 : if (1 != lvds->sHeader.ucTableFormatRevision
1230 0 : || 2 > lvds->sHeader.ucTableContentRevision)
1231 : return BP_RESULT_UNSUPPORTED;
1232 :
1233 0 : memset(info, 0, sizeof(struct embedded_panel_info));
1234 :
1235 : /* We need to convert from 10KHz units into KHz units*/
1236 0 : info->lcd_timing.pixel_clk =
1237 0 : le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1238 : /* usHActive does not include borders, according to VBIOS team*/
1239 0 : info->lcd_timing.horizontal_addressable =
1240 0 : le16_to_cpu(lvds->sLCDTiming.usHActive);
1241 : /* usHBlanking_Time includes borders, so we should really be subtracting
1242 : * borders duing this translation, but LVDS generally*/
1243 : /* doesn't have borders, so we should be okay leaving this as is for
1244 : * now. May need to revisit if we ever have LVDS with borders*/
1245 0 : info->lcd_timing.horizontal_blanking_time =
1246 0 : le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1247 : /* usVActive does not include borders, according to VBIOS team*/
1248 0 : info->lcd_timing.vertical_addressable =
1249 0 : le16_to_cpu(lvds->sLCDTiming.usVActive);
1250 : /* usVBlanking_Time includes borders, so we should really be subtracting
1251 : * borders duing this translation, but LVDS generally*/
1252 : /* doesn't have borders, so we should be okay leaving this as is for
1253 : * now. May need to revisit if we ever have LVDS with borders*/
1254 0 : info->lcd_timing.vertical_blanking_time =
1255 0 : le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1256 0 : info->lcd_timing.horizontal_sync_offset =
1257 0 : le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1258 0 : info->lcd_timing.horizontal_sync_width =
1259 0 : le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1260 0 : info->lcd_timing.vertical_sync_offset =
1261 0 : le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1262 0 : info->lcd_timing.vertical_sync_width =
1263 0 : le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1264 0 : info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1265 0 : info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1266 0 : info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1267 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1268 0 : info->lcd_timing.misc_info.H_SYNC_POLARITY =
1269 0 : ~(uint32_t)
1270 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1271 0 : info->lcd_timing.misc_info.V_SYNC_POLARITY =
1272 0 : ~(uint32_t)
1273 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1274 0 : info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1275 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1276 0 : info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1277 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1278 0 : info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1279 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1280 0 : info->lcd_timing.misc_info.COMPOSITE_SYNC =
1281 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1282 0 : info->lcd_timing.misc_info.INTERLACE =
1283 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1284 0 : info->lcd_timing.misc_info.DOUBLE_CLOCK =
1285 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1286 0 : info->ss_id = lvds->ucSS_Id;
1287 :
1288 : {
1289 0 : uint8_t rr = le16_to_cpu(lvds->usSupportedRefreshRate);
1290 : /* Get minimum supported refresh rate*/
1291 0 : if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1292 0 : info->supported_rr.REFRESH_RATE_30HZ = 1;
1293 0 : else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1294 0 : info->supported_rr.REFRESH_RATE_40HZ = 1;
1295 0 : else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1296 0 : info->supported_rr.REFRESH_RATE_48HZ = 1;
1297 0 : else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1298 0 : info->supported_rr.REFRESH_RATE_50HZ = 1;
1299 0 : else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1300 0 : info->supported_rr.REFRESH_RATE_60HZ = 1;
1301 : }
1302 :
1303 : /*Drr panel support can be reported by VBIOS*/
1304 0 : if (LCDPANEL_CAP_DRR_SUPPORTED
1305 0 : & lvds->ucLCDPanel_SpecialHandlingCap)
1306 0 : info->drr_enabled = 1;
1307 :
1308 0 : if (ATOM_PANEL_MISC_DUAL & lvds->ucLVDS_Misc)
1309 0 : info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1310 :
1311 0 : if (ATOM_PANEL_MISC_888RGB & lvds->ucLVDS_Misc)
1312 0 : info->lcd_timing.misc_info.RGB888 = true;
1313 :
1314 0 : info->lcd_timing.misc_info.GREY_LEVEL =
1315 : (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL &
1316 0 : lvds->ucLVDS_Misc) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT;
1317 :
1318 0 : if (ATOM_PANEL_MISC_SPATIAL & lvds->ucLVDS_Misc)
1319 0 : info->lcd_timing.misc_info.SPATIAL = true;
1320 :
1321 0 : if (ATOM_PANEL_MISC_TEMPORAL & lvds->ucLVDS_Misc)
1322 0 : info->lcd_timing.misc_info.TEMPORAL = true;
1323 :
1324 0 : if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
1325 0 : info->lcd_timing.misc_info.API_ENABLED = true;
1326 :
1327 : return BP_RESULT_OK;
1328 : }
1329 :
1330 0 : static enum bp_result get_embedded_panel_info_v1_3(
1331 : struct bios_parser *bp,
1332 : struct embedded_panel_info *info)
1333 : {
1334 : ATOM_LCD_INFO_V13 *lvds;
1335 :
1336 0 : if (!info)
1337 : return BP_RESULT_BADINPUT;
1338 :
1339 0 : if (!DATA_TABLES(LCD_Info))
1340 : return BP_RESULT_UNSUPPORTED;
1341 :
1342 0 : lvds = GET_IMAGE(ATOM_LCD_INFO_V13, DATA_TABLES(LCD_Info));
1343 :
1344 0 : if (!lvds)
1345 : return BP_RESULT_BADBIOSTABLE;
1346 :
1347 0 : if (!((1 == lvds->sHeader.ucTableFormatRevision)
1348 0 : && (3 <= lvds->sHeader.ucTableContentRevision)))
1349 : return BP_RESULT_UNSUPPORTED;
1350 :
1351 0 : memset(info, 0, sizeof(struct embedded_panel_info));
1352 :
1353 : /* We need to convert from 10KHz units into KHz units */
1354 0 : info->lcd_timing.pixel_clk =
1355 0 : le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1356 : /* usHActive does not include borders, according to VBIOS team */
1357 0 : info->lcd_timing.horizontal_addressable =
1358 0 : le16_to_cpu(lvds->sLCDTiming.usHActive);
1359 : /* usHBlanking_Time includes borders, so we should really be subtracting
1360 : * borders duing this translation, but LVDS generally*/
1361 : /* doesn't have borders, so we should be okay leaving this as is for
1362 : * now. May need to revisit if we ever have LVDS with borders*/
1363 0 : info->lcd_timing.horizontal_blanking_time =
1364 0 : le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1365 : /* usVActive does not include borders, according to VBIOS team*/
1366 0 : info->lcd_timing.vertical_addressable =
1367 0 : le16_to_cpu(lvds->sLCDTiming.usVActive);
1368 : /* usVBlanking_Time includes borders, so we should really be subtracting
1369 : * borders duing this translation, but LVDS generally*/
1370 : /* doesn't have borders, so we should be okay leaving this as is for
1371 : * now. May need to revisit if we ever have LVDS with borders*/
1372 0 : info->lcd_timing.vertical_blanking_time =
1373 0 : le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1374 0 : info->lcd_timing.horizontal_sync_offset =
1375 0 : le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1376 0 : info->lcd_timing.horizontal_sync_width =
1377 0 : le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1378 0 : info->lcd_timing.vertical_sync_offset =
1379 0 : le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1380 0 : info->lcd_timing.vertical_sync_width =
1381 0 : le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1382 0 : info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1383 0 : info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1384 0 : info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1385 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1386 0 : info->lcd_timing.misc_info.H_SYNC_POLARITY =
1387 0 : ~(uint32_t)
1388 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1389 0 : info->lcd_timing.misc_info.V_SYNC_POLARITY =
1390 0 : ~(uint32_t)
1391 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1392 0 : info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1393 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1394 0 : info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1395 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1396 0 : info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1397 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1398 0 : info->lcd_timing.misc_info.COMPOSITE_SYNC =
1399 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1400 0 : info->lcd_timing.misc_info.INTERLACE =
1401 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1402 0 : info->lcd_timing.misc_info.DOUBLE_CLOCK =
1403 0 : lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1404 0 : info->ss_id = lvds->ucSS_Id;
1405 :
1406 : /* Drr panel support can be reported by VBIOS*/
1407 0 : if (LCDPANEL_CAP_V13_DRR_SUPPORTED
1408 0 : & lvds->ucLCDPanel_SpecialHandlingCap)
1409 0 : info->drr_enabled = 1;
1410 :
1411 : /* Get supported refresh rate*/
1412 0 : if (info->drr_enabled == 1) {
1413 0 : uint8_t min_rr =
1414 : lvds->sRefreshRateSupport.ucMinRefreshRateForDRR;
1415 0 : uint8_t rr = lvds->sRefreshRateSupport.ucSupportedRefreshRate;
1416 :
1417 0 : if (min_rr != 0) {
1418 0 : if (SUPPORTED_LCD_REFRESHRATE_30Hz & min_rr)
1419 0 : info->supported_rr.REFRESH_RATE_30HZ = 1;
1420 0 : else if (SUPPORTED_LCD_REFRESHRATE_40Hz & min_rr)
1421 0 : info->supported_rr.REFRESH_RATE_40HZ = 1;
1422 0 : else if (SUPPORTED_LCD_REFRESHRATE_48Hz & min_rr)
1423 0 : info->supported_rr.REFRESH_RATE_48HZ = 1;
1424 0 : else if (SUPPORTED_LCD_REFRESHRATE_50Hz & min_rr)
1425 0 : info->supported_rr.REFRESH_RATE_50HZ = 1;
1426 0 : else if (SUPPORTED_LCD_REFRESHRATE_60Hz & min_rr)
1427 0 : info->supported_rr.REFRESH_RATE_60HZ = 1;
1428 : } else {
1429 0 : if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1430 0 : info->supported_rr.REFRESH_RATE_30HZ = 1;
1431 0 : else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1432 0 : info->supported_rr.REFRESH_RATE_40HZ = 1;
1433 0 : else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1434 0 : info->supported_rr.REFRESH_RATE_48HZ = 1;
1435 0 : else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1436 0 : info->supported_rr.REFRESH_RATE_50HZ = 1;
1437 0 : else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1438 0 : info->supported_rr.REFRESH_RATE_60HZ = 1;
1439 : }
1440 : }
1441 :
1442 0 : if (ATOM_PANEL_MISC_V13_DUAL & lvds->ucLCD_Misc)
1443 0 : info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1444 :
1445 0 : if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR & lvds->ucLCD_Misc)
1446 0 : info->lcd_timing.misc_info.RGB888 = true;
1447 :
1448 0 : info->lcd_timing.misc_info.GREY_LEVEL =
1449 : (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
1450 0 : lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
1451 :
1452 0 : return BP_RESULT_OK;
1453 : }
1454 :
1455 : /**
1456 : * bios_parser_get_encoder_cap_info - get encoder capability
1457 : * information of input object id
1458 : *
1459 : * @dcb: pointer to the DC BIOS
1460 : * @object_id: object id
1461 : * @info: encoder cap information structure
1462 : *
1463 : * return: Bios parser result code
1464 : */
1465 0 : static enum bp_result bios_parser_get_encoder_cap_info(
1466 : struct dc_bios *dcb,
1467 : struct graphics_object_id object_id,
1468 : struct bp_encoder_cap_info *info)
1469 : {
1470 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
1471 : ATOM_OBJECT *object;
1472 0 : ATOM_ENCODER_CAP_RECORD_V2 *record = NULL;
1473 :
1474 0 : if (!info)
1475 : return BP_RESULT_BADINPUT;
1476 :
1477 0 : object = get_bios_object(bp, object_id);
1478 :
1479 0 : if (!object)
1480 : return BP_RESULT_BADINPUT;
1481 :
1482 0 : record = get_encoder_cap_record(bp, object);
1483 0 : if (!record)
1484 : return BP_RESULT_NORECORD;
1485 :
1486 0 : info->DP_HBR2_EN = record->usHBR2En;
1487 0 : info->DP_HBR3_EN = record->usHBR3En;
1488 0 : info->HDMI_6GB_EN = record->usHDMI6GEn;
1489 0 : return BP_RESULT_OK;
1490 : }
1491 :
1492 : /**
1493 : * get_encoder_cap_record - Get encoder cap record for the object
1494 : *
1495 : * @bp: pointer to the BIOS parser
1496 : * @object: ATOM object
1497 : * return: atom encoder cap record
1498 : * note: search all records to find the ATOM_ENCODER_CAP_RECORD_V2 record
1499 : */
1500 0 : static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
1501 : struct bios_parser *bp,
1502 : ATOM_OBJECT *object)
1503 : {
1504 : ATOM_COMMON_RECORD_HEADER *header;
1505 : uint32_t offset;
1506 :
1507 0 : if (!object) {
1508 0 : BREAK_TO_DEBUGGER(); /* Invalid object */
1509 0 : return NULL;
1510 : }
1511 :
1512 0 : offset = le16_to_cpu(object->usRecordOffset)
1513 0 : + bp->object_info_tbl_offset;
1514 :
1515 : for (;;) {
1516 0 : header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1517 :
1518 0 : if (!header)
1519 : return NULL;
1520 :
1521 0 : offset += header->ucRecordSize;
1522 :
1523 0 : if (LAST_RECORD_TYPE == header->ucRecordType ||
1524 : !header->ucRecordSize)
1525 : break;
1526 :
1527 0 : if (ATOM_ENCODER_CAP_RECORD_TYPE != header->ucRecordType)
1528 0 : continue;
1529 :
1530 0 : if (sizeof(ATOM_ENCODER_CAP_RECORD_V2) <= header->ucRecordSize)
1531 : return (ATOM_ENCODER_CAP_RECORD_V2 *)header;
1532 : }
1533 :
1534 : return NULL;
1535 : }
1536 :
1537 : static uint32_t get_ss_entry_number(
1538 : struct bios_parser *bp,
1539 : uint32_t id);
1540 : static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1541 : struct bios_parser *bp,
1542 : uint32_t id);
1543 : static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1544 : struct bios_parser *bp,
1545 : uint32_t id);
1546 : static uint32_t get_ss_entry_number_from_ss_info_tbl(
1547 : struct bios_parser *bp,
1548 : uint32_t id);
1549 :
1550 : /**
1551 : * bios_parser_get_ss_entry_number
1552 : * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
1553 : * the VBIOS that match the SSid (to be converted from signal)
1554 : *
1555 : * @dcb: pointer to the DC BIOS
1556 : * @signal: ASSignalType to be converted to SSid
1557 : * return: number of SS Entry that match the signal
1558 : */
1559 0 : static uint32_t bios_parser_get_ss_entry_number(
1560 : struct dc_bios *dcb,
1561 : enum as_signal_type signal)
1562 : {
1563 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
1564 0 : uint32_t ss_id = 0;
1565 : ATOM_COMMON_TABLE_HEADER *header;
1566 : struct atom_data_revision revision;
1567 :
1568 0 : ss_id = signal_to_ss_id(signal);
1569 :
1570 0 : if (!DATA_TABLES(ASIC_InternalSS_Info))
1571 0 : return get_ss_entry_number_from_ss_info_tbl(bp, ss_id);
1572 :
1573 0 : header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1574 : DATA_TABLES(ASIC_InternalSS_Info));
1575 0 : get_atom_data_table_revision(header, &revision);
1576 :
1577 0 : switch (revision.major) {
1578 : case 2:
1579 0 : switch (revision.minor) {
1580 : case 1:
1581 0 : return get_ss_entry_number(bp, ss_id);
1582 : default:
1583 : break;
1584 : }
1585 : break;
1586 : case 3:
1587 0 : switch (revision.minor) {
1588 : case 1:
1589 : return
1590 0 : get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1591 : bp, ss_id);
1592 : default:
1593 : break;
1594 : }
1595 : break;
1596 : default:
1597 : break;
1598 : }
1599 :
1600 : return 0;
1601 : }
1602 :
1603 : /**
1604 : * get_ss_entry_number_from_ss_info_tbl
1605 : * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
1606 : *
1607 : * @bp: pointer to the BIOS parser
1608 : * @id: spread spectrum id
1609 : * return: number of SS Entry that match the id
1610 : * note: There can only be one entry for each id for SS_Info Table
1611 : */
1612 0 : static uint32_t get_ss_entry_number_from_ss_info_tbl(
1613 : struct bios_parser *bp,
1614 : uint32_t id)
1615 : {
1616 : ATOM_SPREAD_SPECTRUM_INFO *tbl;
1617 : ATOM_COMMON_TABLE_HEADER *header;
1618 : uint32_t table_size;
1619 : uint32_t i;
1620 0 : uint32_t number = 0;
1621 0 : uint32_t id_local = SS_ID_UNKNOWN;
1622 : struct atom_data_revision revision;
1623 :
1624 : /* SS_Info table exist */
1625 0 : if (!DATA_TABLES(SS_Info))
1626 : return number;
1627 :
1628 0 : header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1629 : DATA_TABLES(SS_Info));
1630 0 : get_atom_data_table_revision(header, &revision);
1631 :
1632 0 : tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO,
1633 : DATA_TABLES(SS_Info));
1634 :
1635 0 : if (1 != revision.major || 2 > revision.minor)
1636 : return number;
1637 :
1638 : /* have to convert from Internal_SS format to SS_Info format */
1639 0 : switch (id) {
1640 : case ASIC_INTERNAL_SS_ON_DP:
1641 0 : id_local = SS_ID_DP1;
1642 0 : break;
1643 : case ASIC_INTERNAL_SS_ON_LVDS: {
1644 : struct embedded_panel_info panel_info;
1645 :
1646 0 : if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
1647 : == BP_RESULT_OK)
1648 0 : id_local = panel_info.ss_id;
1649 : break;
1650 : }
1651 : default:
1652 : break;
1653 : }
1654 :
1655 0 : if (id_local == SS_ID_UNKNOWN)
1656 : return number;
1657 :
1658 0 : table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1659 0 : sizeof(ATOM_COMMON_TABLE_HEADER)) /
1660 : sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1661 :
1662 0 : for (i = 0; i < table_size; i++)
1663 0 : if (id_local == (uint32_t)tbl->asSS_Info[i].ucSS_Id) {
1664 : number = 1;
1665 : break;
1666 : }
1667 :
1668 : return number;
1669 : }
1670 :
1671 : /**
1672 : * get_ss_entry_number
1673 : * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
1674 : * SS_Info table from the VBIOS
1675 : * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
1676 : * SS_Info.
1677 : *
1678 : * @bp: pointer to the BIOS parser
1679 : * @id: spread sprectrum info index
1680 : * return: Bios parser result code
1681 : */
1682 0 : static uint32_t get_ss_entry_number(struct bios_parser *bp, uint32_t id)
1683 : {
1684 0 : if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1685 0 : return get_ss_entry_number_from_ss_info_tbl(bp, id);
1686 :
1687 0 : return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp, id);
1688 : }
1689 :
1690 : /**
1691 : * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
1692 : * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
1693 : * Ver 2.1 from the VBIOS
1694 : * There will not be multiple entry for Ver 2.1
1695 : *
1696 : * @bp: pointer to the BIOS parser
1697 : * @id: spread sprectrum info index
1698 : * return: number of SS Entry that match the id
1699 : */
1700 0 : static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1701 : struct bios_parser *bp,
1702 : uint32_t id)
1703 : {
1704 : ATOM_ASIC_INTERNAL_SS_INFO_V2 *header_include;
1705 : ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1706 : uint32_t size;
1707 : uint32_t i;
1708 :
1709 0 : if (!DATA_TABLES(ASIC_InternalSS_Info))
1710 : return 0;
1711 :
1712 0 : header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
1713 : DATA_TABLES(ASIC_InternalSS_Info));
1714 :
1715 0 : size = (le16_to_cpu(header_include->sHeader.usStructureSize)
1716 0 : - sizeof(ATOM_COMMON_TABLE_HEADER))
1717 0 : / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1718 :
1719 0 : tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1720 : &header_include->asSpreadSpectrum[0];
1721 0 : for (i = 0; i < size; i++)
1722 0 : if (tbl[i].ucClockIndication == (uint8_t)id)
1723 : return 1;
1724 :
1725 : return 0;
1726 : }
1727 : /**
1728 : * get_ss_entry_number_from_internal_ss_info_tbl_V3_1
1729 : * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
1730 : * the VBIOS that matches id
1731 : *
1732 : * @bp: pointer to the BIOS parser
1733 : * @id: spread sprectrum id
1734 : * return: number of SS Entry that match the id
1735 : */
1736 0 : static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1737 : struct bios_parser *bp,
1738 : uint32_t id)
1739 : {
1740 0 : uint32_t number = 0;
1741 : ATOM_ASIC_INTERNAL_SS_INFO_V3 *header_include;
1742 : ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
1743 : uint32_t size;
1744 : uint32_t i;
1745 :
1746 0 : if (!DATA_TABLES(ASIC_InternalSS_Info))
1747 : return number;
1748 :
1749 0 : header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
1750 : DATA_TABLES(ASIC_InternalSS_Info));
1751 0 : size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
1752 0 : sizeof(ATOM_COMMON_TABLE_HEADER)) /
1753 : sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
1754 :
1755 0 : tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
1756 : &header_include->asSpreadSpectrum[0];
1757 :
1758 0 : for (i = 0; i < size; i++)
1759 0 : if (tbl[i].ucClockIndication == (uint8_t)id)
1760 0 : number++;
1761 :
1762 : return number;
1763 : }
1764 :
1765 : /**
1766 : * bios_parser_get_gpio_pin_info
1767 : * Get GpioPin information of input gpio id
1768 : *
1769 : * @dcb: pointer to the DC BIOS
1770 : * @gpio_id: GPIO ID
1771 : * @info: GpioPin information structure
1772 : * return: Bios parser result code
1773 : * note:
1774 : * to get the GPIO PIN INFO, we need:
1775 : * 1. get the GPIO_ID from other object table, see GetHPDInfo()
1776 : * 2. in DATA_TABLE.GPIO_Pin_LUT, search all records, to get the registerA
1777 : * offset/mask
1778 : */
1779 0 : static enum bp_result bios_parser_get_gpio_pin_info(
1780 : struct dc_bios *dcb,
1781 : uint32_t gpio_id,
1782 : struct gpio_pin_info *info)
1783 : {
1784 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
1785 : ATOM_GPIO_PIN_LUT *header;
1786 0 : uint32_t count = 0;
1787 0 : uint32_t i = 0;
1788 :
1789 0 : if (!DATA_TABLES(GPIO_Pin_LUT))
1790 : return BP_RESULT_BADBIOSTABLE;
1791 :
1792 0 : header = GET_IMAGE(ATOM_GPIO_PIN_LUT, DATA_TABLES(GPIO_Pin_LUT));
1793 0 : if (!header)
1794 : return BP_RESULT_BADBIOSTABLE;
1795 :
1796 0 : if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_PIN_LUT)
1797 0 : > le16_to_cpu(header->sHeader.usStructureSize))
1798 : return BP_RESULT_BADBIOSTABLE;
1799 :
1800 0 : if (1 != header->sHeader.ucTableContentRevision)
1801 : return BP_RESULT_UNSUPPORTED;
1802 :
1803 0 : count = (le16_to_cpu(header->sHeader.usStructureSize)
1804 0 : - sizeof(ATOM_COMMON_TABLE_HEADER))
1805 0 : / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
1806 0 : for (i = 0; i < count; ++i) {
1807 0 : if (header->asGPIO_Pin[i].ucGPIO_ID != gpio_id)
1808 0 : continue;
1809 :
1810 0 : info->offset =
1811 0 : (uint32_t) le16_to_cpu(header->asGPIO_Pin[i].usGpioPin_AIndex);
1812 0 : info->offset_y = info->offset + 2;
1813 0 : info->offset_en = info->offset + 1;
1814 0 : info->offset_mask = info->offset - 1;
1815 :
1816 0 : info->mask = (uint32_t) (1 <<
1817 0 : header->asGPIO_Pin[i].ucGpioPinBitShift);
1818 0 : info->mask_y = info->mask + 2;
1819 0 : info->mask_en = info->mask + 1;
1820 0 : info->mask_mask = info->mask - 1;
1821 :
1822 0 : return BP_RESULT_OK;
1823 : }
1824 :
1825 : return BP_RESULT_NORECORD;
1826 : }
1827 :
1828 0 : static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
1829 : ATOM_I2C_RECORD *record,
1830 : struct graphics_object_i2c_info *info)
1831 : {
1832 : ATOM_GPIO_I2C_INFO *header;
1833 0 : uint32_t count = 0;
1834 :
1835 0 : if (!info)
1836 : return BP_RESULT_BADINPUT;
1837 :
1838 : /* get the GPIO_I2C info */
1839 0 : if (!DATA_TABLES(GPIO_I2C_Info))
1840 : return BP_RESULT_BADBIOSTABLE;
1841 :
1842 0 : header = GET_IMAGE(ATOM_GPIO_I2C_INFO, DATA_TABLES(GPIO_I2C_Info));
1843 0 : if (!header)
1844 : return BP_RESULT_BADBIOSTABLE;
1845 :
1846 0 : if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_I2C_ASSIGMENT)
1847 0 : > le16_to_cpu(header->sHeader.usStructureSize))
1848 : return BP_RESULT_BADBIOSTABLE;
1849 :
1850 0 : if (1 != header->sHeader.ucTableContentRevision)
1851 : return BP_RESULT_UNSUPPORTED;
1852 :
1853 : /* get data count */
1854 0 : count = (le16_to_cpu(header->sHeader.usStructureSize)
1855 0 : - sizeof(ATOM_COMMON_TABLE_HEADER))
1856 0 : / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
1857 0 : if (count < record->sucI2cId.bfI2C_LineMux)
1858 : return BP_RESULT_BADBIOSTABLE;
1859 :
1860 : /* get the GPIO_I2C_INFO */
1861 0 : info->i2c_hw_assist = record->sucI2cId.bfHW_Capable;
1862 0 : info->i2c_line = record->sucI2cId.bfI2C_LineMux;
1863 0 : info->i2c_engine_id = record->sucI2cId.bfHW_EngineID;
1864 0 : info->i2c_slave_address = record->ucI2CAddr;
1865 :
1866 0 : info->gpio_info.clk_mask_register_index =
1867 0 : le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkMaskRegisterIndex);
1868 0 : info->gpio_info.clk_en_register_index =
1869 0 : le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkEnRegisterIndex);
1870 0 : info->gpio_info.clk_y_register_index =
1871 0 : le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkY_RegisterIndex);
1872 0 : info->gpio_info.clk_a_register_index =
1873 0 : le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkA_RegisterIndex);
1874 0 : info->gpio_info.data_mask_register_index =
1875 0 : le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataMaskRegisterIndex);
1876 0 : info->gpio_info.data_en_register_index =
1877 0 : le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataEnRegisterIndex);
1878 0 : info->gpio_info.data_y_register_index =
1879 0 : le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataY_RegisterIndex);
1880 0 : info->gpio_info.data_a_register_index =
1881 0 : le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataA_RegisterIndex);
1882 :
1883 0 : info->gpio_info.clk_mask_shift =
1884 0 : header->asGPIO_Info[info->i2c_line].ucClkMaskShift;
1885 0 : info->gpio_info.clk_en_shift =
1886 0 : header->asGPIO_Info[info->i2c_line].ucClkEnShift;
1887 0 : info->gpio_info.clk_y_shift =
1888 0 : header->asGPIO_Info[info->i2c_line].ucClkY_Shift;
1889 0 : info->gpio_info.clk_a_shift =
1890 0 : header->asGPIO_Info[info->i2c_line].ucClkA_Shift;
1891 0 : info->gpio_info.data_mask_shift =
1892 0 : header->asGPIO_Info[info->i2c_line].ucDataMaskShift;
1893 0 : info->gpio_info.data_en_shift =
1894 0 : header->asGPIO_Info[info->i2c_line].ucDataEnShift;
1895 0 : info->gpio_info.data_y_shift =
1896 0 : header->asGPIO_Info[info->i2c_line].ucDataY_Shift;
1897 0 : info->gpio_info.data_a_shift =
1898 0 : header->asGPIO_Info[info->i2c_line].ucDataA_Shift;
1899 :
1900 0 : return BP_RESULT_OK;
1901 : }
1902 :
1903 : static bool dal_graphics_object_id_is_valid(struct graphics_object_id id)
1904 : {
1905 0 : bool rc = true;
1906 :
1907 0 : switch (id.type) {
1908 : case OBJECT_TYPE_UNKNOWN:
1909 : rc = false;
1910 : break;
1911 : case OBJECT_TYPE_GPU:
1912 : case OBJECT_TYPE_ENGINE:
1913 : /* do NOT check for id.id == 0 */
1914 0 : if (id.enum_id == ENUM_ID_UNKNOWN)
1915 0 : rc = false;
1916 : break;
1917 : default:
1918 0 : if (id.id == 0 || id.enum_id == ENUM_ID_UNKNOWN)
1919 : rc = false;
1920 : break;
1921 : }
1922 :
1923 : return rc;
1924 : }
1925 :
1926 0 : static bool dal_graphics_object_id_is_equal(
1927 : struct graphics_object_id id1,
1928 : struct graphics_object_id id2)
1929 : {
1930 0 : if (false == dal_graphics_object_id_is_valid(id1)) {
1931 0 : dm_output_to_console(
1932 : "%s: Warning: comparing invalid object 'id1'!\n", __func__);
1933 0 : return false;
1934 : }
1935 :
1936 0 : if (false == dal_graphics_object_id_is_valid(id2)) {
1937 0 : dm_output_to_console(
1938 : "%s: Warning: comparing invalid object 'id2'!\n", __func__);
1939 0 : return false;
1940 : }
1941 :
1942 0 : if (id1.id == id2.id && id1.enum_id == id2.enum_id
1943 0 : && id1.type == id2.type)
1944 : return true;
1945 :
1946 0 : return false;
1947 : }
1948 :
1949 0 : static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
1950 : struct graphics_object_id id)
1951 : {
1952 : uint32_t offset;
1953 : ATOM_OBJECT_TABLE *tbl;
1954 : uint32_t i;
1955 :
1956 0 : switch (id.type) {
1957 : case OBJECT_TYPE_ENCODER:
1958 0 : offset = le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
1959 0 : break;
1960 :
1961 : case OBJECT_TYPE_CONNECTOR:
1962 0 : offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
1963 0 : break;
1964 :
1965 : case OBJECT_TYPE_ROUTER:
1966 0 : offset = le16_to_cpu(bp->object_info_tbl.v1_1->usRouterObjectTableOffset);
1967 0 : break;
1968 :
1969 : case OBJECT_TYPE_GENERIC:
1970 0 : if (bp->object_info_tbl.revision.minor < 3)
1971 : return NULL;
1972 0 : offset = le16_to_cpu(bp->object_info_tbl.v1_3->usMiscObjectTableOffset);
1973 0 : break;
1974 :
1975 : default:
1976 : return NULL;
1977 : }
1978 :
1979 0 : offset += bp->object_info_tbl_offset;
1980 :
1981 0 : tbl = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
1982 0 : if (!tbl)
1983 : return NULL;
1984 :
1985 0 : for (i = 0; i < tbl->ucNumberOfObjects; i++)
1986 0 : if (dal_graphics_object_id_is_equal(id,
1987 : object_id_from_bios_object_id(
1988 0 : le16_to_cpu(tbl->asObjects[i].usObjectID))))
1989 0 : return &tbl->asObjects[i];
1990 :
1991 : return NULL;
1992 : }
1993 :
1994 0 : static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
1995 : uint16_t **id_list)
1996 : {
1997 : uint32_t offset;
1998 : uint8_t *number;
1999 :
2000 0 : if (!object) {
2001 0 : BREAK_TO_DEBUGGER(); /* Invalid object id */
2002 0 : return 0;
2003 : }
2004 :
2005 0 : offset = le16_to_cpu(object->usSrcDstTableOffset)
2006 0 : + bp->object_info_tbl_offset;
2007 :
2008 0 : number = GET_IMAGE(uint8_t, offset);
2009 0 : if (!number)
2010 : return 0;
2011 :
2012 0 : offset += sizeof(uint8_t);
2013 0 : *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
2014 :
2015 0 : if (!*id_list)
2016 : return 0;
2017 :
2018 0 : return *number;
2019 : }
2020 :
2021 0 : static struct device_id device_type_from_device_id(uint16_t device_id)
2022 : {
2023 :
2024 0 : struct device_id result_device_id = {0};
2025 :
2026 0 : switch (device_id) {
2027 : case ATOM_DEVICE_LCD1_SUPPORT:
2028 : result_device_id.device_type = DEVICE_TYPE_LCD;
2029 : result_device_id.enum_id = 1;
2030 : break;
2031 :
2032 : case ATOM_DEVICE_LCD2_SUPPORT:
2033 0 : result_device_id.device_type = DEVICE_TYPE_LCD;
2034 0 : result_device_id.enum_id = 2;
2035 0 : break;
2036 :
2037 : case ATOM_DEVICE_CRT1_SUPPORT:
2038 0 : result_device_id.device_type = DEVICE_TYPE_CRT;
2039 0 : result_device_id.enum_id = 1;
2040 0 : break;
2041 :
2042 : case ATOM_DEVICE_CRT2_SUPPORT:
2043 0 : result_device_id.device_type = DEVICE_TYPE_CRT;
2044 0 : result_device_id.enum_id = 2;
2045 0 : break;
2046 :
2047 : case ATOM_DEVICE_DFP1_SUPPORT:
2048 0 : result_device_id.device_type = DEVICE_TYPE_DFP;
2049 0 : result_device_id.enum_id = 1;
2050 0 : break;
2051 :
2052 : case ATOM_DEVICE_DFP2_SUPPORT:
2053 0 : result_device_id.device_type = DEVICE_TYPE_DFP;
2054 0 : result_device_id.enum_id = 2;
2055 0 : break;
2056 :
2057 : case ATOM_DEVICE_DFP3_SUPPORT:
2058 0 : result_device_id.device_type = DEVICE_TYPE_DFP;
2059 0 : result_device_id.enum_id = 3;
2060 0 : break;
2061 :
2062 : case ATOM_DEVICE_DFP4_SUPPORT:
2063 0 : result_device_id.device_type = DEVICE_TYPE_DFP;
2064 0 : result_device_id.enum_id = 4;
2065 0 : break;
2066 :
2067 : case ATOM_DEVICE_DFP5_SUPPORT:
2068 0 : result_device_id.device_type = DEVICE_TYPE_DFP;
2069 0 : result_device_id.enum_id = 5;
2070 0 : break;
2071 :
2072 : case ATOM_DEVICE_DFP6_SUPPORT:
2073 0 : result_device_id.device_type = DEVICE_TYPE_DFP;
2074 0 : result_device_id.enum_id = 6;
2075 0 : break;
2076 :
2077 : default:
2078 0 : BREAK_TO_DEBUGGER(); /* Invalid device Id */
2079 0 : result_device_id.device_type = DEVICE_TYPE_UNKNOWN;
2080 0 : result_device_id.enum_id = 0;
2081 : }
2082 0 : return result_device_id;
2083 : }
2084 :
2085 : static void get_atom_data_table_revision(
2086 : ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
2087 : struct atom_data_revision *tbl_revision)
2088 : {
2089 0 : if (!tbl_revision)
2090 : return;
2091 :
2092 : /* initialize the revision to 0 which is invalid revision */
2093 0 : tbl_revision->major = 0;
2094 0 : tbl_revision->minor = 0;
2095 :
2096 0 : if (!atom_data_tbl)
2097 : return;
2098 :
2099 0 : tbl_revision->major =
2100 0 : (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl);
2101 0 : tbl_revision->minor =
2102 0 : (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl);
2103 : }
2104 :
2105 : static uint32_t signal_to_ss_id(enum as_signal_type signal)
2106 : {
2107 0 : uint32_t clk_id_ss = 0;
2108 :
2109 : switch (signal) {
2110 : case AS_SIGNAL_TYPE_DVI:
2111 : clk_id_ss = ASIC_INTERNAL_SS_ON_TMDS;
2112 : break;
2113 : case AS_SIGNAL_TYPE_HDMI:
2114 : clk_id_ss = ASIC_INTERNAL_SS_ON_HDMI;
2115 : break;
2116 : case AS_SIGNAL_TYPE_LVDS:
2117 : clk_id_ss = ASIC_INTERNAL_SS_ON_LVDS;
2118 : break;
2119 : case AS_SIGNAL_TYPE_DISPLAY_PORT:
2120 : clk_id_ss = ASIC_INTERNAL_SS_ON_DP;
2121 : break;
2122 : case AS_SIGNAL_TYPE_GPU_PLL:
2123 : clk_id_ss = ASIC_INTERNAL_GPUPLL_SS;
2124 : break;
2125 : default:
2126 : break;
2127 : }
2128 : return clk_id_ss;
2129 : }
2130 :
2131 0 : static uint32_t get_support_mask_for_device_id(struct device_id device_id)
2132 : {
2133 0 : enum dal_device_type device_type = device_id.device_type;
2134 0 : uint32_t enum_id = device_id.enum_id;
2135 :
2136 0 : switch (device_type) {
2137 : case DEVICE_TYPE_LCD:
2138 0 : switch (enum_id) {
2139 : case 1:
2140 : return ATOM_DEVICE_LCD1_SUPPORT;
2141 : case 2:
2142 : return ATOM_DEVICE_LCD2_SUPPORT;
2143 : default:
2144 : break;
2145 : }
2146 : break;
2147 : case DEVICE_TYPE_CRT:
2148 0 : switch (enum_id) {
2149 : case 1:
2150 : return ATOM_DEVICE_CRT1_SUPPORT;
2151 : case 2:
2152 : return ATOM_DEVICE_CRT2_SUPPORT;
2153 : default:
2154 : break;
2155 : }
2156 : break;
2157 : case DEVICE_TYPE_DFP:
2158 0 : switch (enum_id) {
2159 : case 1:
2160 : return ATOM_DEVICE_DFP1_SUPPORT;
2161 : case 2:
2162 : return ATOM_DEVICE_DFP2_SUPPORT;
2163 : case 3:
2164 : return ATOM_DEVICE_DFP3_SUPPORT;
2165 : case 4:
2166 : return ATOM_DEVICE_DFP4_SUPPORT;
2167 : case 5:
2168 : return ATOM_DEVICE_DFP5_SUPPORT;
2169 : case 6:
2170 : return ATOM_DEVICE_DFP6_SUPPORT;
2171 : default:
2172 : break;
2173 : }
2174 : break;
2175 : case DEVICE_TYPE_CV:
2176 0 : switch (enum_id) {
2177 : case 1:
2178 : return ATOM_DEVICE_CV_SUPPORT;
2179 : default:
2180 : break;
2181 : }
2182 : break;
2183 : case DEVICE_TYPE_TV:
2184 0 : switch (enum_id) {
2185 : case 1:
2186 : return ATOM_DEVICE_TV1_SUPPORT;
2187 : default:
2188 : break;
2189 : }
2190 : break;
2191 : default:
2192 : break;
2193 : }
2194 :
2195 : /* Unidentified device ID, return empty support mask. */
2196 : return 0;
2197 : }
2198 :
2199 : /**
2200 : * bios_parser_set_scratch_critical_state - update critical state
2201 : * bit in VBIOS scratch register
2202 : * @dcb: pointer to the DC BIOS
2203 : * @state: set or reset state
2204 : */
2205 0 : static void bios_parser_set_scratch_critical_state(
2206 : struct dc_bios *dcb,
2207 : bool state)
2208 : {
2209 0 : bios_set_scratch_critical_state(dcb, state);
2210 0 : }
2211 :
2212 : /*
2213 : * get_integrated_info_v8
2214 : *
2215 : * @brief
2216 : * Get V8 integrated BIOS information
2217 : *
2218 : * @param
2219 : * bios_parser *bp - [in]BIOS parser handler to get master data table
2220 : * integrated_info *info - [out] store and output integrated info
2221 : *
2222 : * return:
2223 : * enum bp_result - BP_RESULT_OK if information is available,
2224 : * BP_RESULT_BADBIOSTABLE otherwise.
2225 : */
2226 0 : static enum bp_result get_integrated_info_v8(
2227 : struct bios_parser *bp,
2228 : struct integrated_info *info)
2229 : {
2230 : ATOM_INTEGRATED_SYSTEM_INFO_V1_8 *info_v8;
2231 : uint32_t i;
2232 :
2233 0 : info_v8 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8,
2234 : bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2235 :
2236 0 : if (info_v8 == NULL)
2237 : return BP_RESULT_BADBIOSTABLE;
2238 0 : info->boot_up_engine_clock = le32_to_cpu(info_v8->ulBootUpEngineClock) * 10;
2239 0 : info->dentist_vco_freq = le32_to_cpu(info_v8->ulDentistVCOFreq) * 10;
2240 0 : info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
2241 :
2242 0 : for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2243 : /* Convert [10KHz] into [KHz] */
2244 0 : info->disp_clk_voltage[i].max_supported_clk =
2245 0 : le32_to_cpu(info_v8->sDISPCLK_Voltage[i].
2246 0 : ulMaximumSupportedCLK) * 10;
2247 0 : info->disp_clk_voltage[i].voltage_index =
2248 0 : le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
2249 : }
2250 :
2251 0 : info->boot_up_req_display_vector =
2252 0 : le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
2253 0 : info->gpu_cap_info =
2254 0 : le32_to_cpu(info_v8->ulGPUCapInfo);
2255 :
2256 : /*
2257 : * system_config: Bit[0] = 0 : PCIE power gating disabled
2258 : * = 1 : PCIE power gating enabled
2259 : * Bit[1] = 0 : DDR-PLL shut down disabled
2260 : * = 1 : DDR-PLL shut down enabled
2261 : * Bit[2] = 0 : DDR-PLL power down disabled
2262 : * = 1 : DDR-PLL power down enabled
2263 : */
2264 0 : info->system_config = le32_to_cpu(info_v8->ulSystemConfig);
2265 0 : info->cpu_cap_info = le32_to_cpu(info_v8->ulCPUCapInfo);
2266 0 : info->boot_up_nb_voltage =
2267 0 : le16_to_cpu(info_v8->usBootUpNBVoltage);
2268 0 : info->ext_disp_conn_info_offset =
2269 0 : le16_to_cpu(info_v8->usExtDispConnInfoOffset);
2270 0 : info->memory_type = info_v8->ucMemoryType;
2271 0 : info->ma_channel_number = info_v8->ucUMAChannelNumber;
2272 0 : info->gmc_restore_reset_time =
2273 0 : le32_to_cpu(info_v8->ulGMCRestoreResetTime);
2274 :
2275 0 : info->minimum_n_clk =
2276 0 : le32_to_cpu(info_v8->ulNbpStateNClkFreq[0]);
2277 0 : for (i = 1; i < 4; ++i)
2278 0 : info->minimum_n_clk =
2279 : info->minimum_n_clk < le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]) ?
2280 0 : info->minimum_n_clk : le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]);
2281 :
2282 0 : info->idle_n_clk = le32_to_cpu(info_v8->ulIdleNClk);
2283 0 : info->ddr_dll_power_up_time =
2284 0 : le32_to_cpu(info_v8->ulDDR_DLL_PowerUpTime);
2285 0 : info->ddr_pll_power_up_time =
2286 0 : le32_to_cpu(info_v8->ulDDR_PLL_PowerUpTime);
2287 0 : info->pcie_clk_ss_type = le16_to_cpu(info_v8->usPCIEClkSSType);
2288 0 : info->lvds_ss_percentage =
2289 0 : le16_to_cpu(info_v8->usLvdsSSPercentage);
2290 0 : info->lvds_sspread_rate_in_10hz =
2291 0 : le16_to_cpu(info_v8->usLvdsSSpreadRateIn10Hz);
2292 0 : info->hdmi_ss_percentage =
2293 0 : le16_to_cpu(info_v8->usHDMISSPercentage);
2294 0 : info->hdmi_sspread_rate_in_10hz =
2295 0 : le16_to_cpu(info_v8->usHDMISSpreadRateIn10Hz);
2296 0 : info->dvi_ss_percentage =
2297 0 : le16_to_cpu(info_v8->usDVISSPercentage);
2298 0 : info->dvi_sspread_rate_in_10_hz =
2299 0 : le16_to_cpu(info_v8->usDVISSpreadRateIn10Hz);
2300 :
2301 0 : info->max_lvds_pclk_freq_in_single_link =
2302 0 : le16_to_cpu(info_v8->usMaxLVDSPclkFreqInSingleLink);
2303 0 : info->lvds_misc = info_v8->ucLvdsMisc;
2304 0 : info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
2305 0 : info_v8->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
2306 0 : info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
2307 0 : info_v8->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
2308 0 : info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
2309 0 : info_v8->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
2310 0 : info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
2311 0 : info_v8->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
2312 0 : info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
2313 0 : info_v8->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
2314 0 : info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
2315 0 : info_v8->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
2316 0 : info->lvds_off_to_on_delay_in_4ms =
2317 0 : info_v8->ucLVDSOffToOnDelay_in4Ms;
2318 0 : info->lvds_bit_depth_control_val =
2319 0 : le32_to_cpu(info_v8->ulLCDBitDepthControlVal);
2320 :
2321 0 : for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
2322 : /* Convert [10KHz] into [KHz] */
2323 0 : info->avail_s_clk[i].supported_s_clk =
2324 0 : le32_to_cpu(info_v8->sAvail_SCLK[i].ulSupportedSCLK) * 10;
2325 0 : info->avail_s_clk[i].voltage_index =
2326 0 : le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageIndex);
2327 0 : info->avail_s_clk[i].voltage_id =
2328 0 : le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageID);
2329 : }
2330 :
2331 0 : for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
2332 0 : info->ext_disp_conn_info.gu_id[i] =
2333 0 : info_v8->sExtDispConnInfo.ucGuid[i];
2334 : }
2335 :
2336 0 : for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
2337 0 : info->ext_disp_conn_info.path[i].device_connector_id =
2338 0 : object_id_from_bios_object_id(
2339 0 : le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceConnector));
2340 :
2341 0 : info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
2342 0 : object_id_from_bios_object_id(
2343 0 : le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
2344 :
2345 0 : info->ext_disp_conn_info.path[i].device_tag =
2346 0 : le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceTag);
2347 0 : info->ext_disp_conn_info.path[i].device_acpi_enum =
2348 0 : le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
2349 0 : info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
2350 0 : info_v8->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
2351 0 : info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
2352 0 : info_v8->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
2353 0 : info->ext_disp_conn_info.path[i].channel_mapping.raw =
2354 0 : info_v8->sExtDispConnInfo.sPath[i].ucChannelMapping;
2355 : }
2356 0 : info->ext_disp_conn_info.checksum =
2357 0 : info_v8->sExtDispConnInfo.ucChecksum;
2358 :
2359 0 : return BP_RESULT_OK;
2360 : }
2361 :
2362 : /*
2363 : * get_integrated_info_v8
2364 : *
2365 : * @brief
2366 : * Get V8 integrated BIOS information
2367 : *
2368 : * @param
2369 : * bios_parser *bp - [in]BIOS parser handler to get master data table
2370 : * integrated_info *info - [out] store and output integrated info
2371 : *
2372 : * return:
2373 : * enum bp_result - BP_RESULT_OK if information is available,
2374 : * BP_RESULT_BADBIOSTABLE otherwise.
2375 : */
2376 0 : static enum bp_result get_integrated_info_v9(
2377 : struct bios_parser *bp,
2378 : struct integrated_info *info)
2379 : {
2380 : ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info_v9;
2381 : uint32_t i;
2382 :
2383 0 : info_v9 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9,
2384 : bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2385 :
2386 0 : if (!info_v9)
2387 : return BP_RESULT_BADBIOSTABLE;
2388 :
2389 0 : info->boot_up_engine_clock = le32_to_cpu(info_v9->ulBootUpEngineClock) * 10;
2390 0 : info->dentist_vco_freq = le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
2391 0 : info->boot_up_uma_clock = le32_to_cpu(info_v9->ulBootUpUMAClock) * 10;
2392 :
2393 0 : for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2394 : /* Convert [10KHz] into [KHz] */
2395 0 : info->disp_clk_voltage[i].max_supported_clk =
2396 0 : le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
2397 0 : info->disp_clk_voltage[i].voltage_index =
2398 0 : le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
2399 : }
2400 :
2401 0 : info->boot_up_req_display_vector =
2402 0 : le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
2403 0 : info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
2404 :
2405 : /*
2406 : * system_config: Bit[0] = 0 : PCIE power gating disabled
2407 : * = 1 : PCIE power gating enabled
2408 : * Bit[1] = 0 : DDR-PLL shut down disabled
2409 : * = 1 : DDR-PLL shut down enabled
2410 : * Bit[2] = 0 : DDR-PLL power down disabled
2411 : * = 1 : DDR-PLL power down enabled
2412 : */
2413 0 : info->system_config = le32_to_cpu(info_v9->ulSystemConfig);
2414 0 : info->cpu_cap_info = le32_to_cpu(info_v9->ulCPUCapInfo);
2415 0 : info->boot_up_nb_voltage = le16_to_cpu(info_v9->usBootUpNBVoltage);
2416 0 : info->ext_disp_conn_info_offset = le16_to_cpu(info_v9->usExtDispConnInfoOffset);
2417 0 : info->memory_type = info_v9->ucMemoryType;
2418 0 : info->ma_channel_number = info_v9->ucUMAChannelNumber;
2419 0 : info->gmc_restore_reset_time = le32_to_cpu(info_v9->ulGMCRestoreResetTime);
2420 :
2421 0 : info->minimum_n_clk = le32_to_cpu(info_v9->ulNbpStateNClkFreq[0]);
2422 0 : for (i = 1; i < 4; ++i)
2423 0 : info->minimum_n_clk =
2424 : info->minimum_n_clk < le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]) ?
2425 0 : info->minimum_n_clk : le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]);
2426 :
2427 0 : info->idle_n_clk = le32_to_cpu(info_v9->ulIdleNClk);
2428 0 : info->ddr_dll_power_up_time = le32_to_cpu(info_v9->ulDDR_DLL_PowerUpTime);
2429 0 : info->ddr_pll_power_up_time = le32_to_cpu(info_v9->ulDDR_PLL_PowerUpTime);
2430 0 : info->pcie_clk_ss_type = le16_to_cpu(info_v9->usPCIEClkSSType);
2431 0 : info->lvds_ss_percentage = le16_to_cpu(info_v9->usLvdsSSPercentage);
2432 0 : info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v9->usLvdsSSpreadRateIn10Hz);
2433 0 : info->hdmi_ss_percentage = le16_to_cpu(info_v9->usHDMISSPercentage);
2434 0 : info->hdmi_sspread_rate_in_10hz = le16_to_cpu(info_v9->usHDMISSpreadRateIn10Hz);
2435 0 : info->dvi_ss_percentage = le16_to_cpu(info_v9->usDVISSPercentage);
2436 0 : info->dvi_sspread_rate_in_10_hz = le16_to_cpu(info_v9->usDVISSpreadRateIn10Hz);
2437 :
2438 0 : info->max_lvds_pclk_freq_in_single_link =
2439 0 : le16_to_cpu(info_v9->usMaxLVDSPclkFreqInSingleLink);
2440 0 : info->lvds_misc = info_v9->ucLvdsMisc;
2441 0 : info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
2442 0 : info_v9->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
2443 0 : info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
2444 0 : info_v9->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
2445 0 : info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
2446 0 : info_v9->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
2447 0 : info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
2448 0 : info_v9->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
2449 0 : info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
2450 0 : info_v9->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
2451 0 : info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
2452 0 : info_v9->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
2453 0 : info->lvds_off_to_on_delay_in_4ms =
2454 0 : info_v9->ucLVDSOffToOnDelay_in4Ms;
2455 0 : info->lvds_bit_depth_control_val =
2456 0 : le32_to_cpu(info_v9->ulLCDBitDepthControlVal);
2457 :
2458 0 : for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
2459 : /* Convert [10KHz] into [KHz] */
2460 0 : info->avail_s_clk[i].supported_s_clk =
2461 0 : le32_to_cpu(info_v9->sAvail_SCLK[i].ulSupportedSCLK) * 10;
2462 0 : info->avail_s_clk[i].voltage_index =
2463 0 : le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageIndex);
2464 0 : info->avail_s_clk[i].voltage_id =
2465 0 : le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageID);
2466 : }
2467 :
2468 0 : for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
2469 0 : info->ext_disp_conn_info.gu_id[i] =
2470 0 : info_v9->sExtDispConnInfo.ucGuid[i];
2471 : }
2472 :
2473 0 : for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
2474 0 : info->ext_disp_conn_info.path[i].device_connector_id =
2475 0 : object_id_from_bios_object_id(
2476 0 : le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceConnector));
2477 :
2478 0 : info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
2479 0 : object_id_from_bios_object_id(
2480 0 : le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
2481 :
2482 0 : info->ext_disp_conn_info.path[i].device_tag =
2483 0 : le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceTag);
2484 0 : info->ext_disp_conn_info.path[i].device_acpi_enum =
2485 0 : le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
2486 0 : info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
2487 0 : info_v9->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
2488 0 : info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
2489 0 : info_v9->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
2490 0 : info->ext_disp_conn_info.path[i].channel_mapping.raw =
2491 0 : info_v9->sExtDispConnInfo.sPath[i].ucChannelMapping;
2492 : }
2493 0 : info->ext_disp_conn_info.checksum =
2494 0 : info_v9->sExtDispConnInfo.ucChecksum;
2495 :
2496 0 : return BP_RESULT_OK;
2497 : }
2498 :
2499 : /*
2500 : * construct_integrated_info
2501 : *
2502 : * @brief
2503 : * Get integrated BIOS information based on table revision
2504 : *
2505 : * @param
2506 : * bios_parser *bp - [in]BIOS parser handler to get master data table
2507 : * integrated_info *info - [out] store and output integrated info
2508 : *
2509 : * return:
2510 : * enum bp_result - BP_RESULT_OK if information is available,
2511 : * BP_RESULT_BADBIOSTABLE otherwise.
2512 : */
2513 0 : static enum bp_result construct_integrated_info(
2514 : struct bios_parser *bp,
2515 : struct integrated_info *info)
2516 : {
2517 0 : enum bp_result result = BP_RESULT_BADBIOSTABLE;
2518 :
2519 : ATOM_COMMON_TABLE_HEADER *header;
2520 : struct atom_data_revision revision;
2521 :
2522 0 : if (bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo) {
2523 0 : header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
2524 : bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2525 :
2526 0 : get_atom_data_table_revision(header, &revision);
2527 :
2528 : /* Don't need to check major revision as they are all 1 */
2529 0 : switch (revision.minor) {
2530 : case 8:
2531 0 : result = get_integrated_info_v8(bp, info);
2532 0 : break;
2533 : case 9:
2534 0 : result = get_integrated_info_v9(bp, info);
2535 0 : break;
2536 : default:
2537 : return result;
2538 :
2539 : }
2540 : }
2541 :
2542 : /* Sort voltage table from low to high*/
2543 0 : if (result == BP_RESULT_OK) {
2544 : uint32_t i;
2545 : uint32_t j;
2546 :
2547 0 : for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2548 0 : for (j = i; j > 0; --j) {
2549 0 : if (
2550 0 : info->disp_clk_voltage[j].max_supported_clk <
2551 0 : info->disp_clk_voltage[j-1].max_supported_clk) {
2552 : /* swap j and j - 1*/
2553 0 : swap(info->disp_clk_voltage[j - 1],
2554 : info->disp_clk_voltage[j]);
2555 : }
2556 : }
2557 : }
2558 :
2559 : }
2560 :
2561 : return result;
2562 : }
2563 :
2564 0 : static struct integrated_info *bios_parser_create_integrated_info(
2565 : struct dc_bios *dcb)
2566 : {
2567 0 : struct bios_parser *bp = BP_FROM_DCB(dcb);
2568 0 : struct integrated_info *info = NULL;
2569 :
2570 0 : info = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);
2571 :
2572 0 : if (info == NULL) {
2573 0 : ASSERT_CRITICAL(0);
2574 0 : return NULL;
2575 : }
2576 :
2577 0 : if (construct_integrated_info(bp, info) == BP_RESULT_OK)
2578 : return info;
2579 :
2580 0 : kfree(info);
2581 :
2582 0 : return NULL;
2583 : }
2584 :
2585 0 : static enum bp_result update_slot_layout_info(
2586 : struct dc_bios *dcb,
2587 : unsigned int i,
2588 : struct slot_layout_info *slot_layout_info,
2589 : unsigned int record_offset)
2590 : {
2591 : unsigned int j;
2592 : struct bios_parser *bp;
2593 : ATOM_BRACKET_LAYOUT_RECORD *record;
2594 : ATOM_COMMON_RECORD_HEADER *record_header;
2595 0 : enum bp_result result = BP_RESULT_NORECORD;
2596 :
2597 0 : bp = BP_FROM_DCB(dcb);
2598 0 : record = NULL;
2599 0 : record_header = NULL;
2600 :
2601 : for (;;) {
2602 :
2603 0 : record_header = (ATOM_COMMON_RECORD_HEADER *)
2604 0 : GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
2605 0 : if (record_header == NULL) {
2606 : result = BP_RESULT_BADBIOSTABLE;
2607 : break;
2608 : }
2609 :
2610 : /* the end of the list */
2611 0 : if (record_header->ucRecordType == 0xff ||
2612 0 : record_header->ucRecordSize == 0) {
2613 : break;
2614 : }
2615 :
2616 0 : if (record_header->ucRecordType ==
2617 0 : ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
2618 : sizeof(ATOM_BRACKET_LAYOUT_RECORD)
2619 : <= record_header->ucRecordSize) {
2620 : record = (ATOM_BRACKET_LAYOUT_RECORD *)
2621 : (record_header);
2622 : result = BP_RESULT_OK;
2623 : break;
2624 : }
2625 :
2626 0 : record_offset += record_header->ucRecordSize;
2627 : }
2628 :
2629 : /* return if the record not found */
2630 0 : if (result != BP_RESULT_OK)
2631 : return result;
2632 :
2633 : /* get slot sizes */
2634 0 : slot_layout_info->length = record->ucLength;
2635 0 : slot_layout_info->width = record->ucWidth;
2636 :
2637 : /* get info for each connector in the slot */
2638 0 : slot_layout_info->num_of_connectors = record->ucConnNum;
2639 0 : for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
2640 0 : slot_layout_info->connectors[j].connector_type =
2641 0 : (enum connector_layout_type)
2642 0 : (record->asConnInfo[j].ucConnectorType);
2643 0 : switch (record->asConnInfo[j].ucConnectorType) {
2644 : case CONNECTOR_TYPE_DVI_D:
2645 0 : slot_layout_info->connectors[j].connector_type =
2646 : CONNECTOR_LAYOUT_TYPE_DVI_D;
2647 0 : slot_layout_info->connectors[j].length =
2648 : CONNECTOR_SIZE_DVI;
2649 : break;
2650 :
2651 : case CONNECTOR_TYPE_HDMI:
2652 0 : slot_layout_info->connectors[j].connector_type =
2653 : CONNECTOR_LAYOUT_TYPE_HDMI;
2654 0 : slot_layout_info->connectors[j].length =
2655 : CONNECTOR_SIZE_HDMI;
2656 : break;
2657 :
2658 : case CONNECTOR_TYPE_DISPLAY_PORT:
2659 0 : slot_layout_info->connectors[j].connector_type =
2660 : CONNECTOR_LAYOUT_TYPE_DP;
2661 0 : slot_layout_info->connectors[j].length =
2662 : CONNECTOR_SIZE_DP;
2663 : break;
2664 :
2665 : case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
2666 0 : slot_layout_info->connectors[j].connector_type =
2667 : CONNECTOR_LAYOUT_TYPE_MINI_DP;
2668 0 : slot_layout_info->connectors[j].length =
2669 : CONNECTOR_SIZE_MINI_DP;
2670 : break;
2671 :
2672 : default:
2673 0 : slot_layout_info->connectors[j].connector_type =
2674 : CONNECTOR_LAYOUT_TYPE_UNKNOWN;
2675 0 : slot_layout_info->connectors[j].length =
2676 : CONNECTOR_SIZE_UNKNOWN;
2677 : }
2678 :
2679 0 : slot_layout_info->connectors[j].position =
2680 0 : record->asConnInfo[j].ucPosition;
2681 0 : slot_layout_info->connectors[j].connector_id =
2682 0 : object_id_from_bios_object_id(
2683 0 : record->asConnInfo[j].usConnectorObjectId);
2684 : }
2685 : return result;
2686 : }
2687 :
2688 :
2689 0 : static enum bp_result get_bracket_layout_record(
2690 : struct dc_bios *dcb,
2691 : unsigned int bracket_layout_id,
2692 : struct slot_layout_info *slot_layout_info)
2693 : {
2694 : unsigned int i;
2695 : unsigned int record_offset;
2696 : struct bios_parser *bp;
2697 : enum bp_result result;
2698 : ATOM_OBJECT *object;
2699 : ATOM_OBJECT_TABLE *object_table;
2700 : unsigned int genericTableOffset;
2701 :
2702 0 : bp = BP_FROM_DCB(dcb);
2703 0 : object = NULL;
2704 0 : if (slot_layout_info == NULL) {
2705 0 : DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
2706 0 : return BP_RESULT_BADINPUT;
2707 : }
2708 :
2709 :
2710 0 : genericTableOffset = bp->object_info_tbl_offset +
2711 0 : bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
2712 0 : object_table = (ATOM_OBJECT_TABLE *)
2713 0 : GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset);
2714 0 : if (!object_table)
2715 : return BP_RESULT_FAILURE;
2716 :
2717 : result = BP_RESULT_NORECORD;
2718 0 : for (i = 0; i < object_table->ucNumberOfObjects; ++i) {
2719 :
2720 0 : if (bracket_layout_id ==
2721 0 : object_table->asObjects[i].usObjectID) {
2722 :
2723 0 : object = &object_table->asObjects[i];
2724 0 : record_offset = object->usRecordOffset +
2725 0 : bp->object_info_tbl_offset;
2726 :
2727 0 : result = update_slot_layout_info(dcb, i,
2728 : slot_layout_info, record_offset);
2729 0 : break;
2730 : }
2731 : }
2732 : return result;
2733 : }
2734 :
2735 0 : static enum bp_result bios_get_board_layout_info(
2736 : struct dc_bios *dcb,
2737 : struct board_layout_info *board_layout_info)
2738 : {
2739 : unsigned int i;
2740 : enum bp_result record_result;
2741 :
2742 0 : const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
2743 : GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
2744 : GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
2745 : 0, 0
2746 : };
2747 :
2748 0 : if (board_layout_info == NULL) {
2749 0 : DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
2750 0 : return BP_RESULT_BADINPUT;
2751 : }
2752 :
2753 0 : board_layout_info->num_of_slots = 0;
2754 :
2755 0 : for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
2756 0 : record_result = get_bracket_layout_record(dcb,
2757 : slot_index_to_vbios_id[i],
2758 : &board_layout_info->slots[i]);
2759 :
2760 0 : if (record_result == BP_RESULT_NORECORD && i > 0)
2761 : break; /* no more slots present in bios */
2762 0 : else if (record_result != BP_RESULT_OK)
2763 : return record_result; /* fail */
2764 :
2765 0 : ++board_layout_info->num_of_slots;
2766 : }
2767 :
2768 : /* all data is valid */
2769 0 : board_layout_info->is_number_of_slots_valid = 1;
2770 0 : board_layout_info->is_slots_size_valid = 1;
2771 0 : board_layout_info->is_connector_offsets_valid = 1;
2772 0 : board_layout_info->is_connector_lengths_valid = 1;
2773 :
2774 0 : return BP_RESULT_OK;
2775 : }
2776 :
2777 : /******************************************************************************/
2778 :
2779 : static const struct dc_vbios_funcs vbios_funcs = {
2780 : .get_connectors_number = bios_parser_get_connectors_number,
2781 :
2782 : .get_connector_id = bios_parser_get_connector_id,
2783 :
2784 : .get_src_obj = bios_parser_get_src_obj,
2785 :
2786 : .get_i2c_info = bios_parser_get_i2c_info,
2787 :
2788 : .get_hpd_info = bios_parser_get_hpd_info,
2789 :
2790 : .get_device_tag = bios_parser_get_device_tag,
2791 :
2792 : .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info,
2793 :
2794 : .get_ss_entry_number = bios_parser_get_ss_entry_number,
2795 :
2796 : .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
2797 :
2798 : .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
2799 :
2800 : .get_encoder_cap_info = bios_parser_get_encoder_cap_info,
2801 :
2802 : /* bios scratch register communication */
2803 : .is_accelerated_mode = bios_is_accelerated_mode,
2804 :
2805 : .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
2806 :
2807 : .is_device_id_supported = bios_parser_is_device_id_supported,
2808 :
2809 : /* COMMANDS */
2810 : .encoder_control = bios_parser_encoder_control,
2811 :
2812 : .transmitter_control = bios_parser_transmitter_control,
2813 :
2814 : .enable_crtc = bios_parser_enable_crtc,
2815 :
2816 : .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
2817 :
2818 : .set_pixel_clock = bios_parser_set_pixel_clock,
2819 :
2820 : .set_dce_clock = bios_parser_set_dce_clock,
2821 :
2822 : .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
2823 :
2824 : .program_crtc_timing = bios_parser_program_crtc_timing, /* still use. should probably retire and program directly */
2825 :
2826 : .program_display_engine_pll = bios_parser_program_display_engine_pll,
2827 :
2828 : .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
2829 :
2830 : /* SW init and patch */
2831 :
2832 : .bios_parser_destroy = bios_parser_destroy,
2833 :
2834 : .get_board_layout_info = bios_get_board_layout_info,
2835 :
2836 : .get_atom_dc_golden_table = NULL
2837 : };
2838 :
2839 0 : static bool bios_parser_construct(
2840 : struct bios_parser *bp,
2841 : struct bp_init_data *init,
2842 : enum dce_version dce_version)
2843 : {
2844 0 : uint16_t *rom_header_offset = NULL;
2845 0 : ATOM_ROM_HEADER *rom_header = NULL;
2846 : ATOM_OBJECT_HEADER *object_info_tbl;
2847 0 : struct atom_data_revision tbl_rev = {0};
2848 :
2849 0 : if (!init)
2850 : return false;
2851 :
2852 0 : if (!init->bios)
2853 : return false;
2854 :
2855 0 : bp->base.funcs = &vbios_funcs;
2856 0 : bp->base.bios = init->bios;
2857 0 : bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
2858 :
2859 0 : bp->base.ctx = init->ctx;
2860 0 : bp->base.bios_local_image = NULL;
2861 :
2862 0 : rom_header_offset =
2863 0 : GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
2864 :
2865 0 : if (!rom_header_offset)
2866 : return false;
2867 :
2868 0 : rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
2869 :
2870 0 : if (!rom_header)
2871 : return false;
2872 :
2873 0 : get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev);
2874 0 : if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
2875 : return false;
2876 :
2877 0 : bp->master_data_tbl =
2878 0 : GET_IMAGE(ATOM_MASTER_DATA_TABLE,
2879 : rom_header->usMasterDataTableOffset);
2880 :
2881 0 : if (!bp->master_data_tbl)
2882 : return false;
2883 :
2884 0 : bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
2885 :
2886 0 : if (!bp->object_info_tbl_offset)
2887 : return false;
2888 :
2889 0 : object_info_tbl =
2890 : GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
2891 :
2892 0 : if (!object_info_tbl)
2893 : return false;
2894 :
2895 0 : get_atom_data_table_revision(&object_info_tbl->sHeader,
2896 : &bp->object_info_tbl.revision);
2897 :
2898 0 : if (bp->object_info_tbl.revision.major == 1
2899 0 : && bp->object_info_tbl.revision.minor >= 3) {
2900 : ATOM_OBJECT_HEADER_V3 *tbl_v3;
2901 :
2902 0 : tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
2903 : bp->object_info_tbl_offset);
2904 0 : if (!tbl_v3)
2905 : return false;
2906 :
2907 0 : bp->object_info_tbl.v1_3 = tbl_v3;
2908 0 : } else if (bp->object_info_tbl.revision.major == 1
2909 0 : && bp->object_info_tbl.revision.minor >= 1)
2910 0 : bp->object_info_tbl.v1_1 = object_info_tbl;
2911 : else
2912 : return false;
2913 :
2914 0 : dal_bios_parser_init_cmd_tbl(bp);
2915 0 : dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
2916 :
2917 0 : bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base);
2918 0 : bp->base.fw_info_valid = bios_parser_get_firmware_info(&bp->base, &bp->base.fw_info) == BP_RESULT_OK;
2919 :
2920 0 : return true;
2921 : }
2922 :
2923 : /******************************************************************************/
|