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
);
194 uint32_t connector_table_offset
= bp
->object_info_tbl_offset
195 + le16_to_cpu(bp
->object_info_tbl
.v1_1
->usConnectorObjectTableOffset
);
197 ATOM_OBJECT_TABLE
*tbl
=
198 GET_IMAGE(ATOM_OBJECT_TABLE
, connector_table_offset
);
200 if (tbl
&& tbl
->ucNumberOfObjects
> i
) {
201 const uint16_t id
= le16_to_cpu(tbl
->asObjects
[i
].usObjectID
);
203 object_id
= object_id_from_bios_object_id(id
);
209 static uint32_t bios_parser_get_dst_number(struct dc_bios
*dcb
,
210 struct graphics_object_id id
)
212 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
213 ATOM_OBJECT
*object
= get_bios_object(bp
, id
);
215 return get_dst_number_from_object(bp
, object
);
218 static enum bp_result
bios_parser_get_src_obj(struct dc_bios
*dcb
,
219 struct graphics_object_id object_id
, uint32_t index
,
220 struct graphics_object_id
*src_object_id
)
225 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
228 return BP_RESULT_BADINPUT
;
230 object
= get_bios_object(bp
, object_id
);
233 BREAK_TO_DEBUGGER(); /* Invalid object id */
234 return BP_RESULT_BADINPUT
;
237 number
= get_src_obj_list(bp
, object
, &id
);
240 return BP_RESULT_BADINPUT
;
242 *src_object_id
= object_id_from_bios_object_id(id
[index
]);
247 static enum bp_result
bios_parser_get_dst_obj(struct dc_bios
*dcb
,
248 struct graphics_object_id object_id
, uint32_t index
,
249 struct graphics_object_id
*dest_object_id
)
254 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
257 return BP_RESULT_BADINPUT
;
259 object
= get_bios_object(bp
, object_id
);
261 number
= get_dest_obj_list(bp
, object
, &id
);
263 if (number
<= index
|| !id
)
264 return BP_RESULT_BADINPUT
;
266 *dest_object_id
= object_id_from_bios_object_id(id
[index
]);
271 static enum bp_result
bios_parser_get_i2c_info(struct dc_bios
*dcb
,
272 struct graphics_object_id id
,
273 struct graphics_object_i2c_info
*info
)
277 ATOM_COMMON_RECORD_HEADER
*header
;
278 ATOM_I2C_RECORD
*record
;
279 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
282 return BP_RESULT_BADINPUT
;
284 object
= get_bios_object(bp
, id
);
287 return BP_RESULT_BADINPUT
;
289 offset
= le16_to_cpu(object
->usRecordOffset
)
290 + bp
->object_info_tbl_offset
;
293 header
= GET_IMAGE(ATOM_COMMON_RECORD_HEADER
, offset
);
296 return BP_RESULT_BADBIOSTABLE
;
298 if (LAST_RECORD_TYPE
== header
->ucRecordType
||
299 !header
->ucRecordSize
)
302 if (ATOM_I2C_RECORD_TYPE
== header
->ucRecordType
303 && sizeof(ATOM_I2C_RECORD
) <= header
->ucRecordSize
) {
304 /* get the I2C info */
305 record
= (ATOM_I2C_RECORD
*) header
;
307 if (get_gpio_i2c_info(bp
, record
, info
) == BP_RESULT_OK
)
311 offset
+= header
->ucRecordSize
;
314 return BP_RESULT_NORECORD
;
317 static enum bp_result
get_voltage_ddc_info_v1(uint8_t *i2c_line
,
318 ATOM_COMMON_TABLE_HEADER
*header
,
321 enum bp_result result
= BP_RESULT_NORECORD
;
322 ATOM_VOLTAGE_OBJECT_INFO
*info
=
323 (ATOM_VOLTAGE_OBJECT_INFO
*) address
;
325 uint8_t *voltage_current_object
= (uint8_t *) &info
->asVoltageObj
[0];
327 while ((address
+ le16_to_cpu(header
->usStructureSize
)) > voltage_current_object
) {
328 ATOM_VOLTAGE_OBJECT
*object
=
329 (ATOM_VOLTAGE_OBJECT
*) voltage_current_object
;
331 if ((object
->ucVoltageType
== SET_VOLTAGE_INIT_MODE
) &&
332 (object
->ucVoltageType
&
333 VOLTAGE_CONTROLLED_BY_I2C_MASK
)) {
335 *i2c_line
= object
->asControl
.ucVoltageControlI2cLine
337 result
= BP_RESULT_OK
;
341 voltage_current_object
+= object
->ucSize
;
346 static enum bp_result
get_voltage_ddc_info_v3(uint8_t *i2c_line
,
348 ATOM_COMMON_TABLE_HEADER
*header
,
351 enum bp_result result
= BP_RESULT_NORECORD
;
352 ATOM_VOLTAGE_OBJECT_INFO_V3_1
*info
=
353 (ATOM_VOLTAGE_OBJECT_INFO_V3_1
*) address
;
355 uint8_t *voltage_current_object
=
356 (uint8_t *) (&(info
->asVoltageObj
[0]));
358 while ((address
+ le16_to_cpu(header
->usStructureSize
)) > voltage_current_object
) {
359 ATOM_I2C_VOLTAGE_OBJECT_V3
*object
=
360 (ATOM_I2C_VOLTAGE_OBJECT_V3
*) voltage_current_object
;
362 if (object
->sHeader
.ucVoltageMode
==
363 ATOM_INIT_VOLTAGE_REGULATOR
) {
364 if (object
->sHeader
.ucVoltageType
== index
) {
365 *i2c_line
= object
->ucVoltageControlI2cLine
367 result
= BP_RESULT_OK
;
372 voltage_current_object
+= le16_to_cpu(object
->sHeader
.usSize
);
377 static enum bp_result
bios_parser_get_thermal_ddc_info(
379 uint32_t i2c_channel_id
,
380 struct graphics_object_i2c_info
*info
)
382 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
383 ATOM_I2C_ID_CONFIG_ACCESS
*config
;
384 ATOM_I2C_RECORD record
;
387 return BP_RESULT_BADINPUT
;
389 config
= (ATOM_I2C_ID_CONFIG_ACCESS
*) &i2c_channel_id
;
391 record
.sucI2cId
.bfHW_Capable
= config
->sbfAccess
.bfHW_Capable
;
392 record
.sucI2cId
.bfI2C_LineMux
= config
->sbfAccess
.bfI2C_LineMux
;
393 record
.sucI2cId
.bfHW_EngineID
= config
->sbfAccess
.bfHW_EngineID
;
395 return get_gpio_i2c_info(bp
, &record
, info
);
398 static enum bp_result
bios_parser_get_voltage_ddc_info(struct dc_bios
*dcb
,
400 struct graphics_object_i2c_info
*info
)
402 uint8_t i2c_line
= 0;
403 enum bp_result result
= BP_RESULT_NORECORD
;
404 uint8_t *voltage_info_address
;
405 ATOM_COMMON_TABLE_HEADER
*header
;
406 struct atom_data_revision revision
= {0};
407 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
409 if (!DATA_TABLES(VoltageObjectInfo
))
412 voltage_info_address
= bios_get_image(&bp
->base
, DATA_TABLES(VoltageObjectInfo
), sizeof(ATOM_COMMON_TABLE_HEADER
));
414 header
= (ATOM_COMMON_TABLE_HEADER
*) voltage_info_address
;
416 get_atom_data_table_revision(header
, &revision
);
418 switch (revision
.major
) {
421 result
= get_voltage_ddc_info_v1(&i2c_line
, header
,
422 voltage_info_address
);
425 if (revision
.minor
!= 1)
427 result
= get_voltage_ddc_info_v3(&i2c_line
, index
, header
,
428 voltage_info_address
);
432 if (result
== BP_RESULT_OK
)
433 result
= bios_parser_get_thermal_ddc_info(dcb
,
439 /* TODO: temporary commented out to suppress 'defined but not used' warning */
441 static enum bp_result
bios_parser_get_ddc_info_for_i2c_line(
442 struct bios_parser
*bp
,
443 uint8_t i2c_line
, struct graphics_object_i2c_info
*info
)
447 ATOM_OBJECT_TABLE
*table
;
451 return BP_RESULT_BADINPUT
;
453 offset
= le16_to_cpu(bp
->object_info_tbl
.v1_1
->usConnectorObjectTableOffset
);
455 offset
+= bp
->object_info_tbl_offset
;
457 table
= GET_IMAGE(ATOM_OBJECT_TABLE
, offset
);
460 return BP_RESULT_BADBIOSTABLE
;
462 for (i
= 0; i
< table
->ucNumberOfObjects
; i
++) {
463 object
= &table
->asObjects
[i
];
466 BREAK_TO_DEBUGGER(); /* Invalid object id */
467 return BP_RESULT_BADINPUT
;
470 offset
= le16_to_cpu(object
->usRecordOffset
)
471 + bp
->object_info_tbl_offset
;
474 ATOM_COMMON_RECORD_HEADER
*header
=
475 GET_IMAGE(ATOM_COMMON_RECORD_HEADER
, offset
);
478 return BP_RESULT_BADBIOSTABLE
;
480 offset
+= header
->ucRecordSize
;
482 if (LAST_RECORD_TYPE
== header
->ucRecordType
||
483 !header
->ucRecordSize
)
486 if (ATOM_I2C_RECORD_TYPE
== header
->ucRecordType
487 && sizeof(ATOM_I2C_RECORD
) <=
488 header
->ucRecordSize
) {
489 ATOM_I2C_RECORD
*record
=
490 (ATOM_I2C_RECORD
*) header
;
492 if (i2c_line
!= record
->sucI2cId
.bfI2C_LineMux
)
495 /* get the I2C info */
496 if (get_gpio_i2c_info(bp
, record
, info
) ==
503 return BP_RESULT_NORECORD
;
507 static enum bp_result
bios_parser_get_hpd_info(struct dc_bios
*dcb
,
508 struct graphics_object_id id
,
509 struct graphics_object_hpd_info
*info
)
511 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
513 ATOM_HPD_INT_RECORD
*record
= NULL
;
516 return BP_RESULT_BADINPUT
;
518 object
= get_bios_object(bp
, id
);
521 return BP_RESULT_BADINPUT
;
523 record
= get_hpd_record(bp
, object
);
525 if (record
!= NULL
) {
526 info
->hpd_int_gpio_uid
= record
->ucHPDIntGPIOID
;
527 info
->hpd_active
= record
->ucPlugged_PinState
;
531 return BP_RESULT_NORECORD
;
534 static enum bp_result
bios_parser_get_device_tag_record(
535 struct bios_parser
*bp
,
537 ATOM_CONNECTOR_DEVICE_TAG_RECORD
**record
)
539 ATOM_COMMON_RECORD_HEADER
*header
;
542 offset
= le16_to_cpu(object
->usRecordOffset
)
543 + bp
->object_info_tbl_offset
;
546 header
= GET_IMAGE(ATOM_COMMON_RECORD_HEADER
, offset
);
549 return BP_RESULT_BADBIOSTABLE
;
551 offset
+= header
->ucRecordSize
;
553 if (LAST_RECORD_TYPE
== header
->ucRecordType
||
554 !header
->ucRecordSize
)
557 if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE
!=
558 header
->ucRecordType
)
561 if (sizeof(ATOM_CONNECTOR_DEVICE_TAG
) > header
->ucRecordSize
)
564 *record
= (ATOM_CONNECTOR_DEVICE_TAG_RECORD
*) header
;
568 return BP_RESULT_NORECORD
;
571 static enum bp_result
bios_parser_get_device_tag(
573 struct graphics_object_id connector_object_id
,
574 uint32_t device_tag_index
,
575 struct connector_device_tag_info
*info
)
577 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
579 ATOM_CONNECTOR_DEVICE_TAG_RECORD
*record
= NULL
;
580 ATOM_CONNECTOR_DEVICE_TAG
*device_tag
;
583 return BP_RESULT_BADINPUT
;
585 /* getBiosObject will return MXM object */
586 object
= get_bios_object(bp
, connector_object_id
);
589 BREAK_TO_DEBUGGER(); /* Invalid object id */
590 return BP_RESULT_BADINPUT
;
593 if (bios_parser_get_device_tag_record(bp
, object
, &record
)
595 return BP_RESULT_NORECORD
;
597 if (device_tag_index
>= record
->ucNumberOfDevice
)
598 return BP_RESULT_NORECORD
;
600 device_tag
= &record
->asDeviceTag
[device_tag_index
];
602 info
->acpi_device
= le32_to_cpu(device_tag
->ulACPIDeviceEnum
);
604 device_type_from_device_id(le16_to_cpu(device_tag
->usDeviceID
));
609 static enum bp_result
get_firmware_info_v1_4(
610 struct bios_parser
*bp
,
611 struct dc_firmware_info
*info
);
612 static enum bp_result
get_firmware_info_v2_1(
613 struct bios_parser
*bp
,
614 struct dc_firmware_info
*info
);
615 static enum bp_result
get_firmware_info_v2_2(
616 struct bios_parser
*bp
,
617 struct dc_firmware_info
*info
);
619 static enum bp_result
bios_parser_get_firmware_info(
621 struct dc_firmware_info
*info
)
623 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
624 enum bp_result result
= BP_RESULT_BADBIOSTABLE
;
625 ATOM_COMMON_TABLE_HEADER
*header
;
626 struct atom_data_revision revision
;
628 if (info
&& DATA_TABLES(FirmwareInfo
)) {
629 header
= GET_IMAGE(ATOM_COMMON_TABLE_HEADER
,
630 DATA_TABLES(FirmwareInfo
));
631 get_atom_data_table_revision(header
, &revision
);
632 switch (revision
.major
) {
634 switch (revision
.minor
) {
636 result
= get_firmware_info_v1_4(bp
, info
);
644 switch (revision
.minor
) {
646 result
= get_firmware_info_v2_1(bp
, info
);
649 result
= get_firmware_info_v2_2(bp
, info
);
663 static enum bp_result
get_firmware_info_v1_4(
664 struct bios_parser
*bp
,
665 struct dc_firmware_info
*info
)
667 ATOM_FIRMWARE_INFO_V1_4
*firmware_info
=
668 GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4
,
669 DATA_TABLES(FirmwareInfo
));
672 return BP_RESULT_BADINPUT
;
675 return BP_RESULT_BADBIOSTABLE
;
677 memset(info
, 0, sizeof(*info
));
679 /* Pixel clock pll information. We need to convert from 10KHz units into
681 info
->pll_info
.crystal_frequency
=
682 le16_to_cpu(firmware_info
->usReferenceClock
) * 10;
683 info
->pll_info
.min_input_pxl_clk_pll_frequency
=
684 le16_to_cpu(firmware_info
->usMinPixelClockPLL_Input
) * 10;
685 info
->pll_info
.max_input_pxl_clk_pll_frequency
=
686 le16_to_cpu(firmware_info
->usMaxPixelClockPLL_Input
) * 10;
687 info
->pll_info
.min_output_pxl_clk_pll_frequency
=
688 le32_to_cpu(firmware_info
->ulMinPixelClockPLL_Output
) * 10;
689 info
->pll_info
.max_output_pxl_clk_pll_frequency
=
690 le32_to_cpu(firmware_info
->ulMaxPixelClockPLL_Output
) * 10;
692 if (firmware_info
->usFirmwareCapability
.sbfAccess
.MemoryClockSS_Support
)
693 /* Since there is no information on the SS, report conservative
694 * value 3% for bandwidth calculation */
696 info
->feature
.memory_clk_ss_percentage
= THREE_PERCENT_OF_10000
;
698 if (firmware_info
->usFirmwareCapability
.sbfAccess
.EngineClockSS_Support
)
699 /* Since there is no information on the SS,report conservative
700 * value 3% for bandwidth calculation */
702 info
->feature
.engine_clk_ss_percentage
= THREE_PERCENT_OF_10000
;
707 static enum bp_result
get_ss_info_v3_1(
708 struct bios_parser
*bp
,
711 struct spread_spectrum_info
*ss_info
);
713 static enum bp_result
get_firmware_info_v2_1(
714 struct bios_parser
*bp
,
715 struct dc_firmware_info
*info
)
717 ATOM_FIRMWARE_INFO_V2_1
*firmwareInfo
=
718 GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1
, DATA_TABLES(FirmwareInfo
));
719 struct spread_spectrum_info internalSS
;
723 return BP_RESULT_BADINPUT
;
726 return BP_RESULT_BADBIOSTABLE
;
728 memset(info
, 0, sizeof(*info
));
730 /* Pixel clock pll information. We need to convert from 10KHz units into
732 info
->pll_info
.crystal_frequency
=
733 le16_to_cpu(firmwareInfo
->usCoreReferenceClock
) * 10;
734 info
->pll_info
.min_input_pxl_clk_pll_frequency
=
735 le16_to_cpu(firmwareInfo
->usMinPixelClockPLL_Input
) * 10;
736 info
->pll_info
.max_input_pxl_clk_pll_frequency
=
737 le16_to_cpu(firmwareInfo
->usMaxPixelClockPLL_Input
) * 10;
738 info
->pll_info
.min_output_pxl_clk_pll_frequency
=
739 le32_to_cpu(firmwareInfo
->ulMinPixelClockPLL_Output
) * 10;
740 info
->pll_info
.max_output_pxl_clk_pll_frequency
=
741 le32_to_cpu(firmwareInfo
->ulMaxPixelClockPLL_Output
) * 10;
742 info
->default_display_engine_pll_frequency
=
743 le32_to_cpu(firmwareInfo
->ulDefaultDispEngineClkFreq
) * 10;
744 info
->external_clock_source_frequency_for_dp
=
745 le16_to_cpu(firmwareInfo
->usUniphyDPModeExtClkFreq
) * 10;
746 info
->min_allowed_bl_level
= firmwareInfo
->ucMinAllowedBL_Level
;
748 /* There should be only one entry in the SS info table for Memory Clock
751 if (firmwareInfo
->usFirmwareCapability
.sbfAccess
.MemoryClockSS_Support
)
752 /* Since there is no information for external SS, report
753 * conservative value 3% for bandwidth calculation */
755 info
->feature
.memory_clk_ss_percentage
= THREE_PERCENT_OF_10000
;
756 else if (get_ss_info_v3_1(bp
,
757 ASIC_INTERNAL_MEMORY_SS
, index
, &internalSS
) == BP_RESULT_OK
) {
758 if (internalSS
.spread_spectrum_percentage
) {
759 info
->feature
.memory_clk_ss_percentage
=
760 internalSS
.spread_spectrum_percentage
;
761 if (internalSS
.type
.CENTER_MODE
) {
762 /* if it is centermode, the exact SS Percentage
763 * will be round up of half of the percentage
764 * reported in the SS table */
765 ++info
->feature
.memory_clk_ss_percentage
;
766 info
->feature
.memory_clk_ss_percentage
/= 2;
771 /* There should be only one entry in the SS info table for Engine Clock
774 if (firmwareInfo
->usFirmwareCapability
.sbfAccess
.EngineClockSS_Support
)
775 /* Since there is no information for external SS, report
776 * conservative value 3% for bandwidth calculation */
778 info
->feature
.engine_clk_ss_percentage
= THREE_PERCENT_OF_10000
;
779 else if (get_ss_info_v3_1(bp
,
780 ASIC_INTERNAL_ENGINE_SS
, index
, &internalSS
) == BP_RESULT_OK
) {
781 if (internalSS
.spread_spectrum_percentage
) {
782 info
->feature
.engine_clk_ss_percentage
=
783 internalSS
.spread_spectrum_percentage
;
784 if (internalSS
.type
.CENTER_MODE
) {
785 /* if it is centermode, the exact SS Percentage
786 * will be round up of half of the percentage
787 * reported in the SS table */
788 ++info
->feature
.engine_clk_ss_percentage
;
789 info
->feature
.engine_clk_ss_percentage
/= 2;
797 static enum bp_result
get_firmware_info_v2_2(
798 struct bios_parser
*bp
,
799 struct dc_firmware_info
*info
)
801 ATOM_FIRMWARE_INFO_V2_2
*firmware_info
;
802 struct spread_spectrum_info internal_ss
;
806 return BP_RESULT_BADINPUT
;
808 firmware_info
= GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2
,
809 DATA_TABLES(FirmwareInfo
));
812 return BP_RESULT_BADBIOSTABLE
;
814 memset(info
, 0, sizeof(*info
));
816 /* Pixel clock pll information. We need to convert from 10KHz units into
818 info
->pll_info
.crystal_frequency
=
819 le16_to_cpu(firmware_info
->usCoreReferenceClock
) * 10;
820 info
->pll_info
.min_input_pxl_clk_pll_frequency
=
821 le16_to_cpu(firmware_info
->usMinPixelClockPLL_Input
) * 10;
822 info
->pll_info
.max_input_pxl_clk_pll_frequency
=
823 le16_to_cpu(firmware_info
->usMaxPixelClockPLL_Input
) * 10;
824 info
->pll_info
.min_output_pxl_clk_pll_frequency
=
825 le32_to_cpu(firmware_info
->ulMinPixelClockPLL_Output
) * 10;
826 info
->pll_info
.max_output_pxl_clk_pll_frequency
=
827 le32_to_cpu(firmware_info
->ulMaxPixelClockPLL_Output
) * 10;
828 info
->default_display_engine_pll_frequency
=
829 le32_to_cpu(firmware_info
->ulDefaultDispEngineClkFreq
) * 10;
830 info
->external_clock_source_frequency_for_dp
=
831 le16_to_cpu(firmware_info
->usUniphyDPModeExtClkFreq
) * 10;
833 /* There should be only one entry in the SS info table for Memory Clock
836 if (firmware_info
->usFirmwareCapability
.sbfAccess
.MemoryClockSS_Support
)
837 /* Since there is no information for external SS, report
838 * conservative value 3% for bandwidth calculation */
840 info
->feature
.memory_clk_ss_percentage
= THREE_PERCENT_OF_10000
;
841 else if (get_ss_info_v3_1(bp
,
842 ASIC_INTERNAL_MEMORY_SS
, index
, &internal_ss
) == BP_RESULT_OK
) {
843 if (internal_ss
.spread_spectrum_percentage
) {
844 info
->feature
.memory_clk_ss_percentage
=
845 internal_ss
.spread_spectrum_percentage
;
846 if (internal_ss
.type
.CENTER_MODE
) {
847 /* if it is centermode, the exact SS Percentage
848 * will be round up of half of the percentage
849 * reported in the SS table */
850 ++info
->feature
.memory_clk_ss_percentage
;
851 info
->feature
.memory_clk_ss_percentage
/= 2;
856 /* There should be only one entry in the SS info table for Engine Clock
859 if (firmware_info
->usFirmwareCapability
.sbfAccess
.EngineClockSS_Support
)
860 /* Since there is no information for external SS, report
861 * conservative value 3% for bandwidth calculation */
863 info
->feature
.engine_clk_ss_percentage
= THREE_PERCENT_OF_10000
;
864 else if (get_ss_info_v3_1(bp
,
865 ASIC_INTERNAL_ENGINE_SS
, index
, &internal_ss
) == BP_RESULT_OK
) {
866 if (internal_ss
.spread_spectrum_percentage
) {
867 info
->feature
.engine_clk_ss_percentage
=
868 internal_ss
.spread_spectrum_percentage
;
869 if (internal_ss
.type
.CENTER_MODE
) {
870 /* if it is centermode, the exact SS Percentage
871 * will be round up of half of the percentage
872 * reported in the SS table */
873 ++info
->feature
.engine_clk_ss_percentage
;
874 info
->feature
.engine_clk_ss_percentage
/= 2;
880 info
->remote_display_config
= firmware_info
->ucRemoteDisplayConfig
;
882 /* Is allowed minimum BL level */
883 info
->min_allowed_bl_level
= firmware_info
->ucMinAllowedBL_Level
;
884 /* Used starting from CI */
885 info
->smu_gpu_pll_output_freq
=
886 (uint32_t) (le32_to_cpu(firmware_info
->ulGPUPLL_OutputFreq
) * 10);
891 static enum bp_result
get_ss_info_v3_1(
892 struct bios_parser
*bp
,
895 struct spread_spectrum_info
*ss_info
)
897 ATOM_ASIC_INTERNAL_SS_INFO_V3
*ss_table_header_include
;
898 ATOM_ASIC_SS_ASSIGNMENT_V3
*tbl
;
901 uint32_t table_index
= 0;
904 return BP_RESULT_BADINPUT
;
906 if (!DATA_TABLES(ASIC_InternalSS_Info
))
907 return BP_RESULT_UNSUPPORTED
;
909 ss_table_header_include
= GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3
,
910 DATA_TABLES(ASIC_InternalSS_Info
));
912 (le16_to_cpu(ss_table_header_include
->sHeader
.usStructureSize
)
913 - sizeof(ATOM_COMMON_TABLE_HEADER
))
914 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3
);
916 tbl
= (ATOM_ASIC_SS_ASSIGNMENT_V3
*)
917 &ss_table_header_include
->asSpreadSpectrum
[0];
919 memset(ss_info
, 0, sizeof(struct spread_spectrum_info
));
921 for (i
= 0; i
< table_size
; i
++) {
922 if (tbl
[i
].ucClockIndication
!= (uint8_t) id
)
925 if (table_index
!= index
) {
929 /* VBIOS introduced new defines for Version 3, same values as
930 * before, so now use these new ones for Version 3.
931 * Shouldn't affect field VBIOS's V3 as define values are still
933 * #define SS_MODE_V3_CENTRE_SPREAD_MASK 0x01
934 * #define SS_MODE_V3_EXTERNAL_SS_MASK 0x02
937 * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
938 * #define ATOM_EXTERNAL_SS_MASK 0x00000002
941 if (SS_MODE_V3_EXTERNAL_SS_MASK
& tbl
[i
].ucSpreadSpectrumMode
)
942 ss_info
->type
.EXTERNAL
= true;
944 if (SS_MODE_V3_CENTRE_SPREAD_MASK
& tbl
[i
].ucSpreadSpectrumMode
)
945 ss_info
->type
.CENTER_MODE
= true;
947 /* Older VBIOS (in field) always provides SS percentage in 0.01%
948 * units set Divider to 100 */
949 ss_info
->spread_percentage_divider
= 100;
951 /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
952 if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
953 & tbl
[i
].ucSpreadSpectrumMode
)
954 ss_info
->spread_percentage_divider
= 1000;
956 ss_info
->type
.STEP_AND_DELAY_INFO
= false;
957 /* convert [10KHz] into [KHz] */
958 ss_info
->target_clock_range
=
959 le32_to_cpu(tbl
[i
].ulTargetClockRange
) * 10;
960 ss_info
->spread_spectrum_percentage
=
961 (uint32_t)le16_to_cpu(tbl
[i
].usSpreadSpectrumPercentage
);
962 ss_info
->spread_spectrum_range
=
963 (uint32_t)(le16_to_cpu(tbl
[i
].usSpreadRateIn10Hz
) * 10);
967 return BP_RESULT_NORECORD
;
970 static enum bp_result
bios_parser_transmitter_control(
972 struct bp_transmitter_control
*cntl
)
974 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
976 if (!bp
->cmd_tbl
.transmitter_control
)
977 return BP_RESULT_FAILURE
;
979 return bp
->cmd_tbl
.transmitter_control(bp
, cntl
);
982 static enum bp_result
bios_parser_encoder_control(
984 struct bp_encoder_control
*cntl
)
986 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
988 if (!bp
->cmd_tbl
.dig_encoder_control
)
989 return BP_RESULT_FAILURE
;
991 return bp
->cmd_tbl
.dig_encoder_control(bp
, cntl
);
994 static enum bp_result
bios_parser_adjust_pixel_clock(
996 struct bp_adjust_pixel_clock_parameters
*bp_params
)
998 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1000 if (!bp
->cmd_tbl
.adjust_display_pll
)
1001 return BP_RESULT_FAILURE
;
1003 return bp
->cmd_tbl
.adjust_display_pll(bp
, bp_params
);
1006 static enum bp_result
bios_parser_set_pixel_clock(
1007 struct dc_bios
*dcb
,
1008 struct bp_pixel_clock_parameters
*bp_params
)
1010 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1012 if (!bp
->cmd_tbl
.set_pixel_clock
)
1013 return BP_RESULT_FAILURE
;
1015 return bp
->cmd_tbl
.set_pixel_clock(bp
, bp_params
);
1018 static enum bp_result
bios_parser_set_dce_clock(
1019 struct dc_bios
*dcb
,
1020 struct bp_set_dce_clock_parameters
*bp_params
)
1022 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1024 if (!bp
->cmd_tbl
.set_dce_clock
)
1025 return BP_RESULT_FAILURE
;
1027 return bp
->cmd_tbl
.set_dce_clock(bp
, bp_params
);
1030 static enum bp_result
bios_parser_enable_spread_spectrum_on_ppll(
1031 struct dc_bios
*dcb
,
1032 struct bp_spread_spectrum_parameters
*bp_params
,
1035 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1037 if (!bp
->cmd_tbl
.enable_spread_spectrum_on_ppll
)
1038 return BP_RESULT_FAILURE
;
1040 return bp
->cmd_tbl
.enable_spread_spectrum_on_ppll(
1041 bp
, bp_params
, enable
);
1045 static enum bp_result
bios_parser_program_crtc_timing(
1046 struct dc_bios
*dcb
,
1047 struct bp_hw_crtc_timing_parameters
*bp_params
)
1049 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1051 if (!bp
->cmd_tbl
.set_crtc_timing
)
1052 return BP_RESULT_FAILURE
;
1054 return bp
->cmd_tbl
.set_crtc_timing(bp
, bp_params
);
1057 static enum bp_result
bios_parser_program_display_engine_pll(
1058 struct dc_bios
*dcb
,
1059 struct bp_pixel_clock_parameters
*bp_params
)
1061 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1063 if (!bp
->cmd_tbl
.program_clock
)
1064 return BP_RESULT_FAILURE
;
1066 return bp
->cmd_tbl
.program_clock(bp
, bp_params
);
1071 static enum bp_result
bios_parser_enable_crtc(
1072 struct dc_bios
*dcb
,
1073 enum controller_id id
,
1076 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1078 if (!bp
->cmd_tbl
.enable_crtc
)
1079 return BP_RESULT_FAILURE
;
1081 return bp
->cmd_tbl
.enable_crtc(bp
, id
, enable
);
1084 static enum bp_result
bios_parser_crtc_source_select(
1085 struct dc_bios
*dcb
,
1086 struct bp_crtc_source_select
*bp_params
)
1088 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1090 if (!bp
->cmd_tbl
.select_crtc_source
)
1091 return BP_RESULT_FAILURE
;
1093 return bp
->cmd_tbl
.select_crtc_source(bp
, bp_params
);
1096 static enum bp_result
bios_parser_enable_disp_power_gating(
1097 struct dc_bios
*dcb
,
1098 enum controller_id controller_id
,
1099 enum bp_pipe_control_action action
)
1101 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1103 if (!bp
->cmd_tbl
.enable_disp_power_gating
)
1104 return BP_RESULT_FAILURE
;
1106 return bp
->cmd_tbl
.enable_disp_power_gating(bp
, controller_id
,
1110 static bool bios_parser_is_device_id_supported(
1111 struct dc_bios
*dcb
,
1112 struct device_id id
)
1114 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1116 uint32_t mask
= get_support_mask_for_device_id(id
);
1118 return (le16_to_cpu(bp
->object_info_tbl
.v1_1
->usDeviceSupport
) & mask
) != 0;
1121 static enum bp_result
bios_parser_crt_control(
1122 struct dc_bios
*dcb
,
1123 enum engine_id engine_id
,
1125 uint32_t pixel_clock
)
1127 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1130 if (!bp
->cmd_tbl
.dac1_encoder_control
&&
1131 engine_id
== ENGINE_ID_DACA
)
1132 return BP_RESULT_FAILURE
;
1133 if (!bp
->cmd_tbl
.dac2_encoder_control
&&
1134 engine_id
== ENGINE_ID_DACB
)
1135 return BP_RESULT_FAILURE
;
1136 /* validate params */
1137 switch (engine_id
) {
1138 case ENGINE_ID_DACA
:
1139 case ENGINE_ID_DACB
:
1142 /* unsupported engine */
1143 return BP_RESULT_FAILURE
;
1146 standard
= ATOM_DAC1_PS2
; /* == ATOM_DAC2_PS2 */
1149 if (engine_id
== ENGINE_ID_DACA
) {
1150 bp
->cmd_tbl
.dac1_encoder_control(bp
, enable
,
1151 pixel_clock
, standard
);
1152 if (bp
->cmd_tbl
.dac1_output_control
!= NULL
)
1153 bp
->cmd_tbl
.dac1_output_control(bp
, enable
);
1155 bp
->cmd_tbl
.dac2_encoder_control(bp
, enable
,
1156 pixel_clock
, standard
);
1157 if (bp
->cmd_tbl
.dac2_output_control
!= NULL
)
1158 bp
->cmd_tbl
.dac2_output_control(bp
, enable
);
1161 if (engine_id
== ENGINE_ID_DACA
) {
1162 if (bp
->cmd_tbl
.dac1_output_control
!= NULL
)
1163 bp
->cmd_tbl
.dac1_output_control(bp
, enable
);
1164 bp
->cmd_tbl
.dac1_encoder_control(bp
, enable
,
1165 pixel_clock
, standard
);
1167 if (bp
->cmd_tbl
.dac2_output_control
!= NULL
)
1168 bp
->cmd_tbl
.dac2_output_control(bp
, enable
);
1169 bp
->cmd_tbl
.dac2_encoder_control(bp
, enable
,
1170 pixel_clock
, standard
);
1174 return BP_RESULT_OK
;
1177 static ATOM_HPD_INT_RECORD
*get_hpd_record(struct bios_parser
*bp
,
1178 ATOM_OBJECT
*object
)
1180 ATOM_COMMON_RECORD_HEADER
*header
;
1184 BREAK_TO_DEBUGGER(); /* Invalid object */
1188 offset
= le16_to_cpu(object
->usRecordOffset
)
1189 + bp
->object_info_tbl_offset
;
1192 header
= GET_IMAGE(ATOM_COMMON_RECORD_HEADER
, offset
);
1197 if (LAST_RECORD_TYPE
== header
->ucRecordType
||
1198 !header
->ucRecordSize
)
1201 if (ATOM_HPD_INT_RECORD_TYPE
== header
->ucRecordType
1202 && sizeof(ATOM_HPD_INT_RECORD
) <= header
->ucRecordSize
)
1203 return (ATOM_HPD_INT_RECORD
*) header
;
1205 offset
+= header
->ucRecordSize
;
1212 * Get I2C information of input object id
1214 * search all records to find the ATOM_I2C_RECORD_TYPE record IR
1216 static ATOM_I2C_RECORD
*get_i2c_record(
1217 struct bios_parser
*bp
,
1218 ATOM_OBJECT
*object
)
1221 ATOM_COMMON_RECORD_HEADER
*record_header
;
1224 BREAK_TO_DEBUGGER();
1225 /* Invalid object */
1229 offset
= le16_to_cpu(object
->usRecordOffset
)
1230 + bp
->object_info_tbl_offset
;
1233 record_header
= GET_IMAGE(ATOM_COMMON_RECORD_HEADER
, offset
);
1238 if (LAST_RECORD_TYPE
== record_header
->ucRecordType
||
1239 0 == record_header
->ucRecordSize
)
1242 if (ATOM_I2C_RECORD_TYPE
== record_header
->ucRecordType
&&
1243 sizeof(ATOM_I2C_RECORD
) <=
1244 record_header
->ucRecordSize
) {
1245 return (ATOM_I2C_RECORD
*)record_header
;
1248 offset
+= record_header
->ucRecordSize
;
1254 static enum bp_result
get_ss_info_from_ss_info_table(
1255 struct bios_parser
*bp
,
1257 struct spread_spectrum_info
*ss_info
);
1258 static enum bp_result
get_ss_info_from_tbl(
1259 struct bios_parser
*bp
,
1261 struct spread_spectrum_info
*ss_info
);
1263 * bios_parser_get_spread_spectrum_info
1264 * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or
1265 * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info
1266 * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ver 3.1,
1267 * there is only one entry for each signal /ss id. However, there is
1268 * no planning of supporting multiple spread Sprectum entry for EverGreen
1270 * @param [in] signal, ASSignalType to be converted to info index
1271 * @param [in] index, number of entries that match the converted info index
1272 * @param [out] ss_info, sprectrum information structure,
1273 * @return Bios parser result code
1275 static enum bp_result
bios_parser_get_spread_spectrum_info(
1276 struct dc_bios
*dcb
,
1277 enum as_signal_type signal
,
1279 struct spread_spectrum_info
*ss_info
)
1281 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1282 enum bp_result result
= BP_RESULT_UNSUPPORTED
;
1283 uint32_t clk_id_ss
= 0;
1284 ATOM_COMMON_TABLE_HEADER
*header
;
1285 struct atom_data_revision tbl_revision
;
1287 if (!ss_info
) /* check for bad input */
1288 return BP_RESULT_BADINPUT
;
1289 /* signal translation */
1290 clk_id_ss
= signal_to_ss_id(signal
);
1292 if (!DATA_TABLES(ASIC_InternalSS_Info
))
1294 return get_ss_info_from_ss_info_table(bp
, clk_id_ss
,
1297 header
= GET_IMAGE(ATOM_COMMON_TABLE_HEADER
,
1298 DATA_TABLES(ASIC_InternalSS_Info
));
1299 get_atom_data_table_revision(header
, &tbl_revision
);
1301 switch (tbl_revision
.major
) {
1303 switch (tbl_revision
.minor
) {
1305 /* there can not be more then one entry for Internal
1306 * SS Info table version 2.1 */
1308 return get_ss_info_from_tbl(bp
, clk_id_ss
,
1317 switch (tbl_revision
.minor
) {
1319 return get_ss_info_v3_1(bp
, clk_id_ss
, index
, ss_info
);
1327 /* there can not be more then one entry for SS Info table */
1331 static enum bp_result
get_ss_info_from_internal_ss_info_tbl_V2_1(
1332 struct bios_parser
*bp
,
1334 struct spread_spectrum_info
*info
);
1337 * get_ss_info_from_table
1338 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
1339 * SS_Info table from the VBIOS
1340 * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
1344 * @param id, spread sprectrum info index
1345 * @param pSSinfo, sprectrum information structure,
1346 * @return Bios parser result code
1348 static enum bp_result
get_ss_info_from_tbl(
1349 struct bios_parser
*bp
,
1351 struct spread_spectrum_info
*ss_info
)
1353 if (!ss_info
) /* check for bad input, if ss_info is not NULL */
1354 return BP_RESULT_BADINPUT
;
1355 /* for SS_Info table only support DP and LVDS */
1356 if (id
== ASIC_INTERNAL_SS_ON_DP
|| id
== ASIC_INTERNAL_SS_ON_LVDS
)
1357 return get_ss_info_from_ss_info_table(bp
, id
, ss_info
);
1359 return get_ss_info_from_internal_ss_info_tbl_V2_1(bp
, id
,
1364 * get_ss_info_from_internal_ss_info_tbl_V2_1
1365 * Get spread sprectrum information from the ASIC_InternalSS_Info table Ver 2.1
1367 * There will not be multiple entry for Ver 2.1
1369 * @param id, spread sprectrum info index
1370 * @param pSSinfo, sprectrum information structure,
1371 * @return Bios parser result code
1373 static enum bp_result
get_ss_info_from_internal_ss_info_tbl_V2_1(
1374 struct bios_parser
*bp
,
1376 struct spread_spectrum_info
*info
)
1378 enum bp_result result
= BP_RESULT_UNSUPPORTED
;
1379 ATOM_ASIC_INTERNAL_SS_INFO_V2
*header
;
1380 ATOM_ASIC_SS_ASSIGNMENT_V2
*tbl
;
1381 uint32_t tbl_size
, i
;
1383 if (!DATA_TABLES(ASIC_InternalSS_Info
))
1386 header
= GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2
,
1387 DATA_TABLES(ASIC_InternalSS_Info
));
1389 memset(info
, 0, sizeof(struct spread_spectrum_info
));
1391 tbl_size
= (le16_to_cpu(header
->sHeader
.usStructureSize
)
1392 - sizeof(ATOM_COMMON_TABLE_HEADER
))
1393 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2
);
1395 tbl
= (ATOM_ASIC_SS_ASSIGNMENT_V2
*)
1396 &(header
->asSpreadSpectrum
[0]);
1397 for (i
= 0; i
< tbl_size
; i
++) {
1398 result
= BP_RESULT_NORECORD
;
1400 if (tbl
[i
].ucClockIndication
!= (uint8_t)id
)
1403 if (ATOM_EXTERNAL_SS_MASK
1404 & tbl
[i
].ucSpreadSpectrumMode
) {
1405 info
->type
.EXTERNAL
= true;
1407 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
1408 & tbl
[i
].ucSpreadSpectrumMode
) {
1409 info
->type
.CENTER_MODE
= true;
1411 info
->type
.STEP_AND_DELAY_INFO
= false;
1412 /* convert [10KHz] into [KHz] */
1413 info
->target_clock_range
=
1414 le32_to_cpu(tbl
[i
].ulTargetClockRange
) * 10;
1415 info
->spread_spectrum_percentage
=
1416 (uint32_t)le16_to_cpu(tbl
[i
].usSpreadSpectrumPercentage
);
1417 info
->spread_spectrum_range
=
1418 (uint32_t)(le16_to_cpu(tbl
[i
].usSpreadRateIn10Hz
) * 10);
1419 result
= BP_RESULT_OK
;
1428 * get_ss_info_from_ss_info_table
1429 * Get spread sprectrum information from the SS_Info table from the VBIOS
1430 * if the pointer to info is NULL, indicate the caller what to know the number
1431 * of entries that matches the id
1432 * for, the SS_Info table, there should not be more than 1 entry match.
1434 * @param [in] id, spread sprectrum id
1435 * @param [out] pSSinfo, sprectrum information structure,
1436 * @return Bios parser result code
1438 static enum bp_result
get_ss_info_from_ss_info_table(
1439 struct bios_parser
*bp
,
1441 struct spread_spectrum_info
*ss_info
)
1443 enum bp_result result
= BP_RESULT_UNSUPPORTED
;
1444 ATOM_SPREAD_SPECTRUM_INFO
*tbl
;
1445 ATOM_COMMON_TABLE_HEADER
*header
;
1446 uint32_t table_size
;
1448 uint32_t id_local
= SS_ID_UNKNOWN
;
1449 struct atom_data_revision revision
;
1451 /* exist of the SS_Info table */
1452 /* check for bad input, pSSinfo can not be NULL */
1453 if (!DATA_TABLES(SS_Info
) || !ss_info
)
1456 header
= GET_IMAGE(ATOM_COMMON_TABLE_HEADER
, DATA_TABLES(SS_Info
));
1457 get_atom_data_table_revision(header
, &revision
);
1459 tbl
= GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO
, DATA_TABLES(SS_Info
));
1461 if (1 != revision
.major
|| 2 > revision
.minor
)
1464 /* have to convert from Internal_SS format to SS_Info format */
1466 case ASIC_INTERNAL_SS_ON_DP
:
1467 id_local
= SS_ID_DP1
;
1469 case ASIC_INTERNAL_SS_ON_LVDS
:
1471 struct embedded_panel_info panel_info
;
1473 if (bios_parser_get_embedded_panel_info(&bp
->base
, &panel_info
)
1475 id_local
= panel_info
.ss_id
;
1482 if (id_local
== SS_ID_UNKNOWN
)
1485 table_size
= (le16_to_cpu(tbl
->sHeader
.usStructureSize
) -
1486 sizeof(ATOM_COMMON_TABLE_HEADER
)) /
1487 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT
);
1489 for (i
= 0; i
< table_size
; i
++) {
1490 if (id_local
!= (uint32_t)tbl
->asSS_Info
[i
].ucSS_Id
)
1493 memset(ss_info
, 0, sizeof(struct spread_spectrum_info
));
1495 if (ATOM_EXTERNAL_SS_MASK
&
1496 tbl
->asSS_Info
[i
].ucSpreadSpectrumType
)
1497 ss_info
->type
.EXTERNAL
= true;
1499 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
&
1500 tbl
->asSS_Info
[i
].ucSpreadSpectrumType
)
1501 ss_info
->type
.CENTER_MODE
= true;
1503 ss_info
->type
.STEP_AND_DELAY_INFO
= true;
1504 ss_info
->spread_spectrum_percentage
=
1505 (uint32_t)le16_to_cpu(tbl
->asSS_Info
[i
].usSpreadSpectrumPercentage
);
1506 ss_info
->step_and_delay_info
.step
= tbl
->asSS_Info
[i
].ucSS_Step
;
1507 ss_info
->step_and_delay_info
.delay
=
1508 tbl
->asSS_Info
[i
].ucSS_Delay
;
1509 ss_info
->step_and_delay_info
.recommended_ref_div
=
1510 tbl
->asSS_Info
[i
].ucRecommendedRef_Div
;
1511 ss_info
->spread_spectrum_range
=
1512 (uint32_t)tbl
->asSS_Info
[i
].ucSS_Range
* 10000;
1514 /* there will be only one entry for each display type in SS_info
1516 result
= BP_RESULT_OK
;
1522 static enum bp_result
get_embedded_panel_info_v1_2(
1523 struct bios_parser
*bp
,
1524 struct embedded_panel_info
*info
);
1525 static enum bp_result
get_embedded_panel_info_v1_3(
1526 struct bios_parser
*bp
,
1527 struct embedded_panel_info
*info
);
1529 static enum bp_result
bios_parser_get_embedded_panel_info(
1530 struct dc_bios
*dcb
,
1531 struct embedded_panel_info
*info
)
1533 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1534 ATOM_COMMON_TABLE_HEADER
*hdr
;
1536 if (!DATA_TABLES(LCD_Info
))
1537 return BP_RESULT_FAILURE
;
1539 hdr
= GET_IMAGE(ATOM_COMMON_TABLE_HEADER
, DATA_TABLES(LCD_Info
));
1542 return BP_RESULT_BADBIOSTABLE
;
1544 switch (hdr
->ucTableFormatRevision
) {
1546 switch (hdr
->ucTableContentRevision
) {
1550 return get_embedded_panel_info_v1_2(bp
, info
);
1552 return get_embedded_panel_info_v1_3(bp
, info
);
1560 return BP_RESULT_FAILURE
;
1563 static enum bp_result
get_embedded_panel_info_v1_2(
1564 struct bios_parser
*bp
,
1565 struct embedded_panel_info
*info
)
1567 ATOM_LVDS_INFO_V12
*lvds
;
1570 return BP_RESULT_BADINPUT
;
1572 if (!DATA_TABLES(LVDS_Info
))
1573 return BP_RESULT_UNSUPPORTED
;
1576 GET_IMAGE(ATOM_LVDS_INFO_V12
, DATA_TABLES(LVDS_Info
));
1579 return BP_RESULT_BADBIOSTABLE
;
1581 if (1 != lvds
->sHeader
.ucTableFormatRevision
1582 || 2 > lvds
->sHeader
.ucTableContentRevision
)
1583 return BP_RESULT_UNSUPPORTED
;
1585 memset(info
, 0, sizeof(struct embedded_panel_info
));
1587 /* We need to convert from 10KHz units into KHz units*/
1588 info
->lcd_timing
.pixel_clk
=
1589 le16_to_cpu(lvds
->sLCDTiming
.usPixClk
) * 10;
1590 /* usHActive does not include borders, according to VBIOS team*/
1591 info
->lcd_timing
.horizontal_addressable
=
1592 le16_to_cpu(lvds
->sLCDTiming
.usHActive
);
1593 /* usHBlanking_Time includes borders, so we should really be subtracting
1594 * borders duing this translation, but LVDS generally*/
1595 /* doesn't have borders, so we should be okay leaving this as is for
1596 * now. May need to revisit if we ever have LVDS with borders*/
1597 info
->lcd_timing
.horizontal_blanking_time
=
1598 le16_to_cpu(lvds
->sLCDTiming
.usHBlanking_Time
);
1599 /* usVActive does not include borders, according to VBIOS team*/
1600 info
->lcd_timing
.vertical_addressable
=
1601 le16_to_cpu(lvds
->sLCDTiming
.usVActive
);
1602 /* usVBlanking_Time includes borders, so we should really be subtracting
1603 * borders duing this translation, but LVDS generally*/
1604 /* doesn't have borders, so we should be okay leaving this as is for
1605 * now. May need to revisit if we ever have LVDS with borders*/
1606 info
->lcd_timing
.vertical_blanking_time
=
1607 le16_to_cpu(lvds
->sLCDTiming
.usVBlanking_Time
);
1608 info
->lcd_timing
.horizontal_sync_offset
=
1609 le16_to_cpu(lvds
->sLCDTiming
.usHSyncOffset
);
1610 info
->lcd_timing
.horizontal_sync_width
=
1611 le16_to_cpu(lvds
->sLCDTiming
.usHSyncWidth
);
1612 info
->lcd_timing
.vertical_sync_offset
=
1613 le16_to_cpu(lvds
->sLCDTiming
.usVSyncOffset
);
1614 info
->lcd_timing
.vertical_sync_width
=
1615 le16_to_cpu(lvds
->sLCDTiming
.usVSyncWidth
);
1616 info
->lcd_timing
.horizontal_border
= lvds
->sLCDTiming
.ucHBorder
;
1617 info
->lcd_timing
.vertical_border
= lvds
->sLCDTiming
.ucVBorder
;
1618 info
->lcd_timing
.misc_info
.HORIZONTAL_CUT_OFF
=
1619 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.HorizontalCutOff
;
1620 info
->lcd_timing
.misc_info
.H_SYNC_POLARITY
=
1622 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.HSyncPolarity
;
1623 info
->lcd_timing
.misc_info
.V_SYNC_POLARITY
=
1625 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.VSyncPolarity
;
1626 info
->lcd_timing
.misc_info
.VERTICAL_CUT_OFF
=
1627 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.VerticalCutOff
;
1628 info
->lcd_timing
.misc_info
.H_REPLICATION_BY2
=
1629 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.H_ReplicationBy2
;
1630 info
->lcd_timing
.misc_info
.V_REPLICATION_BY2
=
1631 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.V_ReplicationBy2
;
1632 info
->lcd_timing
.misc_info
.COMPOSITE_SYNC
=
1633 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.CompositeSync
;
1634 info
->lcd_timing
.misc_info
.INTERLACE
=
1635 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.Interlace
;
1636 info
->lcd_timing
.misc_info
.DOUBLE_CLOCK
=
1637 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.DoubleClock
;
1638 info
->ss_id
= lvds
->ucSS_Id
;
1641 uint8_t rr
= le16_to_cpu(lvds
->usSupportedRefreshRate
);
1642 /* Get minimum supported refresh rate*/
1643 if (SUPPORTED_LCD_REFRESHRATE_30Hz
& rr
)
1644 info
->supported_rr
.REFRESH_RATE_30HZ
= 1;
1645 else if (SUPPORTED_LCD_REFRESHRATE_40Hz
& rr
)
1646 info
->supported_rr
.REFRESH_RATE_40HZ
= 1;
1647 else if (SUPPORTED_LCD_REFRESHRATE_48Hz
& rr
)
1648 info
->supported_rr
.REFRESH_RATE_48HZ
= 1;
1649 else if (SUPPORTED_LCD_REFRESHRATE_50Hz
& rr
)
1650 info
->supported_rr
.REFRESH_RATE_50HZ
= 1;
1651 else if (SUPPORTED_LCD_REFRESHRATE_60Hz
& rr
)
1652 info
->supported_rr
.REFRESH_RATE_60HZ
= 1;
1655 /*Drr panel support can be reported by VBIOS*/
1656 if (LCDPANEL_CAP_DRR_SUPPORTED
1657 & lvds
->ucLCDPanel_SpecialHandlingCap
)
1658 info
->drr_enabled
= 1;
1660 if (ATOM_PANEL_MISC_DUAL
& lvds
->ucLVDS_Misc
)
1661 info
->lcd_timing
.misc_info
.DOUBLE_CLOCK
= true;
1663 if (ATOM_PANEL_MISC_888RGB
& lvds
->ucLVDS_Misc
)
1664 info
->lcd_timing
.misc_info
.RGB888
= true;
1666 info
->lcd_timing
.misc_info
.GREY_LEVEL
=
1667 (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL
&
1668 lvds
->ucLVDS_Misc
) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT
;
1670 if (ATOM_PANEL_MISC_SPATIAL
& lvds
->ucLVDS_Misc
)
1671 info
->lcd_timing
.misc_info
.SPATIAL
= true;
1673 if (ATOM_PANEL_MISC_TEMPORAL
& lvds
->ucLVDS_Misc
)
1674 info
->lcd_timing
.misc_info
.TEMPORAL
= true;
1676 if (ATOM_PANEL_MISC_API_ENABLED
& lvds
->ucLVDS_Misc
)
1677 info
->lcd_timing
.misc_info
.API_ENABLED
= true;
1679 return BP_RESULT_OK
;
1682 static enum bp_result
get_embedded_panel_info_v1_3(
1683 struct bios_parser
*bp
,
1684 struct embedded_panel_info
*info
)
1686 ATOM_LCD_INFO_V13
*lvds
;
1689 return BP_RESULT_BADINPUT
;
1691 if (!DATA_TABLES(LCD_Info
))
1692 return BP_RESULT_UNSUPPORTED
;
1694 lvds
= GET_IMAGE(ATOM_LCD_INFO_V13
, DATA_TABLES(LCD_Info
));
1697 return BP_RESULT_BADBIOSTABLE
;
1699 if (!((1 == lvds
->sHeader
.ucTableFormatRevision
)
1700 && (3 <= lvds
->sHeader
.ucTableContentRevision
)))
1701 return BP_RESULT_UNSUPPORTED
;
1703 memset(info
, 0, sizeof(struct embedded_panel_info
));
1705 /* We need to convert from 10KHz units into KHz units */
1706 info
->lcd_timing
.pixel_clk
=
1707 le16_to_cpu(lvds
->sLCDTiming
.usPixClk
) * 10;
1708 /* usHActive does not include borders, according to VBIOS team */
1709 info
->lcd_timing
.horizontal_addressable
=
1710 le16_to_cpu(lvds
->sLCDTiming
.usHActive
);
1711 /* usHBlanking_Time includes borders, so we should really be subtracting
1712 * borders duing this translation, but LVDS generally*/
1713 /* doesn't have borders, so we should be okay leaving this as is for
1714 * now. May need to revisit if we ever have LVDS with borders*/
1715 info
->lcd_timing
.horizontal_blanking_time
=
1716 le16_to_cpu(lvds
->sLCDTiming
.usHBlanking_Time
);
1717 /* usVActive does not include borders, according to VBIOS team*/
1718 info
->lcd_timing
.vertical_addressable
=
1719 le16_to_cpu(lvds
->sLCDTiming
.usVActive
);
1720 /* usVBlanking_Time includes borders, so we should really be subtracting
1721 * borders duing this translation, but LVDS generally*/
1722 /* doesn't have borders, so we should be okay leaving this as is for
1723 * now. May need to revisit if we ever have LVDS with borders*/
1724 info
->lcd_timing
.vertical_blanking_time
=
1725 le16_to_cpu(lvds
->sLCDTiming
.usVBlanking_Time
);
1726 info
->lcd_timing
.horizontal_sync_offset
=
1727 le16_to_cpu(lvds
->sLCDTiming
.usHSyncOffset
);
1728 info
->lcd_timing
.horizontal_sync_width
=
1729 le16_to_cpu(lvds
->sLCDTiming
.usHSyncWidth
);
1730 info
->lcd_timing
.vertical_sync_offset
=
1731 le16_to_cpu(lvds
->sLCDTiming
.usVSyncOffset
);
1732 info
->lcd_timing
.vertical_sync_width
=
1733 le16_to_cpu(lvds
->sLCDTiming
.usVSyncWidth
);
1734 info
->lcd_timing
.horizontal_border
= lvds
->sLCDTiming
.ucHBorder
;
1735 info
->lcd_timing
.vertical_border
= lvds
->sLCDTiming
.ucVBorder
;
1736 info
->lcd_timing
.misc_info
.HORIZONTAL_CUT_OFF
=
1737 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.HorizontalCutOff
;
1738 info
->lcd_timing
.misc_info
.H_SYNC_POLARITY
=
1740 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.HSyncPolarity
;
1741 info
->lcd_timing
.misc_info
.V_SYNC_POLARITY
=
1743 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.VSyncPolarity
;
1744 info
->lcd_timing
.misc_info
.VERTICAL_CUT_OFF
=
1745 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.VerticalCutOff
;
1746 info
->lcd_timing
.misc_info
.H_REPLICATION_BY2
=
1747 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.H_ReplicationBy2
;
1748 info
->lcd_timing
.misc_info
.V_REPLICATION_BY2
=
1749 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.V_ReplicationBy2
;
1750 info
->lcd_timing
.misc_info
.COMPOSITE_SYNC
=
1751 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.CompositeSync
;
1752 info
->lcd_timing
.misc_info
.INTERLACE
=
1753 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.Interlace
;
1754 info
->lcd_timing
.misc_info
.DOUBLE_CLOCK
=
1755 lvds
->sLCDTiming
.susModeMiscInfo
.sbfAccess
.DoubleClock
;
1756 info
->ss_id
= lvds
->ucSS_Id
;
1758 /* Drr panel support can be reported by VBIOS*/
1759 if (LCDPANEL_CAP_V13_DRR_SUPPORTED
1760 & lvds
->ucLCDPanel_SpecialHandlingCap
)
1761 info
->drr_enabled
= 1;
1763 /* Get supported refresh rate*/
1764 if (info
->drr_enabled
== 1) {
1766 lvds
->sRefreshRateSupport
.ucMinRefreshRateForDRR
;
1767 uint8_t rr
= lvds
->sRefreshRateSupport
.ucSupportedRefreshRate
;
1770 if (SUPPORTED_LCD_REFRESHRATE_30Hz
& min_rr
)
1771 info
->supported_rr
.REFRESH_RATE_30HZ
= 1;
1772 else if (SUPPORTED_LCD_REFRESHRATE_40Hz
& min_rr
)
1773 info
->supported_rr
.REFRESH_RATE_40HZ
= 1;
1774 else if (SUPPORTED_LCD_REFRESHRATE_48Hz
& min_rr
)
1775 info
->supported_rr
.REFRESH_RATE_48HZ
= 1;
1776 else if (SUPPORTED_LCD_REFRESHRATE_50Hz
& min_rr
)
1777 info
->supported_rr
.REFRESH_RATE_50HZ
= 1;
1778 else if (SUPPORTED_LCD_REFRESHRATE_60Hz
& min_rr
)
1779 info
->supported_rr
.REFRESH_RATE_60HZ
= 1;
1781 if (SUPPORTED_LCD_REFRESHRATE_30Hz
& rr
)
1782 info
->supported_rr
.REFRESH_RATE_30HZ
= 1;
1783 else if (SUPPORTED_LCD_REFRESHRATE_40Hz
& rr
)
1784 info
->supported_rr
.REFRESH_RATE_40HZ
= 1;
1785 else if (SUPPORTED_LCD_REFRESHRATE_48Hz
& rr
)
1786 info
->supported_rr
.REFRESH_RATE_48HZ
= 1;
1787 else if (SUPPORTED_LCD_REFRESHRATE_50Hz
& rr
)
1788 info
->supported_rr
.REFRESH_RATE_50HZ
= 1;
1789 else if (SUPPORTED_LCD_REFRESHRATE_60Hz
& rr
)
1790 info
->supported_rr
.REFRESH_RATE_60HZ
= 1;
1794 if (ATOM_PANEL_MISC_V13_DUAL
& lvds
->ucLCD_Misc
)
1795 info
->lcd_timing
.misc_info
.DOUBLE_CLOCK
= true;
1797 if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR
& lvds
->ucLCD_Misc
)
1798 info
->lcd_timing
.misc_info
.RGB888
= true;
1800 info
->lcd_timing
.misc_info
.GREY_LEVEL
=
1801 (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL
&
1802 lvds
->ucLCD_Misc
) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT
;
1804 return BP_RESULT_OK
;
1808 * bios_parser_get_encoder_cap_info
1811 * Get encoder capability information of input object id
1813 * @param object_id, Object id
1814 * @param object_id, encoder cap information structure
1816 * @return Bios parser result code
1819 static enum bp_result
bios_parser_get_encoder_cap_info(
1820 struct dc_bios
*dcb
,
1821 struct graphics_object_id object_id
,
1822 struct bp_encoder_cap_info
*info
)
1824 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1825 ATOM_OBJECT
*object
;
1826 ATOM_ENCODER_CAP_RECORD_V2
*record
= NULL
;
1829 return BP_RESULT_BADINPUT
;
1831 object
= get_bios_object(bp
, object_id
);
1834 return BP_RESULT_BADINPUT
;
1836 record
= get_encoder_cap_record(bp
, object
);
1838 return BP_RESULT_NORECORD
;
1840 info
->DP_HBR2_EN
= record
->usHBR2En
;
1841 info
->DP_HBR3_EN
= record
->usHBR3En
;
1842 info
->HDMI_6GB_EN
= record
->usHDMI6GEn
;
1843 return BP_RESULT_OK
;
1847 * get_encoder_cap_record
1850 * Get encoder cap record for the object
1852 * @param object, ATOM object
1854 * @return atom encoder cap record
1857 * search all records to find the ATOM_ENCODER_CAP_RECORD_V2 record
1859 static ATOM_ENCODER_CAP_RECORD_V2
*get_encoder_cap_record(
1860 struct bios_parser
*bp
,
1861 ATOM_OBJECT
*object
)
1863 ATOM_COMMON_RECORD_HEADER
*header
;
1867 BREAK_TO_DEBUGGER(); /* Invalid object */
1871 offset
= le16_to_cpu(object
->usRecordOffset
)
1872 + bp
->object_info_tbl_offset
;
1875 header
= GET_IMAGE(ATOM_COMMON_RECORD_HEADER
, offset
);
1880 offset
+= header
->ucRecordSize
;
1882 if (LAST_RECORD_TYPE
== header
->ucRecordType
||
1883 !header
->ucRecordSize
)
1886 if (ATOM_ENCODER_CAP_RECORD_TYPE
!= header
->ucRecordType
)
1889 if (sizeof(ATOM_ENCODER_CAP_RECORD_V2
) <= header
->ucRecordSize
)
1890 return (ATOM_ENCODER_CAP_RECORD_V2
*)header
;
1896 static uint32_t get_ss_entry_number(
1897 struct bios_parser
*bp
,
1899 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1900 struct bios_parser
*bp
,
1902 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1903 struct bios_parser
*bp
,
1905 static uint32_t get_ss_entry_number_from_ss_info_tbl(
1906 struct bios_parser
*bp
,
1910 * BiosParserObject::GetNumberofSpreadSpectrumEntry
1911 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
1912 * the VBIOS that match the SSid (to be converted from signal)
1914 * @param[in] signal, ASSignalType to be converted to SSid
1915 * @return number of SS Entry that match the signal
1917 static uint32_t bios_parser_get_ss_entry_number(
1918 struct dc_bios
*dcb
,
1919 enum as_signal_type signal
)
1921 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
1923 ATOM_COMMON_TABLE_HEADER
*header
;
1924 struct atom_data_revision revision
;
1926 ss_id
= signal_to_ss_id(signal
);
1928 if (!DATA_TABLES(ASIC_InternalSS_Info
))
1929 return get_ss_entry_number_from_ss_info_tbl(bp
, ss_id
);
1931 header
= GET_IMAGE(ATOM_COMMON_TABLE_HEADER
,
1932 DATA_TABLES(ASIC_InternalSS_Info
));
1933 get_atom_data_table_revision(header
, &revision
);
1935 switch (revision
.major
) {
1937 switch (revision
.minor
) {
1939 return get_ss_entry_number(bp
, ss_id
);
1945 switch (revision
.minor
) {
1948 get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1962 * get_ss_entry_number_from_ss_info_tbl
1963 * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
1965 * @note There can only be one entry for each id for SS_Info Table
1967 * @param [in] id, spread spectrum id
1968 * @return number of SS Entry that match the id
1970 static uint32_t get_ss_entry_number_from_ss_info_tbl(
1971 struct bios_parser
*bp
,
1974 ATOM_SPREAD_SPECTRUM_INFO
*tbl
;
1975 ATOM_COMMON_TABLE_HEADER
*header
;
1976 uint32_t table_size
;
1978 uint32_t number
= 0;
1979 uint32_t id_local
= SS_ID_UNKNOWN
;
1980 struct atom_data_revision revision
;
1982 /* SS_Info table exist */
1983 if (!DATA_TABLES(SS_Info
))
1986 header
= GET_IMAGE(ATOM_COMMON_TABLE_HEADER
,
1987 DATA_TABLES(SS_Info
));
1988 get_atom_data_table_revision(header
, &revision
);
1990 tbl
= GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO
,
1991 DATA_TABLES(SS_Info
));
1993 if (1 != revision
.major
|| 2 > revision
.minor
)
1996 /* have to convert from Internal_SS format to SS_Info format */
1998 case ASIC_INTERNAL_SS_ON_DP
:
1999 id_local
= SS_ID_DP1
;
2001 case ASIC_INTERNAL_SS_ON_LVDS
: {
2002 struct embedded_panel_info panel_info
;
2004 if (bios_parser_get_embedded_panel_info(&bp
->base
, &panel_info
)
2006 id_local
= panel_info
.ss_id
;
2013 if (id_local
== SS_ID_UNKNOWN
)
2016 table_size
= (le16_to_cpu(tbl
->sHeader
.usStructureSize
) -
2017 sizeof(ATOM_COMMON_TABLE_HEADER
)) /
2018 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT
);
2020 for (i
= 0; i
< table_size
; i
++)
2021 if (id_local
== (uint32_t)tbl
->asSS_Info
[i
].ucSS_Id
) {
2030 * get_ss_entry_number
2031 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
2032 * SS_Info table from the VBIOS
2033 * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
2036 * @param id, spread sprectrum info index
2037 * @return Bios parser result code
2039 static uint32_t get_ss_entry_number(struct bios_parser
*bp
, uint32_t id
)
2041 if (id
== ASIC_INTERNAL_SS_ON_DP
|| id
== ASIC_INTERNAL_SS_ON_LVDS
)
2042 return get_ss_entry_number_from_ss_info_tbl(bp
, id
);
2044 return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp
, id
);
2048 * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
2049 * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
2050 * Ver 2.1 from the VBIOS
2051 * There will not be multiple entry for Ver 2.1
2053 * @param id, spread sprectrum info index
2054 * @return number of SS Entry that match the id
2056 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
2057 struct bios_parser
*bp
,
2060 ATOM_ASIC_INTERNAL_SS_INFO_V2
*header_include
;
2061 ATOM_ASIC_SS_ASSIGNMENT_V2
*tbl
;
2065 if (!DATA_TABLES(ASIC_InternalSS_Info
))
2068 header_include
= GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2
,
2069 DATA_TABLES(ASIC_InternalSS_Info
));
2071 size
= (le16_to_cpu(header_include
->sHeader
.usStructureSize
)
2072 - sizeof(ATOM_COMMON_TABLE_HEADER
))
2073 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2
);
2075 tbl
= (ATOM_ASIC_SS_ASSIGNMENT_V2
*)
2076 &header_include
->asSpreadSpectrum
[0];
2077 for (i
= 0; i
< size
; i
++)
2078 if (tbl
[i
].ucClockIndication
== (uint8_t)id
)
2084 * get_ss_entry_number_from_internal_ss_info_table_V3_1
2085 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
2086 * the VBIOS that matches id
2088 * @param[in] id, spread sprectrum id
2089 * @return number of SS Entry that match the id
2091 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
2092 struct bios_parser
*bp
,
2095 uint32_t number
= 0;
2096 ATOM_ASIC_INTERNAL_SS_INFO_V3
*header_include
;
2097 ATOM_ASIC_SS_ASSIGNMENT_V3
*tbl
;
2101 if (!DATA_TABLES(ASIC_InternalSS_Info
))
2104 header_include
= GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3
,
2105 DATA_TABLES(ASIC_InternalSS_Info
));
2106 size
= (le16_to_cpu(header_include
->sHeader
.usStructureSize
) -
2107 sizeof(ATOM_COMMON_TABLE_HEADER
)) /
2108 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3
);
2110 tbl
= (ATOM_ASIC_SS_ASSIGNMENT_V3
*)
2111 &header_include
->asSpreadSpectrum
[0];
2113 for (i
= 0; i
< size
; i
++)
2114 if (tbl
[i
].ucClockIndication
== (uint8_t)id
)
2121 * bios_parser_get_gpio_pin_info
2122 * Get GpioPin information of input gpio id
2124 * @param gpio_id, GPIO ID
2125 * @param info, GpioPin information structure
2126 * @return Bios parser result code
2128 * to get the GPIO PIN INFO, we need:
2129 * 1. get the GPIO_ID from other object table, see GetHPDInfo()
2130 * 2. in DATA_TABLE.GPIO_Pin_LUT, search all records, to get the registerA
2133 static enum bp_result
bios_parser_get_gpio_pin_info(
2134 struct dc_bios
*dcb
,
2136 struct gpio_pin_info
*info
)
2138 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
2139 ATOM_GPIO_PIN_LUT
*header
;
2143 if (!DATA_TABLES(GPIO_Pin_LUT
))
2144 return BP_RESULT_BADBIOSTABLE
;
2146 header
= GET_IMAGE(ATOM_GPIO_PIN_LUT
, DATA_TABLES(GPIO_Pin_LUT
));
2148 return BP_RESULT_BADBIOSTABLE
;
2150 if (sizeof(ATOM_COMMON_TABLE_HEADER
) + sizeof(ATOM_GPIO_PIN_LUT
)
2151 > le16_to_cpu(header
->sHeader
.usStructureSize
))
2152 return BP_RESULT_BADBIOSTABLE
;
2154 if (1 != header
->sHeader
.ucTableContentRevision
)
2155 return BP_RESULT_UNSUPPORTED
;
2157 count
= (le16_to_cpu(header
->sHeader
.usStructureSize
)
2158 - sizeof(ATOM_COMMON_TABLE_HEADER
))
2159 / sizeof(ATOM_GPIO_PIN_ASSIGNMENT
);
2160 for (i
= 0; i
< count
; ++i
) {
2161 if (header
->asGPIO_Pin
[i
].ucGPIO_ID
!= gpio_id
)
2165 (uint32_t) le16_to_cpu(header
->asGPIO_Pin
[i
].usGpioPin_AIndex
);
2166 info
->offset_y
= info
->offset
+ 2;
2167 info
->offset_en
= info
->offset
+ 1;
2168 info
->offset_mask
= info
->offset
- 1;
2170 info
->mask
= (uint32_t) (1 <<
2171 header
->asGPIO_Pin
[i
].ucGpioPinBitShift
);
2172 info
->mask_y
= info
->mask
+ 2;
2173 info
->mask_en
= info
->mask
+ 1;
2174 info
->mask_mask
= info
->mask
- 1;
2176 return BP_RESULT_OK
;
2179 return BP_RESULT_NORECORD
;
2182 static enum bp_result
get_gpio_i2c_info(struct bios_parser
*bp
,
2183 ATOM_I2C_RECORD
*record
,
2184 struct graphics_object_i2c_info
*info
)
2186 ATOM_GPIO_I2C_INFO
*header
;
2190 return BP_RESULT_BADINPUT
;
2192 /* get the GPIO_I2C info */
2193 if (!DATA_TABLES(GPIO_I2C_Info
))
2194 return BP_RESULT_BADBIOSTABLE
;
2196 header
= GET_IMAGE(ATOM_GPIO_I2C_INFO
, DATA_TABLES(GPIO_I2C_Info
));
2198 return BP_RESULT_BADBIOSTABLE
;
2200 if (sizeof(ATOM_COMMON_TABLE_HEADER
) + sizeof(ATOM_GPIO_I2C_ASSIGMENT
)
2201 > le16_to_cpu(header
->sHeader
.usStructureSize
))
2202 return BP_RESULT_BADBIOSTABLE
;
2204 if (1 != header
->sHeader
.ucTableContentRevision
)
2205 return BP_RESULT_UNSUPPORTED
;
2207 /* get data count */
2208 count
= (le16_to_cpu(header
->sHeader
.usStructureSize
)
2209 - sizeof(ATOM_COMMON_TABLE_HEADER
))
2210 / sizeof(ATOM_GPIO_I2C_ASSIGMENT
);
2211 if (count
< record
->sucI2cId
.bfI2C_LineMux
)
2212 return BP_RESULT_BADBIOSTABLE
;
2214 /* get the GPIO_I2C_INFO */
2215 info
->i2c_hw_assist
= record
->sucI2cId
.bfHW_Capable
;
2216 info
->i2c_line
= record
->sucI2cId
.bfI2C_LineMux
;
2217 info
->i2c_engine_id
= record
->sucI2cId
.bfHW_EngineID
;
2218 info
->i2c_slave_address
= record
->ucI2CAddr
;
2220 info
->gpio_info
.clk_mask_register_index
=
2221 le16_to_cpu(header
->asGPIO_Info
[info
->i2c_line
].usClkMaskRegisterIndex
);
2222 info
->gpio_info
.clk_en_register_index
=
2223 le16_to_cpu(header
->asGPIO_Info
[info
->i2c_line
].usClkEnRegisterIndex
);
2224 info
->gpio_info
.clk_y_register_index
=
2225 le16_to_cpu(header
->asGPIO_Info
[info
->i2c_line
].usClkY_RegisterIndex
);
2226 info
->gpio_info
.clk_a_register_index
=
2227 le16_to_cpu(header
->asGPIO_Info
[info
->i2c_line
].usClkA_RegisterIndex
);
2228 info
->gpio_info
.data_mask_register_index
=
2229 le16_to_cpu(header
->asGPIO_Info
[info
->i2c_line
].usDataMaskRegisterIndex
);
2230 info
->gpio_info
.data_en_register_index
=
2231 le16_to_cpu(header
->asGPIO_Info
[info
->i2c_line
].usDataEnRegisterIndex
);
2232 info
->gpio_info
.data_y_register_index
=
2233 le16_to_cpu(header
->asGPIO_Info
[info
->i2c_line
].usDataY_RegisterIndex
);
2234 info
->gpio_info
.data_a_register_index
=
2235 le16_to_cpu(header
->asGPIO_Info
[info
->i2c_line
].usDataA_RegisterIndex
);
2237 info
->gpio_info
.clk_mask_shift
=
2238 header
->asGPIO_Info
[info
->i2c_line
].ucClkMaskShift
;
2239 info
->gpio_info
.clk_en_shift
=
2240 header
->asGPIO_Info
[info
->i2c_line
].ucClkEnShift
;
2241 info
->gpio_info
.clk_y_shift
=
2242 header
->asGPIO_Info
[info
->i2c_line
].ucClkY_Shift
;
2243 info
->gpio_info
.clk_a_shift
=
2244 header
->asGPIO_Info
[info
->i2c_line
].ucClkA_Shift
;
2245 info
->gpio_info
.data_mask_shift
=
2246 header
->asGPIO_Info
[info
->i2c_line
].ucDataMaskShift
;
2247 info
->gpio_info
.data_en_shift
=
2248 header
->asGPIO_Info
[info
->i2c_line
].ucDataEnShift
;
2249 info
->gpio_info
.data_y_shift
=
2250 header
->asGPIO_Info
[info
->i2c_line
].ucDataY_Shift
;
2251 info
->gpio_info
.data_a_shift
=
2252 header
->asGPIO_Info
[info
->i2c_line
].ucDataA_Shift
;
2254 return BP_RESULT_OK
;
2257 static ATOM_OBJECT
*get_bios_object(struct bios_parser
*bp
,
2258 struct graphics_object_id id
)
2261 ATOM_OBJECT_TABLE
*tbl
;
2265 case OBJECT_TYPE_ENCODER
:
2266 offset
= le16_to_cpu(bp
->object_info_tbl
.v1_1
->usEncoderObjectTableOffset
);
2269 case OBJECT_TYPE_CONNECTOR
:
2270 offset
= le16_to_cpu(bp
->object_info_tbl
.v1_1
->usConnectorObjectTableOffset
);
2273 case OBJECT_TYPE_ROUTER
:
2274 offset
= le16_to_cpu(bp
->object_info_tbl
.v1_1
->usRouterObjectTableOffset
);
2277 case OBJECT_TYPE_GENERIC
:
2278 if (bp
->object_info_tbl
.revision
.minor
< 3)
2280 offset
= le16_to_cpu(bp
->object_info_tbl
.v1_3
->usMiscObjectTableOffset
);
2287 offset
+= bp
->object_info_tbl_offset
;
2289 tbl
= GET_IMAGE(ATOM_OBJECT_TABLE
, offset
);
2293 for (i
= 0; i
< tbl
->ucNumberOfObjects
; i
++)
2294 if (dal_graphics_object_id_is_equal(id
,
2295 object_id_from_bios_object_id(
2296 le16_to_cpu(tbl
->asObjects
[i
].usObjectID
))))
2297 return &tbl
->asObjects
[i
];
2302 static uint32_t get_dest_obj_list(struct bios_parser
*bp
,
2303 ATOM_OBJECT
*object
, uint16_t **id_list
)
2309 BREAK_TO_DEBUGGER(); /* Invalid object id */
2313 offset
= le16_to_cpu(object
->usSrcDstTableOffset
)
2314 + bp
->object_info_tbl_offset
;
2316 number
= GET_IMAGE(uint8_t, offset
);
2320 offset
+= sizeof(uint8_t);
2321 offset
+= sizeof(uint16_t) * (*number
);
2323 number
= GET_IMAGE(uint8_t, offset
);
2324 if ((!number
) || (!*number
))
2327 offset
+= sizeof(uint8_t);
2328 *id_list
= (uint16_t *)bios_get_image(&bp
->base
, offset
, *number
* sizeof(uint16_t));
2336 static uint32_t get_src_obj_list(struct bios_parser
*bp
, ATOM_OBJECT
*object
,
2343 BREAK_TO_DEBUGGER(); /* Invalid object id */
2347 offset
= le16_to_cpu(object
->usSrcDstTableOffset
)
2348 + bp
->object_info_tbl_offset
;
2350 number
= GET_IMAGE(uint8_t, offset
);
2354 offset
+= sizeof(uint8_t);
2355 *id_list
= (uint16_t *)bios_get_image(&bp
->base
, offset
, *number
* sizeof(uint16_t));
2363 static uint32_t get_dst_number_from_object(struct bios_parser
*bp
,
2364 ATOM_OBJECT
*object
)
2370 BREAK_TO_DEBUGGER(); /* Invalid encoder object id*/
2374 offset
= le16_to_cpu(object
->usSrcDstTableOffset
)
2375 + bp
->object_info_tbl_offset
;
2377 number
= GET_IMAGE(uint8_t, offset
);
2381 offset
+= sizeof(uint8_t);
2382 offset
+= sizeof(uint16_t) * (*number
);
2384 number
= GET_IMAGE(uint8_t, offset
);
2392 static struct device_id
device_type_from_device_id(uint16_t device_id
)
2395 struct device_id result_device_id
;
2397 switch (device_id
) {
2398 case ATOM_DEVICE_LCD1_SUPPORT
:
2399 result_device_id
.device_type
= DEVICE_TYPE_LCD
;
2400 result_device_id
.enum_id
= 1;
2403 case ATOM_DEVICE_LCD2_SUPPORT
:
2404 result_device_id
.device_type
= DEVICE_TYPE_LCD
;
2405 result_device_id
.enum_id
= 2;
2408 case ATOM_DEVICE_CRT1_SUPPORT
:
2409 result_device_id
.device_type
= DEVICE_TYPE_CRT
;
2410 result_device_id
.enum_id
= 1;
2413 case ATOM_DEVICE_CRT2_SUPPORT
:
2414 result_device_id
.device_type
= DEVICE_TYPE_CRT
;
2415 result_device_id
.enum_id
= 2;
2418 case ATOM_DEVICE_DFP1_SUPPORT
:
2419 result_device_id
.device_type
= DEVICE_TYPE_DFP
;
2420 result_device_id
.enum_id
= 1;
2423 case ATOM_DEVICE_DFP2_SUPPORT
:
2424 result_device_id
.device_type
= DEVICE_TYPE_DFP
;
2425 result_device_id
.enum_id
= 2;
2428 case ATOM_DEVICE_DFP3_SUPPORT
:
2429 result_device_id
.device_type
= DEVICE_TYPE_DFP
;
2430 result_device_id
.enum_id
= 3;
2433 case ATOM_DEVICE_DFP4_SUPPORT
:
2434 result_device_id
.device_type
= DEVICE_TYPE_DFP
;
2435 result_device_id
.enum_id
= 4;
2438 case ATOM_DEVICE_DFP5_SUPPORT
:
2439 result_device_id
.device_type
= DEVICE_TYPE_DFP
;
2440 result_device_id
.enum_id
= 5;
2443 case ATOM_DEVICE_DFP6_SUPPORT
:
2444 result_device_id
.device_type
= DEVICE_TYPE_DFP
;
2445 result_device_id
.enum_id
= 6;
2449 BREAK_TO_DEBUGGER(); /* Invalid device Id */
2450 result_device_id
.device_type
= DEVICE_TYPE_UNKNOWN
;
2451 result_device_id
.enum_id
= 0;
2453 return result_device_id
;
2456 static void get_atom_data_table_revision(
2457 ATOM_COMMON_TABLE_HEADER
*atom_data_tbl
,
2458 struct atom_data_revision
*tbl_revision
)
2463 /* initialize the revision to 0 which is invalid revision */
2464 tbl_revision
->major
= 0;
2465 tbl_revision
->minor
= 0;
2470 tbl_revision
->major
=
2471 (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl
);
2472 tbl_revision
->minor
=
2473 (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl
);
2476 static uint32_t signal_to_ss_id(enum as_signal_type signal
)
2478 uint32_t clk_id_ss
= 0;
2481 case AS_SIGNAL_TYPE_DVI
:
2482 clk_id_ss
= ASIC_INTERNAL_SS_ON_TMDS
;
2484 case AS_SIGNAL_TYPE_HDMI
:
2485 clk_id_ss
= ASIC_INTERNAL_SS_ON_HDMI
;
2487 case AS_SIGNAL_TYPE_LVDS
:
2488 clk_id_ss
= ASIC_INTERNAL_SS_ON_LVDS
;
2490 case AS_SIGNAL_TYPE_DISPLAY_PORT
:
2491 clk_id_ss
= ASIC_INTERNAL_SS_ON_DP
;
2493 case AS_SIGNAL_TYPE_GPU_PLL
:
2494 clk_id_ss
= ASIC_INTERNAL_GPUPLL_SS
;
2502 static uint32_t get_support_mask_for_device_id(struct device_id device_id
)
2504 enum dal_device_type device_type
= device_id
.device_type
;
2505 uint32_t enum_id
= device_id
.enum_id
;
2507 switch (device_type
) {
2508 case DEVICE_TYPE_LCD
:
2511 return ATOM_DEVICE_LCD1_SUPPORT
;
2513 return ATOM_DEVICE_LCD2_SUPPORT
;
2518 case DEVICE_TYPE_CRT
:
2521 return ATOM_DEVICE_CRT1_SUPPORT
;
2523 return ATOM_DEVICE_CRT2_SUPPORT
;
2528 case DEVICE_TYPE_DFP
:
2531 return ATOM_DEVICE_DFP1_SUPPORT
;
2533 return ATOM_DEVICE_DFP2_SUPPORT
;
2535 return ATOM_DEVICE_DFP3_SUPPORT
;
2537 return ATOM_DEVICE_DFP4_SUPPORT
;
2539 return ATOM_DEVICE_DFP5_SUPPORT
;
2541 return ATOM_DEVICE_DFP6_SUPPORT
;
2546 case DEVICE_TYPE_CV
:
2549 return ATOM_DEVICE_CV_SUPPORT
;
2554 case DEVICE_TYPE_TV
:
2557 return ATOM_DEVICE_TV1_SUPPORT
;
2566 /* Unidentified device ID, return empty support mask. */
2571 * HwContext interface for writing MM registers
2574 static bool i2c_read(
2575 struct bios_parser
*bp
,
2576 struct graphics_object_i2c_info
*i2c_info
,
2581 uint8_t offset
[2] = { 0, 0 };
2582 bool result
= false;
2583 struct i2c_command cmd
;
2584 struct gpio_ddc_hw_info hw_info
= {
2585 i2c_info
->i2c_hw_assist
,
2586 i2c_info
->i2c_line
};
2588 ddc
= dal_gpio_create_ddc(bp
->base
.ctx
->gpio_service
,
2589 i2c_info
->gpio_info
.clk_a_register_index
,
2590 (1 << i2c_info
->gpio_info
.clk_a_shift
), &hw_info
);
2595 /*Using SW engine */
2596 cmd
.engine
= I2C_COMMAND_ENGINE_SW
;
2597 cmd
.speed
= ddc
->ctx
->dc
->caps
.i2c_speed_in_khz
;
2600 struct i2c_payload payloads
[] = {
2602 .address
= i2c_info
->i2c_slave_address
>> 1,
2604 .length
= sizeof(offset
),
2608 .address
= i2c_info
->i2c_slave_address
>> 1,
2615 cmd
.payloads
= payloads
;
2616 cmd
.number_of_payloads
= ARRAY_SIZE(payloads
);
2618 /* TODO route this through drm i2c_adapter */
2619 result
= dal_i2caux_submit_i2c_command(
2625 dal_gpio_destroy_ddc(&ddc
);
2631 * Read external display connection info table through i2c.
2632 * validate the GUID and checksum.
2634 * @return enum bp_result whether all data was sucessfully read
2636 static enum bp_result
get_ext_display_connection_info(
2637 struct bios_parser
*bp
,
2638 ATOM_OBJECT
*opm_object
,
2639 ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
*ext_display_connection_info_tbl
)
2641 bool config_tbl_present
= false;
2642 ATOM_I2C_RECORD
*i2c_record
= NULL
;
2645 if (opm_object
== NULL
)
2646 return BP_RESULT_BADINPUT
;
2648 i2c_record
= get_i2c_record(bp
, opm_object
);
2650 if (i2c_record
!= NULL
) {
2651 ATOM_GPIO_I2C_INFO
*gpio_i2c_header
;
2652 struct graphics_object_i2c_info i2c_info
;
2654 gpio_i2c_header
= GET_IMAGE(ATOM_GPIO_I2C_INFO
,
2655 bp
->master_data_tbl
->ListOfDataTables
.GPIO_I2C_Info
);
2657 if (NULL
== gpio_i2c_header
)
2658 return BP_RESULT_BADBIOSTABLE
;
2660 if (get_gpio_i2c_info(bp
, i2c_record
, &i2c_info
) !=
2662 return BP_RESULT_BADBIOSTABLE
;
2666 (uint8_t *)ext_display_connection_info_tbl
,
2667 sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
))) {
2668 config_tbl_present
= true;
2673 if (config_tbl_present
)
2674 for (i
= 0; i
< NUMBER_OF_UCHAR_FOR_GUID
; i
++) {
2675 if (ext_display_connection_info_tbl
->ucGuid
[i
]
2676 != ext_display_connection_guid
[i
]) {
2677 config_tbl_present
= false;
2682 /* Validate checksum */
2683 if (config_tbl_present
) {
2684 uint8_t check_sum
= 0;
2686 (uint8_t *)ext_display_connection_info_tbl
;
2688 for (i
= 0; i
< sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
);
2690 check_sum
+= buf
[i
];
2694 config_tbl_present
= false;
2697 if (config_tbl_present
)
2698 return BP_RESULT_OK
;
2700 return BP_RESULT_FAILURE
;
2704 * Gets the first device ID in the same group as the given ID for enumerating.
2705 * For instance, if any DFP device ID is passed, returns the device ID for DFP1.
2707 * The first device ID in the same group as the passed device ID, or 0 if no
2708 * matching device group found.
2710 static uint32_t enum_first_device_id(uint32_t dev_id
)
2712 /* Return the first in the group that this ID belongs to. */
2713 if (dev_id
& ATOM_DEVICE_CRT_SUPPORT
)
2714 return ATOM_DEVICE_CRT1_SUPPORT
;
2715 else if (dev_id
& ATOM_DEVICE_DFP_SUPPORT
)
2716 return ATOM_DEVICE_DFP1_SUPPORT
;
2717 else if (dev_id
& ATOM_DEVICE_LCD_SUPPORT
)
2718 return ATOM_DEVICE_LCD1_SUPPORT
;
2719 else if (dev_id
& ATOM_DEVICE_TV_SUPPORT
)
2720 return ATOM_DEVICE_TV1_SUPPORT
;
2721 else if (dev_id
& ATOM_DEVICE_CV_SUPPORT
)
2722 return ATOM_DEVICE_CV_SUPPORT
;
2724 /* No group found for this device ID. */
2726 dm_error("%s: incorrect input %d\n", __func__
, dev_id
);
2727 /* No matching support flag for given device ID */
2732 * Gets the next device ID in the group for a given device ID.
2734 * The current device ID being enumerated on.
2736 * The next device ID in the group, or 0 if no device exists.
2738 static uint32_t enum_next_dev_id(uint32_t dev_id
)
2740 /* Get next device ID in the group. */
2742 case ATOM_DEVICE_CRT1_SUPPORT
:
2743 return ATOM_DEVICE_CRT2_SUPPORT
;
2744 case ATOM_DEVICE_LCD1_SUPPORT
:
2745 return ATOM_DEVICE_LCD2_SUPPORT
;
2746 case ATOM_DEVICE_DFP1_SUPPORT
:
2747 return ATOM_DEVICE_DFP2_SUPPORT
;
2748 case ATOM_DEVICE_DFP2_SUPPORT
:
2749 return ATOM_DEVICE_DFP3_SUPPORT
;
2750 case ATOM_DEVICE_DFP3_SUPPORT
:
2751 return ATOM_DEVICE_DFP4_SUPPORT
;
2752 case ATOM_DEVICE_DFP4_SUPPORT
:
2753 return ATOM_DEVICE_DFP5_SUPPORT
;
2754 case ATOM_DEVICE_DFP5_SUPPORT
:
2755 return ATOM_DEVICE_DFP6_SUPPORT
;
2758 /* Done enumerating through devices. */
2763 * Returns the new device tag record for patched BIOS object.
2765 * [IN] pExtDisplayPath - External display path to copy device tag from.
2766 * [IN] deviceSupport - Bit vector for device ID support flags.
2767 * [OUT] pDeviceTag - Device tag structure to fill with patched data.
2769 * True if a compatible device ID was found, false otherwise.
2771 static bool get_patched_device_tag(
2772 struct bios_parser
*bp
,
2773 EXT_DISPLAY_PATH
*ext_display_path
,
2774 uint32_t device_support
,
2775 ATOM_CONNECTOR_DEVICE_TAG
*device_tag
)
2778 /* Use fallback behaviour if not supported. */
2779 if (!bp
->remap_device_tags
) {
2780 device_tag
->ulACPIDeviceEnum
=
2781 cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path
->usDeviceACPIEnum
));
2782 device_tag
->usDeviceID
=
2783 cpu_to_le16(le16_to_cpu(ext_display_path
->usDeviceTag
));
2787 /* Find the first unused in the same group. */
2788 dev_id
= enum_first_device_id(le16_to_cpu(ext_display_path
->usDeviceTag
));
2789 while (dev_id
!= 0) {
2790 /* Assign this device ID if supported. */
2791 if ((device_support
& dev_id
) != 0) {
2792 device_tag
->ulACPIDeviceEnum
=
2793 cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path
->usDeviceACPIEnum
));
2794 device_tag
->usDeviceID
= cpu_to_le16((USHORT
) dev_id
);
2798 dev_id
= enum_next_dev_id(dev_id
);
2801 /* No compatible device ID found. */
2806 * Adds a device tag to a BIOS object's device tag record if there is
2807 * matching device ID supported.
2809 * pObject - Pointer to the BIOS object to add the device tag to.
2810 * pExtDisplayPath - Display path to retrieve base device ID from.
2811 * pDeviceSupport - Pointer to bit vector for supported device IDs.
2813 static void add_device_tag_from_ext_display_path(
2814 struct bios_parser
*bp
,
2815 ATOM_OBJECT
*object
,
2816 EXT_DISPLAY_PATH
*ext_display_path
,
2817 uint32_t *device_support
)
2819 /* Get device tag record for object. */
2820 ATOM_CONNECTOR_DEVICE_TAG
*device_tag
= NULL
;
2821 ATOM_CONNECTOR_DEVICE_TAG_RECORD
*device_tag_record
= NULL
;
2822 enum bp_result result
=
2823 bios_parser_get_device_tag_record(
2824 bp
, object
, &device_tag_record
);
2826 if ((le16_to_cpu(ext_display_path
->usDeviceTag
) != CONNECTOR_OBJECT_ID_NONE
)
2827 && (result
== BP_RESULT_OK
)) {
2830 if ((device_tag_record
->ucNumberOfDevice
== 1) &&
2831 (le16_to_cpu(device_tag_record
->asDeviceTag
[0].usDeviceID
) == 0)) {
2832 /*Workaround bug in current VBIOS releases where
2833 * ucNumberOfDevice = 1 but there is no actual device
2834 * tag data. This w/a is temporary until the updated
2835 * VBIOS is distributed. */
2836 device_tag_record
->ucNumberOfDevice
=
2837 device_tag_record
->ucNumberOfDevice
- 1;
2840 /* Attempt to find a matching device ID. */
2841 index
= device_tag_record
->ucNumberOfDevice
;
2842 device_tag
= &device_tag_record
->asDeviceTag
[index
];
2843 if (get_patched_device_tag(
2848 /* Update cached device support to remove assigned ID.
2850 *device_support
&= ~le16_to_cpu(device_tag
->usDeviceID
);
2851 device_tag_record
->ucNumberOfDevice
++;
2857 * Read out a single EXT_DISPLAY_PATH from the external display connection info
2858 * table. The specific entry in the table is determined by the enum_id passed
2861 * EXT_DISPLAY_PATH describing a single Configuration table entry
2864 #define INVALID_CONNECTOR 0xffff
2866 static EXT_DISPLAY_PATH
*get_ext_display_path_entry(
2867 ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
*config_table
,
2868 uint32_t bios_object_id
)
2870 EXT_DISPLAY_PATH
*ext_display_path
;
2871 uint32_t ext_display_path_index
=
2872 ((bios_object_id
& ENUM_ID_MASK
) >> ENUM_ID_SHIFT
) - 1;
2874 if (ext_display_path_index
>= MAX_NUMBER_OF_EXT_DISPLAY_PATH
)
2877 ext_display_path
= &config_table
->sPath
[ext_display_path_index
];
2879 if (le16_to_cpu(ext_display_path
->usDeviceConnector
) == INVALID_CONNECTOR
)
2880 ext_display_path
->usDeviceConnector
= cpu_to_le16(0);
2882 return ext_display_path
;
2886 * Get AUX/DDC information of input object id
2888 * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
2891 static ATOM_CONNECTOR_AUXDDC_LUT_RECORD
*get_ext_connector_aux_ddc_lut_record(
2892 struct bios_parser
*bp
,
2893 ATOM_OBJECT
*object
)
2896 ATOM_COMMON_RECORD_HEADER
*header
;
2899 BREAK_TO_DEBUGGER();
2900 /* Invalid object */
2904 offset
= le16_to_cpu(object
->usRecordOffset
)
2905 + bp
->object_info_tbl_offset
;
2908 header
= GET_IMAGE(ATOM_COMMON_RECORD_HEADER
, offset
);
2913 if (LAST_RECORD_TYPE
== header
->ucRecordType
||
2914 0 == header
->ucRecordSize
)
2917 if (ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE
==
2918 header
->ucRecordType
&&
2919 sizeof(ATOM_CONNECTOR_AUXDDC_LUT_RECORD
) <=
2920 header
->ucRecordSize
)
2921 return (ATOM_CONNECTOR_AUXDDC_LUT_RECORD
*)(header
);
2923 offset
+= header
->ucRecordSize
;
2930 * Get AUX/DDC information of input object id
2932 * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
2935 static ATOM_CONNECTOR_HPDPIN_LUT_RECORD
*get_ext_connector_hpd_pin_lut_record(
2936 struct bios_parser
*bp
,
2937 ATOM_OBJECT
*object
)
2940 ATOM_COMMON_RECORD_HEADER
*header
;
2943 BREAK_TO_DEBUGGER();
2944 /* Invalid object */
2948 offset
= le16_to_cpu(object
->usRecordOffset
)
2949 + bp
->object_info_tbl_offset
;
2952 header
= GET_IMAGE(ATOM_COMMON_RECORD_HEADER
, offset
);
2957 if (LAST_RECORD_TYPE
== header
->ucRecordType
||
2958 0 == header
->ucRecordSize
)
2961 if (ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE
==
2962 header
->ucRecordType
&&
2963 sizeof(ATOM_CONNECTOR_HPDPIN_LUT_RECORD
) <=
2964 header
->ucRecordSize
)
2965 return (ATOM_CONNECTOR_HPDPIN_LUT_RECORD
*)header
;
2967 offset
+= header
->ucRecordSize
;
2974 * Check whether we need to patch the VBIOS connector info table with
2975 * data from an external display connection info table. This is
2976 * necessary to support MXM boards with an OPM (output personality
2977 * module). With these designs, the VBIOS connector info table
2978 * specifies an MXM_CONNECTOR with a unique ID. The driver retrieves
2979 * the external connection info table through i2c and then looks up the
2980 * connector ID to find the real connector type (e.g. DFP1).
2983 static enum bp_result
patch_bios_image_from_ext_display_connection_info(
2984 struct bios_parser
*bp
)
2986 ATOM_OBJECT_TABLE
*connector_tbl
;
2987 uint32_t connector_tbl_offset
;
2988 struct graphics_object_id object_id
;
2989 ATOM_OBJECT
*object
;
2990 ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO ext_display_connection_info_tbl
;
2991 EXT_DISPLAY_PATH
*ext_display_path
;
2992 ATOM_CONNECTOR_AUXDDC_LUT_RECORD
*aux_ddc_lut_record
= NULL
;
2993 ATOM_I2C_RECORD
*i2c_record
= NULL
;
2994 ATOM_CONNECTOR_HPDPIN_LUT_RECORD
*hpd_pin_lut_record
= NULL
;
2995 ATOM_HPD_INT_RECORD
*hpd_record
= NULL
;
2996 ATOM_OBJECT_TABLE
*encoder_table
;
2997 uint32_t encoder_table_offset
;
2998 ATOM_OBJECT
*opm_object
= NULL
;
3000 struct graphics_object_id opm_object_id
=
3001 dal_graphics_object_id_init(
3004 OBJECT_TYPE_GENERIC
);
3005 ATOM_CONNECTOR_DEVICE_TAG_RECORD
*dev_tag_record
;
3006 uint32_t cached_device_support
=
3007 le16_to_cpu(bp
->object_info_tbl
.v1_1
->usDeviceSupport
);
3009 uint32_t dst_number
;
3010 uint16_t *dst_object_id_list
;
3012 opm_object
= get_bios_object(bp
, opm_object_id
);
3014 return BP_RESULT_UNSUPPORTED
;
3016 memset(&ext_display_connection_info_tbl
, 0,
3017 sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO
));
3019 connector_tbl_offset
= bp
->object_info_tbl_offset
3020 + le16_to_cpu(bp
->object_info_tbl
.v1_1
->usConnectorObjectTableOffset
);
3021 connector_tbl
= GET_IMAGE(ATOM_OBJECT_TABLE
, connector_tbl_offset
);
3023 /* Read Connector info table from EEPROM through i2c */
3024 if (get_ext_display_connection_info(bp
,
3026 &ext_display_connection_info_tbl
) != BP_RESULT_OK
) {
3028 dm_logger_write(bp
->base
.ctx
->logger
, LOG_WARNING
,
3029 "%s: Failed to read Connection Info Table", __func__
);
3030 return BP_RESULT_UNSUPPORTED
;
3033 /* Get pointer to AUX/DDC and HPD LUTs */
3034 aux_ddc_lut_record
=
3035 get_ext_connector_aux_ddc_lut_record(bp
, opm_object
);
3036 hpd_pin_lut_record
=
3037 get_ext_connector_hpd_pin_lut_record(bp
, opm_object
);
3039 if ((aux_ddc_lut_record
== NULL
) || (hpd_pin_lut_record
== NULL
))
3040 return BP_RESULT_UNSUPPORTED
;
3042 /* Cache support bits for currently unmapped device types. */
3043 if (bp
->remap_device_tags
) {
3044 for (i
= 0; i
< connector_tbl
->ucNumberOfObjects
; ++i
) {
3046 /* Remove support for all non-MXM connectors. */
3047 object
= &connector_tbl
->asObjects
[i
];
3048 object_id
= object_id_from_bios_object_id(
3049 le16_to_cpu(object
->usObjectID
));
3050 if ((OBJECT_TYPE_CONNECTOR
!= object_id
.type
) ||
3051 (CONNECTOR_ID_MXM
== object_id
.id
))
3054 /* Remove support for all device tags. */
3055 if (bios_parser_get_device_tag_record(
3056 bp
, object
, &dev_tag_record
) != BP_RESULT_OK
)
3059 for (j
= 0; j
< dev_tag_record
->ucNumberOfDevice
; ++j
) {
3060 ATOM_CONNECTOR_DEVICE_TAG
*device_tag
=
3061 &dev_tag_record
->asDeviceTag
[j
];
3062 cached_device_support
&=
3063 ~le16_to_cpu(device_tag
->usDeviceID
);
3068 /* Find all MXM connector objects and patch them with connector info
3069 * from the external display connection info table. */
3070 for (i
= 0; i
< connector_tbl
->ucNumberOfObjects
; i
++) {
3073 object
= &connector_tbl
->asObjects
[i
];
3074 object_id
= object_id_from_bios_object_id(le16_to_cpu(object
->usObjectID
));
3075 if ((OBJECT_TYPE_CONNECTOR
!= object_id
.type
) ||
3076 (CONNECTOR_ID_MXM
!= object_id
.id
))
3079 /* Get the correct connection info table entry based on the enum
3081 ext_display_path
= get_ext_display_path_entry(
3082 &ext_display_connection_info_tbl
,
3083 le16_to_cpu(object
->usObjectID
));
3084 if (!ext_display_path
)
3085 return BP_RESULT_FAILURE
;
3087 /* Patch device connector ID */
3088 object
->usObjectID
=
3089 cpu_to_le16(le16_to_cpu(ext_display_path
->usDeviceConnector
));
3091 /* Patch device tag, ulACPIDeviceEnum. */
3092 add_device_tag_from_ext_display_path(
3096 &cached_device_support
);
3098 /* Patch HPD info */
3099 if (ext_display_path
->ucExtHPDPINLutIndex
<
3100 MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES
) {
3101 hpd_record
= get_hpd_record(bp
, object
);
3104 ext_display_path
->ucExtHPDPINLutIndex
;
3105 hpd_record
->ucHPDIntGPIOID
=
3106 hpd_pin_lut_record
->ucHPDPINMap
[index
];
3108 BREAK_TO_DEBUGGER();
3109 /* Invalid hpd record */
3110 return BP_RESULT_FAILURE
;
3114 /* Patch I2C/AUX info */
3115 if (ext_display_path
->ucExtHPDPINLutIndex
<
3116 MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES
) {
3117 i2c_record
= get_i2c_record(bp
, object
);
3120 ext_display_path
->ucExtAUXDDCLutIndex
;
3121 i2c_record
->sucI2cId
=
3122 aux_ddc_lut_record
->ucAUXDDCMap
[index
];
3124 BREAK_TO_DEBUGGER();
3125 /* Invalid I2C record */
3126 return BP_RESULT_FAILURE
;
3130 /* Merge with other MXM connectors that map to the same physical
3133 j
< connector_tbl
->ucNumberOfObjects
; j
++) {
3134 ATOM_OBJECT
*next_object
;
3135 struct graphics_object_id next_object_id
;
3136 EXT_DISPLAY_PATH
*next_ext_display_path
;
3138 next_object
= &connector_tbl
->asObjects
[j
];
3139 next_object_id
= object_id_from_bios_object_id(
3140 le16_to_cpu(next_object
->usObjectID
));
3142 if ((OBJECT_TYPE_CONNECTOR
!= next_object_id
.type
) &&
3143 (CONNECTOR_ID_MXM
== next_object_id
.id
))
3146 next_ext_display_path
= get_ext_display_path_entry(
3147 &ext_display_connection_info_tbl
,
3148 le16_to_cpu(next_object
->usObjectID
));
3150 if (next_ext_display_path
== NULL
)
3151 return BP_RESULT_FAILURE
;
3153 /* Merge if using same connector. */
3154 if ((le16_to_cpu(next_ext_display_path
->usDeviceConnector
) ==
3155 le16_to_cpu(ext_display_path
->usDeviceConnector
)) &&
3156 (le16_to_cpu(ext_display_path
->usDeviceConnector
) != 0)) {
3157 /* Clear duplicate connector from table. */
3158 next_object
->usObjectID
= cpu_to_le16(0);
3159 add_device_tag_from_ext_display_path(
3163 &cached_device_support
);
3168 /* Find all encoders which have an MXM object as their destination.
3169 * Replace the MXM object with the real connector Id from the external
3170 * display connection info table */
3172 encoder_table_offset
= bp
->object_info_tbl_offset
3173 + le16_to_cpu(bp
->object_info_tbl
.v1_1
->usEncoderObjectTableOffset
);
3174 encoder_table
= GET_IMAGE(ATOM_OBJECT_TABLE
, encoder_table_offset
);
3176 for (i
= 0; i
< encoder_table
->ucNumberOfObjects
; i
++) {
3179 object
= &encoder_table
->asObjects
[i
];
3181 dst_number
= get_dest_obj_list(bp
, object
, &dst_object_id_list
);
3183 for (j
= 0; j
< dst_number
; j
++) {
3184 object_id
= object_id_from_bios_object_id(
3185 dst_object_id_list
[j
]);
3187 if ((OBJECT_TYPE_CONNECTOR
!= object_id
.type
) ||
3188 (CONNECTOR_ID_MXM
!= object_id
.id
))
3191 /* Get the correct connection info table entry based on
3194 get_ext_display_path_entry(
3195 &ext_display_connection_info_tbl
,
3196 dst_object_id_list
[j
]);
3198 if (ext_display_path
== NULL
)
3199 return BP_RESULT_FAILURE
;
3201 dst_object_id_list
[j
] =
3202 le16_to_cpu(ext_display_path
->usDeviceConnector
);
3206 return BP_RESULT_OK
;
3210 * Check whether we need to patch the VBIOS connector info table with
3211 * data from an external display connection info table. This is
3212 * necessary to support MXM boards with an OPM (output personality
3213 * module). With these designs, the VBIOS connector info table
3214 * specifies an MXM_CONNECTOR with a unique ID. The driver retrieves
3215 * the external connection info table through i2c and then looks up the
3216 * connector ID to find the real connector type (e.g. DFP1).
3220 static void process_ext_display_connection_info(struct bios_parser
*bp
)
3222 ATOM_OBJECT_TABLE
*connector_tbl
;
3223 uint32_t connector_tbl_offset
;
3224 struct graphics_object_id object_id
;
3225 ATOM_OBJECT
*object
;
3226 bool mxm_connector_found
= false;
3227 bool null_entry_found
= false;
3230 connector_tbl_offset
= bp
->object_info_tbl_offset
+
3231 le16_to_cpu(bp
->object_info_tbl
.v1_1
->usConnectorObjectTableOffset
);
3232 connector_tbl
= GET_IMAGE(ATOM_OBJECT_TABLE
, connector_tbl_offset
);
3234 /* Look for MXM connectors to determine whether we need patch the VBIOS
3235 * connector info table. Look for null entries to determine whether we
3236 * need to compact connector table. */
3237 for (i
= 0; i
< connector_tbl
->ucNumberOfObjects
; i
++) {
3238 object
= &connector_tbl
->asObjects
[i
];
3239 object_id
= object_id_from_bios_object_id(le16_to_cpu(object
->usObjectID
));
3241 if ((OBJECT_TYPE_CONNECTOR
== object_id
.type
) &&
3242 (CONNECTOR_ID_MXM
== object_id
.id
)) {
3243 /* Once we found MXM connector - we can break */
3244 mxm_connector_found
= true;
3246 } else if (OBJECT_TYPE_CONNECTOR
!= object_id
.type
) {
3247 /* We need to continue looping - to check if MXM
3248 * connector present */
3249 null_entry_found
= true;
3253 /* Patch BIOS image */
3254 if (mxm_connector_found
|| null_entry_found
) {
3255 uint32_t connectors_num
= 0;
3256 uint8_t *original_bios
;
3257 /* Step 1: Replace bios image with the new copy which will be
3259 bp
->base
.bios_local_image
= kzalloc(bp
->base
.bios_size
,
3261 if (bp
->base
.bios_local_image
== NULL
) {
3262 BREAK_TO_DEBUGGER();
3263 /* Failed to alloc bp->base.bios_local_image */
3267 memmove(bp
->base
.bios_local_image
, bp
->base
.bios
, bp
->base
.bios_size
);
3268 original_bios
= bp
->base
.bios
;
3269 bp
->base
.bios
= bp
->base
.bios_local_image
;
3271 GET_IMAGE(ATOM_OBJECT_TABLE
, connector_tbl_offset
);
3273 /* Step 2: (only if MXM connector found) Patch BIOS image with
3274 * info from external module */
3275 if (mxm_connector_found
&&
3276 patch_bios_image_from_ext_display_connection_info(bp
) !=
3278 /* Patching the bios image has failed. We will copy
3279 * again original image provided and afterwards
3280 * only remove null entries */
3282 bp
->base
.bios_local_image
,
3284 bp
->base
.bios_size
);
3287 /* Step 3: Compact connector table (remove null entries, valid
3288 * entries moved to beginning) */
3289 for (i
= 0; i
< connector_tbl
->ucNumberOfObjects
; i
++) {
3290 object
= &connector_tbl
->asObjects
[i
];
3291 object_id
= object_id_from_bios_object_id(
3292 le16_to_cpu(object
->usObjectID
));
3294 if (OBJECT_TYPE_CONNECTOR
!= object_id
.type
)
3297 if (i
!= connectors_num
) {
3300 asObjects
[connectors_num
],
3302 sizeof(ATOM_OBJECT
));
3306 connector_tbl
->ucNumberOfObjects
= (uint8_t)connectors_num
;
3310 static void bios_parser_post_init(struct dc_bios
*dcb
)
3312 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
3314 process_ext_display_connection_info(bp
);
3318 * bios_parser_set_scratch_critical_state
3321 * update critical state bit in VBIOS scratch register
3324 * bool - to set or reset state
3326 static void bios_parser_set_scratch_critical_state(
3327 struct dc_bios
*dcb
,
3330 bios_set_scratch_critical_state(dcb
, state
);
3334 * get_integrated_info_v8
3337 * Get V8 integrated BIOS information
3340 * bios_parser *bp - [in]BIOS parser handler to get master data table
3341 * integrated_info *info - [out] store and output integrated info
3344 * enum bp_result - BP_RESULT_OK if information is available,
3345 * BP_RESULT_BADBIOSTABLE otherwise.
3347 static enum bp_result
get_integrated_info_v8(
3348 struct bios_parser
*bp
,
3349 struct integrated_info
*info
)
3351 ATOM_INTEGRATED_SYSTEM_INFO_V1_8
*info_v8
;
3354 info_v8
= GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8
,
3355 bp
->master_data_tbl
->ListOfDataTables
.IntegratedSystemInfo
);
3357 if (info_v8
== NULL
)
3358 return BP_RESULT_BADBIOSTABLE
;
3359 info
->boot_up_engine_clock
= le32_to_cpu(info_v8
->ulBootUpEngineClock
) * 10;
3360 info
->dentist_vco_freq
= le32_to_cpu(info_v8
->ulDentistVCOFreq
) * 10;
3361 info
->boot_up_uma_clock
= le32_to_cpu(info_v8
->ulBootUpUMAClock
) * 10;
3363 for (i
= 0; i
< NUMBER_OF_DISP_CLK_VOLTAGE
; ++i
) {
3364 /* Convert [10KHz] into [KHz] */
3365 info
->disp_clk_voltage
[i
].max_supported_clk
=
3366 le32_to_cpu(info_v8
->sDISPCLK_Voltage
[i
].
3367 ulMaximumSupportedCLK
) * 10;
3368 info
->disp_clk_voltage
[i
].voltage_index
=
3369 le32_to_cpu(info_v8
->sDISPCLK_Voltage
[i
].ulVoltageIndex
);
3372 info
->boot_up_req_display_vector
=
3373 le32_to_cpu(info_v8
->ulBootUpReqDisplayVector
);
3374 info
->gpu_cap_info
=
3375 le32_to_cpu(info_v8
->ulGPUCapInfo
);
3378 * system_config: Bit[0] = 0 : PCIE power gating disabled
3379 * = 1 : PCIE power gating enabled
3380 * Bit[1] = 0 : DDR-PLL shut down disabled
3381 * = 1 : DDR-PLL shut down enabled
3382 * Bit[2] = 0 : DDR-PLL power down disabled
3383 * = 1 : DDR-PLL power down enabled
3385 info
->system_config
= le32_to_cpu(info_v8
->ulSystemConfig
);
3386 info
->cpu_cap_info
= le32_to_cpu(info_v8
->ulCPUCapInfo
);
3387 info
->boot_up_nb_voltage
=
3388 le16_to_cpu(info_v8
->usBootUpNBVoltage
);
3389 info
->ext_disp_conn_info_offset
=
3390 le16_to_cpu(info_v8
->usExtDispConnInfoOffset
);
3391 info
->memory_type
= info_v8
->ucMemoryType
;
3392 info
->ma_channel_number
= info_v8
->ucUMAChannelNumber
;
3393 info
->gmc_restore_reset_time
=
3394 le32_to_cpu(info_v8
->ulGMCRestoreResetTime
);
3396 info
->minimum_n_clk
=
3397 le32_to_cpu(info_v8
->ulNbpStateNClkFreq
[0]);
3398 for (i
= 1; i
< 4; ++i
)
3399 info
->minimum_n_clk
=
3400 info
->minimum_n_clk
< le32_to_cpu(info_v8
->ulNbpStateNClkFreq
[i
]) ?
3401 info
->minimum_n_clk
: le32_to_cpu(info_v8
->ulNbpStateNClkFreq
[i
]);
3403 info
->idle_n_clk
= le32_to_cpu(info_v8
->ulIdleNClk
);
3404 info
->ddr_dll_power_up_time
=
3405 le32_to_cpu(info_v8
->ulDDR_DLL_PowerUpTime
);
3406 info
->ddr_pll_power_up_time
=
3407 le32_to_cpu(info_v8
->ulDDR_PLL_PowerUpTime
);
3408 info
->pcie_clk_ss_type
= le16_to_cpu(info_v8
->usPCIEClkSSType
);
3409 info
->lvds_ss_percentage
=
3410 le16_to_cpu(info_v8
->usLvdsSSPercentage
);
3411 info
->lvds_sspread_rate_in_10hz
=
3412 le16_to_cpu(info_v8
->usLvdsSSpreadRateIn10Hz
);
3413 info
->hdmi_ss_percentage
=
3414 le16_to_cpu(info_v8
->usHDMISSPercentage
);
3415 info
->hdmi_sspread_rate_in_10hz
=
3416 le16_to_cpu(info_v8
->usHDMISSpreadRateIn10Hz
);
3417 info
->dvi_ss_percentage
=
3418 le16_to_cpu(info_v8
->usDVISSPercentage
);
3419 info
->dvi_sspread_rate_in_10_hz
=
3420 le16_to_cpu(info_v8
->usDVISSpreadRateIn10Hz
);
3422 info
->max_lvds_pclk_freq_in_single_link
=
3423 le16_to_cpu(info_v8
->usMaxLVDSPclkFreqInSingleLink
);
3424 info
->lvds_misc
= info_v8
->ucLvdsMisc
;
3425 info
->lvds_pwr_on_seq_dig_on_to_de_in_4ms
=
3426 info_v8
->ucLVDSPwrOnSeqDIGONtoDE_in4Ms
;
3427 info
->lvds_pwr_on_seq_de_to_vary_bl_in_4ms
=
3428 info_v8
->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms
;
3429 info
->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms
=
3430 info_v8
->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms
;
3431 info
->lvds_pwr_off_seq_vary_bl_to_de_in4ms
=
3432 info_v8
->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms
;
3433 info
->lvds_pwr_off_seq_de_to_dig_on_in4ms
=
3434 info_v8
->ucLVDSPwrOffSeqDEtoDIGON_in4Ms
;
3435 info
->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms
=
3436 info_v8
->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms
;
3437 info
->lvds_off_to_on_delay_in_4ms
=
3438 info_v8
->ucLVDSOffToOnDelay_in4Ms
;
3439 info
->lvds_bit_depth_control_val
=
3440 le32_to_cpu(info_v8
->ulLCDBitDepthControlVal
);
3442 for (i
= 0; i
< NUMBER_OF_AVAILABLE_SCLK
; ++i
) {
3443 /* Convert [10KHz] into [KHz] */
3444 info
->avail_s_clk
[i
].supported_s_clk
=
3445 le32_to_cpu(info_v8
->sAvail_SCLK
[i
].ulSupportedSCLK
) * 10;
3446 info
->avail_s_clk
[i
].voltage_index
=
3447 le16_to_cpu(info_v8
->sAvail_SCLK
[i
].usVoltageIndex
);
3448 info
->avail_s_clk
[i
].voltage_id
=
3449 le16_to_cpu(info_v8
->sAvail_SCLK
[i
].usVoltageID
);
3452 for (i
= 0; i
< NUMBER_OF_UCHAR_FOR_GUID
; ++i
) {
3453 info
->ext_disp_conn_info
.gu_id
[i
] =
3454 info_v8
->sExtDispConnInfo
.ucGuid
[i
];
3457 for (i
= 0; i
< MAX_NUMBER_OF_EXT_DISPLAY_PATH
; ++i
) {
3458 info
->ext_disp_conn_info
.path
[i
].device_connector_id
=
3459 object_id_from_bios_object_id(
3460 le16_to_cpu(info_v8
->sExtDispConnInfo
.sPath
[i
].usDeviceConnector
));
3462 info
->ext_disp_conn_info
.path
[i
].ext_encoder_obj_id
=
3463 object_id_from_bios_object_id(
3464 le16_to_cpu(info_v8
->sExtDispConnInfo
.sPath
[i
].usExtEncoderObjId
));
3466 info
->ext_disp_conn_info
.path
[i
].device_tag
=
3467 le16_to_cpu(info_v8
->sExtDispConnInfo
.sPath
[i
].usDeviceTag
);
3468 info
->ext_disp_conn_info
.path
[i
].device_acpi_enum
=
3469 le16_to_cpu(info_v8
->sExtDispConnInfo
.sPath
[i
].usDeviceACPIEnum
);
3470 info
->ext_disp_conn_info
.path
[i
].ext_aux_ddc_lut_index
=
3471 info_v8
->sExtDispConnInfo
.sPath
[i
].ucExtAUXDDCLutIndex
;
3472 info
->ext_disp_conn_info
.path
[i
].ext_hpd_pin_lut_index
=
3473 info_v8
->sExtDispConnInfo
.sPath
[i
].ucExtHPDPINLutIndex
;
3474 info
->ext_disp_conn_info
.path
[i
].channel_mapping
.raw
=
3475 info_v8
->sExtDispConnInfo
.sPath
[i
].ucChannelMapping
;
3477 info
->ext_disp_conn_info
.checksum
=
3478 info_v8
->sExtDispConnInfo
.ucChecksum
;
3480 return BP_RESULT_OK
;
3484 * get_integrated_info_v8
3487 * Get V8 integrated BIOS information
3490 * bios_parser *bp - [in]BIOS parser handler to get master data table
3491 * integrated_info *info - [out] store and output integrated info
3494 * enum bp_result - BP_RESULT_OK if information is available,
3495 * BP_RESULT_BADBIOSTABLE otherwise.
3497 static enum bp_result
get_integrated_info_v9(
3498 struct bios_parser
*bp
,
3499 struct integrated_info
*info
)
3501 ATOM_INTEGRATED_SYSTEM_INFO_V1_9
*info_v9
;
3504 info_v9
= GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9
,
3505 bp
->master_data_tbl
->ListOfDataTables
.IntegratedSystemInfo
);
3508 return BP_RESULT_BADBIOSTABLE
;
3510 info
->boot_up_engine_clock
= le32_to_cpu(info_v9
->ulBootUpEngineClock
) * 10;
3511 info
->dentist_vco_freq
= le32_to_cpu(info_v9
->ulDentistVCOFreq
) * 10;
3512 info
->boot_up_uma_clock
= le32_to_cpu(info_v9
->ulBootUpUMAClock
) * 10;
3514 for (i
= 0; i
< NUMBER_OF_DISP_CLK_VOLTAGE
; ++i
) {
3515 /* Convert [10KHz] into [KHz] */
3516 info
->disp_clk_voltage
[i
].max_supported_clk
=
3517 le32_to_cpu(info_v9
->sDISPCLK_Voltage
[i
].ulMaximumSupportedCLK
) * 10;
3518 info
->disp_clk_voltage
[i
].voltage_index
=
3519 le32_to_cpu(info_v9
->sDISPCLK_Voltage
[i
].ulVoltageIndex
);
3522 info
->boot_up_req_display_vector
=
3523 le32_to_cpu(info_v9
->ulBootUpReqDisplayVector
);
3524 info
->gpu_cap_info
= le32_to_cpu(info_v9
->ulGPUCapInfo
);
3527 * system_config: Bit[0] = 0 : PCIE power gating disabled
3528 * = 1 : PCIE power gating enabled
3529 * Bit[1] = 0 : DDR-PLL shut down disabled
3530 * = 1 : DDR-PLL shut down enabled
3531 * Bit[2] = 0 : DDR-PLL power down disabled
3532 * = 1 : DDR-PLL power down enabled
3534 info
->system_config
= le32_to_cpu(info_v9
->ulSystemConfig
);
3535 info
->cpu_cap_info
= le32_to_cpu(info_v9
->ulCPUCapInfo
);
3536 info
->boot_up_nb_voltage
= le16_to_cpu(info_v9
->usBootUpNBVoltage
);
3537 info
->ext_disp_conn_info_offset
= le16_to_cpu(info_v9
->usExtDispConnInfoOffset
);
3538 info
->memory_type
= info_v9
->ucMemoryType
;
3539 info
->ma_channel_number
= info_v9
->ucUMAChannelNumber
;
3540 info
->gmc_restore_reset_time
= le32_to_cpu(info_v9
->ulGMCRestoreResetTime
);
3542 info
->minimum_n_clk
= le32_to_cpu(info_v9
->ulNbpStateNClkFreq
[0]);
3543 for (i
= 1; i
< 4; ++i
)
3544 info
->minimum_n_clk
=
3545 info
->minimum_n_clk
< le32_to_cpu(info_v9
->ulNbpStateNClkFreq
[i
]) ?
3546 info
->minimum_n_clk
: le32_to_cpu(info_v9
->ulNbpStateNClkFreq
[i
]);
3548 info
->idle_n_clk
= le32_to_cpu(info_v9
->ulIdleNClk
);
3549 info
->ddr_dll_power_up_time
= le32_to_cpu(info_v9
->ulDDR_DLL_PowerUpTime
);
3550 info
->ddr_pll_power_up_time
= le32_to_cpu(info_v9
->ulDDR_PLL_PowerUpTime
);
3551 info
->pcie_clk_ss_type
= le16_to_cpu(info_v9
->usPCIEClkSSType
);
3552 info
->lvds_ss_percentage
= le16_to_cpu(info_v9
->usLvdsSSPercentage
);
3553 info
->lvds_sspread_rate_in_10hz
= le16_to_cpu(info_v9
->usLvdsSSpreadRateIn10Hz
);
3554 info
->hdmi_ss_percentage
= le16_to_cpu(info_v9
->usHDMISSPercentage
);
3555 info
->hdmi_sspread_rate_in_10hz
= le16_to_cpu(info_v9
->usHDMISSpreadRateIn10Hz
);
3556 info
->dvi_ss_percentage
= le16_to_cpu(info_v9
->usDVISSPercentage
);
3557 info
->dvi_sspread_rate_in_10_hz
= le16_to_cpu(info_v9
->usDVISSpreadRateIn10Hz
);
3559 info
->max_lvds_pclk_freq_in_single_link
=
3560 le16_to_cpu(info_v9
->usMaxLVDSPclkFreqInSingleLink
);
3561 info
->lvds_misc
= info_v9
->ucLvdsMisc
;
3562 info
->lvds_pwr_on_seq_dig_on_to_de_in_4ms
=
3563 info_v9
->ucLVDSPwrOnSeqDIGONtoDE_in4Ms
;
3564 info
->lvds_pwr_on_seq_de_to_vary_bl_in_4ms
=
3565 info_v9
->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms
;
3566 info
->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms
=
3567 info_v9
->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms
;
3568 info
->lvds_pwr_off_seq_vary_bl_to_de_in4ms
=
3569 info_v9
->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms
;
3570 info
->lvds_pwr_off_seq_de_to_dig_on_in4ms
=
3571 info_v9
->ucLVDSPwrOffSeqDEtoDIGON_in4Ms
;
3572 info
->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms
=
3573 info_v9
->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms
;
3574 info
->lvds_off_to_on_delay_in_4ms
=
3575 info_v9
->ucLVDSOffToOnDelay_in4Ms
;
3576 info
->lvds_bit_depth_control_val
=
3577 le32_to_cpu(info_v9
->ulLCDBitDepthControlVal
);
3579 for (i
= 0; i
< NUMBER_OF_AVAILABLE_SCLK
; ++i
) {
3580 /* Convert [10KHz] into [KHz] */
3581 info
->avail_s_clk
[i
].supported_s_clk
=
3582 le32_to_cpu(info_v9
->sAvail_SCLK
[i
].ulSupportedSCLK
) * 10;
3583 info
->avail_s_clk
[i
].voltage_index
=
3584 le16_to_cpu(info_v9
->sAvail_SCLK
[i
].usVoltageIndex
);
3585 info
->avail_s_clk
[i
].voltage_id
=
3586 le16_to_cpu(info_v9
->sAvail_SCLK
[i
].usVoltageID
);
3589 for (i
= 0; i
< NUMBER_OF_UCHAR_FOR_GUID
; ++i
) {
3590 info
->ext_disp_conn_info
.gu_id
[i
] =
3591 info_v9
->sExtDispConnInfo
.ucGuid
[i
];
3594 for (i
= 0; i
< MAX_NUMBER_OF_EXT_DISPLAY_PATH
; ++i
) {
3595 info
->ext_disp_conn_info
.path
[i
].device_connector_id
=
3596 object_id_from_bios_object_id(
3597 le16_to_cpu(info_v9
->sExtDispConnInfo
.sPath
[i
].usDeviceConnector
));
3599 info
->ext_disp_conn_info
.path
[i
].ext_encoder_obj_id
=
3600 object_id_from_bios_object_id(
3601 le16_to_cpu(info_v9
->sExtDispConnInfo
.sPath
[i
].usExtEncoderObjId
));
3603 info
->ext_disp_conn_info
.path
[i
].device_tag
=
3604 le16_to_cpu(info_v9
->sExtDispConnInfo
.sPath
[i
].usDeviceTag
);
3605 info
->ext_disp_conn_info
.path
[i
].device_acpi_enum
=
3606 le16_to_cpu(info_v9
->sExtDispConnInfo
.sPath
[i
].usDeviceACPIEnum
);
3607 info
->ext_disp_conn_info
.path
[i
].ext_aux_ddc_lut_index
=
3608 info_v9
->sExtDispConnInfo
.sPath
[i
].ucExtAUXDDCLutIndex
;
3609 info
->ext_disp_conn_info
.path
[i
].ext_hpd_pin_lut_index
=
3610 info_v9
->sExtDispConnInfo
.sPath
[i
].ucExtHPDPINLutIndex
;
3611 info
->ext_disp_conn_info
.path
[i
].channel_mapping
.raw
=
3612 info_v9
->sExtDispConnInfo
.sPath
[i
].ucChannelMapping
;
3614 info
->ext_disp_conn_info
.checksum
=
3615 info_v9
->sExtDispConnInfo
.ucChecksum
;
3617 return BP_RESULT_OK
;
3621 * construct_integrated_info
3624 * Get integrated BIOS information based on table revision
3627 * bios_parser *bp - [in]BIOS parser handler to get master data table
3628 * integrated_info *info - [out] store and output integrated info
3631 * enum bp_result - BP_RESULT_OK if information is available,
3632 * BP_RESULT_BADBIOSTABLE otherwise.
3634 static enum bp_result
construct_integrated_info(
3635 struct bios_parser
*bp
,
3636 struct integrated_info
*info
)
3638 enum bp_result result
= BP_RESULT_BADBIOSTABLE
;
3640 ATOM_COMMON_TABLE_HEADER
*header
;
3641 struct atom_data_revision revision
;
3643 if (bp
->master_data_tbl
->ListOfDataTables
.IntegratedSystemInfo
) {
3644 header
= GET_IMAGE(ATOM_COMMON_TABLE_HEADER
,
3645 bp
->master_data_tbl
->ListOfDataTables
.IntegratedSystemInfo
);
3647 get_atom_data_table_revision(header
, &revision
);
3649 /* Don't need to check major revision as they are all 1 */
3650 switch (revision
.minor
) {
3652 result
= get_integrated_info_v8(bp
, info
);
3655 result
= get_integrated_info_v9(bp
, info
);
3663 /* Sort voltage table from low to high*/
3664 if (result
== BP_RESULT_OK
) {
3665 struct clock_voltage_caps temp
= {0, 0};
3669 for (i
= 1; i
< NUMBER_OF_DISP_CLK_VOLTAGE
; ++i
) {
3670 for (j
= i
; j
> 0; --j
) {
3672 info
->disp_clk_voltage
[j
].max_supported_clk
<
3673 info
->disp_clk_voltage
[j
-1].max_supported_clk
) {
3674 /* swap j and j - 1*/
3675 temp
= info
->disp_clk_voltage
[j
-1];
3676 info
->disp_clk_voltage
[j
-1] =
3677 info
->disp_clk_voltage
[j
];
3678 info
->disp_clk_voltage
[j
] = temp
;
3688 static struct integrated_info
*bios_parser_create_integrated_info(
3689 struct dc_bios
*dcb
)
3691 struct bios_parser
*bp
= BP_FROM_DCB(dcb
);
3692 struct integrated_info
*info
= NULL
;
3694 info
= kzalloc(sizeof(struct integrated_info
), GFP_KERNEL
);
3701 if (construct_integrated_info(bp
, info
) == BP_RESULT_OK
)
3709 /******************************************************************************/
3711 static const struct dc_vbios_funcs vbios_funcs
= {
3712 .get_connectors_number
= bios_parser_get_connectors_number
,
3714 .get_encoder_id
= bios_parser_get_encoder_id
,
3716 .get_connector_id
= bios_parser_get_connector_id
,
3718 .get_dst_number
= bios_parser_get_dst_number
,
3720 .get_src_obj
= bios_parser_get_src_obj
,
3722 .get_dst_obj
= bios_parser_get_dst_obj
,
3724 .get_i2c_info
= bios_parser_get_i2c_info
,
3726 .get_voltage_ddc_info
= bios_parser_get_voltage_ddc_info
,
3728 .get_thermal_ddc_info
= bios_parser_get_thermal_ddc_info
,
3730 .get_hpd_info
= bios_parser_get_hpd_info
,
3732 .get_device_tag
= bios_parser_get_device_tag
,
3734 .get_firmware_info
= bios_parser_get_firmware_info
,
3736 .get_spread_spectrum_info
= bios_parser_get_spread_spectrum_info
,
3738 .get_ss_entry_number
= bios_parser_get_ss_entry_number
,
3740 .get_embedded_panel_info
= bios_parser_get_embedded_panel_info
,
3742 .get_gpio_pin_info
= bios_parser_get_gpio_pin_info
,
3744 .get_embedded_panel_info
= bios_parser_get_embedded_panel_info
,
3746 .get_gpio_pin_info
= bios_parser_get_gpio_pin_info
,
3748 .get_encoder_cap_info
= bios_parser_get_encoder_cap_info
,
3750 /* bios scratch register communication */
3751 .is_accelerated_mode
= bios_is_accelerated_mode
,
3753 .set_scratch_critical_state
= bios_parser_set_scratch_critical_state
,
3755 .is_device_id_supported
= bios_parser_is_device_id_supported
,
3758 .encoder_control
= bios_parser_encoder_control
,
3760 .transmitter_control
= bios_parser_transmitter_control
,
3762 .crt_control
= bios_parser_crt_control
, /* not used in DAL3. keep for now in case we need to support VGA on Bonaire */
3764 .enable_crtc
= bios_parser_enable_crtc
,
3766 .adjust_pixel_clock
= bios_parser_adjust_pixel_clock
,
3768 .set_pixel_clock
= bios_parser_set_pixel_clock
,
3770 .set_dce_clock
= bios_parser_set_dce_clock
,
3772 .enable_spread_spectrum_on_ppll
= bios_parser_enable_spread_spectrum_on_ppll
,
3774 .program_crtc_timing
= bios_parser_program_crtc_timing
, /* still use. should probably retire and program directly */
3776 .crtc_source_select
= bios_parser_crtc_source_select
, /* still use. should probably retire and program directly */
3778 .program_display_engine_pll
= bios_parser_program_display_engine_pll
,
3780 .enable_disp_power_gating
= bios_parser_enable_disp_power_gating
,
3782 /* SW init and patch */
3783 .post_init
= bios_parser_post_init
, /* patch vbios table for mxm module by reading i2c */
3785 .bios_parser_destroy
= bios_parser_destroy
,
3788 static bool bios_parser_construct(
3789 struct bios_parser
*bp
,
3790 struct bp_init_data
*init
,
3791 enum dce_version dce_version
)
3793 uint16_t *rom_header_offset
= NULL
;
3794 ATOM_ROM_HEADER
*rom_header
= NULL
;
3795 ATOM_OBJECT_HEADER
*object_info_tbl
;
3796 struct atom_data_revision tbl_rev
= {0};
3804 bp
->base
.funcs
= &vbios_funcs
;
3805 bp
->base
.bios
= init
->bios
;
3806 bp
->base
.bios_size
= bp
->base
.bios
[BIOS_IMAGE_SIZE_OFFSET
] * BIOS_IMAGE_SIZE_UNIT
;
3808 bp
->base
.ctx
= init
->ctx
;
3809 bp
->base
.bios_local_image
= NULL
;
3812 GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER
);
3814 if (!rom_header_offset
)
3817 rom_header
= GET_IMAGE(ATOM_ROM_HEADER
, *rom_header_offset
);
3822 get_atom_data_table_revision(&rom_header
->sHeader
, &tbl_rev
);
3823 if (tbl_rev
.major
>= 2 && tbl_rev
.minor
>= 2)
3826 bp
->master_data_tbl
=
3827 GET_IMAGE(ATOM_MASTER_DATA_TABLE
,
3828 rom_header
->usMasterDataTableOffset
);
3830 if (!bp
->master_data_tbl
)
3833 bp
->object_info_tbl_offset
= DATA_TABLES(Object_Header
);
3835 if (!bp
->object_info_tbl_offset
)
3839 GET_IMAGE(ATOM_OBJECT_HEADER
, bp
->object_info_tbl_offset
);
3841 if (!object_info_tbl
)
3844 get_atom_data_table_revision(&object_info_tbl
->sHeader
,
3845 &bp
->object_info_tbl
.revision
);
3847 if (bp
->object_info_tbl
.revision
.major
== 1
3848 && bp
->object_info_tbl
.revision
.minor
>= 3) {
3849 ATOM_OBJECT_HEADER_V3
*tbl_v3
;
3851 tbl_v3
= GET_IMAGE(ATOM_OBJECT_HEADER_V3
,
3852 bp
->object_info_tbl_offset
);
3856 bp
->object_info_tbl
.v1_3
= tbl_v3
;
3857 } else if (bp
->object_info_tbl
.revision
.major
== 1
3858 && bp
->object_info_tbl
.revision
.minor
>= 1)
3859 bp
->object_info_tbl
.v1_1
= object_info_tbl
;
3863 dal_bios_parser_init_cmd_tbl(bp
);
3864 dal_bios_parser_init_cmd_tbl_helper(&bp
->cmd_helper
, dce_version
);
3866 bp
->base
.integrated_info
= bios_parser_create_integrated_info(&bp
->base
);
3871 /******************************************************************************/