WIP FPC-III support
[linux/fpc-iii.git] / drivers / gpu / drm / amd / display / dc / bios / bios_parser.c
blob23a373ca94b5ca7c387add3f984c4ba77eb2612d
1 /*
2 * Copyright 2012-15 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
22 * Authors: AMD
26 #include <linux/slab.h>
28 #include "dm_services.h"
30 #include "atom.h"
32 #include "dc_bios_types.h"
33 #include "include/gpio_service_interface.h"
34 #include "include/grph_object_ctrl_defs.h"
35 #include "include/bios_parser_interface.h"
36 #include "include/i2caux_interface.h"
37 #include "include/logger_interface.h"
39 #include "command_table.h"
40 #include "bios_parser_helper.h"
41 #include "command_table_helper.h"
42 #include "bios_parser.h"
43 #include "bios_parser_types_internal.h"
44 #include "bios_parser_interface.h"
46 #include "bios_parser_common.h"
48 #include "dc.h"
50 #define THREE_PERCENT_OF_10000 300
52 #define LAST_RECORD_TYPE 0xff
54 #define DC_LOGGER \
55 bp->base.ctx->logger
57 #define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
59 static void get_atom_data_table_revision(
60 ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
61 struct atom_data_revision *tbl_revision);
62 static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
63 uint16_t **id_list);
64 static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
65 struct graphics_object_id id);
66 static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
67 ATOM_I2C_RECORD *record,
68 struct graphics_object_i2c_info *info);
69 static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
70 ATOM_OBJECT *object);
71 static struct device_id device_type_from_device_id(uint16_t device_id);
72 static uint32_t signal_to_ss_id(enum as_signal_type signal);
73 static uint32_t get_support_mask_for_device_id(struct device_id device_id);
74 static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
75 struct bios_parser *bp,
76 ATOM_OBJECT *object);
78 #define BIOS_IMAGE_SIZE_OFFSET 2
79 #define BIOS_IMAGE_SIZE_UNIT 512
81 /*****************************************************************************/
82 static bool bios_parser_construct(
83 struct bios_parser *bp,
84 struct bp_init_data *init,
85 enum dce_version dce_version);
87 static uint8_t bios_parser_get_connectors_number(
88 struct dc_bios *dcb);
90 static enum bp_result bios_parser_get_embedded_panel_info(
91 struct dc_bios *dcb,
92 struct embedded_panel_info *info);
94 /*****************************************************************************/
96 struct dc_bios *bios_parser_create(
97 struct bp_init_data *init,
98 enum dce_version dce_version)
100 struct bios_parser *bp = NULL;
102 bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
103 if (!bp)
104 return NULL;
106 if (bios_parser_construct(bp, init, dce_version))
107 return &bp->base;
109 kfree(bp);
110 BREAK_TO_DEBUGGER();
111 return NULL;
114 static void bios_parser_destruct(struct bios_parser *bp)
116 kfree(bp->base.bios_local_image);
117 kfree(bp->base.integrated_info);
120 static void bios_parser_destroy(struct dc_bios **dcb)
122 struct bios_parser *bp = BP_FROM_DCB(*dcb);
124 if (!bp) {
125 BREAK_TO_DEBUGGER();
126 return;
129 bios_parser_destruct(bp);
131 kfree(bp);
132 *dcb = NULL;
135 static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
137 ATOM_OBJECT_TABLE *table;
139 uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
141 table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
143 if (!table)
144 return 0;
145 else
146 return table->ucNumberOfObjects;
149 static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb)
151 struct bios_parser *bp = BP_FROM_DCB(dcb);
153 return get_number_of_objects(bp,
154 le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
157 static struct graphics_object_id bios_parser_get_connector_id(
158 struct dc_bios *dcb,
159 uint8_t i)
161 struct bios_parser *bp = BP_FROM_DCB(dcb);
162 struct graphics_object_id object_id = dal_graphics_object_id_init(
163 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
164 uint16_t id;
166 uint32_t connector_table_offset = bp->object_info_tbl_offset
167 + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
169 ATOM_OBJECT_TABLE *tbl =
170 GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
172 if (!tbl) {
173 dm_error("Can't get connector table from atom bios.\n");
174 return object_id;
177 if (tbl->ucNumberOfObjects <= i) {
178 dm_error("Can't find connector id %d in connector table of size %d.\n",
179 i, tbl->ucNumberOfObjects);
180 return object_id;
183 id = le16_to_cpu(tbl->asObjects[i].usObjectID);
184 object_id = object_id_from_bios_object_id(id);
185 return object_id;
188 static enum bp_result bios_parser_get_src_obj(struct dc_bios *dcb,
189 struct graphics_object_id object_id, uint32_t index,
190 struct graphics_object_id *src_object_id)
192 uint32_t number;
193 uint16_t *id;
194 ATOM_OBJECT *object;
195 struct bios_parser *bp = BP_FROM_DCB(dcb);
197 if (!src_object_id)
198 return BP_RESULT_BADINPUT;
200 object = get_bios_object(bp, object_id);
202 if (!object) {
203 BREAK_TO_DEBUGGER(); /* Invalid object id */
204 return BP_RESULT_BADINPUT;
207 number = get_src_obj_list(bp, object, &id);
209 if (number <= index)
210 return BP_RESULT_BADINPUT;
212 *src_object_id = object_id_from_bios_object_id(id[index]);
214 return BP_RESULT_OK;
217 static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
218 struct graphics_object_id id,
219 struct graphics_object_i2c_info *info)
221 uint32_t offset;
222 ATOM_OBJECT *object;
223 ATOM_COMMON_RECORD_HEADER *header;
224 ATOM_I2C_RECORD *record;
225 struct bios_parser *bp = BP_FROM_DCB(dcb);
227 if (!info)
228 return BP_RESULT_BADINPUT;
230 object = get_bios_object(bp, id);
232 if (!object)
233 return BP_RESULT_BADINPUT;
235 offset = le16_to_cpu(object->usRecordOffset)
236 + bp->object_info_tbl_offset;
238 for (;;) {
239 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
241 if (!header)
242 return BP_RESULT_BADBIOSTABLE;
244 if (LAST_RECORD_TYPE == header->ucRecordType ||
245 !header->ucRecordSize)
246 break;
248 if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
249 && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
250 /* get the I2C info */
251 record = (ATOM_I2C_RECORD *) header;
253 if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
254 return BP_RESULT_OK;
257 offset += header->ucRecordSize;
260 return BP_RESULT_NORECORD;
263 static enum bp_result bios_parser_get_hpd_info(struct dc_bios *dcb,
264 struct graphics_object_id id,
265 struct graphics_object_hpd_info *info)
267 struct bios_parser *bp = BP_FROM_DCB(dcb);
268 ATOM_OBJECT *object;
269 ATOM_HPD_INT_RECORD *record = NULL;
271 if (!info)
272 return BP_RESULT_BADINPUT;
274 object = get_bios_object(bp, id);
276 if (!object)
277 return BP_RESULT_BADINPUT;
279 record = get_hpd_record(bp, object);
281 if (record != NULL) {
282 info->hpd_int_gpio_uid = record->ucHPDIntGPIOID;
283 info->hpd_active = record->ucPlugged_PinState;
284 return BP_RESULT_OK;
287 return BP_RESULT_NORECORD;
290 static enum bp_result bios_parser_get_device_tag_record(
291 struct bios_parser *bp,
292 ATOM_OBJECT *object,
293 ATOM_CONNECTOR_DEVICE_TAG_RECORD **record)
295 ATOM_COMMON_RECORD_HEADER *header;
296 uint32_t offset;
298 offset = le16_to_cpu(object->usRecordOffset)
299 + bp->object_info_tbl_offset;
301 for (;;) {
302 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
304 if (!header)
305 return BP_RESULT_BADBIOSTABLE;
307 offset += header->ucRecordSize;
309 if (LAST_RECORD_TYPE == header->ucRecordType ||
310 !header->ucRecordSize)
311 break;
313 if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
314 header->ucRecordType)
315 continue;
317 if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
318 continue;
320 *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
321 return BP_RESULT_OK;
324 return BP_RESULT_NORECORD;
327 static enum bp_result bios_parser_get_device_tag(
328 struct dc_bios *dcb,
329 struct graphics_object_id connector_object_id,
330 uint32_t device_tag_index,
331 struct connector_device_tag_info *info)
333 struct bios_parser *bp = BP_FROM_DCB(dcb);
334 ATOM_OBJECT *object;
335 ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
336 ATOM_CONNECTOR_DEVICE_TAG *device_tag;
338 if (!info)
339 return BP_RESULT_BADINPUT;
341 /* getBiosObject will return MXM object */
342 object = get_bios_object(bp, connector_object_id);
344 if (!object) {
345 BREAK_TO_DEBUGGER(); /* Invalid object id */
346 return BP_RESULT_BADINPUT;
349 if (bios_parser_get_device_tag_record(bp, object, &record)
350 != BP_RESULT_OK)
351 return BP_RESULT_NORECORD;
353 if (device_tag_index >= record->ucNumberOfDevice)
354 return BP_RESULT_NORECORD;
356 device_tag = &record->asDeviceTag[device_tag_index];
358 info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
359 info->dev_id =
360 device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
362 return BP_RESULT_OK;
365 static enum bp_result get_firmware_info_v1_4(
366 struct bios_parser *bp,
367 struct dc_firmware_info *info);
368 static enum bp_result get_firmware_info_v2_1(
369 struct bios_parser *bp,
370 struct dc_firmware_info *info);
371 static enum bp_result get_firmware_info_v2_2(
372 struct bios_parser *bp,
373 struct dc_firmware_info *info);
375 static enum bp_result bios_parser_get_firmware_info(
376 struct dc_bios *dcb,
377 struct dc_firmware_info *info)
379 struct bios_parser *bp = BP_FROM_DCB(dcb);
380 enum bp_result result = BP_RESULT_BADBIOSTABLE;
381 ATOM_COMMON_TABLE_HEADER *header;
382 struct atom_data_revision revision;
384 if (info && DATA_TABLES(FirmwareInfo)) {
385 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
386 DATA_TABLES(FirmwareInfo));
387 get_atom_data_table_revision(header, &revision);
388 switch (revision.major) {
389 case 1:
390 switch (revision.minor) {
391 case 4:
392 result = get_firmware_info_v1_4(bp, info);
393 break;
394 default:
395 break;
397 break;
399 case 2:
400 switch (revision.minor) {
401 case 1:
402 result = get_firmware_info_v2_1(bp, info);
403 break;
404 case 2:
405 result = get_firmware_info_v2_2(bp, info);
406 break;
407 default:
408 break;
410 break;
411 default:
412 break;
416 return result;
419 static enum bp_result get_firmware_info_v1_4(
420 struct bios_parser *bp,
421 struct dc_firmware_info *info)
423 ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
424 GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
425 DATA_TABLES(FirmwareInfo));
427 if (!info)
428 return BP_RESULT_BADINPUT;
430 if (!firmware_info)
431 return BP_RESULT_BADBIOSTABLE;
433 memset(info, 0, sizeof(*info));
435 /* Pixel clock pll information. We need to convert from 10KHz units into
436 * KHz units */
437 info->pll_info.crystal_frequency =
438 le16_to_cpu(firmware_info->usReferenceClock) * 10;
439 info->pll_info.min_input_pxl_clk_pll_frequency =
440 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
441 info->pll_info.max_input_pxl_clk_pll_frequency =
442 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
443 info->pll_info.min_output_pxl_clk_pll_frequency =
444 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
445 info->pll_info.max_output_pxl_clk_pll_frequency =
446 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
448 if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
449 /* Since there is no information on the SS, report conservative
450 * value 3% for bandwidth calculation */
451 /* unit of 0.01% */
452 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
454 if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
455 /* Since there is no information on the SS,report conservative
456 * value 3% for bandwidth calculation */
457 /* unit of 0.01% */
458 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
460 return BP_RESULT_OK;
463 static enum bp_result get_ss_info_v3_1(
464 struct bios_parser *bp,
465 uint32_t id,
466 uint32_t index,
467 struct spread_spectrum_info *ss_info);
469 static enum bp_result get_firmware_info_v2_1(
470 struct bios_parser *bp,
471 struct dc_firmware_info *info)
473 ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
474 GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
475 struct spread_spectrum_info internalSS;
476 uint32_t index;
478 if (!info)
479 return BP_RESULT_BADINPUT;
481 if (!firmwareInfo)
482 return BP_RESULT_BADBIOSTABLE;
484 memset(info, 0, sizeof(*info));
486 /* Pixel clock pll information. We need to convert from 10KHz units into
487 * KHz units */
488 info->pll_info.crystal_frequency =
489 le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
490 info->pll_info.min_input_pxl_clk_pll_frequency =
491 le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
492 info->pll_info.max_input_pxl_clk_pll_frequency =
493 le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
494 info->pll_info.min_output_pxl_clk_pll_frequency =
495 le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
496 info->pll_info.max_output_pxl_clk_pll_frequency =
497 le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
498 info->default_display_engine_pll_frequency =
499 le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
500 info->external_clock_source_frequency_for_dp =
501 le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
502 info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
504 /* There should be only one entry in the SS info table for Memory Clock
506 index = 0;
507 if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
508 /* Since there is no information for external SS, report
509 * conservative value 3% for bandwidth calculation */
510 /* unit of 0.01% */
511 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
512 else if (get_ss_info_v3_1(bp,
513 ASIC_INTERNAL_MEMORY_SS, index, &internalSS) == BP_RESULT_OK) {
514 if (internalSS.spread_spectrum_percentage) {
515 info->feature.memory_clk_ss_percentage =
516 internalSS.spread_spectrum_percentage;
517 if (internalSS.type.CENTER_MODE) {
518 /* if it is centermode, the exact SS Percentage
519 * will be round up of half of the percentage
520 * reported in the SS table */
521 ++info->feature.memory_clk_ss_percentage;
522 info->feature.memory_clk_ss_percentage /= 2;
527 /* There should be only one entry in the SS info table for Engine Clock
529 index = 1;
530 if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
531 /* Since there is no information for external SS, report
532 * conservative value 3% for bandwidth calculation */
533 /* unit of 0.01% */
534 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
535 else if (get_ss_info_v3_1(bp,
536 ASIC_INTERNAL_ENGINE_SS, index, &internalSS) == BP_RESULT_OK) {
537 if (internalSS.spread_spectrum_percentage) {
538 info->feature.engine_clk_ss_percentage =
539 internalSS.spread_spectrum_percentage;
540 if (internalSS.type.CENTER_MODE) {
541 /* if it is centermode, the exact SS Percentage
542 * will be round up of half of the percentage
543 * reported in the SS table */
544 ++info->feature.engine_clk_ss_percentage;
545 info->feature.engine_clk_ss_percentage /= 2;
550 return BP_RESULT_OK;
553 static enum bp_result get_firmware_info_v2_2(
554 struct bios_parser *bp,
555 struct dc_firmware_info *info)
557 ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
558 struct spread_spectrum_info internal_ss;
559 uint32_t index;
561 if (!info)
562 return BP_RESULT_BADINPUT;
564 firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
565 DATA_TABLES(FirmwareInfo));
567 if (!firmware_info)
568 return BP_RESULT_BADBIOSTABLE;
570 memset(info, 0, sizeof(*info));
572 /* Pixel clock pll information. We need to convert from 10KHz units into
573 * KHz units */
574 info->pll_info.crystal_frequency =
575 le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
576 info->pll_info.min_input_pxl_clk_pll_frequency =
577 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
578 info->pll_info.max_input_pxl_clk_pll_frequency =
579 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
580 info->pll_info.min_output_pxl_clk_pll_frequency =
581 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
582 info->pll_info.max_output_pxl_clk_pll_frequency =
583 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
584 info->default_display_engine_pll_frequency =
585 le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
586 info->external_clock_source_frequency_for_dp =
587 le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
589 /* There should be only one entry in the SS info table for Memory Clock
591 index = 0;
592 if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
593 /* Since there is no information for external SS, report
594 * conservative value 3% for bandwidth calculation */
595 /* unit of 0.01% */
596 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
597 else if (get_ss_info_v3_1(bp,
598 ASIC_INTERNAL_MEMORY_SS, index, &internal_ss) == BP_RESULT_OK) {
599 if (internal_ss.spread_spectrum_percentage) {
600 info->feature.memory_clk_ss_percentage =
601 internal_ss.spread_spectrum_percentage;
602 if (internal_ss.type.CENTER_MODE) {
603 /* if it is centermode, the exact SS Percentage
604 * will be round up of half of the percentage
605 * reported in the SS table */
606 ++info->feature.memory_clk_ss_percentage;
607 info->feature.memory_clk_ss_percentage /= 2;
612 /* There should be only one entry in the SS info table for Engine Clock
614 index = 1;
615 if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
616 /* Since there is no information for external SS, report
617 * conservative value 3% for bandwidth calculation */
618 /* unit of 0.01% */
619 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
620 else if (get_ss_info_v3_1(bp,
621 ASIC_INTERNAL_ENGINE_SS, index, &internal_ss) == BP_RESULT_OK) {
622 if (internal_ss.spread_spectrum_percentage) {
623 info->feature.engine_clk_ss_percentage =
624 internal_ss.spread_spectrum_percentage;
625 if (internal_ss.type.CENTER_MODE) {
626 /* if it is centermode, the exact SS Percentage
627 * will be round up of half of the percentage
628 * reported in the SS table */
629 ++info->feature.engine_clk_ss_percentage;
630 info->feature.engine_clk_ss_percentage /= 2;
635 /* Remote Display */
636 info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
638 /* Is allowed minimum BL level */
639 info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
640 /* Used starting from CI */
641 info->smu_gpu_pll_output_freq =
642 (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
644 return BP_RESULT_OK;
647 static enum bp_result get_ss_info_v3_1(
648 struct bios_parser *bp,
649 uint32_t id,
650 uint32_t index,
651 struct spread_spectrum_info *ss_info)
653 ATOM_ASIC_INTERNAL_SS_INFO_V3 *ss_table_header_include;
654 ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
655 uint32_t table_size;
656 uint32_t i;
657 uint32_t table_index = 0;
659 if (!ss_info)
660 return BP_RESULT_BADINPUT;
662 if (!DATA_TABLES(ASIC_InternalSS_Info))
663 return BP_RESULT_UNSUPPORTED;
665 ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
666 DATA_TABLES(ASIC_InternalSS_Info));
667 table_size =
668 (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
669 - sizeof(ATOM_COMMON_TABLE_HEADER))
670 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
672 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
673 &ss_table_header_include->asSpreadSpectrum[0];
675 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
677 for (i = 0; i < table_size; i++) {
678 if (tbl[i].ucClockIndication != (uint8_t) id)
679 continue;
681 if (table_index != index) {
682 table_index++;
683 continue;
685 /* VBIOS introduced new defines for Version 3, same values as
686 * before, so now use these new ones for Version 3.
687 * Shouldn't affect field VBIOS's V3 as define values are still
688 * same.
689 * #define SS_MODE_V3_CENTRE_SPREAD_MASK 0x01
690 * #define SS_MODE_V3_EXTERNAL_SS_MASK 0x02
692 * Old VBIOS defines:
693 * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
694 * #define ATOM_EXTERNAL_SS_MASK 0x00000002
697 if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
698 ss_info->type.EXTERNAL = true;
700 if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
701 ss_info->type.CENTER_MODE = true;
703 /* Older VBIOS (in field) always provides SS percentage in 0.01%
704 * units set Divider to 100 */
705 ss_info->spread_percentage_divider = 100;
707 /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
708 if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
709 & tbl[i].ucSpreadSpectrumMode)
710 ss_info->spread_percentage_divider = 1000;
712 ss_info->type.STEP_AND_DELAY_INFO = false;
713 /* convert [10KHz] into [KHz] */
714 ss_info->target_clock_range =
715 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
716 ss_info->spread_spectrum_percentage =
717 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
718 ss_info->spread_spectrum_range =
719 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
721 return BP_RESULT_OK;
723 return BP_RESULT_NORECORD;
726 static enum bp_result bios_parser_transmitter_control(
727 struct dc_bios *dcb,
728 struct bp_transmitter_control *cntl)
730 struct bios_parser *bp = BP_FROM_DCB(dcb);
732 if (!bp->cmd_tbl.transmitter_control)
733 return BP_RESULT_FAILURE;
735 return bp->cmd_tbl.transmitter_control(bp, cntl);
738 static enum bp_result bios_parser_encoder_control(
739 struct dc_bios *dcb,
740 struct bp_encoder_control *cntl)
742 struct bios_parser *bp = BP_FROM_DCB(dcb);
744 if (!bp->cmd_tbl.dig_encoder_control)
745 return BP_RESULT_FAILURE;
747 return bp->cmd_tbl.dig_encoder_control(bp, cntl);
750 static enum bp_result bios_parser_adjust_pixel_clock(
751 struct dc_bios *dcb,
752 struct bp_adjust_pixel_clock_parameters *bp_params)
754 struct bios_parser *bp = BP_FROM_DCB(dcb);
756 if (!bp->cmd_tbl.adjust_display_pll)
757 return BP_RESULT_FAILURE;
759 return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
762 static enum bp_result bios_parser_set_pixel_clock(
763 struct dc_bios *dcb,
764 struct bp_pixel_clock_parameters *bp_params)
766 struct bios_parser *bp = BP_FROM_DCB(dcb);
768 if (!bp->cmd_tbl.set_pixel_clock)
769 return BP_RESULT_FAILURE;
771 return bp->cmd_tbl.set_pixel_clock(bp, bp_params);
774 static enum bp_result bios_parser_set_dce_clock(
775 struct dc_bios *dcb,
776 struct bp_set_dce_clock_parameters *bp_params)
778 struct bios_parser *bp = BP_FROM_DCB(dcb);
780 if (!bp->cmd_tbl.set_dce_clock)
781 return BP_RESULT_FAILURE;
783 return bp->cmd_tbl.set_dce_clock(bp, bp_params);
786 static enum bp_result bios_parser_enable_spread_spectrum_on_ppll(
787 struct dc_bios *dcb,
788 struct bp_spread_spectrum_parameters *bp_params,
789 bool enable)
791 struct bios_parser *bp = BP_FROM_DCB(dcb);
793 if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
794 return BP_RESULT_FAILURE;
796 return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
797 bp, bp_params, enable);
801 static enum bp_result bios_parser_program_crtc_timing(
802 struct dc_bios *dcb,
803 struct bp_hw_crtc_timing_parameters *bp_params)
805 struct bios_parser *bp = BP_FROM_DCB(dcb);
807 if (!bp->cmd_tbl.set_crtc_timing)
808 return BP_RESULT_FAILURE;
810 return bp->cmd_tbl.set_crtc_timing(bp, bp_params);
813 static enum bp_result bios_parser_program_display_engine_pll(
814 struct dc_bios *dcb,
815 struct bp_pixel_clock_parameters *bp_params)
817 struct bios_parser *bp = BP_FROM_DCB(dcb);
819 if (!bp->cmd_tbl.program_clock)
820 return BP_RESULT_FAILURE;
822 return bp->cmd_tbl.program_clock(bp, bp_params);
827 static enum bp_result bios_parser_enable_crtc(
828 struct dc_bios *dcb,
829 enum controller_id id,
830 bool enable)
832 struct bios_parser *bp = BP_FROM_DCB(dcb);
834 if (!bp->cmd_tbl.enable_crtc)
835 return BP_RESULT_FAILURE;
837 return bp->cmd_tbl.enable_crtc(bp, id, enable);
840 static enum bp_result bios_parser_enable_disp_power_gating(
841 struct dc_bios *dcb,
842 enum controller_id controller_id,
843 enum bp_pipe_control_action action)
845 struct bios_parser *bp = BP_FROM_DCB(dcb);
847 if (!bp->cmd_tbl.enable_disp_power_gating)
848 return BP_RESULT_FAILURE;
850 return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id,
851 action);
854 static bool bios_parser_is_device_id_supported(
855 struct dc_bios *dcb,
856 struct device_id id)
858 struct bios_parser *bp = BP_FROM_DCB(dcb);
860 uint32_t mask = get_support_mask_for_device_id(id);
862 return (le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport) & mask) != 0;
865 static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
866 ATOM_OBJECT *object)
868 ATOM_COMMON_RECORD_HEADER *header;
869 uint32_t offset;
871 if (!object) {
872 BREAK_TO_DEBUGGER(); /* Invalid object */
873 return NULL;
876 offset = le16_to_cpu(object->usRecordOffset)
877 + bp->object_info_tbl_offset;
879 for (;;) {
880 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
882 if (!header)
883 return NULL;
885 if (LAST_RECORD_TYPE == header->ucRecordType ||
886 !header->ucRecordSize)
887 break;
889 if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
890 && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
891 return (ATOM_HPD_INT_RECORD *) header;
893 offset += header->ucRecordSize;
896 return NULL;
899 static enum bp_result get_ss_info_from_ss_info_table(
900 struct bios_parser *bp,
901 uint32_t id,
902 struct spread_spectrum_info *ss_info);
903 static enum bp_result get_ss_info_from_tbl(
904 struct bios_parser *bp,
905 uint32_t id,
906 struct spread_spectrum_info *ss_info);
908 * bios_parser_get_spread_spectrum_info
909 * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or
910 * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info
911 * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ver 3.1,
912 * there is only one entry for each signal /ss id. However, there is
913 * no planning of supporting multiple spread Sprectum entry for EverGreen
914 * @param [in] this
915 * @param [in] signal, ASSignalType to be converted to info index
916 * @param [in] index, number of entries that match the converted info index
917 * @param [out] ss_info, sprectrum information structure,
918 * @return Bios parser result code
920 static enum bp_result bios_parser_get_spread_spectrum_info(
921 struct dc_bios *dcb,
922 enum as_signal_type signal,
923 uint32_t index,
924 struct spread_spectrum_info *ss_info)
926 struct bios_parser *bp = BP_FROM_DCB(dcb);
927 enum bp_result result = BP_RESULT_UNSUPPORTED;
928 uint32_t clk_id_ss = 0;
929 ATOM_COMMON_TABLE_HEADER *header;
930 struct atom_data_revision tbl_revision;
932 if (!ss_info) /* check for bad input */
933 return BP_RESULT_BADINPUT;
934 /* signal translation */
935 clk_id_ss = signal_to_ss_id(signal);
937 if (!DATA_TABLES(ASIC_InternalSS_Info))
938 if (!index)
939 return get_ss_info_from_ss_info_table(bp, clk_id_ss,
940 ss_info);
942 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
943 DATA_TABLES(ASIC_InternalSS_Info));
944 get_atom_data_table_revision(header, &tbl_revision);
946 switch (tbl_revision.major) {
947 case 2:
948 switch (tbl_revision.minor) {
949 case 1:
950 /* there can not be more then one entry for Internal
951 * SS Info table version 2.1 */
952 if (!index)
953 return get_ss_info_from_tbl(bp, clk_id_ss,
954 ss_info);
955 break;
956 default:
957 break;
959 break;
961 case 3:
962 switch (tbl_revision.minor) {
963 case 1:
964 return get_ss_info_v3_1(bp, clk_id_ss, index, ss_info);
965 default:
966 break;
968 break;
969 default:
970 break;
972 /* there can not be more then one entry for SS Info table */
973 return result;
976 static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
977 struct bios_parser *bp,
978 uint32_t id,
979 struct spread_spectrum_info *info);
982 * get_ss_info_from_table
983 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
984 * SS_Info table from the VBIOS
985 * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
986 * SS_Info.
988 * @param this
989 * @param id, spread sprectrum info index
990 * @param pSSinfo, sprectrum information structure,
991 * @return Bios parser result code
993 static enum bp_result get_ss_info_from_tbl(
994 struct bios_parser *bp,
995 uint32_t id,
996 struct spread_spectrum_info *ss_info)
998 if (!ss_info) /* check for bad input, if ss_info is not NULL */
999 return BP_RESULT_BADINPUT;
1000 /* for SS_Info table only support DP and LVDS */
1001 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1002 return get_ss_info_from_ss_info_table(bp, id, ss_info);
1003 else
1004 return get_ss_info_from_internal_ss_info_tbl_V2_1(bp, id,
1005 ss_info);
1009 * get_ss_info_from_internal_ss_info_tbl_V2_1
1010 * Get spread sprectrum information from the ASIC_InternalSS_Info table Ver 2.1
1011 * from the VBIOS
1012 * There will not be multiple entry for Ver 2.1
1014 * @param id, spread sprectrum info index
1015 * @param pSSinfo, sprectrum information structure,
1016 * @return Bios parser result code
1018 static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1019 struct bios_parser *bp,
1020 uint32_t id,
1021 struct spread_spectrum_info *info)
1023 enum bp_result result = BP_RESULT_UNSUPPORTED;
1024 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header;
1025 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1026 uint32_t tbl_size, i;
1028 if (!DATA_TABLES(ASIC_InternalSS_Info))
1029 return result;
1031 header = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
1032 DATA_TABLES(ASIC_InternalSS_Info));
1034 memset(info, 0, sizeof(struct spread_spectrum_info));
1036 tbl_size = (le16_to_cpu(header->sHeader.usStructureSize)
1037 - sizeof(ATOM_COMMON_TABLE_HEADER))
1038 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1040 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1041 &(header->asSpreadSpectrum[0]);
1042 for (i = 0; i < tbl_size; i++) {
1043 result = BP_RESULT_NORECORD;
1045 if (tbl[i].ucClockIndication != (uint8_t)id)
1046 continue;
1048 if (ATOM_EXTERNAL_SS_MASK
1049 & tbl[i].ucSpreadSpectrumMode) {
1050 info->type.EXTERNAL = true;
1052 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
1053 & tbl[i].ucSpreadSpectrumMode) {
1054 info->type.CENTER_MODE = true;
1056 info->type.STEP_AND_DELAY_INFO = false;
1057 /* convert [10KHz] into [KHz] */
1058 info->target_clock_range =
1059 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
1060 info->spread_spectrum_percentage =
1061 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
1062 info->spread_spectrum_range =
1063 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
1064 result = BP_RESULT_OK;
1065 break;
1068 return result;
1073 * get_ss_info_from_ss_info_table
1074 * Get spread sprectrum information from the SS_Info table from the VBIOS
1075 * if the pointer to info is NULL, indicate the caller what to know the number
1076 * of entries that matches the id
1077 * for, the SS_Info table, there should not be more than 1 entry match.
1079 * @param [in] id, spread sprectrum id
1080 * @param [out] pSSinfo, sprectrum information structure,
1081 * @return Bios parser result code
1083 static enum bp_result get_ss_info_from_ss_info_table(
1084 struct bios_parser *bp,
1085 uint32_t id,
1086 struct spread_spectrum_info *ss_info)
1088 enum bp_result result = BP_RESULT_UNSUPPORTED;
1089 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1090 ATOM_COMMON_TABLE_HEADER *header;
1091 uint32_t table_size;
1092 uint32_t i;
1093 uint32_t id_local = SS_ID_UNKNOWN;
1094 struct atom_data_revision revision;
1096 /* exist of the SS_Info table */
1097 /* check for bad input, pSSinfo can not be NULL */
1098 if (!DATA_TABLES(SS_Info) || !ss_info)
1099 return result;
1101 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(SS_Info));
1102 get_atom_data_table_revision(header, &revision);
1104 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info));
1106 if (1 != revision.major || 2 > revision.minor)
1107 return result;
1109 /* have to convert from Internal_SS format to SS_Info format */
1110 switch (id) {
1111 case ASIC_INTERNAL_SS_ON_DP:
1112 id_local = SS_ID_DP1;
1113 break;
1114 case ASIC_INTERNAL_SS_ON_LVDS:
1116 struct embedded_panel_info panel_info;
1118 if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
1119 == BP_RESULT_OK)
1120 id_local = panel_info.ss_id;
1121 break;
1123 default:
1124 break;
1127 if (id_local == SS_ID_UNKNOWN)
1128 return result;
1130 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1131 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1132 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1134 for (i = 0; i < table_size; i++) {
1135 if (id_local != (uint32_t)tbl->asSS_Info[i].ucSS_Id)
1136 continue;
1138 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
1140 if (ATOM_EXTERNAL_SS_MASK &
1141 tbl->asSS_Info[i].ucSpreadSpectrumType)
1142 ss_info->type.EXTERNAL = true;
1144 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK &
1145 tbl->asSS_Info[i].ucSpreadSpectrumType)
1146 ss_info->type.CENTER_MODE = true;
1148 ss_info->type.STEP_AND_DELAY_INFO = true;
1149 ss_info->spread_spectrum_percentage =
1150 (uint32_t)le16_to_cpu(tbl->asSS_Info[i].usSpreadSpectrumPercentage);
1151 ss_info->step_and_delay_info.step = tbl->asSS_Info[i].ucSS_Step;
1152 ss_info->step_and_delay_info.delay =
1153 tbl->asSS_Info[i].ucSS_Delay;
1154 ss_info->step_and_delay_info.recommended_ref_div =
1155 tbl->asSS_Info[i].ucRecommendedRef_Div;
1156 ss_info->spread_spectrum_range =
1157 (uint32_t)tbl->asSS_Info[i].ucSS_Range * 10000;
1159 /* there will be only one entry for each display type in SS_info
1160 * table */
1161 result = BP_RESULT_OK;
1162 break;
1165 return result;
1167 static enum bp_result get_embedded_panel_info_v1_2(
1168 struct bios_parser *bp,
1169 struct embedded_panel_info *info);
1170 static enum bp_result get_embedded_panel_info_v1_3(
1171 struct bios_parser *bp,
1172 struct embedded_panel_info *info);
1174 static enum bp_result bios_parser_get_embedded_panel_info(
1175 struct dc_bios *dcb,
1176 struct embedded_panel_info *info)
1178 struct bios_parser *bp = BP_FROM_DCB(dcb);
1179 ATOM_COMMON_TABLE_HEADER *hdr;
1181 if (!DATA_TABLES(LCD_Info))
1182 return BP_RESULT_FAILURE;
1184 hdr = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(LCD_Info));
1186 if (!hdr)
1187 return BP_RESULT_BADBIOSTABLE;
1189 switch (hdr->ucTableFormatRevision) {
1190 case 1:
1191 switch (hdr->ucTableContentRevision) {
1192 case 0:
1193 case 1:
1194 case 2:
1195 return get_embedded_panel_info_v1_2(bp, info);
1196 case 3:
1197 return get_embedded_panel_info_v1_3(bp, info);
1198 default:
1199 break;
1201 break;
1202 default:
1203 break;
1206 return BP_RESULT_FAILURE;
1209 static enum bp_result get_embedded_panel_info_v1_2(
1210 struct bios_parser *bp,
1211 struct embedded_panel_info *info)
1213 ATOM_LVDS_INFO_V12 *lvds;
1215 if (!info)
1216 return BP_RESULT_BADINPUT;
1218 if (!DATA_TABLES(LVDS_Info))
1219 return BP_RESULT_UNSUPPORTED;
1221 lvds =
1222 GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
1224 if (!lvds)
1225 return BP_RESULT_BADBIOSTABLE;
1227 if (1 != lvds->sHeader.ucTableFormatRevision
1228 || 2 > lvds->sHeader.ucTableContentRevision)
1229 return BP_RESULT_UNSUPPORTED;
1231 memset(info, 0, sizeof(struct embedded_panel_info));
1233 /* We need to convert from 10KHz units into KHz units*/
1234 info->lcd_timing.pixel_clk =
1235 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1236 /* usHActive does not include borders, according to VBIOS team*/
1237 info->lcd_timing.horizontal_addressable =
1238 le16_to_cpu(lvds->sLCDTiming.usHActive);
1239 /* usHBlanking_Time includes borders, so we should really be subtracting
1240 * borders duing this translation, but LVDS generally*/
1241 /* doesn't have borders, so we should be okay leaving this as is for
1242 * now. May need to revisit if we ever have LVDS with borders*/
1243 info->lcd_timing.horizontal_blanking_time =
1244 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1245 /* usVActive does not include borders, according to VBIOS team*/
1246 info->lcd_timing.vertical_addressable =
1247 le16_to_cpu(lvds->sLCDTiming.usVActive);
1248 /* usVBlanking_Time includes borders, so we should really be subtracting
1249 * borders duing this translation, but LVDS generally*/
1250 /* doesn't have borders, so we should be okay leaving this as is for
1251 * now. May need to revisit if we ever have LVDS with borders*/
1252 info->lcd_timing.vertical_blanking_time =
1253 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1254 info->lcd_timing.horizontal_sync_offset =
1255 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1256 info->lcd_timing.horizontal_sync_width =
1257 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1258 info->lcd_timing.vertical_sync_offset =
1259 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1260 info->lcd_timing.vertical_sync_width =
1261 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1262 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1263 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1264 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1265 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1266 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1267 ~(uint32_t)
1268 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1269 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1270 ~(uint32_t)
1271 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1272 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1273 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1274 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1275 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1276 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1277 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1278 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1279 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1280 info->lcd_timing.misc_info.INTERLACE =
1281 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1282 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1283 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1284 info->ss_id = lvds->ucSS_Id;
1287 uint8_t rr = le16_to_cpu(lvds->usSupportedRefreshRate);
1288 /* Get minimum supported refresh rate*/
1289 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1290 info->supported_rr.REFRESH_RATE_30HZ = 1;
1291 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1292 info->supported_rr.REFRESH_RATE_40HZ = 1;
1293 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1294 info->supported_rr.REFRESH_RATE_48HZ = 1;
1295 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1296 info->supported_rr.REFRESH_RATE_50HZ = 1;
1297 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1298 info->supported_rr.REFRESH_RATE_60HZ = 1;
1301 /*Drr panel support can be reported by VBIOS*/
1302 if (LCDPANEL_CAP_DRR_SUPPORTED
1303 & lvds->ucLCDPanel_SpecialHandlingCap)
1304 info->drr_enabled = 1;
1306 if (ATOM_PANEL_MISC_DUAL & lvds->ucLVDS_Misc)
1307 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1309 if (ATOM_PANEL_MISC_888RGB & lvds->ucLVDS_Misc)
1310 info->lcd_timing.misc_info.RGB888 = true;
1312 info->lcd_timing.misc_info.GREY_LEVEL =
1313 (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL &
1314 lvds->ucLVDS_Misc) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT;
1316 if (ATOM_PANEL_MISC_SPATIAL & lvds->ucLVDS_Misc)
1317 info->lcd_timing.misc_info.SPATIAL = true;
1319 if (ATOM_PANEL_MISC_TEMPORAL & lvds->ucLVDS_Misc)
1320 info->lcd_timing.misc_info.TEMPORAL = true;
1322 if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
1323 info->lcd_timing.misc_info.API_ENABLED = true;
1325 return BP_RESULT_OK;
1328 static enum bp_result get_embedded_panel_info_v1_3(
1329 struct bios_parser *bp,
1330 struct embedded_panel_info *info)
1332 ATOM_LCD_INFO_V13 *lvds;
1334 if (!info)
1335 return BP_RESULT_BADINPUT;
1337 if (!DATA_TABLES(LCD_Info))
1338 return BP_RESULT_UNSUPPORTED;
1340 lvds = GET_IMAGE(ATOM_LCD_INFO_V13, DATA_TABLES(LCD_Info));
1342 if (!lvds)
1343 return BP_RESULT_BADBIOSTABLE;
1345 if (!((1 == lvds->sHeader.ucTableFormatRevision)
1346 && (3 <= lvds->sHeader.ucTableContentRevision)))
1347 return BP_RESULT_UNSUPPORTED;
1349 memset(info, 0, sizeof(struct embedded_panel_info));
1351 /* We need to convert from 10KHz units into KHz units */
1352 info->lcd_timing.pixel_clk =
1353 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1354 /* usHActive does not include borders, according to VBIOS team */
1355 info->lcd_timing.horizontal_addressable =
1356 le16_to_cpu(lvds->sLCDTiming.usHActive);
1357 /* usHBlanking_Time includes borders, so we should really be subtracting
1358 * borders duing this translation, but LVDS generally*/
1359 /* doesn't have borders, so we should be okay leaving this as is for
1360 * now. May need to revisit if we ever have LVDS with borders*/
1361 info->lcd_timing.horizontal_blanking_time =
1362 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1363 /* usVActive does not include borders, according to VBIOS team*/
1364 info->lcd_timing.vertical_addressable =
1365 le16_to_cpu(lvds->sLCDTiming.usVActive);
1366 /* usVBlanking_Time includes borders, so we should really be subtracting
1367 * borders duing this translation, but LVDS generally*/
1368 /* doesn't have borders, so we should be okay leaving this as is for
1369 * now. May need to revisit if we ever have LVDS with borders*/
1370 info->lcd_timing.vertical_blanking_time =
1371 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1372 info->lcd_timing.horizontal_sync_offset =
1373 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1374 info->lcd_timing.horizontal_sync_width =
1375 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1376 info->lcd_timing.vertical_sync_offset =
1377 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1378 info->lcd_timing.vertical_sync_width =
1379 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1380 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1381 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1382 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1383 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1384 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1385 ~(uint32_t)
1386 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1387 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1388 ~(uint32_t)
1389 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1390 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1391 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1392 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1393 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1394 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1395 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1396 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1397 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1398 info->lcd_timing.misc_info.INTERLACE =
1399 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1400 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1401 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1402 info->ss_id = lvds->ucSS_Id;
1404 /* Drr panel support can be reported by VBIOS*/
1405 if (LCDPANEL_CAP_V13_DRR_SUPPORTED
1406 & lvds->ucLCDPanel_SpecialHandlingCap)
1407 info->drr_enabled = 1;
1409 /* Get supported refresh rate*/
1410 if (info->drr_enabled == 1) {
1411 uint8_t min_rr =
1412 lvds->sRefreshRateSupport.ucMinRefreshRateForDRR;
1413 uint8_t rr = lvds->sRefreshRateSupport.ucSupportedRefreshRate;
1415 if (min_rr != 0) {
1416 if (SUPPORTED_LCD_REFRESHRATE_30Hz & min_rr)
1417 info->supported_rr.REFRESH_RATE_30HZ = 1;
1418 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & min_rr)
1419 info->supported_rr.REFRESH_RATE_40HZ = 1;
1420 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & min_rr)
1421 info->supported_rr.REFRESH_RATE_48HZ = 1;
1422 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & min_rr)
1423 info->supported_rr.REFRESH_RATE_50HZ = 1;
1424 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & min_rr)
1425 info->supported_rr.REFRESH_RATE_60HZ = 1;
1426 } else {
1427 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1428 info->supported_rr.REFRESH_RATE_30HZ = 1;
1429 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1430 info->supported_rr.REFRESH_RATE_40HZ = 1;
1431 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1432 info->supported_rr.REFRESH_RATE_48HZ = 1;
1433 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1434 info->supported_rr.REFRESH_RATE_50HZ = 1;
1435 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1436 info->supported_rr.REFRESH_RATE_60HZ = 1;
1440 if (ATOM_PANEL_MISC_V13_DUAL & lvds->ucLCD_Misc)
1441 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1443 if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR & lvds->ucLCD_Misc)
1444 info->lcd_timing.misc_info.RGB888 = true;
1446 info->lcd_timing.misc_info.GREY_LEVEL =
1447 (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
1448 lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
1450 return BP_RESULT_OK;
1454 * bios_parser_get_encoder_cap_info
1456 * @brief
1457 * Get encoder capability information of input object id
1459 * @param object_id, Object id
1460 * @param object_id, encoder cap information structure
1462 * @return Bios parser result code
1465 static enum bp_result bios_parser_get_encoder_cap_info(
1466 struct dc_bios *dcb,
1467 struct graphics_object_id object_id,
1468 struct bp_encoder_cap_info *info)
1470 struct bios_parser *bp = BP_FROM_DCB(dcb);
1471 ATOM_OBJECT *object;
1472 ATOM_ENCODER_CAP_RECORD_V2 *record = NULL;
1474 if (!info)
1475 return BP_RESULT_BADINPUT;
1477 object = get_bios_object(bp, object_id);
1479 if (!object)
1480 return BP_RESULT_BADINPUT;
1482 record = get_encoder_cap_record(bp, object);
1483 if (!record)
1484 return BP_RESULT_NORECORD;
1486 info->DP_HBR2_EN = record->usHBR2En;
1487 info->DP_HBR3_EN = record->usHBR3En;
1488 info->HDMI_6GB_EN = record->usHDMI6GEn;
1489 return BP_RESULT_OK;
1493 * get_encoder_cap_record
1495 * @brief
1496 * Get encoder cap record for the object
1498 * @param object, ATOM object
1500 * @return atom encoder cap record
1502 * @note
1503 * search all records to find the ATOM_ENCODER_CAP_RECORD_V2 record
1505 static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
1506 struct bios_parser *bp,
1507 ATOM_OBJECT *object)
1509 ATOM_COMMON_RECORD_HEADER *header;
1510 uint32_t offset;
1512 if (!object) {
1513 BREAK_TO_DEBUGGER(); /* Invalid object */
1514 return NULL;
1517 offset = le16_to_cpu(object->usRecordOffset)
1518 + bp->object_info_tbl_offset;
1520 for (;;) {
1521 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1523 if (!header)
1524 return NULL;
1526 offset += header->ucRecordSize;
1528 if (LAST_RECORD_TYPE == header->ucRecordType ||
1529 !header->ucRecordSize)
1530 break;
1532 if (ATOM_ENCODER_CAP_RECORD_TYPE != header->ucRecordType)
1533 continue;
1535 if (sizeof(ATOM_ENCODER_CAP_RECORD_V2) <= header->ucRecordSize)
1536 return (ATOM_ENCODER_CAP_RECORD_V2 *)header;
1539 return NULL;
1542 static uint32_t get_ss_entry_number(
1543 struct bios_parser *bp,
1544 uint32_t id);
1545 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1546 struct bios_parser *bp,
1547 uint32_t id);
1548 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1549 struct bios_parser *bp,
1550 uint32_t id);
1551 static uint32_t get_ss_entry_number_from_ss_info_tbl(
1552 struct bios_parser *bp,
1553 uint32_t id);
1556 * BiosParserObject::GetNumberofSpreadSpectrumEntry
1557 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
1558 * the VBIOS that match the SSid (to be converted from signal)
1560 * @param[in] signal, ASSignalType to be converted to SSid
1561 * @return number of SS Entry that match the signal
1563 static uint32_t bios_parser_get_ss_entry_number(
1564 struct dc_bios *dcb,
1565 enum as_signal_type signal)
1567 struct bios_parser *bp = BP_FROM_DCB(dcb);
1568 uint32_t ss_id = 0;
1569 ATOM_COMMON_TABLE_HEADER *header;
1570 struct atom_data_revision revision;
1572 ss_id = signal_to_ss_id(signal);
1574 if (!DATA_TABLES(ASIC_InternalSS_Info))
1575 return get_ss_entry_number_from_ss_info_tbl(bp, ss_id);
1577 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1578 DATA_TABLES(ASIC_InternalSS_Info));
1579 get_atom_data_table_revision(header, &revision);
1581 switch (revision.major) {
1582 case 2:
1583 switch (revision.minor) {
1584 case 1:
1585 return get_ss_entry_number(bp, ss_id);
1586 default:
1587 break;
1589 break;
1590 case 3:
1591 switch (revision.minor) {
1592 case 1:
1593 return
1594 get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1595 bp, ss_id);
1596 default:
1597 break;
1599 break;
1600 default:
1601 break;
1604 return 0;
1608 * get_ss_entry_number_from_ss_info_tbl
1609 * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
1611 * @note There can only be one entry for each id for SS_Info Table
1613 * @param [in] id, spread spectrum id
1614 * @return number of SS Entry that match the id
1616 static uint32_t get_ss_entry_number_from_ss_info_tbl(
1617 struct bios_parser *bp,
1618 uint32_t id)
1620 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1621 ATOM_COMMON_TABLE_HEADER *header;
1622 uint32_t table_size;
1623 uint32_t i;
1624 uint32_t number = 0;
1625 uint32_t id_local = SS_ID_UNKNOWN;
1626 struct atom_data_revision revision;
1628 /* SS_Info table exist */
1629 if (!DATA_TABLES(SS_Info))
1630 return number;
1632 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1633 DATA_TABLES(SS_Info));
1634 get_atom_data_table_revision(header, &revision);
1636 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO,
1637 DATA_TABLES(SS_Info));
1639 if (1 != revision.major || 2 > revision.minor)
1640 return number;
1642 /* have to convert from Internal_SS format to SS_Info format */
1643 switch (id) {
1644 case ASIC_INTERNAL_SS_ON_DP:
1645 id_local = SS_ID_DP1;
1646 break;
1647 case ASIC_INTERNAL_SS_ON_LVDS: {
1648 struct embedded_panel_info panel_info;
1650 if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
1651 == BP_RESULT_OK)
1652 id_local = panel_info.ss_id;
1653 break;
1655 default:
1656 break;
1659 if (id_local == SS_ID_UNKNOWN)
1660 return number;
1662 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1663 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1664 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1666 for (i = 0; i < table_size; i++)
1667 if (id_local == (uint32_t)tbl->asSS_Info[i].ucSS_Id) {
1668 number = 1;
1669 break;
1672 return number;
1676 * get_ss_entry_number
1677 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
1678 * SS_Info table from the VBIOS
1679 * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
1680 * SS_Info.
1682 * @param id, spread sprectrum info index
1683 * @return Bios parser result code
1685 static uint32_t get_ss_entry_number(struct bios_parser *bp, uint32_t id)
1687 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1688 return get_ss_entry_number_from_ss_info_tbl(bp, id);
1690 return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp, id);
1694 * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
1695 * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
1696 * Ver 2.1 from the VBIOS
1697 * There will not be multiple entry for Ver 2.1
1699 * @param id, spread sprectrum info index
1700 * @return number of SS Entry that match the id
1702 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1703 struct bios_parser *bp,
1704 uint32_t id)
1706 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header_include;
1707 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1708 uint32_t size;
1709 uint32_t i;
1711 if (!DATA_TABLES(ASIC_InternalSS_Info))
1712 return 0;
1714 header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
1715 DATA_TABLES(ASIC_InternalSS_Info));
1717 size = (le16_to_cpu(header_include->sHeader.usStructureSize)
1718 - sizeof(ATOM_COMMON_TABLE_HEADER))
1719 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1721 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1722 &header_include->asSpreadSpectrum[0];
1723 for (i = 0; i < size; i++)
1724 if (tbl[i].ucClockIndication == (uint8_t)id)
1725 return 1;
1727 return 0;
1730 * get_ss_entry_number_from_internal_ss_info_table_V3_1
1731 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
1732 * the VBIOS that matches id
1734 * @param[in] id, spread sprectrum id
1735 * @return number of SS Entry that match the id
1737 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1738 struct bios_parser *bp,
1739 uint32_t id)
1741 uint32_t number = 0;
1742 ATOM_ASIC_INTERNAL_SS_INFO_V3 *header_include;
1743 ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
1744 uint32_t size;
1745 uint32_t i;
1747 if (!DATA_TABLES(ASIC_InternalSS_Info))
1748 return number;
1750 header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
1751 DATA_TABLES(ASIC_InternalSS_Info));
1752 size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
1753 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1754 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
1756 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
1757 &header_include->asSpreadSpectrum[0];
1759 for (i = 0; i < size; i++)
1760 if (tbl[i].ucClockIndication == (uint8_t)id)
1761 number++;
1763 return number;
1767 * bios_parser_get_gpio_pin_info
1768 * Get GpioPin information of input gpio id
1770 * @param gpio_id, GPIO ID
1771 * @param info, GpioPin information structure
1772 * @return Bios parser result code
1773 * @note
1774 * to get the GPIO PIN INFO, we need:
1775 * 1. get the GPIO_ID from other object table, see GetHPDInfo()
1776 * 2. in DATA_TABLE.GPIO_Pin_LUT, search all records, to get the registerA
1777 * offset/mask
1779 static enum bp_result bios_parser_get_gpio_pin_info(
1780 struct dc_bios *dcb,
1781 uint32_t gpio_id,
1782 struct gpio_pin_info *info)
1784 struct bios_parser *bp = BP_FROM_DCB(dcb);
1785 ATOM_GPIO_PIN_LUT *header;
1786 uint32_t count = 0;
1787 uint32_t i = 0;
1789 if (!DATA_TABLES(GPIO_Pin_LUT))
1790 return BP_RESULT_BADBIOSTABLE;
1792 header = GET_IMAGE(ATOM_GPIO_PIN_LUT, DATA_TABLES(GPIO_Pin_LUT));
1793 if (!header)
1794 return BP_RESULT_BADBIOSTABLE;
1796 if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_PIN_LUT)
1797 > le16_to_cpu(header->sHeader.usStructureSize))
1798 return BP_RESULT_BADBIOSTABLE;
1800 if (1 != header->sHeader.ucTableContentRevision)
1801 return BP_RESULT_UNSUPPORTED;
1803 count = (le16_to_cpu(header->sHeader.usStructureSize)
1804 - sizeof(ATOM_COMMON_TABLE_HEADER))
1805 / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
1806 for (i = 0; i < count; ++i) {
1807 if (header->asGPIO_Pin[i].ucGPIO_ID != gpio_id)
1808 continue;
1810 info->offset =
1811 (uint32_t) le16_to_cpu(header->asGPIO_Pin[i].usGpioPin_AIndex);
1812 info->offset_y = info->offset + 2;
1813 info->offset_en = info->offset + 1;
1814 info->offset_mask = info->offset - 1;
1816 info->mask = (uint32_t) (1 <<
1817 header->asGPIO_Pin[i].ucGpioPinBitShift);
1818 info->mask_y = info->mask + 2;
1819 info->mask_en = info->mask + 1;
1820 info->mask_mask = info->mask - 1;
1822 return BP_RESULT_OK;
1825 return BP_RESULT_NORECORD;
1828 static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
1829 ATOM_I2C_RECORD *record,
1830 struct graphics_object_i2c_info *info)
1832 ATOM_GPIO_I2C_INFO *header;
1833 uint32_t count = 0;
1835 if (!info)
1836 return BP_RESULT_BADINPUT;
1838 /* get the GPIO_I2C info */
1839 if (!DATA_TABLES(GPIO_I2C_Info))
1840 return BP_RESULT_BADBIOSTABLE;
1842 header = GET_IMAGE(ATOM_GPIO_I2C_INFO, DATA_TABLES(GPIO_I2C_Info));
1843 if (!header)
1844 return BP_RESULT_BADBIOSTABLE;
1846 if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_I2C_ASSIGMENT)
1847 > le16_to_cpu(header->sHeader.usStructureSize))
1848 return BP_RESULT_BADBIOSTABLE;
1850 if (1 != header->sHeader.ucTableContentRevision)
1851 return BP_RESULT_UNSUPPORTED;
1853 /* get data count */
1854 count = (le16_to_cpu(header->sHeader.usStructureSize)
1855 - sizeof(ATOM_COMMON_TABLE_HEADER))
1856 / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
1857 if (count < record->sucI2cId.bfI2C_LineMux)
1858 return BP_RESULT_BADBIOSTABLE;
1860 /* get the GPIO_I2C_INFO */
1861 info->i2c_hw_assist = record->sucI2cId.bfHW_Capable;
1862 info->i2c_line = record->sucI2cId.bfI2C_LineMux;
1863 info->i2c_engine_id = record->sucI2cId.bfHW_EngineID;
1864 info->i2c_slave_address = record->ucI2CAddr;
1866 info->gpio_info.clk_mask_register_index =
1867 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkMaskRegisterIndex);
1868 info->gpio_info.clk_en_register_index =
1869 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkEnRegisterIndex);
1870 info->gpio_info.clk_y_register_index =
1871 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkY_RegisterIndex);
1872 info->gpio_info.clk_a_register_index =
1873 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkA_RegisterIndex);
1874 info->gpio_info.data_mask_register_index =
1875 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataMaskRegisterIndex);
1876 info->gpio_info.data_en_register_index =
1877 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataEnRegisterIndex);
1878 info->gpio_info.data_y_register_index =
1879 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataY_RegisterIndex);
1880 info->gpio_info.data_a_register_index =
1881 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataA_RegisterIndex);
1883 info->gpio_info.clk_mask_shift =
1884 header->asGPIO_Info[info->i2c_line].ucClkMaskShift;
1885 info->gpio_info.clk_en_shift =
1886 header->asGPIO_Info[info->i2c_line].ucClkEnShift;
1887 info->gpio_info.clk_y_shift =
1888 header->asGPIO_Info[info->i2c_line].ucClkY_Shift;
1889 info->gpio_info.clk_a_shift =
1890 header->asGPIO_Info[info->i2c_line].ucClkA_Shift;
1891 info->gpio_info.data_mask_shift =
1892 header->asGPIO_Info[info->i2c_line].ucDataMaskShift;
1893 info->gpio_info.data_en_shift =
1894 header->asGPIO_Info[info->i2c_line].ucDataEnShift;
1895 info->gpio_info.data_y_shift =
1896 header->asGPIO_Info[info->i2c_line].ucDataY_Shift;
1897 info->gpio_info.data_a_shift =
1898 header->asGPIO_Info[info->i2c_line].ucDataA_Shift;
1900 return BP_RESULT_OK;
1903 static bool dal_graphics_object_id_is_valid(struct graphics_object_id id)
1905 bool rc = true;
1907 switch (id.type) {
1908 case OBJECT_TYPE_UNKNOWN:
1909 rc = false;
1910 break;
1911 case OBJECT_TYPE_GPU:
1912 case OBJECT_TYPE_ENGINE:
1913 /* do NOT check for id.id == 0 */
1914 if (id.enum_id == ENUM_ID_UNKNOWN)
1915 rc = false;
1916 break;
1917 default:
1918 if (id.id == 0 || id.enum_id == ENUM_ID_UNKNOWN)
1919 rc = false;
1920 break;
1923 return rc;
1926 static bool dal_graphics_object_id_is_equal(
1927 struct graphics_object_id id1,
1928 struct graphics_object_id id2)
1930 if (false == dal_graphics_object_id_is_valid(id1)) {
1931 dm_output_to_console(
1932 "%s: Warning: comparing invalid object 'id1'!\n", __func__);
1933 return false;
1936 if (false == dal_graphics_object_id_is_valid(id2)) {
1937 dm_output_to_console(
1938 "%s: Warning: comparing invalid object 'id2'!\n", __func__);
1939 return false;
1942 if (id1.id == id2.id && id1.enum_id == id2.enum_id
1943 && id1.type == id2.type)
1944 return true;
1946 return false;
1949 static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
1950 struct graphics_object_id id)
1952 uint32_t offset;
1953 ATOM_OBJECT_TABLE *tbl;
1954 uint32_t i;
1956 switch (id.type) {
1957 case OBJECT_TYPE_ENCODER:
1958 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
1959 break;
1961 case OBJECT_TYPE_CONNECTOR:
1962 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
1963 break;
1965 case OBJECT_TYPE_ROUTER:
1966 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usRouterObjectTableOffset);
1967 break;
1969 case OBJECT_TYPE_GENERIC:
1970 if (bp->object_info_tbl.revision.minor < 3)
1971 return NULL;
1972 offset = le16_to_cpu(bp->object_info_tbl.v1_3->usMiscObjectTableOffset);
1973 break;
1975 default:
1976 return NULL;
1979 offset += bp->object_info_tbl_offset;
1981 tbl = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
1982 if (!tbl)
1983 return NULL;
1985 for (i = 0; i < tbl->ucNumberOfObjects; i++)
1986 if (dal_graphics_object_id_is_equal(id,
1987 object_id_from_bios_object_id(
1988 le16_to_cpu(tbl->asObjects[i].usObjectID))))
1989 return &tbl->asObjects[i];
1991 return NULL;
1994 static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
1995 uint16_t **id_list)
1997 uint32_t offset;
1998 uint8_t *number;
2000 if (!object) {
2001 BREAK_TO_DEBUGGER(); /* Invalid object id */
2002 return 0;
2005 offset = le16_to_cpu(object->usSrcDstTableOffset)
2006 + bp->object_info_tbl_offset;
2008 number = GET_IMAGE(uint8_t, offset);
2009 if (!number)
2010 return 0;
2012 offset += sizeof(uint8_t);
2013 *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
2015 if (!*id_list)
2016 return 0;
2018 return *number;
2021 static struct device_id device_type_from_device_id(uint16_t device_id)
2024 struct device_id result_device_id = {0};
2026 switch (device_id) {
2027 case ATOM_DEVICE_LCD1_SUPPORT:
2028 result_device_id.device_type = DEVICE_TYPE_LCD;
2029 result_device_id.enum_id = 1;
2030 break;
2032 case ATOM_DEVICE_LCD2_SUPPORT:
2033 result_device_id.device_type = DEVICE_TYPE_LCD;
2034 result_device_id.enum_id = 2;
2035 break;
2037 case ATOM_DEVICE_CRT1_SUPPORT:
2038 result_device_id.device_type = DEVICE_TYPE_CRT;
2039 result_device_id.enum_id = 1;
2040 break;
2042 case ATOM_DEVICE_CRT2_SUPPORT:
2043 result_device_id.device_type = DEVICE_TYPE_CRT;
2044 result_device_id.enum_id = 2;
2045 break;
2047 case ATOM_DEVICE_DFP1_SUPPORT:
2048 result_device_id.device_type = DEVICE_TYPE_DFP;
2049 result_device_id.enum_id = 1;
2050 break;
2052 case ATOM_DEVICE_DFP2_SUPPORT:
2053 result_device_id.device_type = DEVICE_TYPE_DFP;
2054 result_device_id.enum_id = 2;
2055 break;
2057 case ATOM_DEVICE_DFP3_SUPPORT:
2058 result_device_id.device_type = DEVICE_TYPE_DFP;
2059 result_device_id.enum_id = 3;
2060 break;
2062 case ATOM_DEVICE_DFP4_SUPPORT:
2063 result_device_id.device_type = DEVICE_TYPE_DFP;
2064 result_device_id.enum_id = 4;
2065 break;
2067 case ATOM_DEVICE_DFP5_SUPPORT:
2068 result_device_id.device_type = DEVICE_TYPE_DFP;
2069 result_device_id.enum_id = 5;
2070 break;
2072 case ATOM_DEVICE_DFP6_SUPPORT:
2073 result_device_id.device_type = DEVICE_TYPE_DFP;
2074 result_device_id.enum_id = 6;
2075 break;
2077 default:
2078 BREAK_TO_DEBUGGER(); /* Invalid device Id */
2079 result_device_id.device_type = DEVICE_TYPE_UNKNOWN;
2080 result_device_id.enum_id = 0;
2082 return result_device_id;
2085 static void get_atom_data_table_revision(
2086 ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
2087 struct atom_data_revision *tbl_revision)
2089 if (!tbl_revision)
2090 return;
2092 /* initialize the revision to 0 which is invalid revision */
2093 tbl_revision->major = 0;
2094 tbl_revision->minor = 0;
2096 if (!atom_data_tbl)
2097 return;
2099 tbl_revision->major =
2100 (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl);
2101 tbl_revision->minor =
2102 (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl);
2105 static uint32_t signal_to_ss_id(enum as_signal_type signal)
2107 uint32_t clk_id_ss = 0;
2109 switch (signal) {
2110 case AS_SIGNAL_TYPE_DVI:
2111 clk_id_ss = ASIC_INTERNAL_SS_ON_TMDS;
2112 break;
2113 case AS_SIGNAL_TYPE_HDMI:
2114 clk_id_ss = ASIC_INTERNAL_SS_ON_HDMI;
2115 break;
2116 case AS_SIGNAL_TYPE_LVDS:
2117 clk_id_ss = ASIC_INTERNAL_SS_ON_LVDS;
2118 break;
2119 case AS_SIGNAL_TYPE_DISPLAY_PORT:
2120 clk_id_ss = ASIC_INTERNAL_SS_ON_DP;
2121 break;
2122 case AS_SIGNAL_TYPE_GPU_PLL:
2123 clk_id_ss = ASIC_INTERNAL_GPUPLL_SS;
2124 break;
2125 default:
2126 break;
2128 return clk_id_ss;
2131 static uint32_t get_support_mask_for_device_id(struct device_id device_id)
2133 enum dal_device_type device_type = device_id.device_type;
2134 uint32_t enum_id = device_id.enum_id;
2136 switch (device_type) {
2137 case DEVICE_TYPE_LCD:
2138 switch (enum_id) {
2139 case 1:
2140 return ATOM_DEVICE_LCD1_SUPPORT;
2141 case 2:
2142 return ATOM_DEVICE_LCD2_SUPPORT;
2143 default:
2144 break;
2146 break;
2147 case DEVICE_TYPE_CRT:
2148 switch (enum_id) {
2149 case 1:
2150 return ATOM_DEVICE_CRT1_SUPPORT;
2151 case 2:
2152 return ATOM_DEVICE_CRT2_SUPPORT;
2153 default:
2154 break;
2156 break;
2157 case DEVICE_TYPE_DFP:
2158 switch (enum_id) {
2159 case 1:
2160 return ATOM_DEVICE_DFP1_SUPPORT;
2161 case 2:
2162 return ATOM_DEVICE_DFP2_SUPPORT;
2163 case 3:
2164 return ATOM_DEVICE_DFP3_SUPPORT;
2165 case 4:
2166 return ATOM_DEVICE_DFP4_SUPPORT;
2167 case 5:
2168 return ATOM_DEVICE_DFP5_SUPPORT;
2169 case 6:
2170 return ATOM_DEVICE_DFP6_SUPPORT;
2171 default:
2172 break;
2174 break;
2175 case DEVICE_TYPE_CV:
2176 switch (enum_id) {
2177 case 1:
2178 return ATOM_DEVICE_CV_SUPPORT;
2179 default:
2180 break;
2182 break;
2183 case DEVICE_TYPE_TV:
2184 switch (enum_id) {
2185 case 1:
2186 return ATOM_DEVICE_TV1_SUPPORT;
2187 default:
2188 break;
2190 break;
2191 default:
2192 break;
2195 /* Unidentified device ID, return empty support mask. */
2196 return 0;
2200 * bios_parser_set_scratch_critical_state
2202 * @brief
2203 * update critical state bit in VBIOS scratch register
2205 * @param
2206 * bool - to set or reset state
2208 static void bios_parser_set_scratch_critical_state(
2209 struct dc_bios *dcb,
2210 bool state)
2212 bios_set_scratch_critical_state(dcb, state);
2216 * get_integrated_info_v8
2218 * @brief
2219 * Get V8 integrated BIOS information
2221 * @param
2222 * bios_parser *bp - [in]BIOS parser handler to get master data table
2223 * integrated_info *info - [out] store and output integrated info
2225 * @return
2226 * enum bp_result - BP_RESULT_OK if information is available,
2227 * BP_RESULT_BADBIOSTABLE otherwise.
2229 static enum bp_result get_integrated_info_v8(
2230 struct bios_parser *bp,
2231 struct integrated_info *info)
2233 ATOM_INTEGRATED_SYSTEM_INFO_V1_8 *info_v8;
2234 uint32_t i;
2236 info_v8 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8,
2237 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2239 if (info_v8 == NULL)
2240 return BP_RESULT_BADBIOSTABLE;
2241 info->boot_up_engine_clock = le32_to_cpu(info_v8->ulBootUpEngineClock) * 10;
2242 info->dentist_vco_freq = le32_to_cpu(info_v8->ulDentistVCOFreq) * 10;
2243 info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
2245 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2246 /* Convert [10KHz] into [KHz] */
2247 info->disp_clk_voltage[i].max_supported_clk =
2248 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].
2249 ulMaximumSupportedCLK) * 10;
2250 info->disp_clk_voltage[i].voltage_index =
2251 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
2254 info->boot_up_req_display_vector =
2255 le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
2256 info->gpu_cap_info =
2257 le32_to_cpu(info_v8->ulGPUCapInfo);
2260 * system_config: Bit[0] = 0 : PCIE power gating disabled
2261 * = 1 : PCIE power gating enabled
2262 * Bit[1] = 0 : DDR-PLL shut down disabled
2263 * = 1 : DDR-PLL shut down enabled
2264 * Bit[2] = 0 : DDR-PLL power down disabled
2265 * = 1 : DDR-PLL power down enabled
2267 info->system_config = le32_to_cpu(info_v8->ulSystemConfig);
2268 info->cpu_cap_info = le32_to_cpu(info_v8->ulCPUCapInfo);
2269 info->boot_up_nb_voltage =
2270 le16_to_cpu(info_v8->usBootUpNBVoltage);
2271 info->ext_disp_conn_info_offset =
2272 le16_to_cpu(info_v8->usExtDispConnInfoOffset);
2273 info->memory_type = info_v8->ucMemoryType;
2274 info->ma_channel_number = info_v8->ucUMAChannelNumber;
2275 info->gmc_restore_reset_time =
2276 le32_to_cpu(info_v8->ulGMCRestoreResetTime);
2278 info->minimum_n_clk =
2279 le32_to_cpu(info_v8->ulNbpStateNClkFreq[0]);
2280 for (i = 1; i < 4; ++i)
2281 info->minimum_n_clk =
2282 info->minimum_n_clk < le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]) ?
2283 info->minimum_n_clk : le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]);
2285 info->idle_n_clk = le32_to_cpu(info_v8->ulIdleNClk);
2286 info->ddr_dll_power_up_time =
2287 le32_to_cpu(info_v8->ulDDR_DLL_PowerUpTime);
2288 info->ddr_pll_power_up_time =
2289 le32_to_cpu(info_v8->ulDDR_PLL_PowerUpTime);
2290 info->pcie_clk_ss_type = le16_to_cpu(info_v8->usPCIEClkSSType);
2291 info->lvds_ss_percentage =
2292 le16_to_cpu(info_v8->usLvdsSSPercentage);
2293 info->lvds_sspread_rate_in_10hz =
2294 le16_to_cpu(info_v8->usLvdsSSpreadRateIn10Hz);
2295 info->hdmi_ss_percentage =
2296 le16_to_cpu(info_v8->usHDMISSPercentage);
2297 info->hdmi_sspread_rate_in_10hz =
2298 le16_to_cpu(info_v8->usHDMISSpreadRateIn10Hz);
2299 info->dvi_ss_percentage =
2300 le16_to_cpu(info_v8->usDVISSPercentage);
2301 info->dvi_sspread_rate_in_10_hz =
2302 le16_to_cpu(info_v8->usDVISSpreadRateIn10Hz);
2304 info->max_lvds_pclk_freq_in_single_link =
2305 le16_to_cpu(info_v8->usMaxLVDSPclkFreqInSingleLink);
2306 info->lvds_misc = info_v8->ucLvdsMisc;
2307 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
2308 info_v8->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
2309 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
2310 info_v8->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
2311 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
2312 info_v8->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
2313 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
2314 info_v8->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
2315 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
2316 info_v8->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
2317 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
2318 info_v8->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
2319 info->lvds_off_to_on_delay_in_4ms =
2320 info_v8->ucLVDSOffToOnDelay_in4Ms;
2321 info->lvds_bit_depth_control_val =
2322 le32_to_cpu(info_v8->ulLCDBitDepthControlVal);
2324 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
2325 /* Convert [10KHz] into [KHz] */
2326 info->avail_s_clk[i].supported_s_clk =
2327 le32_to_cpu(info_v8->sAvail_SCLK[i].ulSupportedSCLK) * 10;
2328 info->avail_s_clk[i].voltage_index =
2329 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageIndex);
2330 info->avail_s_clk[i].voltage_id =
2331 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageID);
2334 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
2335 info->ext_disp_conn_info.gu_id[i] =
2336 info_v8->sExtDispConnInfo.ucGuid[i];
2339 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
2340 info->ext_disp_conn_info.path[i].device_connector_id =
2341 object_id_from_bios_object_id(
2342 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceConnector));
2344 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
2345 object_id_from_bios_object_id(
2346 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
2348 info->ext_disp_conn_info.path[i].device_tag =
2349 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceTag);
2350 info->ext_disp_conn_info.path[i].device_acpi_enum =
2351 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
2352 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
2353 info_v8->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
2354 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
2355 info_v8->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
2356 info->ext_disp_conn_info.path[i].channel_mapping.raw =
2357 info_v8->sExtDispConnInfo.sPath[i].ucChannelMapping;
2359 info->ext_disp_conn_info.checksum =
2360 info_v8->sExtDispConnInfo.ucChecksum;
2362 return BP_RESULT_OK;
2366 * get_integrated_info_v8
2368 * @brief
2369 * Get V8 integrated BIOS information
2371 * @param
2372 * bios_parser *bp - [in]BIOS parser handler to get master data table
2373 * integrated_info *info - [out] store and output integrated info
2375 * @return
2376 * enum bp_result - BP_RESULT_OK if information is available,
2377 * BP_RESULT_BADBIOSTABLE otherwise.
2379 static enum bp_result get_integrated_info_v9(
2380 struct bios_parser *bp,
2381 struct integrated_info *info)
2383 ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info_v9;
2384 uint32_t i;
2386 info_v9 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9,
2387 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2389 if (!info_v9)
2390 return BP_RESULT_BADBIOSTABLE;
2392 info->boot_up_engine_clock = le32_to_cpu(info_v9->ulBootUpEngineClock) * 10;
2393 info->dentist_vco_freq = le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
2394 info->boot_up_uma_clock = le32_to_cpu(info_v9->ulBootUpUMAClock) * 10;
2396 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2397 /* Convert [10KHz] into [KHz] */
2398 info->disp_clk_voltage[i].max_supported_clk =
2399 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
2400 info->disp_clk_voltage[i].voltage_index =
2401 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
2404 info->boot_up_req_display_vector =
2405 le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
2406 info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
2409 * system_config: Bit[0] = 0 : PCIE power gating disabled
2410 * = 1 : PCIE power gating enabled
2411 * Bit[1] = 0 : DDR-PLL shut down disabled
2412 * = 1 : DDR-PLL shut down enabled
2413 * Bit[2] = 0 : DDR-PLL power down disabled
2414 * = 1 : DDR-PLL power down enabled
2416 info->system_config = le32_to_cpu(info_v9->ulSystemConfig);
2417 info->cpu_cap_info = le32_to_cpu(info_v9->ulCPUCapInfo);
2418 info->boot_up_nb_voltage = le16_to_cpu(info_v9->usBootUpNBVoltage);
2419 info->ext_disp_conn_info_offset = le16_to_cpu(info_v9->usExtDispConnInfoOffset);
2420 info->memory_type = info_v9->ucMemoryType;
2421 info->ma_channel_number = info_v9->ucUMAChannelNumber;
2422 info->gmc_restore_reset_time = le32_to_cpu(info_v9->ulGMCRestoreResetTime);
2424 info->minimum_n_clk = le32_to_cpu(info_v9->ulNbpStateNClkFreq[0]);
2425 for (i = 1; i < 4; ++i)
2426 info->minimum_n_clk =
2427 info->minimum_n_clk < le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]) ?
2428 info->minimum_n_clk : le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]);
2430 info->idle_n_clk = le32_to_cpu(info_v9->ulIdleNClk);
2431 info->ddr_dll_power_up_time = le32_to_cpu(info_v9->ulDDR_DLL_PowerUpTime);
2432 info->ddr_pll_power_up_time = le32_to_cpu(info_v9->ulDDR_PLL_PowerUpTime);
2433 info->pcie_clk_ss_type = le16_to_cpu(info_v9->usPCIEClkSSType);
2434 info->lvds_ss_percentage = le16_to_cpu(info_v9->usLvdsSSPercentage);
2435 info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v9->usLvdsSSpreadRateIn10Hz);
2436 info->hdmi_ss_percentage = le16_to_cpu(info_v9->usHDMISSPercentage);
2437 info->hdmi_sspread_rate_in_10hz = le16_to_cpu(info_v9->usHDMISSpreadRateIn10Hz);
2438 info->dvi_ss_percentage = le16_to_cpu(info_v9->usDVISSPercentage);
2439 info->dvi_sspread_rate_in_10_hz = le16_to_cpu(info_v9->usDVISSpreadRateIn10Hz);
2441 info->max_lvds_pclk_freq_in_single_link =
2442 le16_to_cpu(info_v9->usMaxLVDSPclkFreqInSingleLink);
2443 info->lvds_misc = info_v9->ucLvdsMisc;
2444 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
2445 info_v9->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
2446 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
2447 info_v9->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
2448 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
2449 info_v9->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
2450 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
2451 info_v9->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
2452 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
2453 info_v9->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
2454 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
2455 info_v9->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
2456 info->lvds_off_to_on_delay_in_4ms =
2457 info_v9->ucLVDSOffToOnDelay_in4Ms;
2458 info->lvds_bit_depth_control_val =
2459 le32_to_cpu(info_v9->ulLCDBitDepthControlVal);
2461 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
2462 /* Convert [10KHz] into [KHz] */
2463 info->avail_s_clk[i].supported_s_clk =
2464 le32_to_cpu(info_v9->sAvail_SCLK[i].ulSupportedSCLK) * 10;
2465 info->avail_s_clk[i].voltage_index =
2466 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageIndex);
2467 info->avail_s_clk[i].voltage_id =
2468 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageID);
2471 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
2472 info->ext_disp_conn_info.gu_id[i] =
2473 info_v9->sExtDispConnInfo.ucGuid[i];
2476 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
2477 info->ext_disp_conn_info.path[i].device_connector_id =
2478 object_id_from_bios_object_id(
2479 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceConnector));
2481 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
2482 object_id_from_bios_object_id(
2483 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
2485 info->ext_disp_conn_info.path[i].device_tag =
2486 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceTag);
2487 info->ext_disp_conn_info.path[i].device_acpi_enum =
2488 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
2489 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
2490 info_v9->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
2491 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
2492 info_v9->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
2493 info->ext_disp_conn_info.path[i].channel_mapping.raw =
2494 info_v9->sExtDispConnInfo.sPath[i].ucChannelMapping;
2496 info->ext_disp_conn_info.checksum =
2497 info_v9->sExtDispConnInfo.ucChecksum;
2499 return BP_RESULT_OK;
2503 * construct_integrated_info
2505 * @brief
2506 * Get integrated BIOS information based on table revision
2508 * @param
2509 * bios_parser *bp - [in]BIOS parser handler to get master data table
2510 * integrated_info *info - [out] store and output integrated info
2512 * @return
2513 * enum bp_result - BP_RESULT_OK if information is available,
2514 * BP_RESULT_BADBIOSTABLE otherwise.
2516 static enum bp_result construct_integrated_info(
2517 struct bios_parser *bp,
2518 struct integrated_info *info)
2520 enum bp_result result = BP_RESULT_BADBIOSTABLE;
2522 ATOM_COMMON_TABLE_HEADER *header;
2523 struct atom_data_revision revision;
2525 if (bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo) {
2526 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
2527 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2529 get_atom_data_table_revision(header, &revision);
2531 /* Don't need to check major revision as they are all 1 */
2532 switch (revision.minor) {
2533 case 8:
2534 result = get_integrated_info_v8(bp, info);
2535 break;
2536 case 9:
2537 result = get_integrated_info_v9(bp, info);
2538 break;
2539 default:
2540 return result;
2545 /* Sort voltage table from low to high*/
2546 if (result == BP_RESULT_OK) {
2547 uint32_t i;
2548 uint32_t j;
2550 for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2551 for (j = i; j > 0; --j) {
2552 if (
2553 info->disp_clk_voltage[j].max_supported_clk <
2554 info->disp_clk_voltage[j-1].max_supported_clk) {
2555 /* swap j and j - 1*/
2556 swap(info->disp_clk_voltage[j - 1],
2557 info->disp_clk_voltage[j]);
2564 return result;
2567 static struct integrated_info *bios_parser_create_integrated_info(
2568 struct dc_bios *dcb)
2570 struct bios_parser *bp = BP_FROM_DCB(dcb);
2571 struct integrated_info *info = NULL;
2573 info = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);
2575 if (info == NULL) {
2576 ASSERT_CRITICAL(0);
2577 return NULL;
2580 if (construct_integrated_info(bp, info) == BP_RESULT_OK)
2581 return info;
2583 kfree(info);
2585 return NULL;
2588 enum bp_result update_slot_layout_info(
2589 struct dc_bios *dcb,
2590 unsigned int i,
2591 struct slot_layout_info *slot_layout_info,
2592 unsigned int record_offset)
2594 unsigned int j;
2595 struct bios_parser *bp;
2596 ATOM_BRACKET_LAYOUT_RECORD *record;
2597 ATOM_COMMON_RECORD_HEADER *record_header;
2598 enum bp_result result = BP_RESULT_NORECORD;
2600 bp = BP_FROM_DCB(dcb);
2601 record = NULL;
2602 record_header = NULL;
2604 for (;;) {
2606 record_header = (ATOM_COMMON_RECORD_HEADER *)
2607 GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
2608 if (record_header == NULL) {
2609 result = BP_RESULT_BADBIOSTABLE;
2610 break;
2613 /* the end of the list */
2614 if (record_header->ucRecordType == 0xff ||
2615 record_header->ucRecordSize == 0) {
2616 break;
2619 if (record_header->ucRecordType ==
2620 ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
2621 sizeof(ATOM_BRACKET_LAYOUT_RECORD)
2622 <= record_header->ucRecordSize) {
2623 record = (ATOM_BRACKET_LAYOUT_RECORD *)
2624 (record_header);
2625 result = BP_RESULT_OK;
2626 break;
2629 record_offset += record_header->ucRecordSize;
2632 /* return if the record not found */
2633 if (result != BP_RESULT_OK)
2634 return result;
2636 /* get slot sizes */
2637 slot_layout_info->length = record->ucLength;
2638 slot_layout_info->width = record->ucWidth;
2640 /* get info for each connector in the slot */
2641 slot_layout_info->num_of_connectors = record->ucConnNum;
2642 for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
2643 slot_layout_info->connectors[j].connector_type =
2644 (enum connector_layout_type)
2645 (record->asConnInfo[j].ucConnectorType);
2646 switch (record->asConnInfo[j].ucConnectorType) {
2647 case CONNECTOR_TYPE_DVI_D:
2648 slot_layout_info->connectors[j].connector_type =
2649 CONNECTOR_LAYOUT_TYPE_DVI_D;
2650 slot_layout_info->connectors[j].length =
2651 CONNECTOR_SIZE_DVI;
2652 break;
2654 case CONNECTOR_TYPE_HDMI:
2655 slot_layout_info->connectors[j].connector_type =
2656 CONNECTOR_LAYOUT_TYPE_HDMI;
2657 slot_layout_info->connectors[j].length =
2658 CONNECTOR_SIZE_HDMI;
2659 break;
2661 case CONNECTOR_TYPE_DISPLAY_PORT:
2662 slot_layout_info->connectors[j].connector_type =
2663 CONNECTOR_LAYOUT_TYPE_DP;
2664 slot_layout_info->connectors[j].length =
2665 CONNECTOR_SIZE_DP;
2666 break;
2668 case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
2669 slot_layout_info->connectors[j].connector_type =
2670 CONNECTOR_LAYOUT_TYPE_MINI_DP;
2671 slot_layout_info->connectors[j].length =
2672 CONNECTOR_SIZE_MINI_DP;
2673 break;
2675 default:
2676 slot_layout_info->connectors[j].connector_type =
2677 CONNECTOR_LAYOUT_TYPE_UNKNOWN;
2678 slot_layout_info->connectors[j].length =
2679 CONNECTOR_SIZE_UNKNOWN;
2682 slot_layout_info->connectors[j].position =
2683 record->asConnInfo[j].ucPosition;
2684 slot_layout_info->connectors[j].connector_id =
2685 object_id_from_bios_object_id(
2686 record->asConnInfo[j].usConnectorObjectId);
2688 return result;
2692 enum bp_result get_bracket_layout_record(
2693 struct dc_bios *dcb,
2694 unsigned int bracket_layout_id,
2695 struct slot_layout_info *slot_layout_info)
2697 unsigned int i;
2698 unsigned int record_offset;
2699 struct bios_parser *bp;
2700 enum bp_result result;
2701 ATOM_OBJECT *object;
2702 ATOM_OBJECT_TABLE *object_table;
2703 unsigned int genericTableOffset;
2705 bp = BP_FROM_DCB(dcb);
2706 object = NULL;
2707 if (slot_layout_info == NULL) {
2708 DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
2709 return BP_RESULT_BADINPUT;
2713 genericTableOffset = bp->object_info_tbl_offset +
2714 bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
2715 object_table = (ATOM_OBJECT_TABLE *)
2716 GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset);
2717 if (!object_table)
2718 return BP_RESULT_FAILURE;
2720 result = BP_RESULT_NORECORD;
2721 for (i = 0; i < object_table->ucNumberOfObjects; ++i) {
2723 if (bracket_layout_id ==
2724 object_table->asObjects[i].usObjectID) {
2726 object = &object_table->asObjects[i];
2727 record_offset = object->usRecordOffset +
2728 bp->object_info_tbl_offset;
2730 result = update_slot_layout_info(dcb, i,
2731 slot_layout_info, record_offset);
2732 break;
2735 return result;
2738 static enum bp_result bios_get_board_layout_info(
2739 struct dc_bios *dcb,
2740 struct board_layout_info *board_layout_info)
2742 unsigned int i;
2743 enum bp_result record_result;
2745 const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
2746 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
2747 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
2748 0, 0
2751 if (board_layout_info == NULL) {
2752 DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
2753 return BP_RESULT_BADINPUT;
2756 board_layout_info->num_of_slots = 0;
2758 for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
2759 record_result = get_bracket_layout_record(dcb,
2760 slot_index_to_vbios_id[i],
2761 &board_layout_info->slots[i]);
2763 if (record_result == BP_RESULT_NORECORD && i > 0)
2764 break; /* no more slots present in bios */
2765 else if (record_result != BP_RESULT_OK)
2766 return record_result; /* fail */
2768 ++board_layout_info->num_of_slots;
2771 /* all data is valid */
2772 board_layout_info->is_number_of_slots_valid = 1;
2773 board_layout_info->is_slots_size_valid = 1;
2774 board_layout_info->is_connector_offsets_valid = 1;
2775 board_layout_info->is_connector_lengths_valid = 1;
2777 return BP_RESULT_OK;
2780 /******************************************************************************/
2782 static const struct dc_vbios_funcs vbios_funcs = {
2783 .get_connectors_number = bios_parser_get_connectors_number,
2785 .get_connector_id = bios_parser_get_connector_id,
2787 .get_src_obj = bios_parser_get_src_obj,
2789 .get_i2c_info = bios_parser_get_i2c_info,
2791 .get_hpd_info = bios_parser_get_hpd_info,
2793 .get_device_tag = bios_parser_get_device_tag,
2795 .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info,
2797 .get_ss_entry_number = bios_parser_get_ss_entry_number,
2799 .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
2801 .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
2803 .get_encoder_cap_info = bios_parser_get_encoder_cap_info,
2805 /* bios scratch register communication */
2806 .is_accelerated_mode = bios_is_accelerated_mode,
2808 .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
2810 .is_device_id_supported = bios_parser_is_device_id_supported,
2812 /* COMMANDS */
2813 .encoder_control = bios_parser_encoder_control,
2815 .transmitter_control = bios_parser_transmitter_control,
2817 .enable_crtc = bios_parser_enable_crtc,
2819 .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
2821 .set_pixel_clock = bios_parser_set_pixel_clock,
2823 .set_dce_clock = bios_parser_set_dce_clock,
2825 .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
2827 .program_crtc_timing = bios_parser_program_crtc_timing, /* still use. should probably retire and program directly */
2829 .program_display_engine_pll = bios_parser_program_display_engine_pll,
2831 .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
2833 /* SW init and patch */
2835 .bios_parser_destroy = bios_parser_destroy,
2837 .get_board_layout_info = bios_get_board_layout_info,
2839 .get_atom_dc_golden_table = NULL
2842 static bool bios_parser_construct(
2843 struct bios_parser *bp,
2844 struct bp_init_data *init,
2845 enum dce_version dce_version)
2847 uint16_t *rom_header_offset = NULL;
2848 ATOM_ROM_HEADER *rom_header = NULL;
2849 ATOM_OBJECT_HEADER *object_info_tbl;
2850 struct atom_data_revision tbl_rev = {0};
2852 if (!init)
2853 return false;
2855 if (!init->bios)
2856 return false;
2858 bp->base.funcs = &vbios_funcs;
2859 bp->base.bios = init->bios;
2860 bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
2862 bp->base.ctx = init->ctx;
2863 bp->base.bios_local_image = NULL;
2865 rom_header_offset =
2866 GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
2868 if (!rom_header_offset)
2869 return false;
2871 rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
2873 if (!rom_header)
2874 return false;
2876 get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev);
2877 if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
2878 return false;
2880 bp->master_data_tbl =
2881 GET_IMAGE(ATOM_MASTER_DATA_TABLE,
2882 rom_header->usMasterDataTableOffset);
2884 if (!bp->master_data_tbl)
2885 return false;
2887 bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
2889 if (!bp->object_info_tbl_offset)
2890 return false;
2892 object_info_tbl =
2893 GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
2895 if (!object_info_tbl)
2896 return false;
2898 get_atom_data_table_revision(&object_info_tbl->sHeader,
2899 &bp->object_info_tbl.revision);
2901 if (bp->object_info_tbl.revision.major == 1
2902 && bp->object_info_tbl.revision.minor >= 3) {
2903 ATOM_OBJECT_HEADER_V3 *tbl_v3;
2905 tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
2906 bp->object_info_tbl_offset);
2907 if (!tbl_v3)
2908 return false;
2910 bp->object_info_tbl.v1_3 = tbl_v3;
2911 } else if (bp->object_info_tbl.revision.major == 1
2912 && bp->object_info_tbl.revision.minor >= 1)
2913 bp->object_info_tbl.v1_1 = object_info_tbl;
2914 else
2915 return false;
2917 dal_bios_parser_init_cmd_tbl(bp);
2918 dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
2920 bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base);
2921 bp->base.fw_info_valid = bios_parser_get_firmware_info(&bp->base, &bp->base.fw_info) == BP_RESULT_OK;
2923 return true;
2926 /******************************************************************************/