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.
26 #include "dm_services.h"
30 #include "dc_bios_types.h"
31 #include "include/gpio_service_interface.h"
32 #include "include/grph_object_ctrl_defs.h"
33 #include "include/bios_parser_interface.h"
34 #include "include/i2caux_interface.h"
35 #include "include/logger_interface.h"
37 #include "command_table.h"
38 #include "bios_parser_helper.h"
39 #include "command_table_helper.h"
40 #include "bios_parser.h"
41 #include "bios_parser_types_internal.h"
42 #include "bios_parser_interface.h"
44 #include "bios_parser_common.h"
45 /* TODO remove - only needed for default i2c speed */
48 #define THREE_PERCENT_OF_10000 300
50 #define LAST_RECORD_TYPE 0xff
52 /* GUID to validate external display connection info table (aka OPM module) */
53 static const uint8_t ext_display_connection_guid[NUMBER_OF_UCHAR_FOR_GUID] = {
54 0x91, 0x6E, 0x57, 0x09,
55 0x3F, 0x6D, 0xD2, 0x11,
56 0x39, 0x8E, 0x00, 0xA0,
57 0xC9, 0x69, 0x72, 0x3B};
59 #define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
61 static void get_atom_data_table_revision(
62 ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
63 struct atom_data_revision *tbl_revision);
64 static uint32_t get_dst_number_from_object(struct bios_parser *bp,
66 static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
68 static uint32_t get_dest_obj_list(struct bios_parser *bp,
69 ATOM_OBJECT *object, uint16_t **id_list);
70 static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
71 struct graphics_object_id id);
72 static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
73 ATOM_I2C_RECORD *record,
74 struct graphics_object_i2c_info *info);
75 static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
77 static struct device_id device_type_from_device_id(uint16_t device_id);
78 static uint32_t signal_to_ss_id(enum as_signal_type signal);
79 static uint32_t get_support_mask_for_device_id(struct device_id device_id);
80 static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
81 struct bios_parser *bp,
84 #define BIOS_IMAGE_SIZE_OFFSET 2
85 #define BIOS_IMAGE_SIZE_UNIT 512
87 /*****************************************************************************/
88 static bool bios_parser_construct(
89 struct bios_parser *bp,
90 struct bp_init_data *init,
91 enum dce_version dce_version);
93 static uint8_t bios_parser_get_connectors_number(
96 static enum bp_result bios_parser_get_embedded_panel_info(
98 struct embedded_panel_info *info);
100 /*****************************************************************************/
102 struct dc_bios *bios_parser_create(
103 struct bp_init_data *init,
104 enum dce_version dce_version)
106 struct bios_parser *bp = NULL;
108 bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
112 if (bios_parser_construct(bp, init, dce_version))
120 static void destruct(struct bios_parser *bp)
122 kfree(bp->base.bios_local_image);
123 kfree(bp->base.integrated_info);
126 static void bios_parser_destroy(struct dc_bios **dcb)
128 struct bios_parser *bp = BP_FROM_DCB(*dcb);
141 static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
143 ATOM_OBJECT_TABLE *table;
145 uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
147 table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
152 return table->ucNumberOfObjects;
155 static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb)
157 struct bios_parser *bp = BP_FROM_DCB(dcb);
159 return get_number_of_objects(bp,
160 le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
163 static struct graphics_object_id bios_parser_get_encoder_id(
167 struct bios_parser *bp = BP_FROM_DCB(dcb);
168 struct graphics_object_id object_id = dal_graphics_object_id_init(
169 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
171 uint32_t encoder_table_offset = bp->object_info_tbl_offset
172 + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
174 ATOM_OBJECT_TABLE *tbl =
175 GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
177 if (tbl && tbl->ucNumberOfObjects > i) {
178 const uint16_t id = le16_to_cpu(tbl->asObjects[i].usObjectID);
180 object_id = object_id_from_bios_object_id(id);
186 static struct graphics_object_id bios_parser_get_connector_id(
190 struct bios_parser *bp = BP_FROM_DCB(dcb);
191 struct graphics_object_id object_id = dal_graphics_object_id_init(
192 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
195 uint32_t connector_table_offset = bp->object_info_tbl_offset
196 + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
198 ATOM_OBJECT_TABLE *tbl =
199 GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
202 dm_error("Can't get connector table from atom bios.\n");
206 if (tbl->ucNumberOfObjects <= i) {
207 dm_error("Can't find connector id %d in connector table of size %d.\n",
208 i, tbl->ucNumberOfObjects);
212 id = le16_to_cpu(tbl->asObjects[i].usObjectID);
213 object_id = object_id_from_bios_object_id(id);
217 static uint32_t bios_parser_get_dst_number(struct dc_bios *dcb,
218 struct graphics_object_id id)
220 struct bios_parser *bp = BP_FROM_DCB(dcb);
221 ATOM_OBJECT *object = get_bios_object(bp, id);
223 return get_dst_number_from_object(bp, object);
226 static enum bp_result bios_parser_get_src_obj(struct dc_bios *dcb,
227 struct graphics_object_id object_id, uint32_t index,
228 struct graphics_object_id *src_object_id)
233 struct bios_parser *bp = BP_FROM_DCB(dcb);
236 return BP_RESULT_BADINPUT;
238 object = get_bios_object(bp, object_id);
241 BREAK_TO_DEBUGGER(); /* Invalid object id */
242 return BP_RESULT_BADINPUT;
245 number = get_src_obj_list(bp, object, &id);
248 return BP_RESULT_BADINPUT;
250 *src_object_id = object_id_from_bios_object_id(id[index]);
255 static enum bp_result bios_parser_get_dst_obj(struct dc_bios *dcb,
256 struct graphics_object_id object_id, uint32_t index,
257 struct graphics_object_id *dest_object_id)
262 struct bios_parser *bp = BP_FROM_DCB(dcb);
265 return BP_RESULT_BADINPUT;
267 object = get_bios_object(bp, object_id);
269 number = get_dest_obj_list(bp, object, &id);
271 if (number <= index || !id)
272 return BP_RESULT_BADINPUT;
274 *dest_object_id = object_id_from_bios_object_id(id[index]);
279 static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
280 struct graphics_object_id id,
281 struct graphics_object_i2c_info *info)
285 ATOM_COMMON_RECORD_HEADER *header;
286 ATOM_I2C_RECORD *record;
287 struct bios_parser *bp = BP_FROM_DCB(dcb);
290 return BP_RESULT_BADINPUT;
292 object = get_bios_object(bp, id);
295 return BP_RESULT_BADINPUT;
297 offset = le16_to_cpu(object->usRecordOffset)
298 + bp->object_info_tbl_offset;
301 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
304 return BP_RESULT_BADBIOSTABLE;
306 if (LAST_RECORD_TYPE == header->ucRecordType ||
307 !header->ucRecordSize)
310 if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
311 && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
312 /* get the I2C info */
313 record = (ATOM_I2C_RECORD *) header;
315 if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
319 offset += header->ucRecordSize;
322 return BP_RESULT_NORECORD;
325 static enum bp_result get_voltage_ddc_info_v1(uint8_t *i2c_line,
326 ATOM_COMMON_TABLE_HEADER *header,
329 enum bp_result result = BP_RESULT_NORECORD;
330 ATOM_VOLTAGE_OBJECT_INFO *info =
331 (ATOM_VOLTAGE_OBJECT_INFO *) address;
333 uint8_t *voltage_current_object = (uint8_t *) &info->asVoltageObj[0];
335 while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
336 ATOM_VOLTAGE_OBJECT *object =
337 (ATOM_VOLTAGE_OBJECT *) voltage_current_object;
339 if ((object->ucVoltageType == SET_VOLTAGE_INIT_MODE) &&
340 (object->ucVoltageType &
341 VOLTAGE_CONTROLLED_BY_I2C_MASK)) {
343 *i2c_line = object->asControl.ucVoltageControlI2cLine
345 result = BP_RESULT_OK;
349 voltage_current_object += object->ucSize;
354 static enum bp_result get_voltage_ddc_info_v3(uint8_t *i2c_line,
356 ATOM_COMMON_TABLE_HEADER *header,
359 enum bp_result result = BP_RESULT_NORECORD;
360 ATOM_VOLTAGE_OBJECT_INFO_V3_1 *info =
361 (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *) address;
363 uint8_t *voltage_current_object =
364 (uint8_t *) (&(info->asVoltageObj[0]));
366 while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
367 ATOM_I2C_VOLTAGE_OBJECT_V3 *object =
368 (ATOM_I2C_VOLTAGE_OBJECT_V3 *) voltage_current_object;
370 if (object->sHeader.ucVoltageMode ==
371 ATOM_INIT_VOLTAGE_REGULATOR) {
372 if (object->sHeader.ucVoltageType == index) {
373 *i2c_line = object->ucVoltageControlI2cLine
375 result = BP_RESULT_OK;
380 voltage_current_object += le16_to_cpu(object->sHeader.usSize);
385 static enum bp_result bios_parser_get_thermal_ddc_info(
387 uint32_t i2c_channel_id,
388 struct graphics_object_i2c_info *info)
390 struct bios_parser *bp = BP_FROM_DCB(dcb);
391 ATOM_I2C_ID_CONFIG_ACCESS *config;
392 ATOM_I2C_RECORD record;
395 return BP_RESULT_BADINPUT;
397 config = (ATOM_I2C_ID_CONFIG_ACCESS *) &i2c_channel_id;
399 record.sucI2cId.bfHW_Capable = config->sbfAccess.bfHW_Capable;
400 record.sucI2cId.bfI2C_LineMux = config->sbfAccess.bfI2C_LineMux;
401 record.sucI2cId.bfHW_EngineID = config->sbfAccess.bfHW_EngineID;
403 return get_gpio_i2c_info(bp, &record, info);
406 static enum bp_result bios_parser_get_voltage_ddc_info(struct dc_bios *dcb,
408 struct graphics_object_i2c_info *info)
410 uint8_t i2c_line = 0;
411 enum bp_result result = BP_RESULT_NORECORD;
412 uint8_t *voltage_info_address;
413 ATOM_COMMON_TABLE_HEADER *header;
414 struct atom_data_revision revision = {0};
415 struct bios_parser *bp = BP_FROM_DCB(dcb);
417 if (!DATA_TABLES(VoltageObjectInfo))
420 voltage_info_address = bios_get_image(&bp->base, DATA_TABLES(VoltageObjectInfo), sizeof(ATOM_COMMON_TABLE_HEADER));
422 header = (ATOM_COMMON_TABLE_HEADER *) voltage_info_address;
424 get_atom_data_table_revision(header, &revision);
426 switch (revision.major) {
429 result = get_voltage_ddc_info_v1(&i2c_line, header,
430 voltage_info_address);
433 if (revision.minor != 1)
435 result = get_voltage_ddc_info_v3(&i2c_line, index, header,
436 voltage_info_address);
440 if (result == BP_RESULT_OK)
441 result = bios_parser_get_thermal_ddc_info(dcb,
447 /* TODO: temporary commented out to suppress 'defined but not used' warning */
449 static enum bp_result bios_parser_get_ddc_info_for_i2c_line(
450 struct bios_parser *bp,
451 uint8_t i2c_line, struct graphics_object_i2c_info *info)
455 ATOM_OBJECT_TABLE *table;
459 return BP_RESULT_BADINPUT;
461 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
463 offset += bp->object_info_tbl_offset;
465 table = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
468 return BP_RESULT_BADBIOSTABLE;
470 for (i = 0; i < table->ucNumberOfObjects; i++) {
471 object = &table->asObjects[i];
474 BREAK_TO_DEBUGGER(); /* Invalid object id */
475 return BP_RESULT_BADINPUT;
478 offset = le16_to_cpu(object->usRecordOffset)
479 + bp->object_info_tbl_offset;
482 ATOM_COMMON_RECORD_HEADER *header =
483 GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
486 return BP_RESULT_BADBIOSTABLE;
488 offset += header->ucRecordSize;
490 if (LAST_RECORD_TYPE == header->ucRecordType ||
491 !header->ucRecordSize)
494 if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
495 && sizeof(ATOM_I2C_RECORD) <=
496 header->ucRecordSize) {
497 ATOM_I2C_RECORD *record =
498 (ATOM_I2C_RECORD *) header;
500 if (i2c_line != record->sucI2cId.bfI2C_LineMux)
503 /* get the I2C info */
504 if (get_gpio_i2c_info(bp, record, info) ==
511 return BP_RESULT_NORECORD;
515 static enum bp_result bios_parser_get_hpd_info(struct dc_bios *dcb,
516 struct graphics_object_id id,
517 struct graphics_object_hpd_info *info)
519 struct bios_parser *bp = BP_FROM_DCB(dcb);
521 ATOM_HPD_INT_RECORD *record = NULL;
524 return BP_RESULT_BADINPUT;
526 object = get_bios_object(bp, id);
529 return BP_RESULT_BADINPUT;
531 record = get_hpd_record(bp, object);
533 if (record != NULL) {
534 info->hpd_int_gpio_uid = record->ucHPDIntGPIOID;
535 info->hpd_active = record->ucPlugged_PinState;
539 return BP_RESULT_NORECORD;
542 static enum bp_result bios_parser_get_device_tag_record(
543 struct bios_parser *bp,
545 ATOM_CONNECTOR_DEVICE_TAG_RECORD **record)
547 ATOM_COMMON_RECORD_HEADER *header;
550 offset = le16_to_cpu(object->usRecordOffset)
551 + bp->object_info_tbl_offset;
554 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
557 return BP_RESULT_BADBIOSTABLE;
559 offset += header->ucRecordSize;
561 if (LAST_RECORD_TYPE == header->ucRecordType ||
562 !header->ucRecordSize)
565 if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
566 header->ucRecordType)
569 if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
572 *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
576 return BP_RESULT_NORECORD;
579 static enum bp_result bios_parser_get_device_tag(
581 struct graphics_object_id connector_object_id,
582 uint32_t device_tag_index,
583 struct connector_device_tag_info *info)
585 struct bios_parser *bp = BP_FROM_DCB(dcb);
587 ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
588 ATOM_CONNECTOR_DEVICE_TAG *device_tag;
591 return BP_RESULT_BADINPUT;
593 /* getBiosObject will return MXM object */
594 object = get_bios_object(bp, connector_object_id);
597 BREAK_TO_DEBUGGER(); /* Invalid object id */
598 return BP_RESULT_BADINPUT;
601 if (bios_parser_get_device_tag_record(bp, object, &record)
603 return BP_RESULT_NORECORD;
605 if (device_tag_index >= record->ucNumberOfDevice)
606 return BP_RESULT_NORECORD;
608 device_tag = &record->asDeviceTag[device_tag_index];
610 info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
612 device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
617 static enum bp_result get_firmware_info_v1_4(
618 struct bios_parser *bp,
619 struct dc_firmware_info *info);
620 static enum bp_result get_firmware_info_v2_1(
621 struct bios_parser *bp,
622 struct dc_firmware_info *info);
623 static enum bp_result get_firmware_info_v2_2(
624 struct bios_parser *bp,
625 struct dc_firmware_info *info);
627 static enum bp_result bios_parser_get_firmware_info(
629 struct dc_firmware_info *info)
631 struct bios_parser *bp = BP_FROM_DCB(dcb);
632 enum bp_result result = BP_RESULT_BADBIOSTABLE;
633 ATOM_COMMON_TABLE_HEADER *header;
634 struct atom_data_revision revision;
636 if (info && DATA_TABLES(FirmwareInfo)) {
637 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
638 DATA_TABLES(FirmwareInfo));
639 get_atom_data_table_revision(header, &revision);
640 switch (revision.major) {
642 switch (revision.minor) {
644 result = get_firmware_info_v1_4(bp, info);
652 switch (revision.minor) {
654 result = get_firmware_info_v2_1(bp, info);
657 result = get_firmware_info_v2_2(bp, info);
671 static enum bp_result get_firmware_info_v1_4(
672 struct bios_parser *bp,
673 struct dc_firmware_info *info)
675 ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
676 GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
677 DATA_TABLES(FirmwareInfo));
680 return BP_RESULT_BADINPUT;
683 return BP_RESULT_BADBIOSTABLE;
685 memset(info, 0, sizeof(*info));
687 /* Pixel clock pll information. We need to convert from 10KHz units into
689 info->pll_info.crystal_frequency =
690 le16_to_cpu(firmware_info->usReferenceClock) * 10;
691 info->pll_info.min_input_pxl_clk_pll_frequency =
692 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
693 info->pll_info.max_input_pxl_clk_pll_frequency =
694 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
695 info->pll_info.min_output_pxl_clk_pll_frequency =
696 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
697 info->pll_info.max_output_pxl_clk_pll_frequency =
698 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
700 if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
701 /* Since there is no information on the SS, report conservative
702 * value 3% for bandwidth calculation */
704 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
706 if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
707 /* Since there is no information on the SS,report conservative
708 * value 3% for bandwidth calculation */
710 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
715 static enum bp_result get_ss_info_v3_1(
716 struct bios_parser *bp,
719 struct spread_spectrum_info *ss_info);
721 static enum bp_result get_firmware_info_v2_1(
722 struct bios_parser *bp,
723 struct dc_firmware_info *info)
725 ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
726 GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
727 struct spread_spectrum_info internalSS;
731 return BP_RESULT_BADINPUT;
734 return BP_RESULT_BADBIOSTABLE;
736 memset(info, 0, sizeof(*info));
738 /* Pixel clock pll information. We need to convert from 10KHz units into
740 info->pll_info.crystal_frequency =
741 le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
742 info->pll_info.min_input_pxl_clk_pll_frequency =
743 le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
744 info->pll_info.max_input_pxl_clk_pll_frequency =
745 le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
746 info->pll_info.min_output_pxl_clk_pll_frequency =
747 le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
748 info->pll_info.max_output_pxl_clk_pll_frequency =
749 le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
750 info->default_display_engine_pll_frequency =
751 le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
752 info->external_clock_source_frequency_for_dp =
753 le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
754 info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
756 /* There should be only one entry in the SS info table for Memory Clock
759 if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
760 /* Since there is no information for external SS, report
761 * conservative value 3% for bandwidth calculation */
763 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
764 else if (get_ss_info_v3_1(bp,
765 ASIC_INTERNAL_MEMORY_SS, index, &internalSS) == BP_RESULT_OK) {
766 if (internalSS.spread_spectrum_percentage) {
767 info->feature.memory_clk_ss_percentage =
768 internalSS.spread_spectrum_percentage;
769 if (internalSS.type.CENTER_MODE) {
770 /* if it is centermode, the exact SS Percentage
771 * will be round up of half of the percentage
772 * reported in the SS table */
773 ++info->feature.memory_clk_ss_percentage;
774 info->feature.memory_clk_ss_percentage /= 2;
779 /* There should be only one entry in the SS info table for Engine Clock
782 if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
783 /* Since there is no information for external SS, report
784 * conservative value 3% for bandwidth calculation */
786 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
787 else if (get_ss_info_v3_1(bp,
788 ASIC_INTERNAL_ENGINE_SS, index, &internalSS) == BP_RESULT_OK) {
789 if (internalSS.spread_spectrum_percentage) {
790 info->feature.engine_clk_ss_percentage =
791 internalSS.spread_spectrum_percentage;
792 if (internalSS.type.CENTER_MODE) {
793 /* if it is centermode, the exact SS Percentage
794 * will be round up of half of the percentage
795 * reported in the SS table */
796 ++info->feature.engine_clk_ss_percentage;
797 info->feature.engine_clk_ss_percentage /= 2;
805 static enum bp_result get_firmware_info_v2_2(
806 struct bios_parser *bp,
807 struct dc_firmware_info *info)
809 ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
810 struct spread_spectrum_info internal_ss;
814 return BP_RESULT_BADINPUT;
816 firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
817 DATA_TABLES(FirmwareInfo));
820 return BP_RESULT_BADBIOSTABLE;
822 memset(info, 0, sizeof(*info));
824 /* Pixel clock pll information. We need to convert from 10KHz units into
826 info->pll_info.crystal_frequency =
827 le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
828 info->pll_info.min_input_pxl_clk_pll_frequency =
829 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
830 info->pll_info.max_input_pxl_clk_pll_frequency =
831 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
832 info->pll_info.min_output_pxl_clk_pll_frequency =
833 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
834 info->pll_info.max_output_pxl_clk_pll_frequency =
835 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
836 info->default_display_engine_pll_frequency =
837 le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
838 info->external_clock_source_frequency_for_dp =
839 le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
841 /* There should be only one entry in the SS info table for Memory Clock
844 if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
845 /* Since there is no information for external SS, report
846 * conservative value 3% for bandwidth calculation */
848 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
849 else if (get_ss_info_v3_1(bp,
850 ASIC_INTERNAL_MEMORY_SS, index, &internal_ss) == BP_RESULT_OK) {
851 if (internal_ss.spread_spectrum_percentage) {
852 info->feature.memory_clk_ss_percentage =
853 internal_ss.spread_spectrum_percentage;
854 if (internal_ss.type.CENTER_MODE) {
855 /* if it is centermode, the exact SS Percentage
856 * will be round up of half of the percentage
857 * reported in the SS table */
858 ++info->feature.memory_clk_ss_percentage;
859 info->feature.memory_clk_ss_percentage /= 2;
864 /* There should be only one entry in the SS info table for Engine Clock
867 if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
868 /* Since there is no information for external SS, report
869 * conservative value 3% for bandwidth calculation */
871 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
872 else if (get_ss_info_v3_1(bp,
873 ASIC_INTERNAL_ENGINE_SS, index, &internal_ss) == BP_RESULT_OK) {
874 if (internal_ss.spread_spectrum_percentage) {
875 info->feature.engine_clk_ss_percentage =
876 internal_ss.spread_spectrum_percentage;
877 if (internal_ss.type.CENTER_MODE) {
878 /* if it is centermode, the exact SS Percentage
879 * will be round up of half of the percentage
880 * reported in the SS table */
881 ++info->feature.engine_clk_ss_percentage;
882 info->feature.engine_clk_ss_percentage /= 2;
888 info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
890 /* Is allowed minimum BL level */
891 info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
892 /* Used starting from CI */
893 info->smu_gpu_pll_output_freq =
894 (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
899 static enum bp_result get_ss_info_v3_1(
900 struct bios_parser *bp,
903 struct spread_spectrum_info *ss_info)
905 ATOM_ASIC_INTERNAL_SS_INFO_V3 *ss_table_header_include;
906 ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
909 uint32_t table_index = 0;
912 return BP_RESULT_BADINPUT;
914 if (!DATA_TABLES(ASIC_InternalSS_Info))
915 return BP_RESULT_UNSUPPORTED;
917 ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
918 DATA_TABLES(ASIC_InternalSS_Info));
920 (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
921 - sizeof(ATOM_COMMON_TABLE_HEADER))
922 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
924 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
925 &ss_table_header_include->asSpreadSpectrum[0];
927 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
929 for (i = 0; i < table_size; i++) {
930 if (tbl[i].ucClockIndication != (uint8_t) id)
933 if (table_index != index) {
937 /* VBIOS introduced new defines for Version 3, same values as
938 * before, so now use these new ones for Version 3.
939 * Shouldn't affect field VBIOS's V3 as define values are still
941 * #define SS_MODE_V3_CENTRE_SPREAD_MASK 0x01
942 * #define SS_MODE_V3_EXTERNAL_SS_MASK 0x02
945 * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
946 * #define ATOM_EXTERNAL_SS_MASK 0x00000002
949 if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
950 ss_info->type.EXTERNAL = true;
952 if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
953 ss_info->type.CENTER_MODE = true;
955 /* Older VBIOS (in field) always provides SS percentage in 0.01%
956 * units set Divider to 100 */
957 ss_info->spread_percentage_divider = 100;
959 /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
960 if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
961 & tbl[i].ucSpreadSpectrumMode)
962 ss_info->spread_percentage_divider = 1000;
964 ss_info->type.STEP_AND_DELAY_INFO = false;
965 /* convert [10KHz] into [KHz] */
966 ss_info->target_clock_range =
967 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
968 ss_info->spread_spectrum_percentage =
969 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
970 ss_info->spread_spectrum_range =
971 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
975 return BP_RESULT_NORECORD;
978 static enum bp_result bios_parser_transmitter_control(
980 struct bp_transmitter_control *cntl)
982 struct bios_parser *bp = BP_FROM_DCB(dcb);
984 if (!bp->cmd_tbl.transmitter_control)
985 return BP_RESULT_FAILURE;
987 return bp->cmd_tbl.transmitter_control(bp, cntl);
990 static enum bp_result bios_parser_encoder_control(
992 struct bp_encoder_control *cntl)
994 struct bios_parser *bp = BP_FROM_DCB(dcb);
996 if (!bp->cmd_tbl.dig_encoder_control)
997 return BP_RESULT_FAILURE;
999 return bp->cmd_tbl.dig_encoder_control(bp, cntl);
1002 static enum bp_result bios_parser_adjust_pixel_clock(
1003 struct dc_bios *dcb,
1004 struct bp_adjust_pixel_clock_parameters *bp_params)
1006 struct bios_parser *bp = BP_FROM_DCB(dcb);
1008 if (!bp->cmd_tbl.adjust_display_pll)
1009 return BP_RESULT_FAILURE;
1011 return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
1014 static enum bp_result bios_parser_set_pixel_clock(
1015 struct dc_bios *dcb,
1016 struct bp_pixel_clock_parameters *bp_params)
1018 struct bios_parser *bp = BP_FROM_DCB(dcb);
1020 if (!bp->cmd_tbl.set_pixel_clock)
1021 return BP_RESULT_FAILURE;
1023 return bp->cmd_tbl.set_pixel_clock(bp, bp_params);
1026 static enum bp_result bios_parser_set_dce_clock(
1027 struct dc_bios *dcb,
1028 struct bp_set_dce_clock_parameters *bp_params)
1030 struct bios_parser *bp = BP_FROM_DCB(dcb);
1032 if (!bp->cmd_tbl.set_dce_clock)
1033 return BP_RESULT_FAILURE;
1035 return bp->cmd_tbl.set_dce_clock(bp, bp_params);
1038 static enum bp_result bios_parser_enable_spread_spectrum_on_ppll(
1039 struct dc_bios *dcb,
1040 struct bp_spread_spectrum_parameters *bp_params,
1043 struct bios_parser *bp = BP_FROM_DCB(dcb);
1045 if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
1046 return BP_RESULT_FAILURE;
1048 return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
1049 bp, bp_params, enable);
1053 static enum bp_result bios_parser_program_crtc_timing(
1054 struct dc_bios *dcb,
1055 struct bp_hw_crtc_timing_parameters *bp_params)
1057 struct bios_parser *bp = BP_FROM_DCB(dcb);
1059 if (!bp->cmd_tbl.set_crtc_timing)
1060 return BP_RESULT_FAILURE;
1062 return bp->cmd_tbl.set_crtc_timing(bp, bp_params);
1065 static enum bp_result bios_parser_program_display_engine_pll(
1066 struct dc_bios *dcb,
1067 struct bp_pixel_clock_parameters *bp_params)
1069 struct bios_parser *bp = BP_FROM_DCB(dcb);
1071 if (!bp->cmd_tbl.program_clock)
1072 return BP_RESULT_FAILURE;
1074 return bp->cmd_tbl.program_clock(bp, bp_params);
1079 static enum bp_result bios_parser_enable_crtc(
1080 struct dc_bios *dcb,
1081 enum controller_id id,
1084 struct bios_parser *bp = BP_FROM_DCB(dcb);
1086 if (!bp->cmd_tbl.enable_crtc)
1087 return BP_RESULT_FAILURE;
1089 return bp->cmd_tbl.enable_crtc(bp, id, enable);
1092 static enum bp_result bios_parser_crtc_source_select(
1093 struct dc_bios *dcb,
1094 struct bp_crtc_source_select *bp_params)
1096 struct bios_parser *bp = BP_FROM_DCB(dcb);
1098 if (!bp->cmd_tbl.select_crtc_source)
1099 return BP_RESULT_FAILURE;
1101 return bp->cmd_tbl.select_crtc_source(bp, bp_params);
1104 static enum bp_result bios_parser_enable_disp_power_gating(
1105 struct dc_bios *dcb,
1106 enum controller_id controller_id,
1107 enum bp_pipe_control_action action)
1109 struct bios_parser *bp = BP_FROM_DCB(dcb);
1111 if (!bp->cmd_tbl.enable_disp_power_gating)
1112 return BP_RESULT_FAILURE;
1114 return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id,
1118 static bool bios_parser_is_device_id_supported(
1119 struct dc_bios *dcb,
1120 struct device_id id)
1122 struct bios_parser *bp = BP_FROM_DCB(dcb);
1124 uint32_t mask = get_support_mask_for_device_id(id);
1126 return (le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport) & mask) != 0;
1129 static enum bp_result bios_parser_crt_control(
1130 struct dc_bios *dcb,
1131 enum engine_id engine_id,
1133 uint32_t pixel_clock)
1135 struct bios_parser *bp = BP_FROM_DCB(dcb);
1138 if (!bp->cmd_tbl.dac1_encoder_control &&
1139 engine_id == ENGINE_ID_DACA)
1140 return BP_RESULT_FAILURE;
1141 if (!bp->cmd_tbl.dac2_encoder_control &&
1142 engine_id == ENGINE_ID_DACB)
1143 return BP_RESULT_FAILURE;
1144 /* validate params */
1145 switch (engine_id) {
1146 case ENGINE_ID_DACA:
1147 case ENGINE_ID_DACB:
1150 /* unsupported engine */
1151 return BP_RESULT_FAILURE;
1154 standard = ATOM_DAC1_PS2; /* == ATOM_DAC2_PS2 */
1157 if (engine_id == ENGINE_ID_DACA) {
1158 bp->cmd_tbl.dac1_encoder_control(bp, enable,
1159 pixel_clock, standard);
1160 if (bp->cmd_tbl.dac1_output_control != NULL)
1161 bp->cmd_tbl.dac1_output_control(bp, enable);
1163 bp->cmd_tbl.dac2_encoder_control(bp, enable,
1164 pixel_clock, standard);
1165 if (bp->cmd_tbl.dac2_output_control != NULL)
1166 bp->cmd_tbl.dac2_output_control(bp, enable);
1169 if (engine_id == ENGINE_ID_DACA) {
1170 if (bp->cmd_tbl.dac1_output_control != NULL)
1171 bp->cmd_tbl.dac1_output_control(bp, enable);
1172 bp->cmd_tbl.dac1_encoder_control(bp, enable,
1173 pixel_clock, standard);
1175 if (bp->cmd_tbl.dac2_output_control != NULL)
1176 bp->cmd_tbl.dac2_output_control(bp, enable);
1177 bp->cmd_tbl.dac2_encoder_control(bp, enable,
1178 pixel_clock, standard);
1182 return BP_RESULT_OK;
1185 static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
1186 ATOM_OBJECT *object)
1188 ATOM_COMMON_RECORD_HEADER *header;
1192 BREAK_TO_DEBUGGER(); /* Invalid object */
1196 offset = le16_to_cpu(object->usRecordOffset)
1197 + bp->object_info_tbl_offset;
1200 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1205 if (LAST_RECORD_TYPE == header->ucRecordType ||
1206 !header->ucRecordSize)
1209 if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
1210 && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
1211 return (ATOM_HPD_INT_RECORD *) header;
1213 offset += header->ucRecordSize;
1220 * Get I2C information of input object id
1222 * search all records to find the ATOM_I2C_RECORD_TYPE record IR
1224 static ATOM_I2C_RECORD *get_i2c_record(
1225 struct bios_parser *bp,
1226 ATOM_OBJECT *object)
1229 ATOM_COMMON_RECORD_HEADER *record_header;
1232 BREAK_TO_DEBUGGER();
1233 /* Invalid object */
1237 offset = le16_to_cpu(object->usRecordOffset)
1238 + bp->object_info_tbl_offset;
1241 record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1246 if (LAST_RECORD_TYPE == record_header->ucRecordType ||
1247 0 == record_header->ucRecordSize)
1250 if (ATOM_I2C_RECORD_TYPE == record_header->ucRecordType &&
1251 sizeof(ATOM_I2C_RECORD) <=
1252 record_header->ucRecordSize) {
1253 return (ATOM_I2C_RECORD *)record_header;
1256 offset += record_header->ucRecordSize;
1262 static enum bp_result get_ss_info_from_ss_info_table(
1263 struct bios_parser *bp,
1265 struct spread_spectrum_info *ss_info);
1266 static enum bp_result get_ss_info_from_tbl(
1267 struct bios_parser *bp,
1269 struct spread_spectrum_info *ss_info);
1271 * bios_parser_get_spread_spectrum_info
1272 * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or
1273 * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info
1274 * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ver 3.1,
1275 * there is only one entry for each signal /ss id. However, there is
1276 * no planning of supporting multiple spread Sprectum entry for EverGreen
1278 * @param [in] signal, ASSignalType to be converted to info index
1279 * @param [in] index, number of entries that match the converted info index
1280 * @param [out] ss_info, sprectrum information structure,
1281 * @return Bios parser result code
1283 static enum bp_result bios_parser_get_spread_spectrum_info(
1284 struct dc_bios *dcb,
1285 enum as_signal_type signal,
1287 struct spread_spectrum_info *ss_info)
1289 struct bios_parser *bp = BP_FROM_DCB(dcb);
1290 enum bp_result result = BP_RESULT_UNSUPPORTED;
1291 uint32_t clk_id_ss = 0;
1292 ATOM_COMMON_TABLE_HEADER *header;
1293 struct atom_data_revision tbl_revision;
1295 if (!ss_info) /* check for bad input */
1296 return BP_RESULT_BADINPUT;
1297 /* signal translation */
1298 clk_id_ss = signal_to_ss_id(signal);
1300 if (!DATA_TABLES(ASIC_InternalSS_Info))
1302 return get_ss_info_from_ss_info_table(bp, clk_id_ss,
1305 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1306 DATA_TABLES(ASIC_InternalSS_Info));
1307 get_atom_data_table_revision(header, &tbl_revision);
1309 switch (tbl_revision.major) {
1311 switch (tbl_revision.minor) {
1313 /* there can not be more then one entry for Internal
1314 * SS Info table version 2.1 */
1316 return get_ss_info_from_tbl(bp, clk_id_ss,
1325 switch (tbl_revision.minor) {
1327 return get_ss_info_v3_1(bp, clk_id_ss, index, ss_info);
1335 /* there can not be more then one entry for SS Info table */
1339 static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1340 struct bios_parser *bp,
1342 struct spread_spectrum_info *info);
1345 * get_ss_info_from_table
1346 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
1347 * SS_Info table from the VBIOS
1348 * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
1352 * @param id, spread sprectrum info index
1353 * @param pSSinfo, sprectrum information structure,
1354 * @return Bios parser result code
1356 static enum bp_result get_ss_info_from_tbl(
1357 struct bios_parser *bp,
1359 struct spread_spectrum_info *ss_info)
1361 if (!ss_info) /* check for bad input, if ss_info is not NULL */
1362 return BP_RESULT_BADINPUT;
1363 /* for SS_Info table only support DP and LVDS */
1364 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1365 return get_ss_info_from_ss_info_table(bp, id, ss_info);
1367 return get_ss_info_from_internal_ss_info_tbl_V2_1(bp, id,
1372 * get_ss_info_from_internal_ss_info_tbl_V2_1
1373 * Get spread sprectrum information from the ASIC_InternalSS_Info table Ver 2.1
1375 * There will not be multiple entry for Ver 2.1
1377 * @param id, spread sprectrum info index
1378 * @param pSSinfo, sprectrum information structure,
1379 * @return Bios parser result code
1381 static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1382 struct bios_parser *bp,
1384 struct spread_spectrum_info *info)
1386 enum bp_result result = BP_RESULT_UNSUPPORTED;
1387 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header;
1388 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1389 uint32_t tbl_size, i;
1391 if (!DATA_TABLES(ASIC_InternalSS_Info))
1394 header = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
1395 DATA_TABLES(ASIC_InternalSS_Info));
1397 memset(info, 0, sizeof(struct spread_spectrum_info));
1399 tbl_size = (le16_to_cpu(header->sHeader.usStructureSize)
1400 - sizeof(ATOM_COMMON_TABLE_HEADER))
1401 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1403 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1404 &(header->asSpreadSpectrum[0]);
1405 for (i = 0; i < tbl_size; i++) {
1406 result = BP_RESULT_NORECORD;
1408 if (tbl[i].ucClockIndication != (uint8_t)id)
1411 if (ATOM_EXTERNAL_SS_MASK
1412 & tbl[i].ucSpreadSpectrumMode) {
1413 info->type.EXTERNAL = true;
1415 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
1416 & tbl[i].ucSpreadSpectrumMode) {
1417 info->type.CENTER_MODE = true;
1419 info->type.STEP_AND_DELAY_INFO = false;
1420 /* convert [10KHz] into [KHz] */
1421 info->target_clock_range =
1422 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
1423 info->spread_spectrum_percentage =
1424 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
1425 info->spread_spectrum_range =
1426 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
1427 result = BP_RESULT_OK;
1436 * get_ss_info_from_ss_info_table
1437 * Get spread sprectrum information from the SS_Info table from the VBIOS
1438 * if the pointer to info is NULL, indicate the caller what to know the number
1439 * of entries that matches the id
1440 * for, the SS_Info table, there should not be more than 1 entry match.
1442 * @param [in] id, spread sprectrum id
1443 * @param [out] pSSinfo, sprectrum information structure,
1444 * @return Bios parser result code
1446 static enum bp_result get_ss_info_from_ss_info_table(
1447 struct bios_parser *bp,
1449 struct spread_spectrum_info *ss_info)
1451 enum bp_result result = BP_RESULT_UNSUPPORTED;
1452 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1453 ATOM_COMMON_TABLE_HEADER *header;
1454 uint32_t table_size;
1456 uint32_t id_local = SS_ID_UNKNOWN;
1457 struct atom_data_revision revision;
1459 /* exist of the SS_Info table */
1460 /* check for bad input, pSSinfo can not be NULL */
1461 if (!DATA_TABLES(SS_Info) || !ss_info)
1464 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(SS_Info));
1465 get_atom_data_table_revision(header, &revision);
1467 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info));
1469 if (1 != revision.major || 2 > revision.minor)
1472 /* have to convert from Internal_SS format to SS_Info format */
1474 case ASIC_INTERNAL_SS_ON_DP:
1475 id_local = SS_ID_DP1;
1477 case ASIC_INTERNAL_SS_ON_LVDS:
1479 struct embedded_panel_info panel_info;
1481 if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
1483 id_local = panel_info.ss_id;
1490 if (id_local == SS_ID_UNKNOWN)
1493 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1494 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1495 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1497 for (i = 0; i < table_size; i++) {
1498 if (id_local != (uint32_t)tbl->asSS_Info[i].ucSS_Id)
1501 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
1503 if (ATOM_EXTERNAL_SS_MASK &
1504 tbl->asSS_Info[i].ucSpreadSpectrumType)
1505 ss_info->type.EXTERNAL = true;
1507 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK &
1508 tbl->asSS_Info[i].ucSpreadSpectrumType)
1509 ss_info->type.CENTER_MODE = true;
1511 ss_info->type.STEP_AND_DELAY_INFO = true;
1512 ss_info->spread_spectrum_percentage =
1513 (uint32_t)le16_to_cpu(tbl->asSS_Info[i].usSpreadSpectrumPercentage);
1514 ss_info->step_and_delay_info.step = tbl->asSS_Info[i].ucSS_Step;
1515 ss_info->step_and_delay_info.delay =
1516 tbl->asSS_Info[i].ucSS_Delay;
1517 ss_info->step_and_delay_info.recommended_ref_div =
1518 tbl->asSS_Info[i].ucRecommendedRef_Div;
1519 ss_info->spread_spectrum_range =
1520 (uint32_t)tbl->asSS_Info[i].ucSS_Range * 10000;
1522 /* there will be only one entry for each display type in SS_info
1524 result = BP_RESULT_OK;
1530 static enum bp_result get_embedded_panel_info_v1_2(
1531 struct bios_parser *bp,
1532 struct embedded_panel_info *info);
1533 static enum bp_result get_embedded_panel_info_v1_3(
1534 struct bios_parser *bp,
1535 struct embedded_panel_info *info);
1537 static enum bp_result bios_parser_get_embedded_panel_info(
1538 struct dc_bios *dcb,
1539 struct embedded_panel_info *info)
1541 struct bios_parser *bp = BP_FROM_DCB(dcb);
1542 ATOM_COMMON_TABLE_HEADER *hdr;
1544 if (!DATA_TABLES(LCD_Info))
1545 return BP_RESULT_FAILURE;
1547 hdr = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(LCD_Info));
1550 return BP_RESULT_BADBIOSTABLE;
1552 switch (hdr->ucTableFormatRevision) {
1554 switch (hdr->ucTableContentRevision) {
1558 return get_embedded_panel_info_v1_2(bp, info);
1560 return get_embedded_panel_info_v1_3(bp, info);
1568 return BP_RESULT_FAILURE;
1571 static enum bp_result get_embedded_panel_info_v1_2(
1572 struct bios_parser *bp,
1573 struct embedded_panel_info *info)
1575 ATOM_LVDS_INFO_V12 *lvds;
1578 return BP_RESULT_BADINPUT;
1580 if (!DATA_TABLES(LVDS_Info))
1581 return BP_RESULT_UNSUPPORTED;
1584 GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
1587 return BP_RESULT_BADBIOSTABLE;
1589 if (1 != lvds->sHeader.ucTableFormatRevision
1590 || 2 > lvds->sHeader.ucTableContentRevision)
1591 return BP_RESULT_UNSUPPORTED;
1593 memset(info, 0, sizeof(struct embedded_panel_info));
1595 /* We need to convert from 10KHz units into KHz units*/
1596 info->lcd_timing.pixel_clk =
1597 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1598 /* usHActive does not include borders, according to VBIOS team*/
1599 info->lcd_timing.horizontal_addressable =
1600 le16_to_cpu(lvds->sLCDTiming.usHActive);
1601 /* usHBlanking_Time includes borders, so we should really be subtracting
1602 * borders duing this translation, but LVDS generally*/
1603 /* doesn't have borders, so we should be okay leaving this as is for
1604 * now. May need to revisit if we ever have LVDS with borders*/
1605 info->lcd_timing.horizontal_blanking_time =
1606 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1607 /* usVActive does not include borders, according to VBIOS team*/
1608 info->lcd_timing.vertical_addressable =
1609 le16_to_cpu(lvds->sLCDTiming.usVActive);
1610 /* usVBlanking_Time includes borders, so we should really be subtracting
1611 * borders duing this translation, but LVDS generally*/
1612 /* doesn't have borders, so we should be okay leaving this as is for
1613 * now. May need to revisit if we ever have LVDS with borders*/
1614 info->lcd_timing.vertical_blanking_time =
1615 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1616 info->lcd_timing.horizontal_sync_offset =
1617 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1618 info->lcd_timing.horizontal_sync_width =
1619 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1620 info->lcd_timing.vertical_sync_offset =
1621 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1622 info->lcd_timing.vertical_sync_width =
1623 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1624 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1625 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1626 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1627 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1628 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1630 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1631 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1633 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1634 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1635 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1636 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1637 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1638 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1639 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1640 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1641 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1642 info->lcd_timing.misc_info.INTERLACE =
1643 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1644 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1645 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1646 info->ss_id = lvds->ucSS_Id;
1649 uint8_t rr = le16_to_cpu(lvds->usSupportedRefreshRate);
1650 /* Get minimum supported refresh rate*/
1651 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1652 info->supported_rr.REFRESH_RATE_30HZ = 1;
1653 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1654 info->supported_rr.REFRESH_RATE_40HZ = 1;
1655 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1656 info->supported_rr.REFRESH_RATE_48HZ = 1;
1657 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1658 info->supported_rr.REFRESH_RATE_50HZ = 1;
1659 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1660 info->supported_rr.REFRESH_RATE_60HZ = 1;
1663 /*Drr panel support can be reported by VBIOS*/
1664 if (LCDPANEL_CAP_DRR_SUPPORTED
1665 & lvds->ucLCDPanel_SpecialHandlingCap)
1666 info->drr_enabled = 1;
1668 if (ATOM_PANEL_MISC_DUAL & lvds->ucLVDS_Misc)
1669 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1671 if (ATOM_PANEL_MISC_888RGB & lvds->ucLVDS_Misc)
1672 info->lcd_timing.misc_info.RGB888 = true;
1674 info->lcd_timing.misc_info.GREY_LEVEL =
1675 (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL &
1676 lvds->ucLVDS_Misc) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT;
1678 if (ATOM_PANEL_MISC_SPATIAL & lvds->ucLVDS_Misc)
1679 info->lcd_timing.misc_info.SPATIAL = true;
1681 if (ATOM_PANEL_MISC_TEMPORAL & lvds->ucLVDS_Misc)
1682 info->lcd_timing.misc_info.TEMPORAL = true;
1684 if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
1685 info->lcd_timing.misc_info.API_ENABLED = true;
1687 return BP_RESULT_OK;
1690 static enum bp_result get_embedded_panel_info_v1_3(
1691 struct bios_parser *bp,
1692 struct embedded_panel_info *info)
1694 ATOM_LCD_INFO_V13 *lvds;
1697 return BP_RESULT_BADINPUT;
1699 if (!DATA_TABLES(LCD_Info))
1700 return BP_RESULT_UNSUPPORTED;
1702 lvds = GET_IMAGE(ATOM_LCD_INFO_V13, DATA_TABLES(LCD_Info));
1705 return BP_RESULT_BADBIOSTABLE;
1707 if (!((1 == lvds->sHeader.ucTableFormatRevision)
1708 && (3 <= lvds->sHeader.ucTableContentRevision)))
1709 return BP_RESULT_UNSUPPORTED;
1711 memset(info, 0, sizeof(struct embedded_panel_info));
1713 /* We need to convert from 10KHz units into KHz units */
1714 info->lcd_timing.pixel_clk =
1715 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1716 /* usHActive does not include borders, according to VBIOS team */
1717 info->lcd_timing.horizontal_addressable =
1718 le16_to_cpu(lvds->sLCDTiming.usHActive);
1719 /* usHBlanking_Time includes borders, so we should really be subtracting
1720 * borders duing this translation, but LVDS generally*/
1721 /* doesn't have borders, so we should be okay leaving this as is for
1722 * now. May need to revisit if we ever have LVDS with borders*/
1723 info->lcd_timing.horizontal_blanking_time =
1724 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1725 /* usVActive does not include borders, according to VBIOS team*/
1726 info->lcd_timing.vertical_addressable =
1727 le16_to_cpu(lvds->sLCDTiming.usVActive);
1728 /* usVBlanking_Time includes borders, so we should really be subtracting
1729 * borders duing this translation, but LVDS generally*/
1730 /* doesn't have borders, so we should be okay leaving this as is for
1731 * now. May need to revisit if we ever have LVDS with borders*/
1732 info->lcd_timing.vertical_blanking_time =
1733 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1734 info->lcd_timing.horizontal_sync_offset =
1735 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1736 info->lcd_timing.horizontal_sync_width =
1737 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1738 info->lcd_timing.vertical_sync_offset =
1739 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1740 info->lcd_timing.vertical_sync_width =
1741 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1742 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1743 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1744 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1745 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1746 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1748 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1749 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1751 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1752 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1753 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1754 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1755 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1756 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1757 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1758 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1759 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1760 info->lcd_timing.misc_info.INTERLACE =
1761 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1762 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1763 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1764 info->ss_id = lvds->ucSS_Id;
1766 /* Drr panel support can be reported by VBIOS*/
1767 if (LCDPANEL_CAP_V13_DRR_SUPPORTED
1768 & lvds->ucLCDPanel_SpecialHandlingCap)
1769 info->drr_enabled = 1;
1771 /* Get supported refresh rate*/
1772 if (info->drr_enabled == 1) {
1774 lvds->sRefreshRateSupport.ucMinRefreshRateForDRR;
1775 uint8_t rr = lvds->sRefreshRateSupport.ucSupportedRefreshRate;
1778 if (SUPPORTED_LCD_REFRESHRATE_30Hz & min_rr)
1779 info->supported_rr.REFRESH_RATE_30HZ = 1;
1780 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & min_rr)
1781 info->supported_rr.REFRESH_RATE_40HZ = 1;
1782 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & min_rr)
1783 info->supported_rr.REFRESH_RATE_48HZ = 1;
1784 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & min_rr)
1785 info->supported_rr.REFRESH_RATE_50HZ = 1;
1786 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & min_rr)
1787 info->supported_rr.REFRESH_RATE_60HZ = 1;
1789 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1790 info->supported_rr.REFRESH_RATE_30HZ = 1;
1791 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1792 info->supported_rr.REFRESH_RATE_40HZ = 1;
1793 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1794 info->supported_rr.REFRESH_RATE_48HZ = 1;
1795 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1796 info->supported_rr.REFRESH_RATE_50HZ = 1;
1797 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1798 info->supported_rr.REFRESH_RATE_60HZ = 1;
1802 if (ATOM_PANEL_MISC_V13_DUAL & lvds->ucLCD_Misc)
1803 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1805 if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR & lvds->ucLCD_Misc)
1806 info->lcd_timing.misc_info.RGB888 = true;
1808 info->lcd_timing.misc_info.GREY_LEVEL =
1809 (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
1810 lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
1812 return BP_RESULT_OK;
1816 * bios_parser_get_encoder_cap_info
1819 * Get encoder capability information of input object id
1821 * @param object_id, Object id
1822 * @param object_id, encoder cap information structure
1824 * @return Bios parser result code
1827 static enum bp_result bios_parser_get_encoder_cap_info(
1828 struct dc_bios *dcb,
1829 struct graphics_object_id object_id,
1830 struct bp_encoder_cap_info *info)
1832 struct bios_parser *bp = BP_FROM_DCB(dcb);
1833 ATOM_OBJECT *object;
1834 ATOM_ENCODER_CAP_RECORD_V2 *record = NULL;
1837 return BP_RESULT_BADINPUT;
1839 object = get_bios_object(bp, object_id);
1842 return BP_RESULT_BADINPUT;
1844 record = get_encoder_cap_record(bp, object);
1846 return BP_RESULT_NORECORD;
1848 info->DP_HBR2_EN = record->usHBR2En;
1849 info->DP_HBR3_EN = record->usHBR3En;
1850 info->HDMI_6GB_EN = record->usHDMI6GEn;
1851 return BP_RESULT_OK;
1855 * get_encoder_cap_record
1858 * Get encoder cap record for the object
1860 * @param object, ATOM object
1862 * @return atom encoder cap record
1865 * search all records to find the ATOM_ENCODER_CAP_RECORD_V2 record
1867 static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
1868 struct bios_parser *bp,
1869 ATOM_OBJECT *object)
1871 ATOM_COMMON_RECORD_HEADER *header;
1875 BREAK_TO_DEBUGGER(); /* Invalid object */
1879 offset = le16_to_cpu(object->usRecordOffset)
1880 + bp->object_info_tbl_offset;
1883 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1888 offset += header->ucRecordSize;
1890 if (LAST_RECORD_TYPE == header->ucRecordType ||
1891 !header->ucRecordSize)
1894 if (ATOM_ENCODER_CAP_RECORD_TYPE != header->ucRecordType)
1897 if (sizeof(ATOM_ENCODER_CAP_RECORD_V2) <= header->ucRecordSize)
1898 return (ATOM_ENCODER_CAP_RECORD_V2 *)header;
1904 static uint32_t get_ss_entry_number(
1905 struct bios_parser *bp,
1907 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1908 struct bios_parser *bp,
1910 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1911 struct bios_parser *bp,
1913 static uint32_t get_ss_entry_number_from_ss_info_tbl(
1914 struct bios_parser *bp,
1918 * BiosParserObject::GetNumberofSpreadSpectrumEntry
1919 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
1920 * the VBIOS that match the SSid (to be converted from signal)
1922 * @param[in] signal, ASSignalType to be converted to SSid
1923 * @return number of SS Entry that match the signal
1925 static uint32_t bios_parser_get_ss_entry_number(
1926 struct dc_bios *dcb,
1927 enum as_signal_type signal)
1929 struct bios_parser *bp = BP_FROM_DCB(dcb);
1931 ATOM_COMMON_TABLE_HEADER *header;
1932 struct atom_data_revision revision;
1934 ss_id = signal_to_ss_id(signal);
1936 if (!DATA_TABLES(ASIC_InternalSS_Info))
1937 return get_ss_entry_number_from_ss_info_tbl(bp, ss_id);
1939 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1940 DATA_TABLES(ASIC_InternalSS_Info));
1941 get_atom_data_table_revision(header, &revision);
1943 switch (revision.major) {
1945 switch (revision.minor) {
1947 return get_ss_entry_number(bp, ss_id);
1953 switch (revision.minor) {
1956 get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1970 * get_ss_entry_number_from_ss_info_tbl
1971 * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
1973 * @note There can only be one entry for each id for SS_Info Table
1975 * @param [in] id, spread spectrum id
1976 * @return number of SS Entry that match the id
1978 static uint32_t get_ss_entry_number_from_ss_info_tbl(
1979 struct bios_parser *bp,
1982 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1983 ATOM_COMMON_TABLE_HEADER *header;
1984 uint32_t table_size;
1986 uint32_t number = 0;
1987 uint32_t id_local = SS_ID_UNKNOWN;
1988 struct atom_data_revision revision;
1990 /* SS_Info table exist */
1991 if (!DATA_TABLES(SS_Info))
1994 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1995 DATA_TABLES(SS_Info));
1996 get_atom_data_table_revision(header, &revision);
1998 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO,
1999 DATA_TABLES(SS_Info));
2001 if (1 != revision.major || 2 > revision.minor)
2004 /* have to convert from Internal_SS format to SS_Info format */
2006 case ASIC_INTERNAL_SS_ON_DP:
2007 id_local = SS_ID_DP1;
2009 case ASIC_INTERNAL_SS_ON_LVDS: {
2010 struct embedded_panel_info panel_info;
2012 if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
2014 id_local = panel_info.ss_id;
2021 if (id_local == SS_ID_UNKNOWN)
2024 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
2025 sizeof(ATOM_COMMON_TABLE_HEADER)) /
2026 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
2028 for (i = 0; i < table_size; i++)
2029 if (id_local == (uint32_t)tbl->asSS_Info[i].ucSS_Id) {
2038 * get_ss_entry_number
2039 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
2040 * SS_Info table from the VBIOS
2041 * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
2044 * @param id, spread sprectrum info index
2045 * @return Bios parser result code
2047 static uint32_t get_ss_entry_number(struct bios_parser *bp, uint32_t id)
2049 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
2050 return get_ss_entry_number_from_ss_info_tbl(bp, id);
2052 return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp, id);
2056 * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
2057 * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
2058 * Ver 2.1 from the VBIOS
2059 * There will not be multiple entry for Ver 2.1
2061 * @param id, spread sprectrum info index
2062 * @return number of SS Entry that match the id
2064 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
2065 struct bios_parser *bp,
2068 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header_include;
2069 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
2073 if (!DATA_TABLES(ASIC_InternalSS_Info))
2076 header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
2077 DATA_TABLES(ASIC_InternalSS_Info));
2079 size = (le16_to_cpu(header_include->sHeader.usStructureSize)
2080 - sizeof(ATOM_COMMON_TABLE_HEADER))
2081 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
2083 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
2084 &header_include->asSpreadSpectrum[0];
2085 for (i = 0; i < size; i++)
2086 if (tbl[i].ucClockIndication == (uint8_t)id)
2092 * get_ss_entry_number_from_internal_ss_info_table_V3_1
2093 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
2094 * the VBIOS that matches id
2096 * @param[in] id, spread sprectrum id
2097 * @return number of SS Entry that match the id
2099 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
2100 struct bios_parser *bp,
2103 uint32_t number = 0;
2104 ATOM_ASIC_INTERNAL_SS_INFO_V3 *header_include;
2105 ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
2109 if (!DATA_TABLES(ASIC_InternalSS_Info))
2112 header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
2113 DATA_TABLES(ASIC_InternalSS_Info));
2114 size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
2115 sizeof(ATOM_COMMON_TABLE_HEADER)) /
2116 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
2118 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
2119 &header_include->asSpreadSpectrum[0];
2121 for (i = 0; i < size; i++)
2122 if (tbl[i].ucClockIndication == (uint8_t)id)
2129 * bios_parser_get_gpio_pin_info
2130 * Get GpioPin information of input gpio id
2132 * @param gpio_id, GPIO ID
2133 * @param info, GpioPin information structure
2134 * @return Bios parser result code
2136 * to get the GPIO PIN INFO, we need:
2137 * 1. get the GPIO_ID from other object table, see GetHPDInfo()
2138 * 2. in DATA_TABLE.GPIO_Pin_LUT, search all records, to get the registerA
2141 static enum bp_result bios_parser_get_gpio_pin_info(
2142 struct dc_bios *dcb,
2144 struct gpio_pin_info *info)
2146 struct bios_parser *bp = BP_FROM_DCB(dcb);
2147 ATOM_GPIO_PIN_LUT *header;
2151 if (!DATA_TABLES(GPIO_Pin_LUT))
2152 return BP_RESULT_BADBIOSTABLE;
2154 header = GET_IMAGE(ATOM_GPIO_PIN_LUT, DATA_TABLES(GPIO_Pin_LUT));
2156 return BP_RESULT_BADBIOSTABLE;
2158 if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_PIN_LUT)
2159 > le16_to_cpu(header->sHeader.usStructureSize))
2160 return BP_RESULT_BADBIOSTABLE;
2162 if (1 != header->sHeader.ucTableContentRevision)
2163 return BP_RESULT_UNSUPPORTED;
2165 count = (le16_to_cpu(header->sHeader.usStructureSize)
2166 - sizeof(ATOM_COMMON_TABLE_HEADER))
2167 / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
2168 for (i = 0; i < count; ++i) {
2169 if (header->asGPIO_Pin[i].ucGPIO_ID != gpio_id)
2173 (uint32_t) le16_to_cpu(header->asGPIO_Pin[i].usGpioPin_AIndex);
2174 info->offset_y = info->offset + 2;
2175 info->offset_en = info->offset + 1;
2176 info->offset_mask = info->offset - 1;
2178 info->mask = (uint32_t) (1 <<
2179 header->asGPIO_Pin[i].ucGpioPinBitShift);
2180 info->mask_y = info->mask + 2;
2181 info->mask_en = info->mask + 1;
2182 info->mask_mask = info->mask - 1;
2184 return BP_RESULT_OK;
2187 return BP_RESULT_NORECORD;
2190 static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
2191 ATOM_I2C_RECORD *record,
2192 struct graphics_object_i2c_info *info)
2194 ATOM_GPIO_I2C_INFO *header;
2198 return BP_RESULT_BADINPUT;
2200 /* get the GPIO_I2C info */
2201 if (!DATA_TABLES(GPIO_I2C_Info))
2202 return BP_RESULT_BADBIOSTABLE;
2204 header = GET_IMAGE(ATOM_GPIO_I2C_INFO, DATA_TABLES(GPIO_I2C_Info));
2206 return BP_RESULT_BADBIOSTABLE;
2208 if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_I2C_ASSIGMENT)
2209 > le16_to_cpu(header->sHeader.usStructureSize))
2210 return BP_RESULT_BADBIOSTABLE;
2212 if (1 != header->sHeader.ucTableContentRevision)
2213 return BP_RESULT_UNSUPPORTED;
2215 /* get data count */
2216 count = (le16_to_cpu(header->sHeader.usStructureSize)
2217 - sizeof(ATOM_COMMON_TABLE_HEADER))
2218 / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
2219 if (count < record->sucI2cId.bfI2C_LineMux)
2220 return BP_RESULT_BADBIOSTABLE;
2222 /* get the GPIO_I2C_INFO */
2223 info->i2c_hw_assist = record->sucI2cId.bfHW_Capable;
2224 info->i2c_line = record->sucI2cId.bfI2C_LineMux;
2225 info->i2c_engine_id = record->sucI2cId.bfHW_EngineID;
2226 info->i2c_slave_address = record->ucI2CAddr;
2228 info->gpio_info.clk_mask_register_index =
2229 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkMaskRegisterIndex);
2230 info->gpio_info.clk_en_register_index =
2231 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkEnRegisterIndex);
2232 info->gpio_info.clk_y_register_index =
2233 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkY_RegisterIndex);
2234 info->gpio_info.clk_a_register_index =
2235 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkA_RegisterIndex);
2236 info->gpio_info.data_mask_register_index =
2237 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataMaskRegisterIndex);
2238 info->gpio_info.data_en_register_index =
2239 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataEnRegisterIndex);
2240 info->gpio_info.data_y_register_index =
2241 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataY_RegisterIndex);
2242 info->gpio_info.data_a_register_index =
2243 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataA_RegisterIndex);
2245 info->gpio_info.clk_mask_shift =
2246 header->asGPIO_Info[info->i2c_line].ucClkMaskShift;
2247 info->gpio_info.clk_en_shift =
2248 header->asGPIO_Info[info->i2c_line].ucClkEnShift;
2249 info->gpio_info.clk_y_shift =
2250 header->asGPIO_Info[info->i2c_line].ucClkY_Shift;
2251 info->gpio_info.clk_a_shift =
2252 header->asGPIO_Info[info->i2c_line].ucClkA_Shift;
2253 info->gpio_info.data_mask_shift =
2254 header->asGPIO_Info[info->i2c_line].ucDataMaskShift;
2255 info->gpio_info.data_en_shift =
2256 header->asGPIO_Info[info->i2c_line].ucDataEnShift;
2257 info->gpio_info.data_y_shift =
2258 header->asGPIO_Info[info->i2c_line].ucDataY_Shift;
2259 info->gpio_info.data_a_shift =
2260 header->asGPIO_Info[info->i2c_line].ucDataA_Shift;
2262 return BP_RESULT_OK;
2265 static bool dal_graphics_object_id_is_valid(struct graphics_object_id id)
2270 case OBJECT_TYPE_UNKNOWN:
2273 case OBJECT_TYPE_GPU:
2274 case OBJECT_TYPE_ENGINE:
2275 /* do NOT check for id.id == 0 */
2276 if (id.enum_id == ENUM_ID_UNKNOWN)
2280 if (id.id == 0 || id.enum_id == ENUM_ID_UNKNOWN)
2288 static bool dal_graphics_object_id_is_equal(
2289 struct graphics_object_id id1,
2290 struct graphics_object_id id2)
2292 if (false == dal_graphics_object_id_is_valid(id1)) {
2293 dm_output_to_console(
2294 "%s: Warning: comparing invalid object 'id1'!\n", __func__);
2298 if (false == dal_graphics_object_id_is_valid(id2)) {
2299 dm_output_to_console(
2300 "%s: Warning: comparing invalid object 'id2'!\n", __func__);
2304 if (id1.id == id2.id && id1.enum_id == id2.enum_id
2305 && id1.type == id2.type)
2311 static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
2312 struct graphics_object_id id)
2315 ATOM_OBJECT_TABLE *tbl;
2319 case OBJECT_TYPE_ENCODER:
2320 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
2323 case OBJECT_TYPE_CONNECTOR:
2324 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
2327 case OBJECT_TYPE_ROUTER:
2328 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usRouterObjectTableOffset);
2331 case OBJECT_TYPE_GENERIC:
2332 if (bp->object_info_tbl.revision.minor < 3)
2334 offset = le16_to_cpu(bp->object_info_tbl.v1_3->usMiscObjectTableOffset);
2341 offset += bp->object_info_tbl_offset;
2343 tbl = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
2347 for (i = 0; i < tbl->ucNumberOfObjects; i++)
2348 if (dal_graphics_object_id_is_equal(id,
2349 object_id_from_bios_object_id(
2350 le16_to_cpu(tbl->asObjects[i].usObjectID))))
2351 return &tbl->asObjects[i];
2356 static uint32_t get_dest_obj_list(struct bios_parser *bp,
2357 ATOM_OBJECT *object, uint16_t **id_list)
2363 BREAK_TO_DEBUGGER(); /* Invalid object id */
2367 offset = le16_to_cpu(object->usSrcDstTableOffset)
2368 + bp->object_info_tbl_offset;
2370 number = GET_IMAGE(uint8_t, offset);
2374 offset += sizeof(uint8_t);
2375 offset += sizeof(uint16_t) * (*number);
2377 number = GET_IMAGE(uint8_t, offset);
2378 if ((!number) || (!*number))
2381 offset += sizeof(uint8_t);
2382 *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
2390 static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
2397 BREAK_TO_DEBUGGER(); /* Invalid object id */
2401 offset = le16_to_cpu(object->usSrcDstTableOffset)
2402 + bp->object_info_tbl_offset;
2404 number = GET_IMAGE(uint8_t, offset);
2408 offset += sizeof(uint8_t);
2409 *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
2417 static uint32_t get_dst_number_from_object(struct bios_parser *bp,
2418 ATOM_OBJECT *object)
2424 BREAK_TO_DEBUGGER(); /* Invalid encoder object id*/
2428 offset = le16_to_cpu(object->usSrcDstTableOffset)
2429 + bp->object_info_tbl_offset;
2431 number = GET_IMAGE(uint8_t, offset);
2435 offset += sizeof(uint8_t);
2436 offset += sizeof(uint16_t) * (*number);
2438 number = GET_IMAGE(uint8_t, offset);
2446 static struct device_id device_type_from_device_id(uint16_t device_id)
2449 struct device_id result_device_id;
2451 switch (device_id) {
2452 case ATOM_DEVICE_LCD1_SUPPORT:
2453 result_device_id.device_type = DEVICE_TYPE_LCD;
2454 result_device_id.enum_id = 1;
2457 case ATOM_DEVICE_LCD2_SUPPORT:
2458 result_device_id.device_type = DEVICE_TYPE_LCD;
2459 result_device_id.enum_id = 2;
2462 case ATOM_DEVICE_CRT1_SUPPORT:
2463 result_device_id.device_type = DEVICE_TYPE_CRT;
2464 result_device_id.enum_id = 1;
2467 case ATOM_DEVICE_CRT2_SUPPORT:
2468 result_device_id.device_type = DEVICE_TYPE_CRT;
2469 result_device_id.enum_id = 2;
2472 case ATOM_DEVICE_DFP1_SUPPORT:
2473 result_device_id.device_type = DEVICE_TYPE_DFP;
2474 result_device_id.enum_id = 1;
2477 case ATOM_DEVICE_DFP2_SUPPORT:
2478 result_device_id.device_type = DEVICE_TYPE_DFP;
2479 result_device_id.enum_id = 2;
2482 case ATOM_DEVICE_DFP3_SUPPORT:
2483 result_device_id.device_type = DEVICE_TYPE_DFP;
2484 result_device_id.enum_id = 3;
2487 case ATOM_DEVICE_DFP4_SUPPORT:
2488 result_device_id.device_type = DEVICE_TYPE_DFP;
2489 result_device_id.enum_id = 4;
2492 case ATOM_DEVICE_DFP5_SUPPORT:
2493 result_device_id.device_type = DEVICE_TYPE_DFP;
2494 result_device_id.enum_id = 5;
2497 case ATOM_DEVICE_DFP6_SUPPORT:
2498 result_device_id.device_type = DEVICE_TYPE_DFP;
2499 result_device_id.enum_id = 6;
2503 BREAK_TO_DEBUGGER(); /* Invalid device Id */
2504 result_device_id.device_type = DEVICE_TYPE_UNKNOWN;
2505 result_device_id.enum_id = 0;
2507 return result_device_id;
2510 static void get_atom_data_table_revision(
2511 ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
2512 struct atom_data_revision *tbl_revision)
2517 /* initialize the revision to 0 which is invalid revision */
2518 tbl_revision->major = 0;
2519 tbl_revision->minor = 0;
2524 tbl_revision->major =
2525 (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl);
2526 tbl_revision->minor =
2527 (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl);
2530 static uint32_t signal_to_ss_id(enum as_signal_type signal)
2532 uint32_t clk_id_ss = 0;
2535 case AS_SIGNAL_TYPE_DVI:
2536 clk_id_ss = ASIC_INTERNAL_SS_ON_TMDS;
2538 case AS_SIGNAL_TYPE_HDMI:
2539 clk_id_ss = ASIC_INTERNAL_SS_ON_HDMI;
2541 case AS_SIGNAL_TYPE_LVDS:
2542 clk_id_ss = ASIC_INTERNAL_SS_ON_LVDS;
2544 case AS_SIGNAL_TYPE_DISPLAY_PORT:
2545 clk_id_ss = ASIC_INTERNAL_SS_ON_DP;
2547 case AS_SIGNAL_TYPE_GPU_PLL:
2548 clk_id_ss = ASIC_INTERNAL_GPUPLL_SS;
2556 static uint32_t get_support_mask_for_device_id(struct device_id device_id)
2558 enum dal_device_type device_type = device_id.device_type;
2559 uint32_t enum_id = device_id.enum_id;
2561 switch (device_type) {
2562 case DEVICE_TYPE_LCD:
2565 return ATOM_DEVICE_LCD1_SUPPORT;
2567 return ATOM_DEVICE_LCD2_SUPPORT;
2572 case DEVICE_TYPE_CRT:
2575 return ATOM_DEVICE_CRT1_SUPPORT;
2577 return ATOM_DEVICE_CRT2_SUPPORT;
2582 case DEVICE_TYPE_DFP:
2585 return ATOM_DEVICE_DFP1_SUPPORT;
2587 return ATOM_DEVICE_DFP2_SUPPORT;
2589 return ATOM_DEVICE_DFP3_SUPPORT;
2591 return ATOM_DEVICE_DFP4_SUPPORT;
2593 return ATOM_DEVICE_DFP5_SUPPORT;
2595 return ATOM_DEVICE_DFP6_SUPPORT;
2600 case DEVICE_TYPE_CV:
2603 return ATOM_DEVICE_CV_SUPPORT;
2608 case DEVICE_TYPE_TV:
2611 return ATOM_DEVICE_TV1_SUPPORT;
2620 /* Unidentified device ID, return empty support mask. */
2625 * HwContext interface for writing MM registers
2628 static bool i2c_read(
2629 struct bios_parser *bp,
2630 struct graphics_object_i2c_info *i2c_info,
2635 uint8_t offset[2] = { 0, 0 };
2636 bool result = false;
2637 struct i2c_command cmd;
2638 struct gpio_ddc_hw_info hw_info = {
2639 i2c_info->i2c_hw_assist,
2640 i2c_info->i2c_line };
2642 ddc = dal_gpio_create_ddc(bp->base.ctx->gpio_service,
2643 i2c_info->gpio_info.clk_a_register_index,
2644 (1 << i2c_info->gpio_info.clk_a_shift), &hw_info);
2649 /*Using SW engine */
2650 cmd.engine = I2C_COMMAND_ENGINE_SW;
2651 cmd.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
2654 struct i2c_payload payloads[] = {
2656 .address = i2c_info->i2c_slave_address >> 1,
2658 .length = sizeof(offset),
2662 .address = i2c_info->i2c_slave_address >> 1,
2669 cmd.payloads = payloads;
2670 cmd.number_of_payloads = ARRAY_SIZE(payloads);
2672 /* TODO route this through drm i2c_adapter */
2673 result = dal_i2caux_submit_i2c_command(
2679 dal_gpio_destroy_ddc(&ddc);
2685 * Read external display connection info table through i2c.
2686 * validate the GUID and checksum.
2688 * @return enum bp_result whether all data was sucessfully read
2690 static enum bp_result get_ext_display_connection_info(
2691 struct bios_parser *bp,
2692 ATOM_OBJECT *opm_object,
2693 ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *ext_display_connection_info_tbl)
2695 bool config_tbl_present = false;
2696 ATOM_I2C_RECORD *i2c_record = NULL;
2699 if (opm_object == NULL)
2700 return BP_RESULT_BADINPUT;
2702 i2c_record = get_i2c_record(bp, opm_object);
2704 if (i2c_record != NULL) {
2705 ATOM_GPIO_I2C_INFO *gpio_i2c_header;
2706 struct graphics_object_i2c_info i2c_info;
2708 gpio_i2c_header = GET_IMAGE(ATOM_GPIO_I2C_INFO,
2709 bp->master_data_tbl->ListOfDataTables.GPIO_I2C_Info);
2711 if (NULL == gpio_i2c_header)
2712 return BP_RESULT_BADBIOSTABLE;
2714 if (get_gpio_i2c_info(bp, i2c_record, &i2c_info) !=
2716 return BP_RESULT_BADBIOSTABLE;
2720 (uint8_t *)ext_display_connection_info_tbl,
2721 sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO))) {
2722 config_tbl_present = true;
2727 if (config_tbl_present)
2728 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; i++) {
2729 if (ext_display_connection_info_tbl->ucGuid[i]
2730 != ext_display_connection_guid[i]) {
2731 config_tbl_present = false;
2736 /* Validate checksum */
2737 if (config_tbl_present) {
2738 uint8_t check_sum = 0;
2740 (uint8_t *)ext_display_connection_info_tbl;
2742 for (i = 0; i < sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO);
2744 check_sum += buf[i];
2748 config_tbl_present = false;
2751 if (config_tbl_present)
2752 return BP_RESULT_OK;
2754 return BP_RESULT_FAILURE;
2758 * Gets the first device ID in the same group as the given ID for enumerating.
2759 * For instance, if any DFP device ID is passed, returns the device ID for DFP1.
2761 * The first device ID in the same group as the passed device ID, or 0 if no
2762 * matching device group found.
2764 static uint32_t enum_first_device_id(uint32_t dev_id)
2766 /* Return the first in the group that this ID belongs to. */
2767 if (dev_id & ATOM_DEVICE_CRT_SUPPORT)
2768 return ATOM_DEVICE_CRT1_SUPPORT;
2769 else if (dev_id & ATOM_DEVICE_DFP_SUPPORT)
2770 return ATOM_DEVICE_DFP1_SUPPORT;
2771 else if (dev_id & ATOM_DEVICE_LCD_SUPPORT)
2772 return ATOM_DEVICE_LCD1_SUPPORT;
2773 else if (dev_id & ATOM_DEVICE_TV_SUPPORT)
2774 return ATOM_DEVICE_TV1_SUPPORT;
2775 else if (dev_id & ATOM_DEVICE_CV_SUPPORT)
2776 return ATOM_DEVICE_CV_SUPPORT;
2778 /* No group found for this device ID. */
2780 dm_error("%s: incorrect input %d\n", __func__, dev_id);
2781 /* No matching support flag for given device ID */
2786 * Gets the next device ID in the group for a given device ID.
2788 * The current device ID being enumerated on.
2790 * The next device ID in the group, or 0 if no device exists.
2792 static uint32_t enum_next_dev_id(uint32_t dev_id)
2794 /* Get next device ID in the group. */
2796 case ATOM_DEVICE_CRT1_SUPPORT:
2797 return ATOM_DEVICE_CRT2_SUPPORT;
2798 case ATOM_DEVICE_LCD1_SUPPORT:
2799 return ATOM_DEVICE_LCD2_SUPPORT;
2800 case ATOM_DEVICE_DFP1_SUPPORT:
2801 return ATOM_DEVICE_DFP2_SUPPORT;
2802 case ATOM_DEVICE_DFP2_SUPPORT:
2803 return ATOM_DEVICE_DFP3_SUPPORT;
2804 case ATOM_DEVICE_DFP3_SUPPORT:
2805 return ATOM_DEVICE_DFP4_SUPPORT;
2806 case ATOM_DEVICE_DFP4_SUPPORT:
2807 return ATOM_DEVICE_DFP5_SUPPORT;
2808 case ATOM_DEVICE_DFP5_SUPPORT:
2809 return ATOM_DEVICE_DFP6_SUPPORT;
2812 /* Done enumerating through devices. */
2817 * Returns the new device tag record for patched BIOS object.
2819 * [IN] pExtDisplayPath - External display path to copy device tag from.
2820 * [IN] deviceSupport - Bit vector for device ID support flags.
2821 * [OUT] pDeviceTag - Device tag structure to fill with patched data.
2823 * True if a compatible device ID was found, false otherwise.
2825 static bool get_patched_device_tag(
2826 struct bios_parser *bp,
2827 EXT_DISPLAY_PATH *ext_display_path,
2828 uint32_t device_support,
2829 ATOM_CONNECTOR_DEVICE_TAG *device_tag)
2832 /* Use fallback behaviour if not supported. */
2833 if (!bp->remap_device_tags) {
2834 device_tag->ulACPIDeviceEnum =
2835 cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
2836 device_tag->usDeviceID =
2837 cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceTag));
2841 /* Find the first unused in the same group. */
2842 dev_id = enum_first_device_id(le16_to_cpu(ext_display_path->usDeviceTag));
2843 while (dev_id != 0) {
2844 /* Assign this device ID if supported. */
2845 if ((device_support & dev_id) != 0) {
2846 device_tag->ulACPIDeviceEnum =
2847 cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
2848 device_tag->usDeviceID = cpu_to_le16((USHORT) dev_id);
2852 dev_id = enum_next_dev_id(dev_id);
2855 /* No compatible device ID found. */
2860 * Adds a device tag to a BIOS object's device tag record if there is
2861 * matching device ID supported.
2863 * pObject - Pointer to the BIOS object to add the device tag to.
2864 * pExtDisplayPath - Display path to retrieve base device ID from.
2865 * pDeviceSupport - Pointer to bit vector for supported device IDs.
2867 static void add_device_tag_from_ext_display_path(
2868 struct bios_parser *bp,
2869 ATOM_OBJECT *object,
2870 EXT_DISPLAY_PATH *ext_display_path,
2871 uint32_t *device_support)
2873 /* Get device tag record for object. */
2874 ATOM_CONNECTOR_DEVICE_TAG *device_tag = NULL;
2875 ATOM_CONNECTOR_DEVICE_TAG_RECORD *device_tag_record = NULL;
2876 enum bp_result result =
2877 bios_parser_get_device_tag_record(
2878 bp, object, &device_tag_record);
2880 if ((le16_to_cpu(ext_display_path->usDeviceTag) != CONNECTOR_OBJECT_ID_NONE)
2881 && (result == BP_RESULT_OK)) {
2884 if ((device_tag_record->ucNumberOfDevice == 1) &&
2885 (le16_to_cpu(device_tag_record->asDeviceTag[0].usDeviceID) == 0)) {
2886 /*Workaround bug in current VBIOS releases where
2887 * ucNumberOfDevice = 1 but there is no actual device
2888 * tag data. This w/a is temporary until the updated
2889 * VBIOS is distributed. */
2890 device_tag_record->ucNumberOfDevice =
2891 device_tag_record->ucNumberOfDevice - 1;
2894 /* Attempt to find a matching device ID. */
2895 index = device_tag_record->ucNumberOfDevice;
2896 device_tag = &device_tag_record->asDeviceTag[index];
2897 if (get_patched_device_tag(
2902 /* Update cached device support to remove assigned ID.
2904 *device_support &= ~le16_to_cpu(device_tag->usDeviceID);
2905 device_tag_record->ucNumberOfDevice++;
2911 * Read out a single EXT_DISPLAY_PATH from the external display connection info
2912 * table. The specific entry in the table is determined by the enum_id passed
2915 * EXT_DISPLAY_PATH describing a single Configuration table entry
2918 #define INVALID_CONNECTOR 0xffff
2920 static EXT_DISPLAY_PATH *get_ext_display_path_entry(
2921 ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *config_table,
2922 uint32_t bios_object_id)
2924 EXT_DISPLAY_PATH *ext_display_path;
2925 uint32_t ext_display_path_index =
2926 ((bios_object_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT) - 1;
2928 if (ext_display_path_index >= MAX_NUMBER_OF_EXT_DISPLAY_PATH)
2931 ext_display_path = &config_table->sPath[ext_display_path_index];
2933 if (le16_to_cpu(ext_display_path->usDeviceConnector) == INVALID_CONNECTOR)
2934 ext_display_path->usDeviceConnector = cpu_to_le16(0);
2936 return ext_display_path;
2940 * Get AUX/DDC information of input object id
2942 * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
2945 static ATOM_CONNECTOR_AUXDDC_LUT_RECORD *get_ext_connector_aux_ddc_lut_record(
2946 struct bios_parser *bp,
2947 ATOM_OBJECT *object)
2950 ATOM_COMMON_RECORD_HEADER *header;
2953 BREAK_TO_DEBUGGER();
2954 /* Invalid object */
2958 offset = le16_to_cpu(object->usRecordOffset)
2959 + bp->object_info_tbl_offset;
2962 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
2967 if (LAST_RECORD_TYPE == header->ucRecordType ||
2968 0 == header->ucRecordSize)
2971 if (ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE ==
2972 header->ucRecordType &&
2973 sizeof(ATOM_CONNECTOR_AUXDDC_LUT_RECORD) <=
2974 header->ucRecordSize)
2975 return (ATOM_CONNECTOR_AUXDDC_LUT_RECORD *)(header);
2977 offset += header->ucRecordSize;
2984 * Get AUX/DDC information of input object id
2986 * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
2989 static ATOM_CONNECTOR_HPDPIN_LUT_RECORD *get_ext_connector_hpd_pin_lut_record(
2990 struct bios_parser *bp,
2991 ATOM_OBJECT *object)
2994 ATOM_COMMON_RECORD_HEADER *header;
2997 BREAK_TO_DEBUGGER();
2998 /* Invalid object */
3002 offset = le16_to_cpu(object->usRecordOffset)
3003 + bp->object_info_tbl_offset;
3006 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
3011 if (LAST_RECORD_TYPE == header->ucRecordType ||
3012 0 == header->ucRecordSize)
3015 if (ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE ==
3016 header->ucRecordType &&
3017 sizeof(ATOM_CONNECTOR_HPDPIN_LUT_RECORD) <=
3018 header->ucRecordSize)
3019 return (ATOM_CONNECTOR_HPDPIN_LUT_RECORD *)header;
3021 offset += header->ucRecordSize;
3028 * Check whether we need to patch the VBIOS connector info table with
3029 * data from an external display connection info table. This is
3030 * necessary to support MXM boards with an OPM (output personality
3031 * module). With these designs, the VBIOS connector info table
3032 * specifies an MXM_CONNECTOR with a unique ID. The driver retrieves
3033 * the external connection info table through i2c and then looks up the
3034 * connector ID to find the real connector type (e.g. DFP1).
3037 static enum bp_result patch_bios_image_from_ext_display_connection_info(
3038 struct bios_parser *bp)
3040 ATOM_OBJECT_TABLE *connector_tbl;
3041 uint32_t connector_tbl_offset;
3042 struct graphics_object_id object_id;
3043 ATOM_OBJECT *object;
3044 ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO ext_display_connection_info_tbl;
3045 EXT_DISPLAY_PATH *ext_display_path;
3046 ATOM_CONNECTOR_AUXDDC_LUT_RECORD *aux_ddc_lut_record = NULL;
3047 ATOM_I2C_RECORD *i2c_record = NULL;
3048 ATOM_CONNECTOR_HPDPIN_LUT_RECORD *hpd_pin_lut_record = NULL;
3049 ATOM_HPD_INT_RECORD *hpd_record = NULL;
3050 ATOM_OBJECT_TABLE *encoder_table;
3051 uint32_t encoder_table_offset;
3052 ATOM_OBJECT *opm_object = NULL;
3054 struct graphics_object_id opm_object_id =
3055 dal_graphics_object_id_init(
3058 OBJECT_TYPE_GENERIC);
3059 ATOM_CONNECTOR_DEVICE_TAG_RECORD *dev_tag_record;
3060 uint32_t cached_device_support =
3061 le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport);
3063 uint32_t dst_number;
3064 uint16_t *dst_object_id_list;
3066 opm_object = get_bios_object(bp, opm_object_id);
3068 return BP_RESULT_UNSUPPORTED;
3070 memset(&ext_display_connection_info_tbl, 0,
3071 sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO));
3073 connector_tbl_offset = bp->object_info_tbl_offset
3074 + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
3075 connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
3077 /* Read Connector info table from EEPROM through i2c */
3078 if (get_ext_display_connection_info(bp,
3080 &ext_display_connection_info_tbl) != BP_RESULT_OK) {
3082 dm_logger_write(bp->base.ctx->logger, LOG_WARNING,
3083 "%s: Failed to read Connection Info Table", __func__);
3084 return BP_RESULT_UNSUPPORTED;
3087 /* Get pointer to AUX/DDC and HPD LUTs */
3088 aux_ddc_lut_record =
3089 get_ext_connector_aux_ddc_lut_record(bp, opm_object);
3090 hpd_pin_lut_record =
3091 get_ext_connector_hpd_pin_lut_record(bp, opm_object);
3093 if ((aux_ddc_lut_record == NULL) || (hpd_pin_lut_record == NULL))
3094 return BP_RESULT_UNSUPPORTED;
3096 /* Cache support bits for currently unmapped device types. */
3097 if (bp->remap_device_tags) {
3098 for (i = 0; i < connector_tbl->ucNumberOfObjects; ++i) {
3100 /* Remove support for all non-MXM connectors. */
3101 object = &connector_tbl->asObjects[i];
3102 object_id = object_id_from_bios_object_id(
3103 le16_to_cpu(object->usObjectID));
3104 if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
3105 (CONNECTOR_ID_MXM == object_id.id))
3108 /* Remove support for all device tags. */
3109 if (bios_parser_get_device_tag_record(
3110 bp, object, &dev_tag_record) != BP_RESULT_OK)
3113 for (j = 0; j < dev_tag_record->ucNumberOfDevice; ++j) {
3114 ATOM_CONNECTOR_DEVICE_TAG *device_tag =
3115 &dev_tag_record->asDeviceTag[j];
3116 cached_device_support &=
3117 ~le16_to_cpu(device_tag->usDeviceID);
3122 /* Find all MXM connector objects and patch them with connector info
3123 * from the external display connection info table. */
3124 for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
3127 object = &connector_tbl->asObjects[i];
3128 object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
3129 if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
3130 (CONNECTOR_ID_MXM != object_id.id))
3133 /* Get the correct connection info table entry based on the enum
3135 ext_display_path = get_ext_display_path_entry(
3136 &ext_display_connection_info_tbl,
3137 le16_to_cpu(object->usObjectID));
3138 if (!ext_display_path)
3139 return BP_RESULT_FAILURE;
3141 /* Patch device connector ID */
3142 object->usObjectID =
3143 cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceConnector));
3145 /* Patch device tag, ulACPIDeviceEnum. */
3146 add_device_tag_from_ext_display_path(
3150 &cached_device_support);
3152 /* Patch HPD info */
3153 if (ext_display_path->ucExtHPDPINLutIndex <
3154 MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES) {
3155 hpd_record = get_hpd_record(bp, object);
3158 ext_display_path->ucExtHPDPINLutIndex;
3159 hpd_record->ucHPDIntGPIOID =
3160 hpd_pin_lut_record->ucHPDPINMap[index];
3162 BREAK_TO_DEBUGGER();
3163 /* Invalid hpd record */
3164 return BP_RESULT_FAILURE;
3168 /* Patch I2C/AUX info */
3169 if (ext_display_path->ucExtHPDPINLutIndex <
3170 MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES) {
3171 i2c_record = get_i2c_record(bp, object);
3174 ext_display_path->ucExtAUXDDCLutIndex;
3175 i2c_record->sucI2cId =
3176 aux_ddc_lut_record->ucAUXDDCMap[index];
3178 BREAK_TO_DEBUGGER();
3179 /* Invalid I2C record */
3180 return BP_RESULT_FAILURE;
3184 /* Merge with other MXM connectors that map to the same physical
3187 j < connector_tbl->ucNumberOfObjects; j++) {
3188 ATOM_OBJECT *next_object;
3189 struct graphics_object_id next_object_id;
3190 EXT_DISPLAY_PATH *next_ext_display_path;
3192 next_object = &connector_tbl->asObjects[j];
3193 next_object_id = object_id_from_bios_object_id(
3194 le16_to_cpu(next_object->usObjectID));
3196 if ((OBJECT_TYPE_CONNECTOR != next_object_id.type) &&
3197 (CONNECTOR_ID_MXM == next_object_id.id))
3200 next_ext_display_path = get_ext_display_path_entry(
3201 &ext_display_connection_info_tbl,
3202 le16_to_cpu(next_object->usObjectID));
3204 if (next_ext_display_path == NULL)
3205 return BP_RESULT_FAILURE;
3207 /* Merge if using same connector. */
3208 if ((le16_to_cpu(next_ext_display_path->usDeviceConnector) ==
3209 le16_to_cpu(ext_display_path->usDeviceConnector)) &&
3210 (le16_to_cpu(ext_display_path->usDeviceConnector) != 0)) {
3211 /* Clear duplicate connector from table. */
3212 next_object->usObjectID = cpu_to_le16(0);
3213 add_device_tag_from_ext_display_path(
3217 &cached_device_support);
3222 /* Find all encoders which have an MXM object as their destination.
3223 * Replace the MXM object with the real connector Id from the external
3224 * display connection info table */
3226 encoder_table_offset = bp->object_info_tbl_offset
3227 + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
3228 encoder_table = GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
3230 for (i = 0; i < encoder_table->ucNumberOfObjects; i++) {
3233 object = &encoder_table->asObjects[i];
3235 dst_number = get_dest_obj_list(bp, object, &dst_object_id_list);
3237 for (j = 0; j < dst_number; j++) {
3238 object_id = object_id_from_bios_object_id(
3239 dst_object_id_list[j]);
3241 if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
3242 (CONNECTOR_ID_MXM != object_id.id))
3245 /* Get the correct connection info table entry based on
3248 get_ext_display_path_entry(
3249 &ext_display_connection_info_tbl,
3250 dst_object_id_list[j]);
3252 if (ext_display_path == NULL)
3253 return BP_RESULT_FAILURE;
3255 dst_object_id_list[j] =
3256 le16_to_cpu(ext_display_path->usDeviceConnector);
3260 return BP_RESULT_OK;
3264 * Check whether we need to patch the VBIOS connector info table with
3265 * data from an external display connection info table. This is
3266 * necessary to support MXM boards with an OPM (output personality
3267 * module). With these designs, the VBIOS connector info table
3268 * specifies an MXM_CONNECTOR with a unique ID. The driver retrieves
3269 * the external connection info table through i2c and then looks up the
3270 * connector ID to find the real connector type (e.g. DFP1).
3274 static void process_ext_display_connection_info(struct bios_parser *bp)
3276 ATOM_OBJECT_TABLE *connector_tbl;
3277 uint32_t connector_tbl_offset;
3278 struct graphics_object_id object_id;
3279 ATOM_OBJECT *object;
3280 bool mxm_connector_found = false;
3281 bool null_entry_found = false;
3284 connector_tbl_offset = bp->object_info_tbl_offset +
3285 le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
3286 connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
3288 /* Look for MXM connectors to determine whether we need patch the VBIOS
3289 * connector info table. Look for null entries to determine whether we
3290 * need to compact connector table. */
3291 for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
3292 object = &connector_tbl->asObjects[i];
3293 object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
3295 if ((OBJECT_TYPE_CONNECTOR == object_id.type) &&
3296 (CONNECTOR_ID_MXM == object_id.id)) {
3297 /* Once we found MXM connector - we can break */
3298 mxm_connector_found = true;
3300 } else if (OBJECT_TYPE_CONNECTOR != object_id.type) {
3301 /* We need to continue looping - to check if MXM
3302 * connector present */
3303 null_entry_found = true;
3307 /* Patch BIOS image */
3308 if (mxm_connector_found || null_entry_found) {
3309 uint32_t connectors_num = 0;
3310 uint8_t *original_bios;
3311 /* Step 1: Replace bios image with the new copy which will be
3313 bp->base.bios_local_image = kzalloc(bp->base.bios_size,
3315 if (bp->base.bios_local_image == NULL) {
3316 BREAK_TO_DEBUGGER();
3317 /* Failed to alloc bp->base.bios_local_image */
3321 memmove(bp->base.bios_local_image, bp->base.bios, bp->base.bios_size);
3322 original_bios = bp->base.bios;
3323 bp->base.bios = bp->base.bios_local_image;
3325 GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
3327 /* Step 2: (only if MXM connector found) Patch BIOS image with
3328 * info from external module */
3329 if (mxm_connector_found &&
3330 patch_bios_image_from_ext_display_connection_info(bp) !=
3332 /* Patching the bios image has failed. We will copy
3333 * again original image provided and afterwards
3334 * only remove null entries */
3336 bp->base.bios_local_image,
3338 bp->base.bios_size);
3341 /* Step 3: Compact connector table (remove null entries, valid
3342 * entries moved to beginning) */
3343 for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
3344 object = &connector_tbl->asObjects[i];
3345 object_id = object_id_from_bios_object_id(
3346 le16_to_cpu(object->usObjectID));
3348 if (OBJECT_TYPE_CONNECTOR != object_id.type)
3351 if (i != connectors_num) {
3354 asObjects[connectors_num],
3356 sizeof(ATOM_OBJECT));
3360 connector_tbl->ucNumberOfObjects = (uint8_t)connectors_num;
3364 static void bios_parser_post_init(struct dc_bios *dcb)
3366 struct bios_parser *bp = BP_FROM_DCB(dcb);
3368 process_ext_display_connection_info(bp);
3372 * bios_parser_set_scratch_critical_state
3375 * update critical state bit in VBIOS scratch register
3378 * bool - to set or reset state
3380 static void bios_parser_set_scratch_critical_state(
3381 struct dc_bios *dcb,
3384 bios_set_scratch_critical_state(dcb, state);
3388 * get_integrated_info_v8
3391 * Get V8 integrated BIOS information
3394 * bios_parser *bp - [in]BIOS parser handler to get master data table
3395 * integrated_info *info - [out] store and output integrated info
3398 * enum bp_result - BP_RESULT_OK if information is available,
3399 * BP_RESULT_BADBIOSTABLE otherwise.
3401 static enum bp_result get_integrated_info_v8(
3402 struct bios_parser *bp,
3403 struct integrated_info *info)
3405 ATOM_INTEGRATED_SYSTEM_INFO_V1_8 *info_v8;
3408 info_v8 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8,
3409 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
3411 if (info_v8 == NULL)
3412 return BP_RESULT_BADBIOSTABLE;
3413 info->boot_up_engine_clock = le32_to_cpu(info_v8->ulBootUpEngineClock) * 10;
3414 info->dentist_vco_freq = le32_to_cpu(info_v8->ulDentistVCOFreq) * 10;
3415 info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
3417 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
3418 /* Convert [10KHz] into [KHz] */
3419 info->disp_clk_voltage[i].max_supported_clk =
3420 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].
3421 ulMaximumSupportedCLK) * 10;
3422 info->disp_clk_voltage[i].voltage_index =
3423 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
3426 info->boot_up_req_display_vector =
3427 le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
3428 info->gpu_cap_info =
3429 le32_to_cpu(info_v8->ulGPUCapInfo);
3432 * system_config: Bit[0] = 0 : PCIE power gating disabled
3433 * = 1 : PCIE power gating enabled
3434 * Bit[1] = 0 : DDR-PLL shut down disabled
3435 * = 1 : DDR-PLL shut down enabled
3436 * Bit[2] = 0 : DDR-PLL power down disabled
3437 * = 1 : DDR-PLL power down enabled
3439 info->system_config = le32_to_cpu(info_v8->ulSystemConfig);
3440 info->cpu_cap_info = le32_to_cpu(info_v8->ulCPUCapInfo);
3441 info->boot_up_nb_voltage =
3442 le16_to_cpu(info_v8->usBootUpNBVoltage);
3443 info->ext_disp_conn_info_offset =
3444 le16_to_cpu(info_v8->usExtDispConnInfoOffset);
3445 info->memory_type = info_v8->ucMemoryType;
3446 info->ma_channel_number = info_v8->ucUMAChannelNumber;
3447 info->gmc_restore_reset_time =
3448 le32_to_cpu(info_v8->ulGMCRestoreResetTime);
3450 info->minimum_n_clk =
3451 le32_to_cpu(info_v8->ulNbpStateNClkFreq[0]);
3452 for (i = 1; i < 4; ++i)
3453 info->minimum_n_clk =
3454 info->minimum_n_clk < le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]) ?
3455 info->minimum_n_clk : le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]);
3457 info->idle_n_clk = le32_to_cpu(info_v8->ulIdleNClk);
3458 info->ddr_dll_power_up_time =
3459 le32_to_cpu(info_v8->ulDDR_DLL_PowerUpTime);
3460 info->ddr_pll_power_up_time =
3461 le32_to_cpu(info_v8->ulDDR_PLL_PowerUpTime);
3462 info->pcie_clk_ss_type = le16_to_cpu(info_v8->usPCIEClkSSType);
3463 info->lvds_ss_percentage =
3464 le16_to_cpu(info_v8->usLvdsSSPercentage);
3465 info->lvds_sspread_rate_in_10hz =
3466 le16_to_cpu(info_v8->usLvdsSSpreadRateIn10Hz);
3467 info->hdmi_ss_percentage =
3468 le16_to_cpu(info_v8->usHDMISSPercentage);
3469 info->hdmi_sspread_rate_in_10hz =
3470 le16_to_cpu(info_v8->usHDMISSpreadRateIn10Hz);
3471 info->dvi_ss_percentage =
3472 le16_to_cpu(info_v8->usDVISSPercentage);
3473 info->dvi_sspread_rate_in_10_hz =
3474 le16_to_cpu(info_v8->usDVISSpreadRateIn10Hz);
3476 info->max_lvds_pclk_freq_in_single_link =
3477 le16_to_cpu(info_v8->usMaxLVDSPclkFreqInSingleLink);
3478 info->lvds_misc = info_v8->ucLvdsMisc;
3479 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
3480 info_v8->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
3481 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
3482 info_v8->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
3483 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
3484 info_v8->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
3485 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
3486 info_v8->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
3487 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
3488 info_v8->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
3489 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
3490 info_v8->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
3491 info->lvds_off_to_on_delay_in_4ms =
3492 info_v8->ucLVDSOffToOnDelay_in4Ms;
3493 info->lvds_bit_depth_control_val =
3494 le32_to_cpu(info_v8->ulLCDBitDepthControlVal);
3496 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
3497 /* Convert [10KHz] into [KHz] */
3498 info->avail_s_clk[i].supported_s_clk =
3499 le32_to_cpu(info_v8->sAvail_SCLK[i].ulSupportedSCLK) * 10;
3500 info->avail_s_clk[i].voltage_index =
3501 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageIndex);
3502 info->avail_s_clk[i].voltage_id =
3503 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageID);
3506 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
3507 info->ext_disp_conn_info.gu_id[i] =
3508 info_v8->sExtDispConnInfo.ucGuid[i];
3511 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
3512 info->ext_disp_conn_info.path[i].device_connector_id =
3513 object_id_from_bios_object_id(
3514 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceConnector));
3516 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
3517 object_id_from_bios_object_id(
3518 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
3520 info->ext_disp_conn_info.path[i].device_tag =
3521 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceTag);
3522 info->ext_disp_conn_info.path[i].device_acpi_enum =
3523 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
3524 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
3525 info_v8->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
3526 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
3527 info_v8->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
3528 info->ext_disp_conn_info.path[i].channel_mapping.raw =
3529 info_v8->sExtDispConnInfo.sPath[i].ucChannelMapping;
3531 info->ext_disp_conn_info.checksum =
3532 info_v8->sExtDispConnInfo.ucChecksum;
3534 return BP_RESULT_OK;
3538 * get_integrated_info_v8
3541 * Get V8 integrated BIOS information
3544 * bios_parser *bp - [in]BIOS parser handler to get master data table
3545 * integrated_info *info - [out] store and output integrated info
3548 * enum bp_result - BP_RESULT_OK if information is available,
3549 * BP_RESULT_BADBIOSTABLE otherwise.
3551 static enum bp_result get_integrated_info_v9(
3552 struct bios_parser *bp,
3553 struct integrated_info *info)
3555 ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info_v9;
3558 info_v9 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9,
3559 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
3562 return BP_RESULT_BADBIOSTABLE;
3564 info->boot_up_engine_clock = le32_to_cpu(info_v9->ulBootUpEngineClock) * 10;
3565 info->dentist_vco_freq = le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
3566 info->boot_up_uma_clock = le32_to_cpu(info_v9->ulBootUpUMAClock) * 10;
3568 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
3569 /* Convert [10KHz] into [KHz] */
3570 info->disp_clk_voltage[i].max_supported_clk =
3571 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
3572 info->disp_clk_voltage[i].voltage_index =
3573 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
3576 info->boot_up_req_display_vector =
3577 le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
3578 info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
3581 * system_config: Bit[0] = 0 : PCIE power gating disabled
3582 * = 1 : PCIE power gating enabled
3583 * Bit[1] = 0 : DDR-PLL shut down disabled
3584 * = 1 : DDR-PLL shut down enabled
3585 * Bit[2] = 0 : DDR-PLL power down disabled
3586 * = 1 : DDR-PLL power down enabled
3588 info->system_config = le32_to_cpu(info_v9->ulSystemConfig);
3589 info->cpu_cap_info = le32_to_cpu(info_v9->ulCPUCapInfo);
3590 info->boot_up_nb_voltage = le16_to_cpu(info_v9->usBootUpNBVoltage);
3591 info->ext_disp_conn_info_offset = le16_to_cpu(info_v9->usExtDispConnInfoOffset);
3592 info->memory_type = info_v9->ucMemoryType;
3593 info->ma_channel_number = info_v9->ucUMAChannelNumber;
3594 info->gmc_restore_reset_time = le32_to_cpu(info_v9->ulGMCRestoreResetTime);
3596 info->minimum_n_clk = le32_to_cpu(info_v9->ulNbpStateNClkFreq[0]);
3597 for (i = 1; i < 4; ++i)
3598 info->minimum_n_clk =
3599 info->minimum_n_clk < le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]) ?
3600 info->minimum_n_clk : le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]);
3602 info->idle_n_clk = le32_to_cpu(info_v9->ulIdleNClk);
3603 info->ddr_dll_power_up_time = le32_to_cpu(info_v9->ulDDR_DLL_PowerUpTime);
3604 info->ddr_pll_power_up_time = le32_to_cpu(info_v9->ulDDR_PLL_PowerUpTime);
3605 info->pcie_clk_ss_type = le16_to_cpu(info_v9->usPCIEClkSSType);
3606 info->lvds_ss_percentage = le16_to_cpu(info_v9->usLvdsSSPercentage);
3607 info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v9->usLvdsSSpreadRateIn10Hz);
3608 info->hdmi_ss_percentage = le16_to_cpu(info_v9->usHDMISSPercentage);
3609 info->hdmi_sspread_rate_in_10hz = le16_to_cpu(info_v9->usHDMISSpreadRateIn10Hz);
3610 info->dvi_ss_percentage = le16_to_cpu(info_v9->usDVISSPercentage);
3611 info->dvi_sspread_rate_in_10_hz = le16_to_cpu(info_v9->usDVISSpreadRateIn10Hz);
3613 info->max_lvds_pclk_freq_in_single_link =
3614 le16_to_cpu(info_v9->usMaxLVDSPclkFreqInSingleLink);
3615 info->lvds_misc = info_v9->ucLvdsMisc;
3616 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
3617 info_v9->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
3618 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
3619 info_v9->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
3620 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
3621 info_v9->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
3622 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
3623 info_v9->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
3624 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
3625 info_v9->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
3626 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
3627 info_v9->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
3628 info->lvds_off_to_on_delay_in_4ms =
3629 info_v9->ucLVDSOffToOnDelay_in4Ms;
3630 info->lvds_bit_depth_control_val =
3631 le32_to_cpu(info_v9->ulLCDBitDepthControlVal);
3633 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
3634 /* Convert [10KHz] into [KHz] */
3635 info->avail_s_clk[i].supported_s_clk =
3636 le32_to_cpu(info_v9->sAvail_SCLK[i].ulSupportedSCLK) * 10;
3637 info->avail_s_clk[i].voltage_index =
3638 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageIndex);
3639 info->avail_s_clk[i].voltage_id =
3640 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageID);
3643 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
3644 info->ext_disp_conn_info.gu_id[i] =
3645 info_v9->sExtDispConnInfo.ucGuid[i];
3648 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
3649 info->ext_disp_conn_info.path[i].device_connector_id =
3650 object_id_from_bios_object_id(
3651 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceConnector));
3653 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
3654 object_id_from_bios_object_id(
3655 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
3657 info->ext_disp_conn_info.path[i].device_tag =
3658 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceTag);
3659 info->ext_disp_conn_info.path[i].device_acpi_enum =
3660 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
3661 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
3662 info_v9->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
3663 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
3664 info_v9->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
3665 info->ext_disp_conn_info.path[i].channel_mapping.raw =
3666 info_v9->sExtDispConnInfo.sPath[i].ucChannelMapping;
3668 info->ext_disp_conn_info.checksum =
3669 info_v9->sExtDispConnInfo.ucChecksum;
3671 return BP_RESULT_OK;
3675 * construct_integrated_info
3678 * Get integrated BIOS information based on table revision
3681 * bios_parser *bp - [in]BIOS parser handler to get master data table
3682 * integrated_info *info - [out] store and output integrated info
3685 * enum bp_result - BP_RESULT_OK if information is available,
3686 * BP_RESULT_BADBIOSTABLE otherwise.
3688 static enum bp_result construct_integrated_info(
3689 struct bios_parser *bp,
3690 struct integrated_info *info)
3692 enum bp_result result = BP_RESULT_BADBIOSTABLE;
3694 ATOM_COMMON_TABLE_HEADER *header;
3695 struct atom_data_revision revision;
3697 if (bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo) {
3698 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
3699 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
3701 get_atom_data_table_revision(header, &revision);
3703 /* Don't need to check major revision as they are all 1 */
3704 switch (revision.minor) {
3706 result = get_integrated_info_v8(bp, info);
3709 result = get_integrated_info_v9(bp, info);
3717 /* Sort voltage table from low to high*/
3718 if (result == BP_RESULT_OK) {
3719 struct clock_voltage_caps temp = {0, 0};
3723 for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
3724 for (j = i; j > 0; --j) {
3726 info->disp_clk_voltage[j].max_supported_clk <
3727 info->disp_clk_voltage[j-1].max_supported_clk) {
3728 /* swap j and j - 1*/
3729 temp = info->disp_clk_voltage[j-1];
3730 info->disp_clk_voltage[j-1] =
3731 info->disp_clk_voltage[j];
3732 info->disp_clk_voltage[j] = temp;
3742 static struct integrated_info *bios_parser_create_integrated_info(
3743 struct dc_bios *dcb)
3745 struct bios_parser *bp = BP_FROM_DCB(dcb);
3746 struct integrated_info *info = NULL;
3748 info = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);
3755 if (construct_integrated_info(bp, info) == BP_RESULT_OK)
3763 /******************************************************************************/
3765 static const struct dc_vbios_funcs vbios_funcs = {
3766 .get_connectors_number = bios_parser_get_connectors_number,
3768 .get_encoder_id = bios_parser_get_encoder_id,
3770 .get_connector_id = bios_parser_get_connector_id,
3772 .get_dst_number = bios_parser_get_dst_number,
3774 .get_src_obj = bios_parser_get_src_obj,
3776 .get_dst_obj = bios_parser_get_dst_obj,
3778 .get_i2c_info = bios_parser_get_i2c_info,
3780 .get_voltage_ddc_info = bios_parser_get_voltage_ddc_info,
3782 .get_thermal_ddc_info = bios_parser_get_thermal_ddc_info,
3784 .get_hpd_info = bios_parser_get_hpd_info,
3786 .get_device_tag = bios_parser_get_device_tag,
3788 .get_firmware_info = bios_parser_get_firmware_info,
3790 .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info,
3792 .get_ss_entry_number = bios_parser_get_ss_entry_number,
3794 .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
3796 .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
3798 .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
3800 .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
3802 .get_encoder_cap_info = bios_parser_get_encoder_cap_info,
3804 /* bios scratch register communication */
3805 .is_accelerated_mode = bios_is_accelerated_mode,
3807 .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
3809 .is_device_id_supported = bios_parser_is_device_id_supported,
3812 .encoder_control = bios_parser_encoder_control,
3814 .transmitter_control = bios_parser_transmitter_control,
3816 .crt_control = bios_parser_crt_control, /* not used in DAL3. keep for now in case we need to support VGA on Bonaire */
3818 .enable_crtc = bios_parser_enable_crtc,
3820 .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
3822 .set_pixel_clock = bios_parser_set_pixel_clock,
3824 .set_dce_clock = bios_parser_set_dce_clock,
3826 .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
3828 .program_crtc_timing = bios_parser_program_crtc_timing, /* still use. should probably retire and program directly */
3830 .crtc_source_select = bios_parser_crtc_source_select, /* still use. should probably retire and program directly */
3832 .program_display_engine_pll = bios_parser_program_display_engine_pll,
3834 .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
3836 /* SW init and patch */
3837 .post_init = bios_parser_post_init, /* patch vbios table for mxm module by reading i2c */
3839 .bios_parser_destroy = bios_parser_destroy,
3842 static bool bios_parser_construct(
3843 struct bios_parser *bp,
3844 struct bp_init_data *init,
3845 enum dce_version dce_version)
3847 uint16_t *rom_header_offset = NULL;
3848 ATOM_ROM_HEADER *rom_header = NULL;
3849 ATOM_OBJECT_HEADER *object_info_tbl;
3850 struct atom_data_revision tbl_rev = {0};
3858 bp->base.funcs = &vbios_funcs;
3859 bp->base.bios = init->bios;
3860 bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
3862 bp->base.ctx = init->ctx;
3863 bp->base.bios_local_image = NULL;
3866 GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
3868 if (!rom_header_offset)
3871 rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
3876 get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev);
3877 if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
3880 bp->master_data_tbl =
3881 GET_IMAGE(ATOM_MASTER_DATA_TABLE,
3882 rom_header->usMasterDataTableOffset);
3884 if (!bp->master_data_tbl)
3887 bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
3889 if (!bp->object_info_tbl_offset)
3893 GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
3895 if (!object_info_tbl)
3898 get_atom_data_table_revision(&object_info_tbl->sHeader,
3899 &bp->object_info_tbl.revision);
3901 if (bp->object_info_tbl.revision.major == 1
3902 && bp->object_info_tbl.revision.minor >= 3) {
3903 ATOM_OBJECT_HEADER_V3 *tbl_v3;
3905 tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
3906 bp->object_info_tbl_offset);
3910 bp->object_info_tbl.v1_3 = tbl_v3;
3911 } else if (bp->object_info_tbl.revision.major == 1
3912 && bp->object_info_tbl.revision.minor >= 1)
3913 bp->object_info_tbl.v1_1 = object_info_tbl;
3917 dal_bios_parser_init_cmd_tbl(bp);
3918 dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
3920 bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base);
3925 /******************************************************************************/