treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / gpu / drm / amd / display / dc / bios / bios_parser.c
blob008d4d11339d9056fe93d962503d267b4439457d
1 /*
2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
22 * Authors: AMD
26 #include <linux/slab.h>
28 #include "dm_services.h"
30 #include "atom.h"
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"
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"
46 #include "bios_parser_common.h"
48 #include "dc.h"
50 #define THREE_PERCENT_OF_10000 300
52 #define LAST_RECORD_TYPE 0xff
54 #define DC_LOGGER \
55 bp->base.ctx->logger
57 #define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
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);
78 #define BIOS_IMAGE_SIZE_OFFSET 2
79 #define BIOS_IMAGE_SIZE_UNIT 512
81 /*****************************************************************************/
82 static bool bios_parser_construct(
83 struct bios_parser *bp,
84 struct bp_init_data *init,
85 enum dce_version dce_version);
87 static uint8_t bios_parser_get_connectors_number(
88 struct dc_bios *dcb);
90 static enum bp_result bios_parser_get_embedded_panel_info(
91 struct dc_bios *dcb,
92 struct embedded_panel_info *info);
94 /*****************************************************************************/
96 struct dc_bios *bios_parser_create(
97 struct bp_init_data *init,
98 enum dce_version dce_version)
100 struct bios_parser *bp = NULL;
102 bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
103 if (!bp)
104 return NULL;
106 if (bios_parser_construct(bp, init, dce_version))
107 return &bp->base;
109 kfree(bp);
110 BREAK_TO_DEBUGGER();
111 return NULL;
114 static void bios_parser_destruct(struct bios_parser *bp)
116 kfree(bp->base.bios_local_image);
117 kfree(bp->base.integrated_info);
120 static void bios_parser_destroy(struct dc_bios **dcb)
122 struct bios_parser *bp = BP_FROM_DCB(*dcb);
124 if (!bp) {
125 BREAK_TO_DEBUGGER();
126 return;
129 bios_parser_destruct(bp);
131 kfree(bp);
132 *dcb = NULL;
135 static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
137 ATOM_OBJECT_TABLE *table;
139 uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
141 table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
143 if (!table)
144 return 0;
145 else
146 return table->ucNumberOfObjects;
149 static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb)
151 struct bios_parser *bp = BP_FROM_DCB(dcb);
153 return get_number_of_objects(bp,
154 le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
157 static struct graphics_object_id bios_parser_get_connector_id(
158 struct dc_bios *dcb,
159 uint8_t i)
161 struct bios_parser *bp = BP_FROM_DCB(dcb);
162 struct graphics_object_id object_id = dal_graphics_object_id_init(
163 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
164 uint16_t id;
166 uint32_t connector_table_offset = bp->object_info_tbl_offset
167 + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
169 ATOM_OBJECT_TABLE *tbl =
170 GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
172 if (!tbl) {
173 dm_error("Can't get connector table from atom bios.\n");
174 return object_id;
177 if (tbl->ucNumberOfObjects <= i) {
178 dm_error("Can't find connector id %d in connector table of size %d.\n",
179 i, tbl->ucNumberOfObjects);
180 return object_id;
183 id = le16_to_cpu(tbl->asObjects[i].usObjectID);
184 object_id = object_id_from_bios_object_id(id);
185 return object_id;
188 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)
192 uint32_t number;
193 uint16_t *id;
194 ATOM_OBJECT *object;
195 struct bios_parser *bp = BP_FROM_DCB(dcb);
197 if (!src_object_id)
198 return BP_RESULT_BADINPUT;
200 object = get_bios_object(bp, object_id);
202 if (!object) {
203 BREAK_TO_DEBUGGER(); /* Invalid object id */
204 return BP_RESULT_BADINPUT;
207 number = get_src_obj_list(bp, object, &id);
209 if (number <= index)
210 return BP_RESULT_BADINPUT;
212 *src_object_id = object_id_from_bios_object_id(id[index]);
214 return BP_RESULT_OK;
217 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)
221 uint32_t offset;
222 ATOM_OBJECT *object;
223 ATOM_COMMON_RECORD_HEADER *header;
224 ATOM_I2C_RECORD *record;
225 struct bios_parser *bp = BP_FROM_DCB(dcb);
227 if (!info)
228 return BP_RESULT_BADINPUT;
230 object = get_bios_object(bp, id);
232 if (!object)
233 return BP_RESULT_BADINPUT;
235 offset = le16_to_cpu(object->usRecordOffset)
236 + bp->object_info_tbl_offset;
238 for (;;) {
239 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
241 if (!header)
242 return BP_RESULT_BADBIOSTABLE;
244 if (LAST_RECORD_TYPE == header->ucRecordType ||
245 !header->ucRecordSize)
246 break;
248 if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
249 && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
250 /* get the I2C info */
251 record = (ATOM_I2C_RECORD *) header;
253 if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
254 return BP_RESULT_OK;
257 offset += header->ucRecordSize;
260 return BP_RESULT_NORECORD;
263 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)
267 struct bios_parser *bp = BP_FROM_DCB(dcb);
268 ATOM_OBJECT *object;
269 ATOM_HPD_INT_RECORD *record = NULL;
271 if (!info)
272 return BP_RESULT_BADINPUT;
274 object = get_bios_object(bp, id);
276 if (!object)
277 return BP_RESULT_BADINPUT;
279 record = get_hpd_record(bp, object);
281 if (record != NULL) {
282 info->hpd_int_gpio_uid = record->ucHPDIntGPIOID;
283 info->hpd_active = record->ucPlugged_PinState;
284 return BP_RESULT_OK;
287 return BP_RESULT_NORECORD;
290 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)
295 ATOM_COMMON_RECORD_HEADER *header;
296 uint32_t offset;
298 offset = le16_to_cpu(object->usRecordOffset)
299 + bp->object_info_tbl_offset;
301 for (;;) {
302 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
304 if (!header)
305 return BP_RESULT_BADBIOSTABLE;
307 offset += header->ucRecordSize;
309 if (LAST_RECORD_TYPE == header->ucRecordType ||
310 !header->ucRecordSize)
311 break;
313 if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
314 header->ucRecordType)
315 continue;
317 if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
318 continue;
320 *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
321 return BP_RESULT_OK;
324 return BP_RESULT_NORECORD;
327 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)
333 struct bios_parser *bp = BP_FROM_DCB(dcb);
334 ATOM_OBJECT *object;
335 ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
336 ATOM_CONNECTOR_DEVICE_TAG *device_tag;
338 if (!info)
339 return BP_RESULT_BADINPUT;
341 /* getBiosObject will return MXM object */
342 object = get_bios_object(bp, connector_object_id);
344 if (!object) {
345 BREAK_TO_DEBUGGER(); /* Invalid object id */
346 return BP_RESULT_BADINPUT;
349 if (bios_parser_get_device_tag_record(bp, object, &record)
350 != BP_RESULT_OK)
351 return BP_RESULT_NORECORD;
353 if (device_tag_index >= record->ucNumberOfDevice)
354 return BP_RESULT_NORECORD;
356 device_tag = &record->asDeviceTag[device_tag_index];
358 info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
359 info->dev_id =
360 device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
362 return BP_RESULT_OK;
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);
375 static enum bp_result bios_parser_get_firmware_info(
376 struct dc_bios *dcb,
377 struct dc_firmware_info *info)
379 struct bios_parser *bp = BP_FROM_DCB(dcb);
380 enum bp_result result = BP_RESULT_BADBIOSTABLE;
381 ATOM_COMMON_TABLE_HEADER *header;
382 struct atom_data_revision revision;
384 if (info && DATA_TABLES(FirmwareInfo)) {
385 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
386 DATA_TABLES(FirmwareInfo));
387 get_atom_data_table_revision(header, &revision);
388 switch (revision.major) {
389 case 1:
390 switch (revision.minor) {
391 case 4:
392 result = get_firmware_info_v1_4(bp, info);
393 break;
394 default:
395 break;
397 break;
399 case 2:
400 switch (revision.minor) {
401 case 1:
402 result = get_firmware_info_v2_1(bp, info);
403 break;
404 case 2:
405 result = get_firmware_info_v2_2(bp, info);
406 break;
407 default:
408 break;
410 break;
411 default:
412 break;
416 return result;
419 static enum bp_result get_firmware_info_v1_4(
420 struct bios_parser *bp,
421 struct dc_firmware_info *info)
423 ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
424 GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
425 DATA_TABLES(FirmwareInfo));
427 if (!info)
428 return BP_RESULT_BADINPUT;
430 if (!firmware_info)
431 return BP_RESULT_BADBIOSTABLE;
433 memset(info, 0, sizeof(*info));
435 /* Pixel clock pll information. We need to convert from 10KHz units into
436 * KHz units */
437 info->pll_info.crystal_frequency =
438 le16_to_cpu(firmware_info->usReferenceClock) * 10;
439 info->pll_info.min_input_pxl_clk_pll_frequency =
440 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
441 info->pll_info.max_input_pxl_clk_pll_frequency =
442 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
443 info->pll_info.min_output_pxl_clk_pll_frequency =
444 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
445 info->pll_info.max_output_pxl_clk_pll_frequency =
446 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
448 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 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
454 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 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
460 return BP_RESULT_OK;
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);
469 static enum bp_result get_firmware_info_v2_1(
470 struct bios_parser *bp,
471 struct dc_firmware_info *info)
473 ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
474 GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
475 struct spread_spectrum_info internalSS;
476 uint32_t index;
478 if (!info)
479 return BP_RESULT_BADINPUT;
481 if (!firmwareInfo)
482 return BP_RESULT_BADBIOSTABLE;
484 memset(info, 0, sizeof(*info));
486 /* Pixel clock pll information. We need to convert from 10KHz units into
487 * KHz units */
488 info->pll_info.crystal_frequency =
489 le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
490 info->pll_info.min_input_pxl_clk_pll_frequency =
491 le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
492 info->pll_info.max_input_pxl_clk_pll_frequency =
493 le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
494 info->pll_info.min_output_pxl_clk_pll_frequency =
495 le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
496 info->pll_info.max_output_pxl_clk_pll_frequency =
497 le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
498 info->default_display_engine_pll_frequency =
499 le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
500 info->external_clock_source_frequency_for_dp =
501 le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
502 info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
504 /* There should be only one entry in the SS info table for Memory Clock
506 index = 0;
507 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 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
512 else if (get_ss_info_v3_1(bp,
513 ASIC_INTERNAL_MEMORY_SS, index, &internalSS) == BP_RESULT_OK) {
514 if (internalSS.spread_spectrum_percentage) {
515 info->feature.memory_clk_ss_percentage =
516 internalSS.spread_spectrum_percentage;
517 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 ++info->feature.memory_clk_ss_percentage;
522 info->feature.memory_clk_ss_percentage /= 2;
527 /* There should be only one entry in the SS info table for Engine Clock
529 index = 1;
530 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 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
535 else if (get_ss_info_v3_1(bp,
536 ASIC_INTERNAL_ENGINE_SS, index, &internalSS) == BP_RESULT_OK) {
537 if (internalSS.spread_spectrum_percentage) {
538 info->feature.engine_clk_ss_percentage =
539 internalSS.spread_spectrum_percentage;
540 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 ++info->feature.engine_clk_ss_percentage;
545 info->feature.engine_clk_ss_percentage /= 2;
550 return BP_RESULT_OK;
553 static enum bp_result get_firmware_info_v2_2(
554 struct bios_parser *bp,
555 struct dc_firmware_info *info)
557 ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
558 struct spread_spectrum_info internal_ss;
559 uint32_t index;
561 if (!info)
562 return BP_RESULT_BADINPUT;
564 firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
565 DATA_TABLES(FirmwareInfo));
567 if (!firmware_info)
568 return BP_RESULT_BADBIOSTABLE;
570 memset(info, 0, sizeof(*info));
572 /* Pixel clock pll information. We need to convert from 10KHz units into
573 * KHz units */
574 info->pll_info.crystal_frequency =
575 le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
576 info->pll_info.min_input_pxl_clk_pll_frequency =
577 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
578 info->pll_info.max_input_pxl_clk_pll_frequency =
579 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
580 info->pll_info.min_output_pxl_clk_pll_frequency =
581 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
582 info->pll_info.max_output_pxl_clk_pll_frequency =
583 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
584 info->default_display_engine_pll_frequency =
585 le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
586 info->external_clock_source_frequency_for_dp =
587 le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
589 /* There should be only one entry in the SS info table for Memory Clock
591 index = 0;
592 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 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
597 else if (get_ss_info_v3_1(bp,
598 ASIC_INTERNAL_MEMORY_SS, index, &internal_ss) == BP_RESULT_OK) {
599 if (internal_ss.spread_spectrum_percentage) {
600 info->feature.memory_clk_ss_percentage =
601 internal_ss.spread_spectrum_percentage;
602 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 ++info->feature.memory_clk_ss_percentage;
607 info->feature.memory_clk_ss_percentage /= 2;
612 /* There should be only one entry in the SS info table for Engine Clock
614 index = 1;
615 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 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
620 else if (get_ss_info_v3_1(bp,
621 ASIC_INTERNAL_ENGINE_SS, index, &internal_ss) == BP_RESULT_OK) {
622 if (internal_ss.spread_spectrum_percentage) {
623 info->feature.engine_clk_ss_percentage =
624 internal_ss.spread_spectrum_percentage;
625 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 ++info->feature.engine_clk_ss_percentage;
630 info->feature.engine_clk_ss_percentage /= 2;
635 /* Remote Display */
636 info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
638 /* Is allowed minimum BL level */
639 info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
640 /* Used starting from CI */
641 info->smu_gpu_pll_output_freq =
642 (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
644 return BP_RESULT_OK;
647 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)
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 uint32_t table_index = 0;
659 if (!ss_info)
660 return BP_RESULT_BADINPUT;
662 if (!DATA_TABLES(ASIC_InternalSS_Info))
663 return BP_RESULT_UNSUPPORTED;
665 ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
666 DATA_TABLES(ASIC_InternalSS_Info));
667 table_size =
668 (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
669 - sizeof(ATOM_COMMON_TABLE_HEADER))
670 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
672 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
673 &ss_table_header_include->asSpreadSpectrum[0];
675 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
677 for (i = 0; i < table_size; i++) {
678 if (tbl[i].ucClockIndication != (uint8_t) id)
679 continue;
681 if (table_index != index) {
682 table_index++;
683 continue;
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
692 * Old VBIOS defines:
693 * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
694 * #define ATOM_EXTERNAL_SS_MASK 0x00000002
697 if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
698 ss_info->type.EXTERNAL = true;
700 if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
701 ss_info->type.CENTER_MODE = true;
703 /* Older VBIOS (in field) always provides SS percentage in 0.01%
704 * units set Divider to 100 */
705 ss_info->spread_percentage_divider = 100;
707 /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
708 if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
709 & tbl[i].ucSpreadSpectrumMode)
710 ss_info->spread_percentage_divider = 1000;
712 ss_info->type.STEP_AND_DELAY_INFO = false;
713 /* convert [10KHz] into [KHz] */
714 ss_info->target_clock_range =
715 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
716 ss_info->spread_spectrum_percentage =
717 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
718 ss_info->spread_spectrum_range =
719 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
721 return BP_RESULT_OK;
723 return BP_RESULT_NORECORD;
726 static enum bp_result bios_parser_transmitter_control(
727 struct dc_bios *dcb,
728 struct bp_transmitter_control *cntl)
730 struct bios_parser *bp = BP_FROM_DCB(dcb);
732 if (!bp->cmd_tbl.transmitter_control)
733 return BP_RESULT_FAILURE;
735 return bp->cmd_tbl.transmitter_control(bp, cntl);
738 static enum bp_result bios_parser_encoder_control(
739 struct dc_bios *dcb,
740 struct bp_encoder_control *cntl)
742 struct bios_parser *bp = BP_FROM_DCB(dcb);
744 if (!bp->cmd_tbl.dig_encoder_control)
745 return BP_RESULT_FAILURE;
747 return bp->cmd_tbl.dig_encoder_control(bp, cntl);
750 static enum bp_result bios_parser_adjust_pixel_clock(
751 struct dc_bios *dcb,
752 struct bp_adjust_pixel_clock_parameters *bp_params)
754 struct bios_parser *bp = BP_FROM_DCB(dcb);
756 if (!bp->cmd_tbl.adjust_display_pll)
757 return BP_RESULT_FAILURE;
759 return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
762 static enum bp_result bios_parser_set_pixel_clock(
763 struct dc_bios *dcb,
764 struct bp_pixel_clock_parameters *bp_params)
766 struct bios_parser *bp = BP_FROM_DCB(dcb);
768 if (!bp->cmd_tbl.set_pixel_clock)
769 return BP_RESULT_FAILURE;
771 return bp->cmd_tbl.set_pixel_clock(bp, bp_params);
774 static enum bp_result bios_parser_set_dce_clock(
775 struct dc_bios *dcb,
776 struct bp_set_dce_clock_parameters *bp_params)
778 struct bios_parser *bp = BP_FROM_DCB(dcb);
780 if (!bp->cmd_tbl.set_dce_clock)
781 return BP_RESULT_FAILURE;
783 return bp->cmd_tbl.set_dce_clock(bp, bp_params);
786 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)
791 struct bios_parser *bp = BP_FROM_DCB(dcb);
793 if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
794 return BP_RESULT_FAILURE;
796 return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
797 bp, bp_params, enable);
801 static enum bp_result bios_parser_program_crtc_timing(
802 struct dc_bios *dcb,
803 struct bp_hw_crtc_timing_parameters *bp_params)
805 struct bios_parser *bp = BP_FROM_DCB(dcb);
807 if (!bp->cmd_tbl.set_crtc_timing)
808 return BP_RESULT_FAILURE;
810 return bp->cmd_tbl.set_crtc_timing(bp, bp_params);
813 static enum bp_result bios_parser_program_display_engine_pll(
814 struct dc_bios *dcb,
815 struct bp_pixel_clock_parameters *bp_params)
817 struct bios_parser *bp = BP_FROM_DCB(dcb);
819 if (!bp->cmd_tbl.program_clock)
820 return BP_RESULT_FAILURE;
822 return bp->cmd_tbl.program_clock(bp, bp_params);
827 static enum bp_result bios_parser_enable_crtc(
828 struct dc_bios *dcb,
829 enum controller_id id,
830 bool enable)
832 struct bios_parser *bp = BP_FROM_DCB(dcb);
834 if (!bp->cmd_tbl.enable_crtc)
835 return BP_RESULT_FAILURE;
837 return bp->cmd_tbl.enable_crtc(bp, id, enable);
840 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)
845 struct bios_parser *bp = BP_FROM_DCB(dcb);
847 if (!bp->cmd_tbl.enable_disp_power_gating)
848 return BP_RESULT_FAILURE;
850 return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id,
851 action);
854 static bool bios_parser_is_device_id_supported(
855 struct dc_bios *dcb,
856 struct device_id id)
858 struct bios_parser *bp = BP_FROM_DCB(dcb);
860 uint32_t mask = get_support_mask_for_device_id(id);
862 return (le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport) & mask) != 0;
865 static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
866 ATOM_OBJECT *object)
868 ATOM_COMMON_RECORD_HEADER *header;
869 uint32_t offset;
871 if (!object) {
872 BREAK_TO_DEBUGGER(); /* Invalid object */
873 return NULL;
876 offset = le16_to_cpu(object->usRecordOffset)
877 + bp->object_info_tbl_offset;
879 for (;;) {
880 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
882 if (!header)
883 return NULL;
885 if (LAST_RECORD_TYPE == header->ucRecordType ||
886 !header->ucRecordSize)
887 break;
889 if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
890 && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
891 return (ATOM_HPD_INT_RECORD *) header;
893 offset += header->ucRecordSize;
896 return NULL;
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);
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 * @param [in] this
915 * @param [in] signal, ASSignalType to be converted to info index
916 * @param [in] index, number of entries that match the converted info index
917 * @param [out] ss_info, sprectrum information structure,
918 * @return Bios parser result code
920 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)
926 struct bios_parser *bp = BP_FROM_DCB(dcb);
927 enum bp_result result = BP_RESULT_UNSUPPORTED;
928 uint32_t clk_id_ss = 0;
929 ATOM_COMMON_TABLE_HEADER *header;
930 struct atom_data_revision tbl_revision;
932 if (!ss_info) /* check for bad input */
933 return BP_RESULT_BADINPUT;
934 /* signal translation */
935 clk_id_ss = signal_to_ss_id(signal);
937 if (!DATA_TABLES(ASIC_InternalSS_Info))
938 if (!index)
939 return get_ss_info_from_ss_info_table(bp, clk_id_ss,
940 ss_info);
942 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
943 DATA_TABLES(ASIC_InternalSS_Info));
944 get_atom_data_table_revision(header, &tbl_revision);
946 switch (tbl_revision.major) {
947 case 2:
948 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 if (!index)
953 return get_ss_info_from_tbl(bp, clk_id_ss,
954 ss_info);
955 break;
956 default:
957 break;
959 break;
961 case 3:
962 switch (tbl_revision.minor) {
963 case 1:
964 return get_ss_info_v3_1(bp, clk_id_ss, index, ss_info);
965 default:
966 break;
968 break;
969 default:
970 break;
972 /* there can not be more then one entry for SS Info table */
973 return result;
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);
982 * get_ss_info_from_table
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.
988 * @param this
989 * @param id, spread sprectrum info index
990 * @param pSSinfo, sprectrum information structure,
991 * @return Bios parser result code
993 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)
998 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 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1002 return get_ss_info_from_ss_info_table(bp, id, ss_info);
1003 else
1004 return get_ss_info_from_internal_ss_info_tbl_V2_1(bp, id,
1005 ss_info);
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
1014 * @param id, spread sprectrum info index
1015 * @param pSSinfo, sprectrum information structure,
1016 * @return Bios parser result code
1018 static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1019 struct bios_parser *bp,
1020 uint32_t id,
1021 struct spread_spectrum_info *info)
1023 enum bp_result result = BP_RESULT_UNSUPPORTED;
1024 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header;
1025 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1026 uint32_t tbl_size, i;
1028 if (!DATA_TABLES(ASIC_InternalSS_Info))
1029 return result;
1031 header = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
1032 DATA_TABLES(ASIC_InternalSS_Info));
1034 memset(info, 0, sizeof(struct spread_spectrum_info));
1036 tbl_size = (le16_to_cpu(header->sHeader.usStructureSize)
1037 - sizeof(ATOM_COMMON_TABLE_HEADER))
1038 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1040 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1041 &(header->asSpreadSpectrum[0]);
1042 for (i = 0; i < tbl_size; i++) {
1043 result = BP_RESULT_NORECORD;
1045 if (tbl[i].ucClockIndication != (uint8_t)id)
1046 continue;
1048 if (ATOM_EXTERNAL_SS_MASK
1049 & tbl[i].ucSpreadSpectrumMode) {
1050 info->type.EXTERNAL = true;
1052 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
1053 & tbl[i].ucSpreadSpectrumMode) {
1054 info->type.CENTER_MODE = true;
1056 info->type.STEP_AND_DELAY_INFO = false;
1057 /* convert [10KHz] into [KHz] */
1058 info->target_clock_range =
1059 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
1060 info->spread_spectrum_percentage =
1061 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
1062 info->spread_spectrum_range =
1063 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
1064 result = BP_RESULT_OK;
1065 break;
1068 return result;
1073 * get_ss_info_from_ss_info_table
1074 * Get spread sprectrum information from the SS_Info table from the VBIOS
1075 * if the pointer to info is NULL, indicate the caller what to know the number
1076 * of entries that matches the id
1077 * for, the SS_Info table, there should not be more than 1 entry match.
1079 * @param [in] id, spread sprectrum id
1080 * @param [out] pSSinfo, sprectrum information structure,
1081 * @return Bios parser result code
1083 static enum bp_result get_ss_info_from_ss_info_table(
1084 struct bios_parser *bp,
1085 uint32_t id,
1086 struct spread_spectrum_info *ss_info)
1088 enum bp_result result = BP_RESULT_UNSUPPORTED;
1089 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1090 ATOM_COMMON_TABLE_HEADER *header;
1091 uint32_t table_size;
1092 uint32_t i;
1093 uint32_t id_local = SS_ID_UNKNOWN;
1094 struct atom_data_revision revision;
1096 /* exist of the SS_Info table */
1097 /* check for bad input, pSSinfo can not be NULL */
1098 if (!DATA_TABLES(SS_Info) || !ss_info)
1099 return result;
1101 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(SS_Info));
1102 get_atom_data_table_revision(header, &revision);
1104 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info));
1106 if (1 != revision.major || 2 > revision.minor)
1107 return result;
1109 /* have to convert from Internal_SS format to SS_Info format */
1110 switch (id) {
1111 case ASIC_INTERNAL_SS_ON_DP:
1112 id_local = SS_ID_DP1;
1113 break;
1114 case ASIC_INTERNAL_SS_ON_LVDS:
1116 struct embedded_panel_info panel_info;
1118 if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
1119 == BP_RESULT_OK)
1120 id_local = panel_info.ss_id;
1121 break;
1123 default:
1124 break;
1127 if (id_local == SS_ID_UNKNOWN)
1128 return result;
1130 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1131 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1132 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1134 for (i = 0; i < table_size; i++) {
1135 if (id_local != (uint32_t)tbl->asSS_Info[i].ucSS_Id)
1136 continue;
1138 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
1140 if (ATOM_EXTERNAL_SS_MASK &
1141 tbl->asSS_Info[i].ucSpreadSpectrumType)
1142 ss_info->type.EXTERNAL = true;
1144 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK &
1145 tbl->asSS_Info[i].ucSpreadSpectrumType)
1146 ss_info->type.CENTER_MODE = true;
1148 ss_info->type.STEP_AND_DELAY_INFO = true;
1149 ss_info->spread_spectrum_percentage =
1150 (uint32_t)le16_to_cpu(tbl->asSS_Info[i].usSpreadSpectrumPercentage);
1151 ss_info->step_and_delay_info.step = tbl->asSS_Info[i].ucSS_Step;
1152 ss_info->step_and_delay_info.delay =
1153 tbl->asSS_Info[i].ucSS_Delay;
1154 ss_info->step_and_delay_info.recommended_ref_div =
1155 tbl->asSS_Info[i].ucRecommendedRef_Div;
1156 ss_info->spread_spectrum_range =
1157 (uint32_t)tbl->asSS_Info[i].ucSS_Range * 10000;
1159 /* there will be only one entry for each display type in SS_info
1160 * table */
1161 result = BP_RESULT_OK;
1162 break;
1165 return result;
1167 static enum bp_result get_embedded_panel_info_v1_2(
1168 struct bios_parser *bp,
1169 struct embedded_panel_info *info);
1170 static enum bp_result get_embedded_panel_info_v1_3(
1171 struct bios_parser *bp,
1172 struct embedded_panel_info *info);
1174 static enum bp_result bios_parser_get_embedded_panel_info(
1175 struct dc_bios *dcb,
1176 struct embedded_panel_info *info)
1178 struct bios_parser *bp = BP_FROM_DCB(dcb);
1179 ATOM_COMMON_TABLE_HEADER *hdr;
1181 if (!DATA_TABLES(LCD_Info))
1182 return BP_RESULT_FAILURE;
1184 hdr = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(LCD_Info));
1186 if (!hdr)
1187 return BP_RESULT_BADBIOSTABLE;
1189 switch (hdr->ucTableFormatRevision) {
1190 case 1:
1191 switch (hdr->ucTableContentRevision) {
1192 case 0:
1193 case 1:
1194 case 2:
1195 return get_embedded_panel_info_v1_2(bp, info);
1196 case 3:
1197 return get_embedded_panel_info_v1_3(bp, info);
1198 default:
1199 break;
1201 default:
1202 break;
1205 return BP_RESULT_FAILURE;
1208 static enum bp_result get_embedded_panel_info_v1_2(
1209 struct bios_parser *bp,
1210 struct embedded_panel_info *info)
1212 ATOM_LVDS_INFO_V12 *lvds;
1214 if (!info)
1215 return BP_RESULT_BADINPUT;
1217 if (!DATA_TABLES(LVDS_Info))
1218 return BP_RESULT_UNSUPPORTED;
1220 lvds =
1221 GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
1223 if (!lvds)
1224 return BP_RESULT_BADBIOSTABLE;
1226 if (1 != lvds->sHeader.ucTableFormatRevision
1227 || 2 > lvds->sHeader.ucTableContentRevision)
1228 return BP_RESULT_UNSUPPORTED;
1230 memset(info, 0, sizeof(struct embedded_panel_info));
1232 /* We need to convert from 10KHz units into KHz units*/
1233 info->lcd_timing.pixel_clk =
1234 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1235 /* usHActive does not include borders, according to VBIOS team*/
1236 info->lcd_timing.horizontal_addressable =
1237 le16_to_cpu(lvds->sLCDTiming.usHActive);
1238 /* usHBlanking_Time includes borders, so we should really be subtracting
1239 * borders duing this translation, but LVDS generally*/
1240 /* doesn't have borders, so we should be okay leaving this as is for
1241 * now. May need to revisit if we ever have LVDS with borders*/
1242 info->lcd_timing.horizontal_blanking_time =
1243 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1244 /* usVActive does not include borders, according to VBIOS team*/
1245 info->lcd_timing.vertical_addressable =
1246 le16_to_cpu(lvds->sLCDTiming.usVActive);
1247 /* usVBlanking_Time includes borders, so we should really be subtracting
1248 * borders duing this translation, but LVDS generally*/
1249 /* doesn't have borders, so we should be okay leaving this as is for
1250 * now. May need to revisit if we ever have LVDS with borders*/
1251 info->lcd_timing.vertical_blanking_time =
1252 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1253 info->lcd_timing.horizontal_sync_offset =
1254 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1255 info->lcd_timing.horizontal_sync_width =
1256 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1257 info->lcd_timing.vertical_sync_offset =
1258 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1259 info->lcd_timing.vertical_sync_width =
1260 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1261 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1262 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1263 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1264 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1265 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1266 ~(uint32_t)
1267 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1268 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1269 ~(uint32_t)
1270 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1271 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1272 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1273 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1274 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1275 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1276 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1277 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1278 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1279 info->lcd_timing.misc_info.INTERLACE =
1280 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1281 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1282 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1283 info->ss_id = lvds->ucSS_Id;
1286 uint8_t rr = le16_to_cpu(lvds->usSupportedRefreshRate);
1287 /* Get minimum supported refresh rate*/
1288 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1289 info->supported_rr.REFRESH_RATE_30HZ = 1;
1290 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1291 info->supported_rr.REFRESH_RATE_40HZ = 1;
1292 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1293 info->supported_rr.REFRESH_RATE_48HZ = 1;
1294 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1295 info->supported_rr.REFRESH_RATE_50HZ = 1;
1296 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1297 info->supported_rr.REFRESH_RATE_60HZ = 1;
1300 /*Drr panel support can be reported by VBIOS*/
1301 if (LCDPANEL_CAP_DRR_SUPPORTED
1302 & lvds->ucLCDPanel_SpecialHandlingCap)
1303 info->drr_enabled = 1;
1305 if (ATOM_PANEL_MISC_DUAL & lvds->ucLVDS_Misc)
1306 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1308 if (ATOM_PANEL_MISC_888RGB & lvds->ucLVDS_Misc)
1309 info->lcd_timing.misc_info.RGB888 = true;
1311 info->lcd_timing.misc_info.GREY_LEVEL =
1312 (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL &
1313 lvds->ucLVDS_Misc) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT;
1315 if (ATOM_PANEL_MISC_SPATIAL & lvds->ucLVDS_Misc)
1316 info->lcd_timing.misc_info.SPATIAL = true;
1318 if (ATOM_PANEL_MISC_TEMPORAL & lvds->ucLVDS_Misc)
1319 info->lcd_timing.misc_info.TEMPORAL = true;
1321 if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
1322 info->lcd_timing.misc_info.API_ENABLED = true;
1324 return BP_RESULT_OK;
1327 static enum bp_result get_embedded_panel_info_v1_3(
1328 struct bios_parser *bp,
1329 struct embedded_panel_info *info)
1331 ATOM_LCD_INFO_V13 *lvds;
1333 if (!info)
1334 return BP_RESULT_BADINPUT;
1336 if (!DATA_TABLES(LCD_Info))
1337 return BP_RESULT_UNSUPPORTED;
1339 lvds = GET_IMAGE(ATOM_LCD_INFO_V13, DATA_TABLES(LCD_Info));
1341 if (!lvds)
1342 return BP_RESULT_BADBIOSTABLE;
1344 if (!((1 == lvds->sHeader.ucTableFormatRevision)
1345 && (3 <= lvds->sHeader.ucTableContentRevision)))
1346 return BP_RESULT_UNSUPPORTED;
1348 memset(info, 0, sizeof(struct embedded_panel_info));
1350 /* We need to convert from 10KHz units into KHz units */
1351 info->lcd_timing.pixel_clk =
1352 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1353 /* usHActive does not include borders, according to VBIOS team */
1354 info->lcd_timing.horizontal_addressable =
1355 le16_to_cpu(lvds->sLCDTiming.usHActive);
1356 /* usHBlanking_Time includes borders, so we should really be subtracting
1357 * borders duing this translation, but LVDS generally*/
1358 /* doesn't have borders, so we should be okay leaving this as is for
1359 * now. May need to revisit if we ever have LVDS with borders*/
1360 info->lcd_timing.horizontal_blanking_time =
1361 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1362 /* usVActive does not include borders, according to VBIOS team*/
1363 info->lcd_timing.vertical_addressable =
1364 le16_to_cpu(lvds->sLCDTiming.usVActive);
1365 /* usVBlanking_Time includes borders, so we should really be subtracting
1366 * borders duing this translation, but LVDS generally*/
1367 /* doesn't have borders, so we should be okay leaving this as is for
1368 * now. May need to revisit if we ever have LVDS with borders*/
1369 info->lcd_timing.vertical_blanking_time =
1370 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1371 info->lcd_timing.horizontal_sync_offset =
1372 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1373 info->lcd_timing.horizontal_sync_width =
1374 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1375 info->lcd_timing.vertical_sync_offset =
1376 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1377 info->lcd_timing.vertical_sync_width =
1378 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1379 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1380 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1381 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1382 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1383 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1384 ~(uint32_t)
1385 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1386 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1387 ~(uint32_t)
1388 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1389 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1390 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1391 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1392 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1393 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1394 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1395 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1396 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1397 info->lcd_timing.misc_info.INTERLACE =
1398 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1399 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1400 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1401 info->ss_id = lvds->ucSS_Id;
1403 /* Drr panel support can be reported by VBIOS*/
1404 if (LCDPANEL_CAP_V13_DRR_SUPPORTED
1405 & lvds->ucLCDPanel_SpecialHandlingCap)
1406 info->drr_enabled = 1;
1408 /* Get supported refresh rate*/
1409 if (info->drr_enabled == 1) {
1410 uint8_t min_rr =
1411 lvds->sRefreshRateSupport.ucMinRefreshRateForDRR;
1412 uint8_t rr = lvds->sRefreshRateSupport.ucSupportedRefreshRate;
1414 if (min_rr != 0) {
1415 if (SUPPORTED_LCD_REFRESHRATE_30Hz & min_rr)
1416 info->supported_rr.REFRESH_RATE_30HZ = 1;
1417 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & min_rr)
1418 info->supported_rr.REFRESH_RATE_40HZ = 1;
1419 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & min_rr)
1420 info->supported_rr.REFRESH_RATE_48HZ = 1;
1421 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & min_rr)
1422 info->supported_rr.REFRESH_RATE_50HZ = 1;
1423 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & min_rr)
1424 info->supported_rr.REFRESH_RATE_60HZ = 1;
1425 } else {
1426 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1427 info->supported_rr.REFRESH_RATE_30HZ = 1;
1428 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1429 info->supported_rr.REFRESH_RATE_40HZ = 1;
1430 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1431 info->supported_rr.REFRESH_RATE_48HZ = 1;
1432 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1433 info->supported_rr.REFRESH_RATE_50HZ = 1;
1434 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1435 info->supported_rr.REFRESH_RATE_60HZ = 1;
1439 if (ATOM_PANEL_MISC_V13_DUAL & lvds->ucLCD_Misc)
1440 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1442 if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR & lvds->ucLCD_Misc)
1443 info->lcd_timing.misc_info.RGB888 = true;
1445 info->lcd_timing.misc_info.GREY_LEVEL =
1446 (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
1447 lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
1449 return BP_RESULT_OK;
1453 * bios_parser_get_encoder_cap_info
1455 * @brief
1456 * Get encoder capability information of input object id
1458 * @param object_id, Object id
1459 * @param object_id, encoder cap information structure
1461 * @return Bios parser result code
1464 static enum bp_result bios_parser_get_encoder_cap_info(
1465 struct dc_bios *dcb,
1466 struct graphics_object_id object_id,
1467 struct bp_encoder_cap_info *info)
1469 struct bios_parser *bp = BP_FROM_DCB(dcb);
1470 ATOM_OBJECT *object;
1471 ATOM_ENCODER_CAP_RECORD_V2 *record = NULL;
1473 if (!info)
1474 return BP_RESULT_BADINPUT;
1476 object = get_bios_object(bp, object_id);
1478 if (!object)
1479 return BP_RESULT_BADINPUT;
1481 record = get_encoder_cap_record(bp, object);
1482 if (!record)
1483 return BP_RESULT_NORECORD;
1485 info->DP_HBR2_EN = record->usHBR2En;
1486 info->DP_HBR3_EN = record->usHBR3En;
1487 info->HDMI_6GB_EN = record->usHDMI6GEn;
1488 return BP_RESULT_OK;
1492 * get_encoder_cap_record
1494 * @brief
1495 * Get encoder cap record for the object
1497 * @param object, ATOM object
1499 * @return atom encoder cap record
1501 * @note
1502 * search all records to find the ATOM_ENCODER_CAP_RECORD_V2 record
1504 static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
1505 struct bios_parser *bp,
1506 ATOM_OBJECT *object)
1508 ATOM_COMMON_RECORD_HEADER *header;
1509 uint32_t offset;
1511 if (!object) {
1512 BREAK_TO_DEBUGGER(); /* Invalid object */
1513 return NULL;
1516 offset = le16_to_cpu(object->usRecordOffset)
1517 + bp->object_info_tbl_offset;
1519 for (;;) {
1520 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1522 if (!header)
1523 return NULL;
1525 offset += header->ucRecordSize;
1527 if (LAST_RECORD_TYPE == header->ucRecordType ||
1528 !header->ucRecordSize)
1529 break;
1531 if (ATOM_ENCODER_CAP_RECORD_TYPE != header->ucRecordType)
1532 continue;
1534 if (sizeof(ATOM_ENCODER_CAP_RECORD_V2) <= header->ucRecordSize)
1535 return (ATOM_ENCODER_CAP_RECORD_V2 *)header;
1538 return NULL;
1541 static uint32_t get_ss_entry_number(
1542 struct bios_parser *bp,
1543 uint32_t id);
1544 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1545 struct bios_parser *bp,
1546 uint32_t id);
1547 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1548 struct bios_parser *bp,
1549 uint32_t id);
1550 static uint32_t get_ss_entry_number_from_ss_info_tbl(
1551 struct bios_parser *bp,
1552 uint32_t id);
1555 * BiosParserObject::GetNumberofSpreadSpectrumEntry
1556 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
1557 * the VBIOS that match the SSid (to be converted from signal)
1559 * @param[in] signal, ASSignalType to be converted to SSid
1560 * @return number of SS Entry that match the signal
1562 static uint32_t bios_parser_get_ss_entry_number(
1563 struct dc_bios *dcb,
1564 enum as_signal_type signal)
1566 struct bios_parser *bp = BP_FROM_DCB(dcb);
1567 uint32_t ss_id = 0;
1568 ATOM_COMMON_TABLE_HEADER *header;
1569 struct atom_data_revision revision;
1571 ss_id = signal_to_ss_id(signal);
1573 if (!DATA_TABLES(ASIC_InternalSS_Info))
1574 return get_ss_entry_number_from_ss_info_tbl(bp, ss_id);
1576 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1577 DATA_TABLES(ASIC_InternalSS_Info));
1578 get_atom_data_table_revision(header, &revision);
1580 switch (revision.major) {
1581 case 2:
1582 switch (revision.minor) {
1583 case 1:
1584 return get_ss_entry_number(bp, ss_id);
1585 default:
1586 break;
1588 break;
1589 case 3:
1590 switch (revision.minor) {
1591 case 1:
1592 return
1593 get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1594 bp, ss_id);
1595 default:
1596 break;
1598 break;
1599 default:
1600 break;
1603 return 0;
1607 * get_ss_entry_number_from_ss_info_tbl
1608 * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
1610 * @note There can only be one entry for each id for SS_Info Table
1612 * @param [in] id, spread spectrum id
1613 * @return number of SS Entry that match the id
1615 static uint32_t get_ss_entry_number_from_ss_info_tbl(
1616 struct bios_parser *bp,
1617 uint32_t id)
1619 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1620 ATOM_COMMON_TABLE_HEADER *header;
1621 uint32_t table_size;
1622 uint32_t i;
1623 uint32_t number = 0;
1624 uint32_t id_local = SS_ID_UNKNOWN;
1625 struct atom_data_revision revision;
1627 /* SS_Info table exist */
1628 if (!DATA_TABLES(SS_Info))
1629 return number;
1631 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1632 DATA_TABLES(SS_Info));
1633 get_atom_data_table_revision(header, &revision);
1635 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO,
1636 DATA_TABLES(SS_Info));
1638 if (1 != revision.major || 2 > revision.minor)
1639 return number;
1641 /* have to convert from Internal_SS format to SS_Info format */
1642 switch (id) {
1643 case ASIC_INTERNAL_SS_ON_DP:
1644 id_local = SS_ID_DP1;
1645 break;
1646 case ASIC_INTERNAL_SS_ON_LVDS: {
1647 struct embedded_panel_info panel_info;
1649 if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
1650 == BP_RESULT_OK)
1651 id_local = panel_info.ss_id;
1652 break;
1654 default:
1655 break;
1658 if (id_local == SS_ID_UNKNOWN)
1659 return number;
1661 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1662 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1663 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1665 for (i = 0; i < table_size; i++)
1666 if (id_local == (uint32_t)tbl->asSS_Info[i].ucSS_Id) {
1667 number = 1;
1668 break;
1671 return number;
1675 * get_ss_entry_number
1676 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
1677 * SS_Info table from the VBIOS
1678 * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
1679 * SS_Info.
1681 * @param id, spread sprectrum info index
1682 * @return Bios parser result code
1684 static uint32_t get_ss_entry_number(struct bios_parser *bp, uint32_t id)
1686 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1687 return get_ss_entry_number_from_ss_info_tbl(bp, id);
1689 return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp, id);
1693 * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
1694 * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
1695 * Ver 2.1 from the VBIOS
1696 * There will not be multiple entry for Ver 2.1
1698 * @param id, spread sprectrum info index
1699 * @return number of SS Entry that match the id
1701 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1702 struct bios_parser *bp,
1703 uint32_t id)
1705 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header_include;
1706 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1707 uint32_t size;
1708 uint32_t i;
1710 if (!DATA_TABLES(ASIC_InternalSS_Info))
1711 return 0;
1713 header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
1714 DATA_TABLES(ASIC_InternalSS_Info));
1716 size = (le16_to_cpu(header_include->sHeader.usStructureSize)
1717 - sizeof(ATOM_COMMON_TABLE_HEADER))
1718 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1720 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1721 &header_include->asSpreadSpectrum[0];
1722 for (i = 0; i < size; i++)
1723 if (tbl[i].ucClockIndication == (uint8_t)id)
1724 return 1;
1726 return 0;
1729 * get_ss_entry_number_from_internal_ss_info_table_V3_1
1730 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
1731 * the VBIOS that matches id
1733 * @param[in] id, spread sprectrum id
1734 * @return number of SS Entry that match the id
1736 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1737 struct bios_parser *bp,
1738 uint32_t id)
1740 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;
1746 if (!DATA_TABLES(ASIC_InternalSS_Info))
1747 return number;
1749 header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
1750 DATA_TABLES(ASIC_InternalSS_Info));
1751 size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
1752 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1753 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
1755 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
1756 &header_include->asSpreadSpectrum[0];
1758 for (i = 0; i < size; i++)
1759 if (tbl[i].ucClockIndication == (uint8_t)id)
1760 number++;
1762 return number;
1766 * bios_parser_get_gpio_pin_info
1767 * Get GpioPin information of input gpio id
1769 * @param gpio_id, GPIO ID
1770 * @param info, GpioPin information structure
1771 * @return Bios parser result code
1772 * @note
1773 * to get the GPIO PIN INFO, we need:
1774 * 1. get the GPIO_ID from other object table, see GetHPDInfo()
1775 * 2. in DATA_TABLE.GPIO_Pin_LUT, search all records, to get the registerA
1776 * offset/mask
1778 static enum bp_result bios_parser_get_gpio_pin_info(
1779 struct dc_bios *dcb,
1780 uint32_t gpio_id,
1781 struct gpio_pin_info *info)
1783 struct bios_parser *bp = BP_FROM_DCB(dcb);
1784 ATOM_GPIO_PIN_LUT *header;
1785 uint32_t count = 0;
1786 uint32_t i = 0;
1788 if (!DATA_TABLES(GPIO_Pin_LUT))
1789 return BP_RESULT_BADBIOSTABLE;
1791 header = GET_IMAGE(ATOM_GPIO_PIN_LUT, DATA_TABLES(GPIO_Pin_LUT));
1792 if (!header)
1793 return BP_RESULT_BADBIOSTABLE;
1795 if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_PIN_LUT)
1796 > le16_to_cpu(header->sHeader.usStructureSize))
1797 return BP_RESULT_BADBIOSTABLE;
1799 if (1 != header->sHeader.ucTableContentRevision)
1800 return BP_RESULT_UNSUPPORTED;
1802 count = (le16_to_cpu(header->sHeader.usStructureSize)
1803 - sizeof(ATOM_COMMON_TABLE_HEADER))
1804 / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
1805 for (i = 0; i < count; ++i) {
1806 if (header->asGPIO_Pin[i].ucGPIO_ID != gpio_id)
1807 continue;
1809 info->offset =
1810 (uint32_t) le16_to_cpu(header->asGPIO_Pin[i].usGpioPin_AIndex);
1811 info->offset_y = info->offset + 2;
1812 info->offset_en = info->offset + 1;
1813 info->offset_mask = info->offset - 1;
1815 info->mask = (uint32_t) (1 <<
1816 header->asGPIO_Pin[i].ucGpioPinBitShift);
1817 info->mask_y = info->mask + 2;
1818 info->mask_en = info->mask + 1;
1819 info->mask_mask = info->mask - 1;
1821 return BP_RESULT_OK;
1824 return BP_RESULT_NORECORD;
1827 static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
1828 ATOM_I2C_RECORD *record,
1829 struct graphics_object_i2c_info *info)
1831 ATOM_GPIO_I2C_INFO *header;
1832 uint32_t count = 0;
1834 if (!info)
1835 return BP_RESULT_BADINPUT;
1837 /* get the GPIO_I2C info */
1838 if (!DATA_TABLES(GPIO_I2C_Info))
1839 return BP_RESULT_BADBIOSTABLE;
1841 header = GET_IMAGE(ATOM_GPIO_I2C_INFO, DATA_TABLES(GPIO_I2C_Info));
1842 if (!header)
1843 return BP_RESULT_BADBIOSTABLE;
1845 if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_I2C_ASSIGMENT)
1846 > le16_to_cpu(header->sHeader.usStructureSize))
1847 return BP_RESULT_BADBIOSTABLE;
1849 if (1 != header->sHeader.ucTableContentRevision)
1850 return BP_RESULT_UNSUPPORTED;
1852 /* get data count */
1853 count = (le16_to_cpu(header->sHeader.usStructureSize)
1854 - sizeof(ATOM_COMMON_TABLE_HEADER))
1855 / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
1856 if (count < record->sucI2cId.bfI2C_LineMux)
1857 return BP_RESULT_BADBIOSTABLE;
1859 /* get the GPIO_I2C_INFO */
1860 info->i2c_hw_assist = record->sucI2cId.bfHW_Capable;
1861 info->i2c_line = record->sucI2cId.bfI2C_LineMux;
1862 info->i2c_engine_id = record->sucI2cId.bfHW_EngineID;
1863 info->i2c_slave_address = record->ucI2CAddr;
1865 info->gpio_info.clk_mask_register_index =
1866 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkMaskRegisterIndex);
1867 info->gpio_info.clk_en_register_index =
1868 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkEnRegisterIndex);
1869 info->gpio_info.clk_y_register_index =
1870 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkY_RegisterIndex);
1871 info->gpio_info.clk_a_register_index =
1872 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkA_RegisterIndex);
1873 info->gpio_info.data_mask_register_index =
1874 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataMaskRegisterIndex);
1875 info->gpio_info.data_en_register_index =
1876 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataEnRegisterIndex);
1877 info->gpio_info.data_y_register_index =
1878 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataY_RegisterIndex);
1879 info->gpio_info.data_a_register_index =
1880 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataA_RegisterIndex);
1882 info->gpio_info.clk_mask_shift =
1883 header->asGPIO_Info[info->i2c_line].ucClkMaskShift;
1884 info->gpio_info.clk_en_shift =
1885 header->asGPIO_Info[info->i2c_line].ucClkEnShift;
1886 info->gpio_info.clk_y_shift =
1887 header->asGPIO_Info[info->i2c_line].ucClkY_Shift;
1888 info->gpio_info.clk_a_shift =
1889 header->asGPIO_Info[info->i2c_line].ucClkA_Shift;
1890 info->gpio_info.data_mask_shift =
1891 header->asGPIO_Info[info->i2c_line].ucDataMaskShift;
1892 info->gpio_info.data_en_shift =
1893 header->asGPIO_Info[info->i2c_line].ucDataEnShift;
1894 info->gpio_info.data_y_shift =
1895 header->asGPIO_Info[info->i2c_line].ucDataY_Shift;
1896 info->gpio_info.data_a_shift =
1897 header->asGPIO_Info[info->i2c_line].ucDataA_Shift;
1899 return BP_RESULT_OK;
1902 static bool dal_graphics_object_id_is_valid(struct graphics_object_id id)
1904 bool rc = true;
1906 switch (id.type) {
1907 case OBJECT_TYPE_UNKNOWN:
1908 rc = false;
1909 break;
1910 case OBJECT_TYPE_GPU:
1911 case OBJECT_TYPE_ENGINE:
1912 /* do NOT check for id.id == 0 */
1913 if (id.enum_id == ENUM_ID_UNKNOWN)
1914 rc = false;
1915 break;
1916 default:
1917 if (id.id == 0 || id.enum_id == ENUM_ID_UNKNOWN)
1918 rc = false;
1919 break;
1922 return rc;
1925 static bool dal_graphics_object_id_is_equal(
1926 struct graphics_object_id id1,
1927 struct graphics_object_id id2)
1929 if (false == dal_graphics_object_id_is_valid(id1)) {
1930 dm_output_to_console(
1931 "%s: Warning: comparing invalid object 'id1'!\n", __func__);
1932 return false;
1935 if (false == dal_graphics_object_id_is_valid(id2)) {
1936 dm_output_to_console(
1937 "%s: Warning: comparing invalid object 'id2'!\n", __func__);
1938 return false;
1941 if (id1.id == id2.id && id1.enum_id == id2.enum_id
1942 && id1.type == id2.type)
1943 return true;
1945 return false;
1948 static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
1949 struct graphics_object_id id)
1951 uint32_t offset;
1952 ATOM_OBJECT_TABLE *tbl;
1953 uint32_t i;
1955 switch (id.type) {
1956 case OBJECT_TYPE_ENCODER:
1957 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
1958 break;
1960 case OBJECT_TYPE_CONNECTOR:
1961 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
1962 break;
1964 case OBJECT_TYPE_ROUTER:
1965 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usRouterObjectTableOffset);
1966 break;
1968 case OBJECT_TYPE_GENERIC:
1969 if (bp->object_info_tbl.revision.minor < 3)
1970 return NULL;
1971 offset = le16_to_cpu(bp->object_info_tbl.v1_3->usMiscObjectTableOffset);
1972 break;
1974 default:
1975 return NULL;
1978 offset += bp->object_info_tbl_offset;
1980 tbl = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
1981 if (!tbl)
1982 return NULL;
1984 for (i = 0; i < tbl->ucNumberOfObjects; i++)
1985 if (dal_graphics_object_id_is_equal(id,
1986 object_id_from_bios_object_id(
1987 le16_to_cpu(tbl->asObjects[i].usObjectID))))
1988 return &tbl->asObjects[i];
1990 return NULL;
1993 static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
1994 uint16_t **id_list)
1996 uint32_t offset;
1997 uint8_t *number;
1999 if (!object) {
2000 BREAK_TO_DEBUGGER(); /* Invalid object id */
2001 return 0;
2004 offset = le16_to_cpu(object->usSrcDstTableOffset)
2005 + bp->object_info_tbl_offset;
2007 number = GET_IMAGE(uint8_t, offset);
2008 if (!number)
2009 return 0;
2011 offset += sizeof(uint8_t);
2012 *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
2014 if (!*id_list)
2015 return 0;
2017 return *number;
2020 static struct device_id device_type_from_device_id(uint16_t device_id)
2023 struct device_id result_device_id = {0};
2025 switch (device_id) {
2026 case ATOM_DEVICE_LCD1_SUPPORT:
2027 result_device_id.device_type = DEVICE_TYPE_LCD;
2028 result_device_id.enum_id = 1;
2029 break;
2031 case ATOM_DEVICE_LCD2_SUPPORT:
2032 result_device_id.device_type = DEVICE_TYPE_LCD;
2033 result_device_id.enum_id = 2;
2034 break;
2036 case ATOM_DEVICE_CRT1_SUPPORT:
2037 result_device_id.device_type = DEVICE_TYPE_CRT;
2038 result_device_id.enum_id = 1;
2039 break;
2041 case ATOM_DEVICE_CRT2_SUPPORT:
2042 result_device_id.device_type = DEVICE_TYPE_CRT;
2043 result_device_id.enum_id = 2;
2044 break;
2046 case ATOM_DEVICE_DFP1_SUPPORT:
2047 result_device_id.device_type = DEVICE_TYPE_DFP;
2048 result_device_id.enum_id = 1;
2049 break;
2051 case ATOM_DEVICE_DFP2_SUPPORT:
2052 result_device_id.device_type = DEVICE_TYPE_DFP;
2053 result_device_id.enum_id = 2;
2054 break;
2056 case ATOM_DEVICE_DFP3_SUPPORT:
2057 result_device_id.device_type = DEVICE_TYPE_DFP;
2058 result_device_id.enum_id = 3;
2059 break;
2061 case ATOM_DEVICE_DFP4_SUPPORT:
2062 result_device_id.device_type = DEVICE_TYPE_DFP;
2063 result_device_id.enum_id = 4;
2064 break;
2066 case ATOM_DEVICE_DFP5_SUPPORT:
2067 result_device_id.device_type = DEVICE_TYPE_DFP;
2068 result_device_id.enum_id = 5;
2069 break;
2071 case ATOM_DEVICE_DFP6_SUPPORT:
2072 result_device_id.device_type = DEVICE_TYPE_DFP;
2073 result_device_id.enum_id = 6;
2074 break;
2076 default:
2077 BREAK_TO_DEBUGGER(); /* Invalid device Id */
2078 result_device_id.device_type = DEVICE_TYPE_UNKNOWN;
2079 result_device_id.enum_id = 0;
2081 return result_device_id;
2084 static void get_atom_data_table_revision(
2085 ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
2086 struct atom_data_revision *tbl_revision)
2088 if (!tbl_revision)
2089 return;
2091 /* initialize the revision to 0 which is invalid revision */
2092 tbl_revision->major = 0;
2093 tbl_revision->minor = 0;
2095 if (!atom_data_tbl)
2096 return;
2098 tbl_revision->major =
2099 (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl);
2100 tbl_revision->minor =
2101 (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl);
2104 static uint32_t signal_to_ss_id(enum as_signal_type signal)
2106 uint32_t clk_id_ss = 0;
2108 switch (signal) {
2109 case AS_SIGNAL_TYPE_DVI:
2110 clk_id_ss = ASIC_INTERNAL_SS_ON_TMDS;
2111 break;
2112 case AS_SIGNAL_TYPE_HDMI:
2113 clk_id_ss = ASIC_INTERNAL_SS_ON_HDMI;
2114 break;
2115 case AS_SIGNAL_TYPE_LVDS:
2116 clk_id_ss = ASIC_INTERNAL_SS_ON_LVDS;
2117 break;
2118 case AS_SIGNAL_TYPE_DISPLAY_PORT:
2119 clk_id_ss = ASIC_INTERNAL_SS_ON_DP;
2120 break;
2121 case AS_SIGNAL_TYPE_GPU_PLL:
2122 clk_id_ss = ASIC_INTERNAL_GPUPLL_SS;
2123 break;
2124 default:
2125 break;
2127 return clk_id_ss;
2130 static uint32_t get_support_mask_for_device_id(struct device_id device_id)
2132 enum dal_device_type device_type = device_id.device_type;
2133 uint32_t enum_id = device_id.enum_id;
2135 switch (device_type) {
2136 case DEVICE_TYPE_LCD:
2137 switch (enum_id) {
2138 case 1:
2139 return ATOM_DEVICE_LCD1_SUPPORT;
2140 case 2:
2141 return ATOM_DEVICE_LCD2_SUPPORT;
2142 default:
2143 break;
2145 break;
2146 case DEVICE_TYPE_CRT:
2147 switch (enum_id) {
2148 case 1:
2149 return ATOM_DEVICE_CRT1_SUPPORT;
2150 case 2:
2151 return ATOM_DEVICE_CRT2_SUPPORT;
2152 default:
2153 break;
2155 break;
2156 case DEVICE_TYPE_DFP:
2157 switch (enum_id) {
2158 case 1:
2159 return ATOM_DEVICE_DFP1_SUPPORT;
2160 case 2:
2161 return ATOM_DEVICE_DFP2_SUPPORT;
2162 case 3:
2163 return ATOM_DEVICE_DFP3_SUPPORT;
2164 case 4:
2165 return ATOM_DEVICE_DFP4_SUPPORT;
2166 case 5:
2167 return ATOM_DEVICE_DFP5_SUPPORT;
2168 case 6:
2169 return ATOM_DEVICE_DFP6_SUPPORT;
2170 default:
2171 break;
2173 break;
2174 case DEVICE_TYPE_CV:
2175 switch (enum_id) {
2176 case 1:
2177 return ATOM_DEVICE_CV_SUPPORT;
2178 default:
2179 break;
2181 break;
2182 case DEVICE_TYPE_TV:
2183 switch (enum_id) {
2184 case 1:
2185 return ATOM_DEVICE_TV1_SUPPORT;
2186 default:
2187 break;
2189 break;
2190 default:
2191 break;
2194 /* Unidentified device ID, return empty support mask. */
2195 return 0;
2199 * bios_parser_set_scratch_critical_state
2201 * @brief
2202 * update critical state bit in VBIOS scratch register
2204 * @param
2205 * bool - to set or reset state
2207 static void bios_parser_set_scratch_critical_state(
2208 struct dc_bios *dcb,
2209 bool state)
2211 bios_set_scratch_critical_state(dcb, state);
2215 * get_integrated_info_v8
2217 * @brief
2218 * Get V8 integrated BIOS information
2220 * @param
2221 * bios_parser *bp - [in]BIOS parser handler to get master data table
2222 * integrated_info *info - [out] store and output integrated info
2224 * @return
2225 * enum bp_result - BP_RESULT_OK if information is available,
2226 * BP_RESULT_BADBIOSTABLE otherwise.
2228 static enum bp_result get_integrated_info_v8(
2229 struct bios_parser *bp,
2230 struct integrated_info *info)
2232 ATOM_INTEGRATED_SYSTEM_INFO_V1_8 *info_v8;
2233 uint32_t i;
2235 info_v8 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8,
2236 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2238 if (info_v8 == NULL)
2239 return BP_RESULT_BADBIOSTABLE;
2240 info->boot_up_engine_clock = le32_to_cpu(info_v8->ulBootUpEngineClock) * 10;
2241 info->dentist_vco_freq = le32_to_cpu(info_v8->ulDentistVCOFreq) * 10;
2242 info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
2244 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2245 /* Convert [10KHz] into [KHz] */
2246 info->disp_clk_voltage[i].max_supported_clk =
2247 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].
2248 ulMaximumSupportedCLK) * 10;
2249 info->disp_clk_voltage[i].voltage_index =
2250 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
2253 info->boot_up_req_display_vector =
2254 le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
2255 info->gpu_cap_info =
2256 le32_to_cpu(info_v8->ulGPUCapInfo);
2259 * system_config: Bit[0] = 0 : PCIE power gating disabled
2260 * = 1 : PCIE power gating enabled
2261 * Bit[1] = 0 : DDR-PLL shut down disabled
2262 * = 1 : DDR-PLL shut down enabled
2263 * Bit[2] = 0 : DDR-PLL power down disabled
2264 * = 1 : DDR-PLL power down enabled
2266 info->system_config = le32_to_cpu(info_v8->ulSystemConfig);
2267 info->cpu_cap_info = le32_to_cpu(info_v8->ulCPUCapInfo);
2268 info->boot_up_nb_voltage =
2269 le16_to_cpu(info_v8->usBootUpNBVoltage);
2270 info->ext_disp_conn_info_offset =
2271 le16_to_cpu(info_v8->usExtDispConnInfoOffset);
2272 info->memory_type = info_v8->ucMemoryType;
2273 info->ma_channel_number = info_v8->ucUMAChannelNumber;
2274 info->gmc_restore_reset_time =
2275 le32_to_cpu(info_v8->ulGMCRestoreResetTime);
2277 info->minimum_n_clk =
2278 le32_to_cpu(info_v8->ulNbpStateNClkFreq[0]);
2279 for (i = 1; i < 4; ++i)
2280 info->minimum_n_clk =
2281 info->minimum_n_clk < le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]) ?
2282 info->minimum_n_clk : le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]);
2284 info->idle_n_clk = le32_to_cpu(info_v8->ulIdleNClk);
2285 info->ddr_dll_power_up_time =
2286 le32_to_cpu(info_v8->ulDDR_DLL_PowerUpTime);
2287 info->ddr_pll_power_up_time =
2288 le32_to_cpu(info_v8->ulDDR_PLL_PowerUpTime);
2289 info->pcie_clk_ss_type = le16_to_cpu(info_v8->usPCIEClkSSType);
2290 info->lvds_ss_percentage =
2291 le16_to_cpu(info_v8->usLvdsSSPercentage);
2292 info->lvds_sspread_rate_in_10hz =
2293 le16_to_cpu(info_v8->usLvdsSSpreadRateIn10Hz);
2294 info->hdmi_ss_percentage =
2295 le16_to_cpu(info_v8->usHDMISSPercentage);
2296 info->hdmi_sspread_rate_in_10hz =
2297 le16_to_cpu(info_v8->usHDMISSpreadRateIn10Hz);
2298 info->dvi_ss_percentage =
2299 le16_to_cpu(info_v8->usDVISSPercentage);
2300 info->dvi_sspread_rate_in_10_hz =
2301 le16_to_cpu(info_v8->usDVISSpreadRateIn10Hz);
2303 info->max_lvds_pclk_freq_in_single_link =
2304 le16_to_cpu(info_v8->usMaxLVDSPclkFreqInSingleLink);
2305 info->lvds_misc = info_v8->ucLvdsMisc;
2306 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
2307 info_v8->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
2308 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
2309 info_v8->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
2310 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
2311 info_v8->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
2312 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
2313 info_v8->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
2314 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
2315 info_v8->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
2316 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
2317 info_v8->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
2318 info->lvds_off_to_on_delay_in_4ms =
2319 info_v8->ucLVDSOffToOnDelay_in4Ms;
2320 info->lvds_bit_depth_control_val =
2321 le32_to_cpu(info_v8->ulLCDBitDepthControlVal);
2323 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
2324 /* Convert [10KHz] into [KHz] */
2325 info->avail_s_clk[i].supported_s_clk =
2326 le32_to_cpu(info_v8->sAvail_SCLK[i].ulSupportedSCLK) * 10;
2327 info->avail_s_clk[i].voltage_index =
2328 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageIndex);
2329 info->avail_s_clk[i].voltage_id =
2330 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageID);
2333 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
2334 info->ext_disp_conn_info.gu_id[i] =
2335 info_v8->sExtDispConnInfo.ucGuid[i];
2338 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
2339 info->ext_disp_conn_info.path[i].device_connector_id =
2340 object_id_from_bios_object_id(
2341 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceConnector));
2343 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
2344 object_id_from_bios_object_id(
2345 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
2347 info->ext_disp_conn_info.path[i].device_tag =
2348 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceTag);
2349 info->ext_disp_conn_info.path[i].device_acpi_enum =
2350 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
2351 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
2352 info_v8->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
2353 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
2354 info_v8->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
2355 info->ext_disp_conn_info.path[i].channel_mapping.raw =
2356 info_v8->sExtDispConnInfo.sPath[i].ucChannelMapping;
2358 info->ext_disp_conn_info.checksum =
2359 info_v8->sExtDispConnInfo.ucChecksum;
2361 return BP_RESULT_OK;
2365 * get_integrated_info_v8
2367 * @brief
2368 * Get V8 integrated BIOS information
2370 * @param
2371 * bios_parser *bp - [in]BIOS parser handler to get master data table
2372 * integrated_info *info - [out] store and output integrated info
2374 * @return
2375 * enum bp_result - BP_RESULT_OK if information is available,
2376 * BP_RESULT_BADBIOSTABLE otherwise.
2378 static enum bp_result get_integrated_info_v9(
2379 struct bios_parser *bp,
2380 struct integrated_info *info)
2382 ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info_v9;
2383 uint32_t i;
2385 info_v9 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9,
2386 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2388 if (!info_v9)
2389 return BP_RESULT_BADBIOSTABLE;
2391 info->boot_up_engine_clock = le32_to_cpu(info_v9->ulBootUpEngineClock) * 10;
2392 info->dentist_vco_freq = le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
2393 info->boot_up_uma_clock = le32_to_cpu(info_v9->ulBootUpUMAClock) * 10;
2395 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2396 /* Convert [10KHz] into [KHz] */
2397 info->disp_clk_voltage[i].max_supported_clk =
2398 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
2399 info->disp_clk_voltage[i].voltage_index =
2400 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
2403 info->boot_up_req_display_vector =
2404 le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
2405 info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
2408 * system_config: Bit[0] = 0 : PCIE power gating disabled
2409 * = 1 : PCIE power gating enabled
2410 * Bit[1] = 0 : DDR-PLL shut down disabled
2411 * = 1 : DDR-PLL shut down enabled
2412 * Bit[2] = 0 : DDR-PLL power down disabled
2413 * = 1 : DDR-PLL power down enabled
2415 info->system_config = le32_to_cpu(info_v9->ulSystemConfig);
2416 info->cpu_cap_info = le32_to_cpu(info_v9->ulCPUCapInfo);
2417 info->boot_up_nb_voltage = le16_to_cpu(info_v9->usBootUpNBVoltage);
2418 info->ext_disp_conn_info_offset = le16_to_cpu(info_v9->usExtDispConnInfoOffset);
2419 info->memory_type = info_v9->ucMemoryType;
2420 info->ma_channel_number = info_v9->ucUMAChannelNumber;
2421 info->gmc_restore_reset_time = le32_to_cpu(info_v9->ulGMCRestoreResetTime);
2423 info->minimum_n_clk = le32_to_cpu(info_v9->ulNbpStateNClkFreq[0]);
2424 for (i = 1; i < 4; ++i)
2425 info->minimum_n_clk =
2426 info->minimum_n_clk < le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]) ?
2427 info->minimum_n_clk : le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]);
2429 info->idle_n_clk = le32_to_cpu(info_v9->ulIdleNClk);
2430 info->ddr_dll_power_up_time = le32_to_cpu(info_v9->ulDDR_DLL_PowerUpTime);
2431 info->ddr_pll_power_up_time = le32_to_cpu(info_v9->ulDDR_PLL_PowerUpTime);
2432 info->pcie_clk_ss_type = le16_to_cpu(info_v9->usPCIEClkSSType);
2433 info->lvds_ss_percentage = le16_to_cpu(info_v9->usLvdsSSPercentage);
2434 info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v9->usLvdsSSpreadRateIn10Hz);
2435 info->hdmi_ss_percentage = le16_to_cpu(info_v9->usHDMISSPercentage);
2436 info->hdmi_sspread_rate_in_10hz = le16_to_cpu(info_v9->usHDMISSpreadRateIn10Hz);
2437 info->dvi_ss_percentage = le16_to_cpu(info_v9->usDVISSPercentage);
2438 info->dvi_sspread_rate_in_10_hz = le16_to_cpu(info_v9->usDVISSpreadRateIn10Hz);
2440 info->max_lvds_pclk_freq_in_single_link =
2441 le16_to_cpu(info_v9->usMaxLVDSPclkFreqInSingleLink);
2442 info->lvds_misc = info_v9->ucLvdsMisc;
2443 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
2444 info_v9->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
2445 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
2446 info_v9->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
2447 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
2448 info_v9->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
2449 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
2450 info_v9->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
2451 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
2452 info_v9->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
2453 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
2454 info_v9->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
2455 info->lvds_off_to_on_delay_in_4ms =
2456 info_v9->ucLVDSOffToOnDelay_in4Ms;
2457 info->lvds_bit_depth_control_val =
2458 le32_to_cpu(info_v9->ulLCDBitDepthControlVal);
2460 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
2461 /* Convert [10KHz] into [KHz] */
2462 info->avail_s_clk[i].supported_s_clk =
2463 le32_to_cpu(info_v9->sAvail_SCLK[i].ulSupportedSCLK) * 10;
2464 info->avail_s_clk[i].voltage_index =
2465 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageIndex);
2466 info->avail_s_clk[i].voltage_id =
2467 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageID);
2470 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
2471 info->ext_disp_conn_info.gu_id[i] =
2472 info_v9->sExtDispConnInfo.ucGuid[i];
2475 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
2476 info->ext_disp_conn_info.path[i].device_connector_id =
2477 object_id_from_bios_object_id(
2478 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceConnector));
2480 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
2481 object_id_from_bios_object_id(
2482 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
2484 info->ext_disp_conn_info.path[i].device_tag =
2485 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceTag);
2486 info->ext_disp_conn_info.path[i].device_acpi_enum =
2487 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
2488 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
2489 info_v9->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
2490 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
2491 info_v9->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
2492 info->ext_disp_conn_info.path[i].channel_mapping.raw =
2493 info_v9->sExtDispConnInfo.sPath[i].ucChannelMapping;
2495 info->ext_disp_conn_info.checksum =
2496 info_v9->sExtDispConnInfo.ucChecksum;
2498 return BP_RESULT_OK;
2502 * construct_integrated_info
2504 * @brief
2505 * Get integrated BIOS information based on table revision
2507 * @param
2508 * bios_parser *bp - [in]BIOS parser handler to get master data table
2509 * integrated_info *info - [out] store and output integrated info
2511 * @return
2512 * enum bp_result - BP_RESULT_OK if information is available,
2513 * BP_RESULT_BADBIOSTABLE otherwise.
2515 static enum bp_result construct_integrated_info(
2516 struct bios_parser *bp,
2517 struct integrated_info *info)
2519 enum bp_result result = BP_RESULT_BADBIOSTABLE;
2521 ATOM_COMMON_TABLE_HEADER *header;
2522 struct atom_data_revision revision;
2524 if (bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo) {
2525 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
2526 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2528 get_atom_data_table_revision(header, &revision);
2530 /* Don't need to check major revision as they are all 1 */
2531 switch (revision.minor) {
2532 case 8:
2533 result = get_integrated_info_v8(bp, info);
2534 break;
2535 case 9:
2536 result = get_integrated_info_v9(bp, info);
2537 break;
2538 default:
2539 return result;
2544 /* Sort voltage table from low to high*/
2545 if (result == BP_RESULT_OK) {
2546 uint32_t i;
2547 uint32_t j;
2549 for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2550 for (j = i; j > 0; --j) {
2551 if (
2552 info->disp_clk_voltage[j].max_supported_clk <
2553 info->disp_clk_voltage[j-1].max_supported_clk) {
2554 /* swap j and j - 1*/
2555 swap(info->disp_clk_voltage[j - 1],
2556 info->disp_clk_voltage[j]);
2563 return result;
2566 static struct integrated_info *bios_parser_create_integrated_info(
2567 struct dc_bios *dcb)
2569 struct bios_parser *bp = BP_FROM_DCB(dcb);
2570 struct integrated_info *info = NULL;
2572 info = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);
2574 if (info == NULL) {
2575 ASSERT_CRITICAL(0);
2576 return NULL;
2579 if (construct_integrated_info(bp, info) == BP_RESULT_OK)
2580 return info;
2582 kfree(info);
2584 return NULL;
2587 enum bp_result update_slot_layout_info(
2588 struct dc_bios *dcb,
2589 unsigned int i,
2590 struct slot_layout_info *slot_layout_info,
2591 unsigned int record_offset)
2593 unsigned int j;
2594 struct bios_parser *bp;
2595 ATOM_BRACKET_LAYOUT_RECORD *record;
2596 ATOM_COMMON_RECORD_HEADER *record_header;
2597 enum bp_result result = BP_RESULT_NORECORD;
2599 bp = BP_FROM_DCB(dcb);
2600 record = NULL;
2601 record_header = NULL;
2603 for (;;) {
2605 record_header = (ATOM_COMMON_RECORD_HEADER *)
2606 GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
2607 if (record_header == NULL) {
2608 result = BP_RESULT_BADBIOSTABLE;
2609 break;
2612 /* the end of the list */
2613 if (record_header->ucRecordType == 0xff ||
2614 record_header->ucRecordSize == 0) {
2615 break;
2618 if (record_header->ucRecordType ==
2619 ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
2620 sizeof(ATOM_BRACKET_LAYOUT_RECORD)
2621 <= record_header->ucRecordSize) {
2622 record = (ATOM_BRACKET_LAYOUT_RECORD *)
2623 (record_header);
2624 result = BP_RESULT_OK;
2625 break;
2628 record_offset += record_header->ucRecordSize;
2631 /* return if the record not found */
2632 if (result != BP_RESULT_OK)
2633 return result;
2635 /* get slot sizes */
2636 slot_layout_info->length = record->ucLength;
2637 slot_layout_info->width = record->ucWidth;
2639 /* get info for each connector in the slot */
2640 slot_layout_info->num_of_connectors = record->ucConnNum;
2641 for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
2642 slot_layout_info->connectors[j].connector_type =
2643 (enum connector_layout_type)
2644 (record->asConnInfo[j].ucConnectorType);
2645 switch (record->asConnInfo[j].ucConnectorType) {
2646 case CONNECTOR_TYPE_DVI_D:
2647 slot_layout_info->connectors[j].connector_type =
2648 CONNECTOR_LAYOUT_TYPE_DVI_D;
2649 slot_layout_info->connectors[j].length =
2650 CONNECTOR_SIZE_DVI;
2651 break;
2653 case CONNECTOR_TYPE_HDMI:
2654 slot_layout_info->connectors[j].connector_type =
2655 CONNECTOR_LAYOUT_TYPE_HDMI;
2656 slot_layout_info->connectors[j].length =
2657 CONNECTOR_SIZE_HDMI;
2658 break;
2660 case CONNECTOR_TYPE_DISPLAY_PORT:
2661 slot_layout_info->connectors[j].connector_type =
2662 CONNECTOR_LAYOUT_TYPE_DP;
2663 slot_layout_info->connectors[j].length =
2664 CONNECTOR_SIZE_DP;
2665 break;
2667 case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
2668 slot_layout_info->connectors[j].connector_type =
2669 CONNECTOR_LAYOUT_TYPE_MINI_DP;
2670 slot_layout_info->connectors[j].length =
2671 CONNECTOR_SIZE_MINI_DP;
2672 break;
2674 default:
2675 slot_layout_info->connectors[j].connector_type =
2676 CONNECTOR_LAYOUT_TYPE_UNKNOWN;
2677 slot_layout_info->connectors[j].length =
2678 CONNECTOR_SIZE_UNKNOWN;
2681 slot_layout_info->connectors[j].position =
2682 record->asConnInfo[j].ucPosition;
2683 slot_layout_info->connectors[j].connector_id =
2684 object_id_from_bios_object_id(
2685 record->asConnInfo[j].usConnectorObjectId);
2687 return result;
2691 enum bp_result get_bracket_layout_record(
2692 struct dc_bios *dcb,
2693 unsigned int bracket_layout_id,
2694 struct slot_layout_info *slot_layout_info)
2696 unsigned int i;
2697 unsigned int record_offset;
2698 struct bios_parser *bp;
2699 enum bp_result result;
2700 ATOM_OBJECT *object;
2701 ATOM_OBJECT_TABLE *object_table;
2702 unsigned int genericTableOffset;
2704 bp = BP_FROM_DCB(dcb);
2705 object = NULL;
2706 if (slot_layout_info == NULL) {
2707 DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
2708 return BP_RESULT_BADINPUT;
2712 genericTableOffset = bp->object_info_tbl_offset +
2713 bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
2714 object_table = (ATOM_OBJECT_TABLE *)
2715 GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset);
2716 if (!object_table)
2717 return BP_RESULT_FAILURE;
2719 result = BP_RESULT_NORECORD;
2720 for (i = 0; i < object_table->ucNumberOfObjects; ++i) {
2722 if (bracket_layout_id ==
2723 object_table->asObjects[i].usObjectID) {
2725 object = &object_table->asObjects[i];
2726 record_offset = object->usRecordOffset +
2727 bp->object_info_tbl_offset;
2729 result = update_slot_layout_info(dcb, i,
2730 slot_layout_info, record_offset);
2731 break;
2734 return result;
2737 static enum bp_result bios_get_board_layout_info(
2738 struct dc_bios *dcb,
2739 struct board_layout_info *board_layout_info)
2741 unsigned int i;
2742 enum bp_result record_result;
2744 const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
2745 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
2746 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
2747 0, 0
2750 if (board_layout_info == NULL) {
2751 DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
2752 return BP_RESULT_BADINPUT;
2755 board_layout_info->num_of_slots = 0;
2757 for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
2758 record_result = get_bracket_layout_record(dcb,
2759 slot_index_to_vbios_id[i],
2760 &board_layout_info->slots[i]);
2762 if (record_result == BP_RESULT_NORECORD && i > 0)
2763 break; /* no more slots present in bios */
2764 else if (record_result != BP_RESULT_OK)
2765 return record_result; /* fail */
2767 ++board_layout_info->num_of_slots;
2770 /* all data is valid */
2771 board_layout_info->is_number_of_slots_valid = 1;
2772 board_layout_info->is_slots_size_valid = 1;
2773 board_layout_info->is_connector_offsets_valid = 1;
2774 board_layout_info->is_connector_lengths_valid = 1;
2776 return BP_RESULT_OK;
2779 /******************************************************************************/
2781 static const struct dc_vbios_funcs vbios_funcs = {
2782 .get_connectors_number = bios_parser_get_connectors_number,
2784 .get_connector_id = bios_parser_get_connector_id,
2786 .get_src_obj = bios_parser_get_src_obj,
2788 .get_i2c_info = bios_parser_get_i2c_info,
2790 .get_hpd_info = bios_parser_get_hpd_info,
2792 .get_device_tag = bios_parser_get_device_tag,
2794 .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info,
2796 .get_ss_entry_number = bios_parser_get_ss_entry_number,
2798 .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
2800 .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
2802 .get_encoder_cap_info = bios_parser_get_encoder_cap_info,
2804 /* bios scratch register communication */
2805 .is_accelerated_mode = bios_is_accelerated_mode,
2807 .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
2809 .is_device_id_supported = bios_parser_is_device_id_supported,
2811 /* COMMANDS */
2812 .encoder_control = bios_parser_encoder_control,
2814 .transmitter_control = bios_parser_transmitter_control,
2816 .enable_crtc = bios_parser_enable_crtc,
2818 .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
2820 .set_pixel_clock = bios_parser_set_pixel_clock,
2822 .set_dce_clock = bios_parser_set_dce_clock,
2824 .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
2826 .program_crtc_timing = bios_parser_program_crtc_timing, /* still use. should probably retire and program directly */
2828 .program_display_engine_pll = bios_parser_program_display_engine_pll,
2830 .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
2832 /* SW init and patch */
2834 .bios_parser_destroy = bios_parser_destroy,
2836 .get_board_layout_info = bios_get_board_layout_info,
2839 static bool bios_parser_construct(
2840 struct bios_parser *bp,
2841 struct bp_init_data *init,
2842 enum dce_version dce_version)
2844 uint16_t *rom_header_offset = NULL;
2845 ATOM_ROM_HEADER *rom_header = NULL;
2846 ATOM_OBJECT_HEADER *object_info_tbl;
2847 struct atom_data_revision tbl_rev = {0};
2849 if (!init)
2850 return false;
2852 if (!init->bios)
2853 return false;
2855 bp->base.funcs = &vbios_funcs;
2856 bp->base.bios = init->bios;
2857 bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
2859 bp->base.ctx = init->ctx;
2860 bp->base.bios_local_image = NULL;
2862 rom_header_offset =
2863 GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
2865 if (!rom_header_offset)
2866 return false;
2868 rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
2870 if (!rom_header)
2871 return false;
2873 get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev);
2874 if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
2875 return false;
2877 bp->master_data_tbl =
2878 GET_IMAGE(ATOM_MASTER_DATA_TABLE,
2879 rom_header->usMasterDataTableOffset);
2881 if (!bp->master_data_tbl)
2882 return false;
2884 bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
2886 if (!bp->object_info_tbl_offset)
2887 return false;
2889 object_info_tbl =
2890 GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
2892 if (!object_info_tbl)
2893 return false;
2895 get_atom_data_table_revision(&object_info_tbl->sHeader,
2896 &bp->object_info_tbl.revision);
2898 if (bp->object_info_tbl.revision.major == 1
2899 && bp->object_info_tbl.revision.minor >= 3) {
2900 ATOM_OBJECT_HEADER_V3 *tbl_v3;
2902 tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
2903 bp->object_info_tbl_offset);
2904 if (!tbl_v3)
2905 return false;
2907 bp->object_info_tbl.v1_3 = tbl_v3;
2908 } else if (bp->object_info_tbl.revision.major == 1
2909 && bp->object_info_tbl.revision.minor >= 1)
2910 bp->object_info_tbl.v1_1 = object_info_tbl;
2911 else
2912 return false;
2914 dal_bios_parser_init_cmd_tbl(bp);
2915 dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
2917 bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base);
2918 bp->base.fw_info_valid = bios_parser_get_firmware_info(&bp->base, &bp->base.fw_info) == BP_RESULT_OK;
2920 return true;
2923 /******************************************************************************/