1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "dm_services.h"
27
28#include "atom.h"
29
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"
36
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"
43
44#include "bios_parser_common.h"
45
46#include "dc.h"
47
48#define THREE_PERCENT_OF_10000 300
49
50#define LAST_RECORD_TYPE 0xff
51
52#define DC_LOGGER \
53 bp->base.ctx->logger
54
55
56static const uint8_t ext_display_connection_guid[NUMBER_OF_UCHAR_FOR_GUID] = {
57 0x91, 0x6E, 0x57, 0x09,
58 0x3F, 0x6D, 0xD2, 0x11,
59 0x39, 0x8E, 0x00, 0xA0,
60 0xC9, 0x69, 0x72, 0x3B};
61
62#define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
63
64static void get_atom_data_table_revision(
65 ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
66 struct atom_data_revision *tbl_revision);
67static uint32_t get_dst_number_from_object(struct bios_parser *bp,
68 ATOM_OBJECT *object);
69static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
70 uint16_t **id_list);
71static uint32_t get_dest_obj_list(struct bios_parser *bp,
72 ATOM_OBJECT *object, uint16_t **id_list);
73static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
74 struct graphics_object_id id);
75static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
76 ATOM_I2C_RECORD *record,
77 struct graphics_object_i2c_info *info);
78static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
79 ATOM_OBJECT *object);
80static struct device_id device_type_from_device_id(uint16_t device_id);
81static uint32_t signal_to_ss_id(enum as_signal_type signal);
82static uint32_t get_support_mask_for_device_id(struct device_id device_id);
83static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
84 struct bios_parser *bp,
85 ATOM_OBJECT *object);
86
87#define BIOS_IMAGE_SIZE_OFFSET 2
88#define BIOS_IMAGE_SIZE_UNIT 512
89
90
91static bool bios_parser_construct(
92 struct bios_parser *bp,
93 struct bp_init_data *init,
94 enum dce_version dce_version);
95
96static uint8_t bios_parser_get_connectors_number(
97 struct dc_bios *dcb);
98
99static enum bp_result bios_parser_get_embedded_panel_info(
100 struct dc_bios *dcb,
101 struct embedded_panel_info *info);
102
103
104
105struct dc_bios *bios_parser_create(
106 struct bp_init_data *init,
107 enum dce_version dce_version)
108{
109 struct bios_parser *bp = NULL;
110
111 bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
112 if (!bp)
113 return NULL;
114
115 if (bios_parser_construct(bp, init, dce_version))
116 return &bp->base;
117
118 kfree(bp);
119 BREAK_TO_DEBUGGER();
120 return NULL;
121}
122
123static void destruct(struct bios_parser *bp)
124{
125 kfree(bp->base.bios_local_image);
126 kfree(bp->base.integrated_info);
127}
128
129static void bios_parser_destroy(struct dc_bios **dcb)
130{
131 struct bios_parser *bp = BP_FROM_DCB(*dcb);
132
133 if (!bp) {
134 BREAK_TO_DEBUGGER();
135 return;
136 }
137
138 destruct(bp);
139
140 kfree(bp);
141 *dcb = NULL;
142}
143
144static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
145{
146 ATOM_OBJECT_TABLE *table;
147
148 uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
149
150 table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
151
152 if (!table)
153 return 0;
154 else
155 return table->ucNumberOfObjects;
156}
157
158static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb)
159{
160 struct bios_parser *bp = BP_FROM_DCB(dcb);
161
162 return get_number_of_objects(bp,
163 le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
164}
165
166static struct graphics_object_id bios_parser_get_encoder_id(
167 struct dc_bios *dcb,
168 uint32_t i)
169{
170 struct bios_parser *bp = BP_FROM_DCB(dcb);
171 struct graphics_object_id object_id = dal_graphics_object_id_init(
172 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
173
174 uint32_t encoder_table_offset = bp->object_info_tbl_offset
175 + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
176
177 ATOM_OBJECT_TABLE *tbl =
178 GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
179
180 if (tbl && tbl->ucNumberOfObjects > i) {
181 const uint16_t id = le16_to_cpu(tbl->asObjects[i].usObjectID);
182
183 object_id = object_id_from_bios_object_id(id);
184 }
185
186 return object_id;
187}
188
189static struct graphics_object_id bios_parser_get_connector_id(
190 struct dc_bios *dcb,
191 uint8_t i)
192{
193 struct bios_parser *bp = BP_FROM_DCB(dcb);
194 struct graphics_object_id object_id = dal_graphics_object_id_init(
195 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
196 uint16_t id;
197
198 uint32_t connector_table_offset = bp->object_info_tbl_offset
199 + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
200
201 ATOM_OBJECT_TABLE *tbl =
202 GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
203
204 if (!tbl) {
205 dm_error("Can't get connector table from atom bios.\n");
206 return object_id;
207 }
208
209 if (tbl->ucNumberOfObjects <= i) {
210 dm_error("Can't find connector id %d in connector table of size %d.\n",
211 i, tbl->ucNumberOfObjects);
212 return object_id;
213 }
214
215 id = le16_to_cpu(tbl->asObjects[i].usObjectID);
216 object_id = object_id_from_bios_object_id(id);
217 return object_id;
218}
219
220static uint32_t bios_parser_get_dst_number(struct dc_bios *dcb,
221 struct graphics_object_id id)
222{
223 struct bios_parser *bp = BP_FROM_DCB(dcb);
224 ATOM_OBJECT *object = get_bios_object(bp, id);
225
226 return get_dst_number_from_object(bp, object);
227}
228
229static enum bp_result bios_parser_get_src_obj(struct dc_bios *dcb,
230 struct graphics_object_id object_id, uint32_t index,
231 struct graphics_object_id *src_object_id)
232{
233 uint32_t number;
234 uint16_t *id;
235 ATOM_OBJECT *object;
236 struct bios_parser *bp = BP_FROM_DCB(dcb);
237
238 if (!src_object_id)
239 return BP_RESULT_BADINPUT;
240
241 object = get_bios_object(bp, object_id);
242
243 if (!object) {
244 BREAK_TO_DEBUGGER();
245 return BP_RESULT_BADINPUT;
246 }
247
248 number = get_src_obj_list(bp, object, &id);
249
250 if (number <= index)
251 return BP_RESULT_BADINPUT;
252
253 *src_object_id = object_id_from_bios_object_id(id[index]);
254
255 return BP_RESULT_OK;
256}
257
258static enum bp_result bios_parser_get_dst_obj(struct dc_bios *dcb,
259 struct graphics_object_id object_id, uint32_t index,
260 struct graphics_object_id *dest_object_id)
261{
262 uint32_t number;
263 uint16_t *id = NULL;
264 ATOM_OBJECT *object;
265 struct bios_parser *bp = BP_FROM_DCB(dcb);
266
267 if (!dest_object_id)
268 return BP_RESULT_BADINPUT;
269
270 object = get_bios_object(bp, object_id);
271
272 number = get_dest_obj_list(bp, object, &id);
273
274 if (number <= index || !id)
275 return BP_RESULT_BADINPUT;
276
277 *dest_object_id = object_id_from_bios_object_id(id[index]);
278
279 return BP_RESULT_OK;
280}
281
282static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
283 struct graphics_object_id id,
284 struct graphics_object_i2c_info *info)
285{
286 uint32_t offset;
287 ATOM_OBJECT *object;
288 ATOM_COMMON_RECORD_HEADER *header;
289 ATOM_I2C_RECORD *record;
290 struct bios_parser *bp = BP_FROM_DCB(dcb);
291
292 if (!info)
293 return BP_RESULT_BADINPUT;
294
295 object = get_bios_object(bp, id);
296
297 if (!object)
298 return BP_RESULT_BADINPUT;
299
300 offset = le16_to_cpu(object->usRecordOffset)
301 + bp->object_info_tbl_offset;
302
303 for (;;) {
304 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
305
306 if (!header)
307 return BP_RESULT_BADBIOSTABLE;
308
309 if (LAST_RECORD_TYPE == header->ucRecordType ||
310 !header->ucRecordSize)
311 break;
312
313 if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
314 && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
315
316 record = (ATOM_I2C_RECORD *) header;
317
318 if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
319 return BP_RESULT_OK;
320 }
321
322 offset += header->ucRecordSize;
323 }
324
325 return BP_RESULT_NORECORD;
326}
327
328static enum bp_result get_voltage_ddc_info_v1(uint8_t *i2c_line,
329 ATOM_COMMON_TABLE_HEADER *header,
330 uint8_t *address)
331{
332 enum bp_result result = BP_RESULT_NORECORD;
333 ATOM_VOLTAGE_OBJECT_INFO *info =
334 (ATOM_VOLTAGE_OBJECT_INFO *) address;
335
336 uint8_t *voltage_current_object = (uint8_t *) &info->asVoltageObj[0];
337
338 while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
339 ATOM_VOLTAGE_OBJECT *object =
340 (ATOM_VOLTAGE_OBJECT *) voltage_current_object;
341
342 if ((object->ucVoltageType == SET_VOLTAGE_INIT_MODE) &&
343 (object->ucVoltageType &
344 VOLTAGE_CONTROLLED_BY_I2C_MASK)) {
345
346 *i2c_line = object->asControl.ucVoltageControlI2cLine
347 ^ 0x90;
348 result = BP_RESULT_OK;
349 break;
350 }
351
352 voltage_current_object += object->ucSize;
353 }
354 return result;
355}
356
357static enum bp_result get_voltage_ddc_info_v3(uint8_t *i2c_line,
358 uint32_t index,
359 ATOM_COMMON_TABLE_HEADER *header,
360 uint8_t *address)
361{
362 enum bp_result result = BP_RESULT_NORECORD;
363 ATOM_VOLTAGE_OBJECT_INFO_V3_1 *info =
364 (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *) address;
365
366 uint8_t *voltage_current_object =
367 (uint8_t *) (&(info->asVoltageObj[0]));
368
369 while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
370 ATOM_I2C_VOLTAGE_OBJECT_V3 *object =
371 (ATOM_I2C_VOLTAGE_OBJECT_V3 *) voltage_current_object;
372
373 if (object->sHeader.ucVoltageMode ==
374 ATOM_INIT_VOLTAGE_REGULATOR) {
375 if (object->sHeader.ucVoltageType == index) {
376 *i2c_line = object->ucVoltageControlI2cLine
377 ^ 0x90;
378 result = BP_RESULT_OK;
379 break;
380 }
381 }
382
383 voltage_current_object += le16_to_cpu(object->sHeader.usSize);
384 }
385 return result;
386}
387
388static enum bp_result bios_parser_get_thermal_ddc_info(
389 struct dc_bios *dcb,
390 uint32_t i2c_channel_id,
391 struct graphics_object_i2c_info *info)
392{
393 struct bios_parser *bp = BP_FROM_DCB(dcb);
394 ATOM_I2C_ID_CONFIG_ACCESS *config;
395 ATOM_I2C_RECORD record;
396
397 if (!info)
398 return BP_RESULT_BADINPUT;
399
400 config = (ATOM_I2C_ID_CONFIG_ACCESS *) &i2c_channel_id;
401
402 record.sucI2cId.bfHW_Capable = config->sbfAccess.bfHW_Capable;
403 record.sucI2cId.bfI2C_LineMux = config->sbfAccess.bfI2C_LineMux;
404 record.sucI2cId.bfHW_EngineID = config->sbfAccess.bfHW_EngineID;
405
406 return get_gpio_i2c_info(bp, &record, info);
407}
408
409static enum bp_result bios_parser_get_voltage_ddc_info(struct dc_bios *dcb,
410 uint32_t index,
411 struct graphics_object_i2c_info *info)
412{
413 uint8_t i2c_line = 0;
414 enum bp_result result = BP_RESULT_NORECORD;
415 uint8_t *voltage_info_address;
416 ATOM_COMMON_TABLE_HEADER *header;
417 struct atom_data_revision revision = {0};
418 struct bios_parser *bp = BP_FROM_DCB(dcb);
419
420 if (!DATA_TABLES(VoltageObjectInfo))
421 return result;
422
423 voltage_info_address = bios_get_image(&bp->base, DATA_TABLES(VoltageObjectInfo), sizeof(ATOM_COMMON_TABLE_HEADER));
424
425 header = (ATOM_COMMON_TABLE_HEADER *) voltage_info_address;
426
427 get_atom_data_table_revision(header, &revision);
428
429 switch (revision.major) {
430 case 1:
431 case 2:
432 result = get_voltage_ddc_info_v1(&i2c_line, header,
433 voltage_info_address);
434 break;
435 case 3:
436 if (revision.minor != 1)
437 break;
438 result = get_voltage_ddc_info_v3(&i2c_line, index, header,
439 voltage_info_address);
440 break;
441 }
442
443 if (result == BP_RESULT_OK)
444 result = bios_parser_get_thermal_ddc_info(dcb,
445 i2c_line, info);
446
447 return result;
448}
449
450
451#if 0
452static enum bp_result bios_parser_get_ddc_info_for_i2c_line(
453 struct bios_parser *bp,
454 uint8_t i2c_line, struct graphics_object_i2c_info *info)
455{
456 uint32_t offset;
457 ATOM_OBJECT *object;
458 ATOM_OBJECT_TABLE *table;
459 uint32_t i;
460
461 if (!info)
462 return BP_RESULT_BADINPUT;
463
464 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
465
466 offset += bp->object_info_tbl_offset;
467
468 table = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
469
470 if (!table)
471 return BP_RESULT_BADBIOSTABLE;
472
473 for (i = 0; i < table->ucNumberOfObjects; i++) {
474 object = &table->asObjects[i];
475
476 if (!object) {
477 BREAK_TO_DEBUGGER();
478 return BP_RESULT_BADINPUT;
479 }
480
481 offset = le16_to_cpu(object->usRecordOffset)
482 + bp->object_info_tbl_offset;
483
484 for (;;) {
485 ATOM_COMMON_RECORD_HEADER *header =
486 GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
487
488 if (!header)
489 return BP_RESULT_BADBIOSTABLE;
490
491 offset += header->ucRecordSize;
492
493 if (LAST_RECORD_TYPE == header->ucRecordType ||
494 !header->ucRecordSize)
495 break;
496
497 if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
498 && sizeof(ATOM_I2C_RECORD) <=
499 header->ucRecordSize) {
500 ATOM_I2C_RECORD *record =
501 (ATOM_I2C_RECORD *) header;
502
503 if (i2c_line != record->sucI2cId.bfI2C_LineMux)
504 continue;
505
506
507 if (get_gpio_i2c_info(bp, record, info) ==
508 BP_RESULT_OK)
509 return BP_RESULT_OK;
510 }
511 }
512 }
513
514 return BP_RESULT_NORECORD;
515}
516#endif
517
518static enum bp_result bios_parser_get_hpd_info(struct dc_bios *dcb,
519 struct graphics_object_id id,
520 struct graphics_object_hpd_info *info)
521{
522 struct bios_parser *bp = BP_FROM_DCB(dcb);
523 ATOM_OBJECT *object;
524 ATOM_HPD_INT_RECORD *record = NULL;
525
526 if (!info)
527 return BP_RESULT_BADINPUT;
528
529 object = get_bios_object(bp, id);
530
531 if (!object)
532 return BP_RESULT_BADINPUT;
533
534 record = get_hpd_record(bp, object);
535
536 if (record != NULL) {
537 info->hpd_int_gpio_uid = record->ucHPDIntGPIOID;
538 info->hpd_active = record->ucPlugged_PinState;
539 return BP_RESULT_OK;
540 }
541
542 return BP_RESULT_NORECORD;
543}
544
545static enum bp_result bios_parser_get_device_tag_record(
546 struct bios_parser *bp,
547 ATOM_OBJECT *object,
548 ATOM_CONNECTOR_DEVICE_TAG_RECORD **record)
549{
550 ATOM_COMMON_RECORD_HEADER *header;
551 uint32_t offset;
552
553 offset = le16_to_cpu(object->usRecordOffset)
554 + bp->object_info_tbl_offset;
555
556 for (;;) {
557 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
558
559 if (!header)
560 return BP_RESULT_BADBIOSTABLE;
561
562 offset += header->ucRecordSize;
563
564 if (LAST_RECORD_TYPE == header->ucRecordType ||
565 !header->ucRecordSize)
566 break;
567
568 if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
569 header->ucRecordType)
570 continue;
571
572 if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
573 continue;
574
575 *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
576 return BP_RESULT_OK;
577 }
578
579 return BP_RESULT_NORECORD;
580}
581
582static enum bp_result bios_parser_get_device_tag(
583 struct dc_bios *dcb,
584 struct graphics_object_id connector_object_id,
585 uint32_t device_tag_index,
586 struct connector_device_tag_info *info)
587{
588 struct bios_parser *bp = BP_FROM_DCB(dcb);
589 ATOM_OBJECT *object;
590 ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
591 ATOM_CONNECTOR_DEVICE_TAG *device_tag;
592
593 if (!info)
594 return BP_RESULT_BADINPUT;
595
596
597 object = get_bios_object(bp, connector_object_id);
598
599 if (!object) {
600 BREAK_TO_DEBUGGER();
601 return BP_RESULT_BADINPUT;
602 }
603
604 if (bios_parser_get_device_tag_record(bp, object, &record)
605 != BP_RESULT_OK)
606 return BP_RESULT_NORECORD;
607
608 if (device_tag_index >= record->ucNumberOfDevice)
609 return BP_RESULT_NORECORD;
610
611 device_tag = &record->asDeviceTag[device_tag_index];
612
613 info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
614 info->dev_id =
615 device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
616
617 return BP_RESULT_OK;
618}
619
620static enum bp_result get_firmware_info_v1_4(
621 struct bios_parser *bp,
622 struct dc_firmware_info *info);
623static enum bp_result get_firmware_info_v2_1(
624 struct bios_parser *bp,
625 struct dc_firmware_info *info);
626static enum bp_result get_firmware_info_v2_2(
627 struct bios_parser *bp,
628 struct dc_firmware_info *info);
629
630static enum bp_result bios_parser_get_firmware_info(
631 struct dc_bios *dcb,
632 struct dc_firmware_info *info)
633{
634 struct bios_parser *bp = BP_FROM_DCB(dcb);
635 enum bp_result result = BP_RESULT_BADBIOSTABLE;
636 ATOM_COMMON_TABLE_HEADER *header;
637 struct atom_data_revision revision;
638
639 if (info && DATA_TABLES(FirmwareInfo)) {
640 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
641 DATA_TABLES(FirmwareInfo));
642 get_atom_data_table_revision(header, &revision);
643 switch (revision.major) {
644 case 1:
645 switch (revision.minor) {
646 case 4:
647 result = get_firmware_info_v1_4(bp, info);
648 break;
649 default:
650 break;
651 }
652 break;
653
654 case 2:
655 switch (revision.minor) {
656 case 1:
657 result = get_firmware_info_v2_1(bp, info);
658 break;
659 case 2:
660 result = get_firmware_info_v2_2(bp, info);
661 break;
662 default:
663 break;
664 }
665 break;
666 default:
667 break;
668 }
669 }
670
671 return result;
672}
673
674static enum bp_result get_firmware_info_v1_4(
675 struct bios_parser *bp,
676 struct dc_firmware_info *info)
677{
678 ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
679 GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
680 DATA_TABLES(FirmwareInfo));
681
682 if (!info)
683 return BP_RESULT_BADINPUT;
684
685 if (!firmware_info)
686 return BP_RESULT_BADBIOSTABLE;
687
688 memset(info, 0, sizeof(*info));
689
690
691
692 info->pll_info.crystal_frequency =
693 le16_to_cpu(firmware_info->usReferenceClock) * 10;
694 info->pll_info.min_input_pxl_clk_pll_frequency =
695 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
696 info->pll_info.max_input_pxl_clk_pll_frequency =
697 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
698 info->pll_info.min_output_pxl_clk_pll_frequency =
699 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
700 info->pll_info.max_output_pxl_clk_pll_frequency =
701 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
702
703 if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
704
705
706
707 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
708
709 if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
710
711
712
713 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
714
715 return BP_RESULT_OK;
716}
717
718static enum bp_result get_ss_info_v3_1(
719 struct bios_parser *bp,
720 uint32_t id,
721 uint32_t index,
722 struct spread_spectrum_info *ss_info);
723
724static enum bp_result get_firmware_info_v2_1(
725 struct bios_parser *bp,
726 struct dc_firmware_info *info)
727{
728 ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
729 GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
730 struct spread_spectrum_info internalSS;
731 uint32_t index;
732
733 if (!info)
734 return BP_RESULT_BADINPUT;
735
736 if (!firmwareInfo)
737 return BP_RESULT_BADBIOSTABLE;
738
739 memset(info, 0, sizeof(*info));
740
741
742
743 info->pll_info.crystal_frequency =
744 le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
745 info->pll_info.min_input_pxl_clk_pll_frequency =
746 le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
747 info->pll_info.max_input_pxl_clk_pll_frequency =
748 le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
749 info->pll_info.min_output_pxl_clk_pll_frequency =
750 le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
751 info->pll_info.max_output_pxl_clk_pll_frequency =
752 le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
753 info->default_display_engine_pll_frequency =
754 le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
755 info->external_clock_source_frequency_for_dp =
756 le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
757 info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
758
759
760
761 index = 0;
762 if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
763
764
765
766 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
767 else if (get_ss_info_v3_1(bp,
768 ASIC_INTERNAL_MEMORY_SS, index, &internalSS) == BP_RESULT_OK) {
769 if (internalSS.spread_spectrum_percentage) {
770 info->feature.memory_clk_ss_percentage =
771 internalSS.spread_spectrum_percentage;
772 if (internalSS.type.CENTER_MODE) {
773
774
775
776 ++info->feature.memory_clk_ss_percentage;
777 info->feature.memory_clk_ss_percentage /= 2;
778 }
779 }
780 }
781
782
783
784 index = 1;
785 if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
786
787
788
789 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
790 else if (get_ss_info_v3_1(bp,
791 ASIC_INTERNAL_ENGINE_SS, index, &internalSS) == BP_RESULT_OK) {
792 if (internalSS.spread_spectrum_percentage) {
793 info->feature.engine_clk_ss_percentage =
794 internalSS.spread_spectrum_percentage;
795 if (internalSS.type.CENTER_MODE) {
796
797
798
799 ++info->feature.engine_clk_ss_percentage;
800 info->feature.engine_clk_ss_percentage /= 2;
801 }
802 }
803 }
804
805 return BP_RESULT_OK;
806}
807
808static enum bp_result get_firmware_info_v2_2(
809 struct bios_parser *bp,
810 struct dc_firmware_info *info)
811{
812 ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
813 struct spread_spectrum_info internal_ss;
814 uint32_t index;
815
816 if (!info)
817 return BP_RESULT_BADINPUT;
818
819 firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
820 DATA_TABLES(FirmwareInfo));
821
822 if (!firmware_info)
823 return BP_RESULT_BADBIOSTABLE;
824
825 memset(info, 0, sizeof(*info));
826
827
828
829 info->pll_info.crystal_frequency =
830 le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
831 info->pll_info.min_input_pxl_clk_pll_frequency =
832 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
833 info->pll_info.max_input_pxl_clk_pll_frequency =
834 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
835 info->pll_info.min_output_pxl_clk_pll_frequency =
836 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
837 info->pll_info.max_output_pxl_clk_pll_frequency =
838 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
839 info->default_display_engine_pll_frequency =
840 le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
841 info->external_clock_source_frequency_for_dp =
842 le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
843
844
845
846 index = 0;
847 if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
848
849
850
851 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
852 else if (get_ss_info_v3_1(bp,
853 ASIC_INTERNAL_MEMORY_SS, index, &internal_ss) == BP_RESULT_OK) {
854 if (internal_ss.spread_spectrum_percentage) {
855 info->feature.memory_clk_ss_percentage =
856 internal_ss.spread_spectrum_percentage;
857 if (internal_ss.type.CENTER_MODE) {
858
859
860
861 ++info->feature.memory_clk_ss_percentage;
862 info->feature.memory_clk_ss_percentage /= 2;
863 }
864 }
865 }
866
867
868
869 index = 1;
870 if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
871
872
873
874 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
875 else if (get_ss_info_v3_1(bp,
876 ASIC_INTERNAL_ENGINE_SS, index, &internal_ss) == BP_RESULT_OK) {
877 if (internal_ss.spread_spectrum_percentage) {
878 info->feature.engine_clk_ss_percentage =
879 internal_ss.spread_spectrum_percentage;
880 if (internal_ss.type.CENTER_MODE) {
881
882
883
884 ++info->feature.engine_clk_ss_percentage;
885 info->feature.engine_clk_ss_percentage /= 2;
886 }
887 }
888 }
889
890
891 info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
892
893
894 info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
895
896 info->smu_gpu_pll_output_freq =
897 (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
898
899 return BP_RESULT_OK;
900}
901
902static enum bp_result get_ss_info_v3_1(
903 struct bios_parser *bp,
904 uint32_t id,
905 uint32_t index,
906 struct spread_spectrum_info *ss_info)
907{
908 ATOM_ASIC_INTERNAL_SS_INFO_V3 *ss_table_header_include;
909 ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
910 uint32_t table_size;
911 uint32_t i;
912 uint32_t table_index = 0;
913
914 if (!ss_info)
915 return BP_RESULT_BADINPUT;
916
917 if (!DATA_TABLES(ASIC_InternalSS_Info))
918 return BP_RESULT_UNSUPPORTED;
919
920 ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
921 DATA_TABLES(ASIC_InternalSS_Info));
922 table_size =
923 (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
924 - sizeof(ATOM_COMMON_TABLE_HEADER))
925 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
926
927 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
928 &ss_table_header_include->asSpreadSpectrum[0];
929
930 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
931
932 for (i = 0; i < table_size; i++) {
933 if (tbl[i].ucClockIndication != (uint8_t) id)
934 continue;
935
936 if (table_index != index) {
937 table_index++;
938 continue;
939 }
940
941
942
943
944
945
946
947
948
949
950
951
952 if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
953 ss_info->type.EXTERNAL = true;
954
955 if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
956 ss_info->type.CENTER_MODE = true;
957
958
959
960 ss_info->spread_percentage_divider = 100;
961
962
963 if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
964 & tbl[i].ucSpreadSpectrumMode)
965 ss_info->spread_percentage_divider = 1000;
966
967 ss_info->type.STEP_AND_DELAY_INFO = false;
968
969 ss_info->target_clock_range =
970 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
971 ss_info->spread_spectrum_percentage =
972 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
973 ss_info->spread_spectrum_range =
974 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
975
976 return BP_RESULT_OK;
977 }
978 return BP_RESULT_NORECORD;
979}
980
981static enum bp_result bios_parser_transmitter_control(
982 struct dc_bios *dcb,
983 struct bp_transmitter_control *cntl)
984{
985 struct bios_parser *bp = BP_FROM_DCB(dcb);
986
987 if (!bp->cmd_tbl.transmitter_control)
988 return BP_RESULT_FAILURE;
989
990 return bp->cmd_tbl.transmitter_control(bp, cntl);
991}
992
993static enum bp_result bios_parser_encoder_control(
994 struct dc_bios *dcb,
995 struct bp_encoder_control *cntl)
996{
997 struct bios_parser *bp = BP_FROM_DCB(dcb);
998
999 if (!bp->cmd_tbl.dig_encoder_control)
1000 return BP_RESULT_FAILURE;
1001
1002 return bp->cmd_tbl.dig_encoder_control(bp, cntl);
1003}
1004
1005static enum bp_result bios_parser_adjust_pixel_clock(
1006 struct dc_bios *dcb,
1007 struct bp_adjust_pixel_clock_parameters *bp_params)
1008{
1009 struct bios_parser *bp = BP_FROM_DCB(dcb);
1010
1011 if (!bp->cmd_tbl.adjust_display_pll)
1012 return BP_RESULT_FAILURE;
1013
1014 return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
1015}
1016
1017static enum bp_result bios_parser_set_pixel_clock(
1018 struct dc_bios *dcb,
1019 struct bp_pixel_clock_parameters *bp_params)
1020{
1021 struct bios_parser *bp = BP_FROM_DCB(dcb);
1022
1023 if (!bp->cmd_tbl.set_pixel_clock)
1024 return BP_RESULT_FAILURE;
1025
1026 return bp->cmd_tbl.set_pixel_clock(bp, bp_params);
1027}
1028
1029static enum bp_result bios_parser_set_dce_clock(
1030 struct dc_bios *dcb,
1031 struct bp_set_dce_clock_parameters *bp_params)
1032{
1033 struct bios_parser *bp = BP_FROM_DCB(dcb);
1034
1035 if (!bp->cmd_tbl.set_dce_clock)
1036 return BP_RESULT_FAILURE;
1037
1038 return bp->cmd_tbl.set_dce_clock(bp, bp_params);
1039}
1040
1041static enum bp_result bios_parser_enable_spread_spectrum_on_ppll(
1042 struct dc_bios *dcb,
1043 struct bp_spread_spectrum_parameters *bp_params,
1044 bool enable)
1045{
1046 struct bios_parser *bp = BP_FROM_DCB(dcb);
1047
1048 if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
1049 return BP_RESULT_FAILURE;
1050
1051 return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
1052 bp, bp_params, enable);
1053
1054}
1055
1056static enum bp_result bios_parser_program_crtc_timing(
1057 struct dc_bios *dcb,
1058 struct bp_hw_crtc_timing_parameters *bp_params)
1059{
1060 struct bios_parser *bp = BP_FROM_DCB(dcb);
1061
1062 if (!bp->cmd_tbl.set_crtc_timing)
1063 return BP_RESULT_FAILURE;
1064
1065 return bp->cmd_tbl.set_crtc_timing(bp, bp_params);
1066}
1067
1068static enum bp_result bios_parser_program_display_engine_pll(
1069 struct dc_bios *dcb,
1070 struct bp_pixel_clock_parameters *bp_params)
1071{
1072 struct bios_parser *bp = BP_FROM_DCB(dcb);
1073
1074 if (!bp->cmd_tbl.program_clock)
1075 return BP_RESULT_FAILURE;
1076
1077 return bp->cmd_tbl.program_clock(bp, bp_params);
1078
1079}
1080
1081
1082static enum bp_result bios_parser_enable_crtc(
1083 struct dc_bios *dcb,
1084 enum controller_id id,
1085 bool enable)
1086{
1087 struct bios_parser *bp = BP_FROM_DCB(dcb);
1088
1089 if (!bp->cmd_tbl.enable_crtc)
1090 return BP_RESULT_FAILURE;
1091
1092 return bp->cmd_tbl.enable_crtc(bp, id, enable);
1093}
1094
1095static enum bp_result bios_parser_crtc_source_select(
1096 struct dc_bios *dcb,
1097 struct bp_crtc_source_select *bp_params)
1098{
1099 struct bios_parser *bp = BP_FROM_DCB(dcb);
1100
1101 if (!bp->cmd_tbl.select_crtc_source)
1102 return BP_RESULT_FAILURE;
1103
1104 return bp->cmd_tbl.select_crtc_source(bp, bp_params);
1105}
1106
1107static enum bp_result bios_parser_enable_disp_power_gating(
1108 struct dc_bios *dcb,
1109 enum controller_id controller_id,
1110 enum bp_pipe_control_action action)
1111{
1112 struct bios_parser *bp = BP_FROM_DCB(dcb);
1113
1114 if (!bp->cmd_tbl.enable_disp_power_gating)
1115 return BP_RESULT_FAILURE;
1116
1117 return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id,
1118 action);
1119}
1120
1121static bool bios_parser_is_device_id_supported(
1122 struct dc_bios *dcb,
1123 struct device_id id)
1124{
1125 struct bios_parser *bp = BP_FROM_DCB(dcb);
1126
1127 uint32_t mask = get_support_mask_for_device_id(id);
1128
1129 return (le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport) & mask) != 0;
1130}
1131
1132static enum bp_result bios_parser_crt_control(
1133 struct dc_bios *dcb,
1134 enum engine_id engine_id,
1135 bool enable,
1136 uint32_t pixel_clock)
1137{
1138 struct bios_parser *bp = BP_FROM_DCB(dcb);
1139 uint8_t standard;
1140
1141 if (!bp->cmd_tbl.dac1_encoder_control &&
1142 engine_id == ENGINE_ID_DACA)
1143 return BP_RESULT_FAILURE;
1144 if (!bp->cmd_tbl.dac2_encoder_control &&
1145 engine_id == ENGINE_ID_DACB)
1146 return BP_RESULT_FAILURE;
1147
1148 switch (engine_id) {
1149 case ENGINE_ID_DACA:
1150 case ENGINE_ID_DACB:
1151 break;
1152 default:
1153
1154 return BP_RESULT_FAILURE;
1155 }
1156
1157 standard = ATOM_DAC1_PS2;
1158
1159 if (enable) {
1160 if (engine_id == ENGINE_ID_DACA) {
1161 bp->cmd_tbl.dac1_encoder_control(bp, enable,
1162 pixel_clock, standard);
1163 if (bp->cmd_tbl.dac1_output_control != NULL)
1164 bp->cmd_tbl.dac1_output_control(bp, enable);
1165 } else {
1166 bp->cmd_tbl.dac2_encoder_control(bp, enable,
1167 pixel_clock, standard);
1168 if (bp->cmd_tbl.dac2_output_control != NULL)
1169 bp->cmd_tbl.dac2_output_control(bp, enable);
1170 }
1171 } else {
1172 if (engine_id == ENGINE_ID_DACA) {
1173 if (bp->cmd_tbl.dac1_output_control != NULL)
1174 bp->cmd_tbl.dac1_output_control(bp, enable);
1175 bp->cmd_tbl.dac1_encoder_control(bp, enable,
1176 pixel_clock, standard);
1177 } else {
1178 if (bp->cmd_tbl.dac2_output_control != NULL)
1179 bp->cmd_tbl.dac2_output_control(bp, enable);
1180 bp->cmd_tbl.dac2_encoder_control(bp, enable,
1181 pixel_clock, standard);
1182 }
1183 }
1184
1185 return BP_RESULT_OK;
1186}
1187
1188static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
1189 ATOM_OBJECT *object)
1190{
1191 ATOM_COMMON_RECORD_HEADER *header;
1192 uint32_t offset;
1193
1194 if (!object) {
1195 BREAK_TO_DEBUGGER();
1196 return NULL;
1197 }
1198
1199 offset = le16_to_cpu(object->usRecordOffset)
1200 + bp->object_info_tbl_offset;
1201
1202 for (;;) {
1203 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1204
1205 if (!header)
1206 return NULL;
1207
1208 if (LAST_RECORD_TYPE == header->ucRecordType ||
1209 !header->ucRecordSize)
1210 break;
1211
1212 if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
1213 && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
1214 return (ATOM_HPD_INT_RECORD *) header;
1215
1216 offset += header->ucRecordSize;
1217 }
1218
1219 return NULL;
1220}
1221
1222
1223
1224
1225
1226
1227static ATOM_I2C_RECORD *get_i2c_record(
1228 struct bios_parser *bp,
1229 ATOM_OBJECT *object)
1230{
1231 uint32_t offset;
1232 ATOM_COMMON_RECORD_HEADER *record_header;
1233
1234 if (!object) {
1235 BREAK_TO_DEBUGGER();
1236
1237 return NULL;
1238 }
1239
1240 offset = le16_to_cpu(object->usRecordOffset)
1241 + bp->object_info_tbl_offset;
1242
1243 for (;;) {
1244 record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1245
1246 if (!record_header)
1247 return NULL;
1248
1249 if (LAST_RECORD_TYPE == record_header->ucRecordType ||
1250 0 == record_header->ucRecordSize)
1251 break;
1252
1253 if (ATOM_I2C_RECORD_TYPE == record_header->ucRecordType &&
1254 sizeof(ATOM_I2C_RECORD) <=
1255 record_header->ucRecordSize) {
1256 return (ATOM_I2C_RECORD *)record_header;
1257 }
1258
1259 offset += record_header->ucRecordSize;
1260 }
1261
1262 return NULL;
1263}
1264
1265static enum bp_result get_ss_info_from_ss_info_table(
1266 struct bios_parser *bp,
1267 uint32_t id,
1268 struct spread_spectrum_info *ss_info);
1269static enum bp_result get_ss_info_from_tbl(
1270 struct bios_parser *bp,
1271 uint32_t id,
1272 struct spread_spectrum_info *ss_info);
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286static enum bp_result bios_parser_get_spread_spectrum_info(
1287 struct dc_bios *dcb,
1288 enum as_signal_type signal,
1289 uint32_t index,
1290 struct spread_spectrum_info *ss_info)
1291{
1292 struct bios_parser *bp = BP_FROM_DCB(dcb);
1293 enum bp_result result = BP_RESULT_UNSUPPORTED;
1294 uint32_t clk_id_ss = 0;
1295 ATOM_COMMON_TABLE_HEADER *header;
1296 struct atom_data_revision tbl_revision;
1297
1298 if (!ss_info)
1299 return BP_RESULT_BADINPUT;
1300
1301 clk_id_ss = signal_to_ss_id(signal);
1302
1303 if (!DATA_TABLES(ASIC_InternalSS_Info))
1304 if (!index)
1305 return get_ss_info_from_ss_info_table(bp, clk_id_ss,
1306 ss_info);
1307
1308 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1309 DATA_TABLES(ASIC_InternalSS_Info));
1310 get_atom_data_table_revision(header, &tbl_revision);
1311
1312 switch (tbl_revision.major) {
1313 case 2:
1314 switch (tbl_revision.minor) {
1315 case 1:
1316
1317
1318 if (!index)
1319 return get_ss_info_from_tbl(bp, clk_id_ss,
1320 ss_info);
1321 break;
1322 default:
1323 break;
1324 }
1325 break;
1326
1327 case 3:
1328 switch (tbl_revision.minor) {
1329 case 1:
1330 return get_ss_info_v3_1(bp, clk_id_ss, index, ss_info);
1331 default:
1332 break;
1333 }
1334 break;
1335 default:
1336 break;
1337 }
1338
1339 return result;
1340}
1341
1342static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1343 struct bios_parser *bp,
1344 uint32_t id,
1345 struct spread_spectrum_info *info);
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359static enum bp_result get_ss_info_from_tbl(
1360 struct bios_parser *bp,
1361 uint32_t id,
1362 struct spread_spectrum_info *ss_info)
1363{
1364 if (!ss_info)
1365 return BP_RESULT_BADINPUT;
1366
1367 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1368 return get_ss_info_from_ss_info_table(bp, id, ss_info);
1369 else
1370 return get_ss_info_from_internal_ss_info_tbl_V2_1(bp, id,
1371 ss_info);
1372}
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1385 struct bios_parser *bp,
1386 uint32_t id,
1387 struct spread_spectrum_info *info)
1388{
1389 enum bp_result result = BP_RESULT_UNSUPPORTED;
1390 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header;
1391 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1392 uint32_t tbl_size, i;
1393
1394 if (!DATA_TABLES(ASIC_InternalSS_Info))
1395 return result;
1396
1397 header = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
1398 DATA_TABLES(ASIC_InternalSS_Info));
1399
1400 memset(info, 0, sizeof(struct spread_spectrum_info));
1401
1402 tbl_size = (le16_to_cpu(header->sHeader.usStructureSize)
1403 - sizeof(ATOM_COMMON_TABLE_HEADER))
1404 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1405
1406 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1407 &(header->asSpreadSpectrum[0]);
1408 for (i = 0; i < tbl_size; i++) {
1409 result = BP_RESULT_NORECORD;
1410
1411 if (tbl[i].ucClockIndication != (uint8_t)id)
1412 continue;
1413
1414 if (ATOM_EXTERNAL_SS_MASK
1415 & tbl[i].ucSpreadSpectrumMode) {
1416 info->type.EXTERNAL = true;
1417 }
1418 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
1419 & tbl[i].ucSpreadSpectrumMode) {
1420 info->type.CENTER_MODE = true;
1421 }
1422 info->type.STEP_AND_DELAY_INFO = false;
1423
1424 info->target_clock_range =
1425 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
1426 info->spread_spectrum_percentage =
1427 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
1428 info->spread_spectrum_range =
1429 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
1430 result = BP_RESULT_OK;
1431 break;
1432 }
1433
1434 return result;
1435
1436}
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449static enum bp_result get_ss_info_from_ss_info_table(
1450 struct bios_parser *bp,
1451 uint32_t id,
1452 struct spread_spectrum_info *ss_info)
1453{
1454 enum bp_result result = BP_RESULT_UNSUPPORTED;
1455 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1456 ATOM_COMMON_TABLE_HEADER *header;
1457 uint32_t table_size;
1458 uint32_t i;
1459 uint32_t id_local = SS_ID_UNKNOWN;
1460 struct atom_data_revision revision;
1461
1462
1463
1464 if (!DATA_TABLES(SS_Info) || !ss_info)
1465 return result;
1466
1467 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(SS_Info));
1468 get_atom_data_table_revision(header, &revision);
1469
1470 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info));
1471
1472 if (1 != revision.major || 2 > revision.minor)
1473 return result;
1474
1475
1476 switch (id) {
1477 case ASIC_INTERNAL_SS_ON_DP:
1478 id_local = SS_ID_DP1;
1479 break;
1480 case ASIC_INTERNAL_SS_ON_LVDS:
1481 {
1482 struct embedded_panel_info panel_info;
1483
1484 if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
1485 == BP_RESULT_OK)
1486 id_local = panel_info.ss_id;
1487 break;
1488 }
1489 default:
1490 break;
1491 }
1492
1493 if (id_local == SS_ID_UNKNOWN)
1494 return result;
1495
1496 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1497 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1498 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1499
1500 for (i = 0; i < table_size; i++) {
1501 if (id_local != (uint32_t)tbl->asSS_Info[i].ucSS_Id)
1502 continue;
1503
1504 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
1505
1506 if (ATOM_EXTERNAL_SS_MASK &
1507 tbl->asSS_Info[i].ucSpreadSpectrumType)
1508 ss_info->type.EXTERNAL = true;
1509
1510 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK &
1511 tbl->asSS_Info[i].ucSpreadSpectrumType)
1512 ss_info->type.CENTER_MODE = true;
1513
1514 ss_info->type.STEP_AND_DELAY_INFO = true;
1515 ss_info->spread_spectrum_percentage =
1516 (uint32_t)le16_to_cpu(tbl->asSS_Info[i].usSpreadSpectrumPercentage);
1517 ss_info->step_and_delay_info.step = tbl->asSS_Info[i].ucSS_Step;
1518 ss_info->step_and_delay_info.delay =
1519 tbl->asSS_Info[i].ucSS_Delay;
1520 ss_info->step_and_delay_info.recommended_ref_div =
1521 tbl->asSS_Info[i].ucRecommendedRef_Div;
1522 ss_info->spread_spectrum_range =
1523 (uint32_t)tbl->asSS_Info[i].ucSS_Range * 10000;
1524
1525
1526
1527 result = BP_RESULT_OK;
1528 break;
1529 }
1530
1531 return result;
1532}
1533static enum bp_result get_embedded_panel_info_v1_2(
1534 struct bios_parser *bp,
1535 struct embedded_panel_info *info);
1536static enum bp_result get_embedded_panel_info_v1_3(
1537 struct bios_parser *bp,
1538 struct embedded_panel_info *info);
1539
1540static enum bp_result bios_parser_get_embedded_panel_info(
1541 struct dc_bios *dcb,
1542 struct embedded_panel_info *info)
1543{
1544 struct bios_parser *bp = BP_FROM_DCB(dcb);
1545 ATOM_COMMON_TABLE_HEADER *hdr;
1546
1547 if (!DATA_TABLES(LCD_Info))
1548 return BP_RESULT_FAILURE;
1549
1550 hdr = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(LCD_Info));
1551
1552 if (!hdr)
1553 return BP_RESULT_BADBIOSTABLE;
1554
1555 switch (hdr->ucTableFormatRevision) {
1556 case 1:
1557 switch (hdr->ucTableContentRevision) {
1558 case 0:
1559 case 1:
1560 case 2:
1561 return get_embedded_panel_info_v1_2(bp, info);
1562 case 3:
1563 return get_embedded_panel_info_v1_3(bp, info);
1564 default:
1565 break;
1566 }
1567 default:
1568 break;
1569 }
1570
1571 return BP_RESULT_FAILURE;
1572}
1573
1574static enum bp_result get_embedded_panel_info_v1_2(
1575 struct bios_parser *bp,
1576 struct embedded_panel_info *info)
1577{
1578 ATOM_LVDS_INFO_V12 *lvds;
1579
1580 if (!info)
1581 return BP_RESULT_BADINPUT;
1582
1583 if (!DATA_TABLES(LVDS_Info))
1584 return BP_RESULT_UNSUPPORTED;
1585
1586 lvds =
1587 GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
1588
1589 if (!lvds)
1590 return BP_RESULT_BADBIOSTABLE;
1591
1592 if (1 != lvds->sHeader.ucTableFormatRevision
1593 || 2 > lvds->sHeader.ucTableContentRevision)
1594 return BP_RESULT_UNSUPPORTED;
1595
1596 memset(info, 0, sizeof(struct embedded_panel_info));
1597
1598
1599 info->lcd_timing.pixel_clk =
1600 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1601
1602 info->lcd_timing.horizontal_addressable =
1603 le16_to_cpu(lvds->sLCDTiming.usHActive);
1604
1605
1606
1607
1608 info->lcd_timing.horizontal_blanking_time =
1609 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1610
1611 info->lcd_timing.vertical_addressable =
1612 le16_to_cpu(lvds->sLCDTiming.usVActive);
1613
1614
1615
1616
1617 info->lcd_timing.vertical_blanking_time =
1618 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1619 info->lcd_timing.horizontal_sync_offset =
1620 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1621 info->lcd_timing.horizontal_sync_width =
1622 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1623 info->lcd_timing.vertical_sync_offset =
1624 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1625 info->lcd_timing.vertical_sync_width =
1626 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1627 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1628 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1629 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1630 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1631 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1632 ~(uint32_t)
1633 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1634 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1635 ~(uint32_t)
1636 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1637 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1638 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1639 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1640 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1641 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1642 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1643 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1644 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1645 info->lcd_timing.misc_info.INTERLACE =
1646 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1647 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1648 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1649 info->ss_id = lvds->ucSS_Id;
1650
1651 {
1652 uint8_t rr = le16_to_cpu(lvds->usSupportedRefreshRate);
1653
1654 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1655 info->supported_rr.REFRESH_RATE_30HZ = 1;
1656 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1657 info->supported_rr.REFRESH_RATE_40HZ = 1;
1658 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1659 info->supported_rr.REFRESH_RATE_48HZ = 1;
1660 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1661 info->supported_rr.REFRESH_RATE_50HZ = 1;
1662 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1663 info->supported_rr.REFRESH_RATE_60HZ = 1;
1664 }
1665
1666
1667 if (LCDPANEL_CAP_DRR_SUPPORTED
1668 & lvds->ucLCDPanel_SpecialHandlingCap)
1669 info->drr_enabled = 1;
1670
1671 if (ATOM_PANEL_MISC_DUAL & lvds->ucLVDS_Misc)
1672 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1673
1674 if (ATOM_PANEL_MISC_888RGB & lvds->ucLVDS_Misc)
1675 info->lcd_timing.misc_info.RGB888 = true;
1676
1677 info->lcd_timing.misc_info.GREY_LEVEL =
1678 (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL &
1679 lvds->ucLVDS_Misc) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT;
1680
1681 if (ATOM_PANEL_MISC_SPATIAL & lvds->ucLVDS_Misc)
1682 info->lcd_timing.misc_info.SPATIAL = true;
1683
1684 if (ATOM_PANEL_MISC_TEMPORAL & lvds->ucLVDS_Misc)
1685 info->lcd_timing.misc_info.TEMPORAL = true;
1686
1687 if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
1688 info->lcd_timing.misc_info.API_ENABLED = true;
1689
1690 return BP_RESULT_OK;
1691}
1692
1693static enum bp_result get_embedded_panel_info_v1_3(
1694 struct bios_parser *bp,
1695 struct embedded_panel_info *info)
1696{
1697 ATOM_LCD_INFO_V13 *lvds;
1698
1699 if (!info)
1700 return BP_RESULT_BADINPUT;
1701
1702 if (!DATA_TABLES(LCD_Info))
1703 return BP_RESULT_UNSUPPORTED;
1704
1705 lvds = GET_IMAGE(ATOM_LCD_INFO_V13, DATA_TABLES(LCD_Info));
1706
1707 if (!lvds)
1708 return BP_RESULT_BADBIOSTABLE;
1709
1710 if (!((1 == lvds->sHeader.ucTableFormatRevision)
1711 && (3 <= lvds->sHeader.ucTableContentRevision)))
1712 return BP_RESULT_UNSUPPORTED;
1713
1714 memset(info, 0, sizeof(struct embedded_panel_info));
1715
1716
1717 info->lcd_timing.pixel_clk =
1718 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1719
1720 info->lcd_timing.horizontal_addressable =
1721 le16_to_cpu(lvds->sLCDTiming.usHActive);
1722
1723
1724
1725
1726 info->lcd_timing.horizontal_blanking_time =
1727 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1728
1729 info->lcd_timing.vertical_addressable =
1730 le16_to_cpu(lvds->sLCDTiming.usVActive);
1731
1732
1733
1734
1735 info->lcd_timing.vertical_blanking_time =
1736 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1737 info->lcd_timing.horizontal_sync_offset =
1738 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1739 info->lcd_timing.horizontal_sync_width =
1740 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1741 info->lcd_timing.vertical_sync_offset =
1742 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1743 info->lcd_timing.vertical_sync_width =
1744 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1745 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1746 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1747 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1748 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1749 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1750 ~(uint32_t)
1751 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1752 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1753 ~(uint32_t)
1754 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1755 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1756 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1757 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1758 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1759 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1760 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1761 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1762 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1763 info->lcd_timing.misc_info.INTERLACE =
1764 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1765 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1766 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1767 info->ss_id = lvds->ucSS_Id;
1768
1769
1770 if (LCDPANEL_CAP_V13_DRR_SUPPORTED
1771 & lvds->ucLCDPanel_SpecialHandlingCap)
1772 info->drr_enabled = 1;
1773
1774
1775 if (info->drr_enabled == 1) {
1776 uint8_t min_rr =
1777 lvds->sRefreshRateSupport.ucMinRefreshRateForDRR;
1778 uint8_t rr = lvds->sRefreshRateSupport.ucSupportedRefreshRate;
1779
1780 if (min_rr != 0) {
1781 if (SUPPORTED_LCD_REFRESHRATE_30Hz & min_rr)
1782 info->supported_rr.REFRESH_RATE_30HZ = 1;
1783 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & min_rr)
1784 info->supported_rr.REFRESH_RATE_40HZ = 1;
1785 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & min_rr)
1786 info->supported_rr.REFRESH_RATE_48HZ = 1;
1787 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & min_rr)
1788 info->supported_rr.REFRESH_RATE_50HZ = 1;
1789 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & min_rr)
1790 info->supported_rr.REFRESH_RATE_60HZ = 1;
1791 } else {
1792 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1793 info->supported_rr.REFRESH_RATE_30HZ = 1;
1794 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1795 info->supported_rr.REFRESH_RATE_40HZ = 1;
1796 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1797 info->supported_rr.REFRESH_RATE_48HZ = 1;
1798 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1799 info->supported_rr.REFRESH_RATE_50HZ = 1;
1800 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1801 info->supported_rr.REFRESH_RATE_60HZ = 1;
1802 }
1803 }
1804
1805 if (ATOM_PANEL_MISC_V13_DUAL & lvds->ucLCD_Misc)
1806 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1807
1808 if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR & lvds->ucLCD_Misc)
1809 info->lcd_timing.misc_info.RGB888 = true;
1810
1811 info->lcd_timing.misc_info.GREY_LEVEL =
1812 (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
1813 lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
1814
1815 return BP_RESULT_OK;
1816}
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830static enum bp_result bios_parser_get_encoder_cap_info(
1831 struct dc_bios *dcb,
1832 struct graphics_object_id object_id,
1833 struct bp_encoder_cap_info *info)
1834{
1835 struct bios_parser *bp = BP_FROM_DCB(dcb);
1836 ATOM_OBJECT *object;
1837 ATOM_ENCODER_CAP_RECORD_V2 *record = NULL;
1838
1839 if (!info)
1840 return BP_RESULT_BADINPUT;
1841
1842 object = get_bios_object(bp, object_id);
1843
1844 if (!object)
1845 return BP_RESULT_BADINPUT;
1846
1847 record = get_encoder_cap_record(bp, object);
1848 if (!record)
1849 return BP_RESULT_NORECORD;
1850
1851 info->DP_HBR2_EN = record->usHBR2En;
1852 info->DP_HBR3_EN = record->usHBR3En;
1853 info->HDMI_6GB_EN = record->usHDMI6GEn;
1854 return BP_RESULT_OK;
1855}
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
1871 struct bios_parser *bp,
1872 ATOM_OBJECT *object)
1873{
1874 ATOM_COMMON_RECORD_HEADER *header;
1875 uint32_t offset;
1876
1877 if (!object) {
1878 BREAK_TO_DEBUGGER();
1879 return NULL;
1880 }
1881
1882 offset = le16_to_cpu(object->usRecordOffset)
1883 + bp->object_info_tbl_offset;
1884
1885 for (;;) {
1886 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1887
1888 if (!header)
1889 return NULL;
1890
1891 offset += header->ucRecordSize;
1892
1893 if (LAST_RECORD_TYPE == header->ucRecordType ||
1894 !header->ucRecordSize)
1895 break;
1896
1897 if (ATOM_ENCODER_CAP_RECORD_TYPE != header->ucRecordType)
1898 continue;
1899
1900 if (sizeof(ATOM_ENCODER_CAP_RECORD_V2) <= header->ucRecordSize)
1901 return (ATOM_ENCODER_CAP_RECORD_V2 *)header;
1902 }
1903
1904 return NULL;
1905}
1906
1907static uint32_t get_ss_entry_number(
1908 struct bios_parser *bp,
1909 uint32_t id);
1910static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1911 struct bios_parser *bp,
1912 uint32_t id);
1913static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1914 struct bios_parser *bp,
1915 uint32_t id);
1916static uint32_t get_ss_entry_number_from_ss_info_tbl(
1917 struct bios_parser *bp,
1918 uint32_t id);
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928static uint32_t bios_parser_get_ss_entry_number(
1929 struct dc_bios *dcb,
1930 enum as_signal_type signal)
1931{
1932 struct bios_parser *bp = BP_FROM_DCB(dcb);
1933 uint32_t ss_id = 0;
1934 ATOM_COMMON_TABLE_HEADER *header;
1935 struct atom_data_revision revision;
1936
1937 ss_id = signal_to_ss_id(signal);
1938
1939 if (!DATA_TABLES(ASIC_InternalSS_Info))
1940 return get_ss_entry_number_from_ss_info_tbl(bp, ss_id);
1941
1942 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1943 DATA_TABLES(ASIC_InternalSS_Info));
1944 get_atom_data_table_revision(header, &revision);
1945
1946 switch (revision.major) {
1947 case 2:
1948 switch (revision.minor) {
1949 case 1:
1950 return get_ss_entry_number(bp, ss_id);
1951 default:
1952 break;
1953 }
1954 break;
1955 case 3:
1956 switch (revision.minor) {
1957 case 1:
1958 return
1959 get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1960 bp, ss_id);
1961 default:
1962 break;
1963 }
1964 break;
1965 default:
1966 break;
1967 }
1968
1969 return 0;
1970}
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981static uint32_t get_ss_entry_number_from_ss_info_tbl(
1982 struct bios_parser *bp,
1983 uint32_t id)
1984{
1985 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1986 ATOM_COMMON_TABLE_HEADER *header;
1987 uint32_t table_size;
1988 uint32_t i;
1989 uint32_t number = 0;
1990 uint32_t id_local = SS_ID_UNKNOWN;
1991 struct atom_data_revision revision;
1992
1993
1994 if (!DATA_TABLES(SS_Info))
1995 return number;
1996
1997 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1998 DATA_TABLES(SS_Info));
1999 get_atom_data_table_revision(header, &revision);
2000
2001 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO,
2002 DATA_TABLES(SS_Info));
2003
2004 if (1 != revision.major || 2 > revision.minor)
2005 return number;
2006
2007
2008 switch (id) {
2009 case ASIC_INTERNAL_SS_ON_DP:
2010 id_local = SS_ID_DP1;
2011 break;
2012 case ASIC_INTERNAL_SS_ON_LVDS: {
2013 struct embedded_panel_info panel_info;
2014
2015 if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
2016 == BP_RESULT_OK)
2017 id_local = panel_info.ss_id;
2018 break;
2019 }
2020 default:
2021 break;
2022 }
2023
2024 if (id_local == SS_ID_UNKNOWN)
2025 return number;
2026
2027 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
2028 sizeof(ATOM_COMMON_TABLE_HEADER)) /
2029 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
2030
2031 for (i = 0; i < table_size; i++)
2032 if (id_local == (uint32_t)tbl->asSS_Info[i].ucSS_Id) {
2033 number = 1;
2034 break;
2035 }
2036
2037 return number;
2038}
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050static uint32_t get_ss_entry_number(struct bios_parser *bp, uint32_t id)
2051{
2052 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
2053 return get_ss_entry_number_from_ss_info_tbl(bp, id);
2054
2055 return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp, id);
2056}
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
2068 struct bios_parser *bp,
2069 uint32_t id)
2070{
2071 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header_include;
2072 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
2073 uint32_t size;
2074 uint32_t i;
2075
2076 if (!DATA_TABLES(ASIC_InternalSS_Info))
2077 return 0;
2078
2079 header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
2080 DATA_TABLES(ASIC_InternalSS_Info));
2081
2082 size = (le16_to_cpu(header_include->sHeader.usStructureSize)
2083 - sizeof(ATOM_COMMON_TABLE_HEADER))
2084 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
2085
2086 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
2087 &header_include->asSpreadSpectrum[0];
2088 for (i = 0; i < size; i++)
2089 if (tbl[i].ucClockIndication == (uint8_t)id)
2090 return 1;
2091
2092 return 0;
2093}
2094
2095
2096
2097
2098
2099
2100
2101
2102static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
2103 struct bios_parser *bp,
2104 uint32_t id)
2105{
2106 uint32_t number = 0;
2107 ATOM_ASIC_INTERNAL_SS_INFO_V3 *header_include;
2108 ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
2109 uint32_t size;
2110 uint32_t i;
2111
2112 if (!DATA_TABLES(ASIC_InternalSS_Info))
2113 return number;
2114
2115 header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
2116 DATA_TABLES(ASIC_InternalSS_Info));
2117 size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
2118 sizeof(ATOM_COMMON_TABLE_HEADER)) /
2119 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
2120
2121 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
2122 &header_include->asSpreadSpectrum[0];
2123
2124 for (i = 0; i < size; i++)
2125 if (tbl[i].ucClockIndication == (uint8_t)id)
2126 number++;
2127
2128 return number;
2129}
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144static enum bp_result bios_parser_get_gpio_pin_info(
2145 struct dc_bios *dcb,
2146 uint32_t gpio_id,
2147 struct gpio_pin_info *info)
2148{
2149 struct bios_parser *bp = BP_FROM_DCB(dcb);
2150 ATOM_GPIO_PIN_LUT *header;
2151 uint32_t count = 0;
2152 uint32_t i = 0;
2153
2154 if (!DATA_TABLES(GPIO_Pin_LUT))
2155 return BP_RESULT_BADBIOSTABLE;
2156
2157 header = GET_IMAGE(ATOM_GPIO_PIN_LUT, DATA_TABLES(GPIO_Pin_LUT));
2158 if (!header)
2159 return BP_RESULT_BADBIOSTABLE;
2160
2161 if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_PIN_LUT)
2162 > le16_to_cpu(header->sHeader.usStructureSize))
2163 return BP_RESULT_BADBIOSTABLE;
2164
2165 if (1 != header->sHeader.ucTableContentRevision)
2166 return BP_RESULT_UNSUPPORTED;
2167
2168 count = (le16_to_cpu(header->sHeader.usStructureSize)
2169 - sizeof(ATOM_COMMON_TABLE_HEADER))
2170 / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
2171 for (i = 0; i < count; ++i) {
2172 if (header->asGPIO_Pin[i].ucGPIO_ID != gpio_id)
2173 continue;
2174
2175 info->offset =
2176 (uint32_t) le16_to_cpu(header->asGPIO_Pin[i].usGpioPin_AIndex);
2177 info->offset_y = info->offset + 2;
2178 info->offset_en = info->offset + 1;
2179 info->offset_mask = info->offset - 1;
2180
2181 info->mask = (uint32_t) (1 <<
2182 header->asGPIO_Pin[i].ucGpioPinBitShift);
2183 info->mask_y = info->mask + 2;
2184 info->mask_en = info->mask + 1;
2185 info->mask_mask = info->mask - 1;
2186
2187 return BP_RESULT_OK;
2188 }
2189
2190 return BP_RESULT_NORECORD;
2191}
2192
2193static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
2194 ATOM_I2C_RECORD *record,
2195 struct graphics_object_i2c_info *info)
2196{
2197 ATOM_GPIO_I2C_INFO *header;
2198 uint32_t count = 0;
2199
2200 if (!info)
2201 return BP_RESULT_BADINPUT;
2202
2203
2204 if (!DATA_TABLES(GPIO_I2C_Info))
2205 return BP_RESULT_BADBIOSTABLE;
2206
2207 header = GET_IMAGE(ATOM_GPIO_I2C_INFO, DATA_TABLES(GPIO_I2C_Info));
2208 if (!header)
2209 return BP_RESULT_BADBIOSTABLE;
2210
2211 if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_I2C_ASSIGMENT)
2212 > le16_to_cpu(header->sHeader.usStructureSize))
2213 return BP_RESULT_BADBIOSTABLE;
2214
2215 if (1 != header->sHeader.ucTableContentRevision)
2216 return BP_RESULT_UNSUPPORTED;
2217
2218
2219 count = (le16_to_cpu(header->sHeader.usStructureSize)
2220 - sizeof(ATOM_COMMON_TABLE_HEADER))
2221 / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
2222 if (count < record->sucI2cId.bfI2C_LineMux)
2223 return BP_RESULT_BADBIOSTABLE;
2224
2225
2226 info->i2c_hw_assist = record->sucI2cId.bfHW_Capable;
2227 info->i2c_line = record->sucI2cId.bfI2C_LineMux;
2228 info->i2c_engine_id = record->sucI2cId.bfHW_EngineID;
2229 info->i2c_slave_address = record->ucI2CAddr;
2230
2231 info->gpio_info.clk_mask_register_index =
2232 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkMaskRegisterIndex);
2233 info->gpio_info.clk_en_register_index =
2234 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkEnRegisterIndex);
2235 info->gpio_info.clk_y_register_index =
2236 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkY_RegisterIndex);
2237 info->gpio_info.clk_a_register_index =
2238 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkA_RegisterIndex);
2239 info->gpio_info.data_mask_register_index =
2240 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataMaskRegisterIndex);
2241 info->gpio_info.data_en_register_index =
2242 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataEnRegisterIndex);
2243 info->gpio_info.data_y_register_index =
2244 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataY_RegisterIndex);
2245 info->gpio_info.data_a_register_index =
2246 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataA_RegisterIndex);
2247
2248 info->gpio_info.clk_mask_shift =
2249 header->asGPIO_Info[info->i2c_line].ucClkMaskShift;
2250 info->gpio_info.clk_en_shift =
2251 header->asGPIO_Info[info->i2c_line].ucClkEnShift;
2252 info->gpio_info.clk_y_shift =
2253 header->asGPIO_Info[info->i2c_line].ucClkY_Shift;
2254 info->gpio_info.clk_a_shift =
2255 header->asGPIO_Info[info->i2c_line].ucClkA_Shift;
2256 info->gpio_info.data_mask_shift =
2257 header->asGPIO_Info[info->i2c_line].ucDataMaskShift;
2258 info->gpio_info.data_en_shift =
2259 header->asGPIO_Info[info->i2c_line].ucDataEnShift;
2260 info->gpio_info.data_y_shift =
2261 header->asGPIO_Info[info->i2c_line].ucDataY_Shift;
2262 info->gpio_info.data_a_shift =
2263 header->asGPIO_Info[info->i2c_line].ucDataA_Shift;
2264
2265 return BP_RESULT_OK;
2266}
2267
2268static bool dal_graphics_object_id_is_valid(struct graphics_object_id id)
2269{
2270 bool rc = true;
2271
2272 switch (id.type) {
2273 case OBJECT_TYPE_UNKNOWN:
2274 rc = false;
2275 break;
2276 case OBJECT_TYPE_GPU:
2277 case OBJECT_TYPE_ENGINE:
2278
2279 if (id.enum_id == ENUM_ID_UNKNOWN)
2280 rc = false;
2281 break;
2282 default:
2283 if (id.id == 0 || id.enum_id == ENUM_ID_UNKNOWN)
2284 rc = false;
2285 break;
2286 }
2287
2288 return rc;
2289}
2290
2291static bool dal_graphics_object_id_is_equal(
2292 struct graphics_object_id id1,
2293 struct graphics_object_id id2)
2294{
2295 if (false == dal_graphics_object_id_is_valid(id1)) {
2296 dm_output_to_console(
2297 "%s: Warning: comparing invalid object 'id1'!\n", __func__);
2298 return false;
2299 }
2300
2301 if (false == dal_graphics_object_id_is_valid(id2)) {
2302 dm_output_to_console(
2303 "%s: Warning: comparing invalid object 'id2'!\n", __func__);
2304 return false;
2305 }
2306
2307 if (id1.id == id2.id && id1.enum_id == id2.enum_id
2308 && id1.type == id2.type)
2309 return true;
2310
2311 return false;
2312}
2313
2314static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
2315 struct graphics_object_id id)
2316{
2317 uint32_t offset;
2318 ATOM_OBJECT_TABLE *tbl;
2319 uint32_t i;
2320
2321 switch (id.type) {
2322 case OBJECT_TYPE_ENCODER:
2323 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
2324 break;
2325
2326 case OBJECT_TYPE_CONNECTOR:
2327 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
2328 break;
2329
2330 case OBJECT_TYPE_ROUTER:
2331 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usRouterObjectTableOffset);
2332 break;
2333
2334 case OBJECT_TYPE_GENERIC:
2335 if (bp->object_info_tbl.revision.minor < 3)
2336 return NULL;
2337 offset = le16_to_cpu(bp->object_info_tbl.v1_3->usMiscObjectTableOffset);
2338 break;
2339
2340 default:
2341 return NULL;
2342 }
2343
2344 offset += bp->object_info_tbl_offset;
2345
2346 tbl = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
2347 if (!tbl)
2348 return NULL;
2349
2350 for (i = 0; i < tbl->ucNumberOfObjects; i++)
2351 if (dal_graphics_object_id_is_equal(id,
2352 object_id_from_bios_object_id(
2353 le16_to_cpu(tbl->asObjects[i].usObjectID))))
2354 return &tbl->asObjects[i];
2355
2356 return NULL;
2357}
2358
2359static uint32_t get_dest_obj_list(struct bios_parser *bp,
2360 ATOM_OBJECT *object, uint16_t **id_list)
2361{
2362 uint32_t offset;
2363 uint8_t *number;
2364
2365 if (!object) {
2366 BREAK_TO_DEBUGGER();
2367 return 0;
2368 }
2369
2370 offset = le16_to_cpu(object->usSrcDstTableOffset)
2371 + bp->object_info_tbl_offset;
2372
2373 number = GET_IMAGE(uint8_t, offset);
2374 if (!number)
2375 return 0;
2376
2377 offset += sizeof(uint8_t);
2378 offset += sizeof(uint16_t) * (*number);
2379
2380 number = GET_IMAGE(uint8_t, offset);
2381 if ((!number) || (!*number))
2382 return 0;
2383
2384 offset += sizeof(uint8_t);
2385 *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
2386
2387 if (!*id_list)
2388 return 0;
2389
2390 return *number;
2391}
2392
2393static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
2394 uint16_t **id_list)
2395{
2396 uint32_t offset;
2397 uint8_t *number;
2398
2399 if (!object) {
2400 BREAK_TO_DEBUGGER();
2401 return 0;
2402 }
2403
2404 offset = le16_to_cpu(object->usSrcDstTableOffset)
2405 + bp->object_info_tbl_offset;
2406
2407 number = GET_IMAGE(uint8_t, offset);
2408 if (!number)
2409 return 0;
2410
2411 offset += sizeof(uint8_t);
2412 *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
2413
2414 if (!*id_list)
2415 return 0;
2416
2417 return *number;
2418}
2419
2420static uint32_t get_dst_number_from_object(struct bios_parser *bp,
2421 ATOM_OBJECT *object)
2422{
2423 uint32_t offset;
2424 uint8_t *number;
2425
2426 if (!object) {
2427 BREAK_TO_DEBUGGER();
2428 return 0;
2429 }
2430
2431 offset = le16_to_cpu(object->usSrcDstTableOffset)
2432 + bp->object_info_tbl_offset;
2433
2434 number = GET_IMAGE(uint8_t, offset);
2435 if (!number)
2436 return 0;
2437
2438 offset += sizeof(uint8_t);
2439 offset += sizeof(uint16_t) * (*number);
2440
2441 number = GET_IMAGE(uint8_t, offset);
2442
2443 if (!number)
2444 return 0;
2445
2446 return *number;
2447}
2448
2449static struct device_id device_type_from_device_id(uint16_t device_id)
2450{
2451
2452 struct device_id result_device_id;
2453
2454 switch (device_id) {
2455 case ATOM_DEVICE_LCD1_SUPPORT:
2456 result_device_id.device_type = DEVICE_TYPE_LCD;
2457 result_device_id.enum_id = 1;
2458 break;
2459
2460 case ATOM_DEVICE_LCD2_SUPPORT:
2461 result_device_id.device_type = DEVICE_TYPE_LCD;
2462 result_device_id.enum_id = 2;
2463 break;
2464
2465 case ATOM_DEVICE_CRT1_SUPPORT:
2466 result_device_id.device_type = DEVICE_TYPE_CRT;
2467 result_device_id.enum_id = 1;
2468 break;
2469
2470 case ATOM_DEVICE_CRT2_SUPPORT:
2471 result_device_id.device_type = DEVICE_TYPE_CRT;
2472 result_device_id.enum_id = 2;
2473 break;
2474
2475 case ATOM_DEVICE_DFP1_SUPPORT:
2476 result_device_id.device_type = DEVICE_TYPE_DFP;
2477 result_device_id.enum_id = 1;
2478 break;
2479
2480 case ATOM_DEVICE_DFP2_SUPPORT:
2481 result_device_id.device_type = DEVICE_TYPE_DFP;
2482 result_device_id.enum_id = 2;
2483 break;
2484
2485 case ATOM_DEVICE_DFP3_SUPPORT:
2486 result_device_id.device_type = DEVICE_TYPE_DFP;
2487 result_device_id.enum_id = 3;
2488 break;
2489
2490 case ATOM_DEVICE_DFP4_SUPPORT:
2491 result_device_id.device_type = DEVICE_TYPE_DFP;
2492 result_device_id.enum_id = 4;
2493 break;
2494
2495 case ATOM_DEVICE_DFP5_SUPPORT:
2496 result_device_id.device_type = DEVICE_TYPE_DFP;
2497 result_device_id.enum_id = 5;
2498 break;
2499
2500 case ATOM_DEVICE_DFP6_SUPPORT:
2501 result_device_id.device_type = DEVICE_TYPE_DFP;
2502 result_device_id.enum_id = 6;
2503 break;
2504
2505 default:
2506 BREAK_TO_DEBUGGER();
2507 result_device_id.device_type = DEVICE_TYPE_UNKNOWN;
2508 result_device_id.enum_id = 0;
2509 }
2510 return result_device_id;
2511}
2512
2513static void get_atom_data_table_revision(
2514 ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
2515 struct atom_data_revision *tbl_revision)
2516{
2517 if (!tbl_revision)
2518 return;
2519
2520
2521 tbl_revision->major = 0;
2522 tbl_revision->minor = 0;
2523
2524 if (!atom_data_tbl)
2525 return;
2526
2527 tbl_revision->major =
2528 (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl);
2529 tbl_revision->minor =
2530 (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl);
2531}
2532
2533static uint32_t signal_to_ss_id(enum as_signal_type signal)
2534{
2535 uint32_t clk_id_ss = 0;
2536
2537 switch (signal) {
2538 case AS_SIGNAL_TYPE_DVI:
2539 clk_id_ss = ASIC_INTERNAL_SS_ON_TMDS;
2540 break;
2541 case AS_SIGNAL_TYPE_HDMI:
2542 clk_id_ss = ASIC_INTERNAL_SS_ON_HDMI;
2543 break;
2544 case AS_SIGNAL_TYPE_LVDS:
2545 clk_id_ss = ASIC_INTERNAL_SS_ON_LVDS;
2546 break;
2547 case AS_SIGNAL_TYPE_DISPLAY_PORT:
2548 clk_id_ss = ASIC_INTERNAL_SS_ON_DP;
2549 break;
2550 case AS_SIGNAL_TYPE_GPU_PLL:
2551 clk_id_ss = ASIC_INTERNAL_GPUPLL_SS;
2552 break;
2553 default:
2554 break;
2555 }
2556 return clk_id_ss;
2557}
2558
2559static uint32_t get_support_mask_for_device_id(struct device_id device_id)
2560{
2561 enum dal_device_type device_type = device_id.device_type;
2562 uint32_t enum_id = device_id.enum_id;
2563
2564 switch (device_type) {
2565 case DEVICE_TYPE_LCD:
2566 switch (enum_id) {
2567 case 1:
2568 return ATOM_DEVICE_LCD1_SUPPORT;
2569 case 2:
2570 return ATOM_DEVICE_LCD2_SUPPORT;
2571 default:
2572 break;
2573 }
2574 break;
2575 case DEVICE_TYPE_CRT:
2576 switch (enum_id) {
2577 case 1:
2578 return ATOM_DEVICE_CRT1_SUPPORT;
2579 case 2:
2580 return ATOM_DEVICE_CRT2_SUPPORT;
2581 default:
2582 break;
2583 }
2584 break;
2585 case DEVICE_TYPE_DFP:
2586 switch (enum_id) {
2587 case 1:
2588 return ATOM_DEVICE_DFP1_SUPPORT;
2589 case 2:
2590 return ATOM_DEVICE_DFP2_SUPPORT;
2591 case 3:
2592 return ATOM_DEVICE_DFP3_SUPPORT;
2593 case 4:
2594 return ATOM_DEVICE_DFP4_SUPPORT;
2595 case 5:
2596 return ATOM_DEVICE_DFP5_SUPPORT;
2597 case 6:
2598 return ATOM_DEVICE_DFP6_SUPPORT;
2599 default:
2600 break;
2601 }
2602 break;
2603 case DEVICE_TYPE_CV:
2604 switch (enum_id) {
2605 case 1:
2606 return ATOM_DEVICE_CV_SUPPORT;
2607 default:
2608 break;
2609 }
2610 break;
2611 case DEVICE_TYPE_TV:
2612 switch (enum_id) {
2613 case 1:
2614 return ATOM_DEVICE_TV1_SUPPORT;
2615 default:
2616 break;
2617 }
2618 break;
2619 default:
2620 break;
2621 };
2622
2623
2624 return 0;
2625}
2626
2627
2628
2629
2630
2631static bool i2c_read(
2632 struct bios_parser *bp,
2633 struct graphics_object_i2c_info *i2c_info,
2634 uint8_t *buffer,
2635 uint32_t length)
2636{
2637 struct ddc *ddc;
2638 uint8_t offset[2] = { 0, 0 };
2639 bool result = false;
2640 struct i2c_command cmd;
2641 struct gpio_ddc_hw_info hw_info = {
2642 i2c_info->i2c_hw_assist,
2643 i2c_info->i2c_line };
2644
2645 ddc = dal_gpio_create_ddc(bp->base.ctx->gpio_service,
2646 i2c_info->gpio_info.clk_a_register_index,
2647 (1 << i2c_info->gpio_info.clk_a_shift), &hw_info);
2648
2649 if (!ddc)
2650 return result;
2651
2652
2653 cmd.engine = I2C_COMMAND_ENGINE_SW;
2654 cmd.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
2655
2656 {
2657 struct i2c_payload payloads[] = {
2658 {
2659 .address = i2c_info->i2c_slave_address >> 1,
2660 .data = offset,
2661 .length = sizeof(offset),
2662 .write = true
2663 },
2664 {
2665 .address = i2c_info->i2c_slave_address >> 1,
2666 .data = buffer,
2667 .length = length,
2668 .write = false
2669 }
2670 };
2671
2672 cmd.payloads = payloads;
2673 cmd.number_of_payloads = ARRAY_SIZE(payloads);
2674
2675
2676 result = dal_i2caux_submit_i2c_command(
2677 ddc->ctx->i2caux,
2678 ddc,
2679 &cmd);
2680 }
2681
2682 dal_gpio_destroy_ddc(&ddc);
2683
2684 return result;
2685}
2686
2687
2688
2689
2690
2691
2692
2693static enum bp_result get_ext_display_connection_info(
2694 struct bios_parser *bp,
2695 ATOM_OBJECT *opm_object,
2696 ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *ext_display_connection_info_tbl)
2697{
2698 bool config_tbl_present = false;
2699 ATOM_I2C_RECORD *i2c_record = NULL;
2700 uint32_t i = 0;
2701
2702 if (opm_object == NULL)
2703 return BP_RESULT_BADINPUT;
2704
2705 i2c_record = get_i2c_record(bp, opm_object);
2706
2707 if (i2c_record != NULL) {
2708 ATOM_GPIO_I2C_INFO *gpio_i2c_header;
2709 struct graphics_object_i2c_info i2c_info;
2710
2711 gpio_i2c_header = GET_IMAGE(ATOM_GPIO_I2C_INFO,
2712 bp->master_data_tbl->ListOfDataTables.GPIO_I2C_Info);
2713
2714 if (NULL == gpio_i2c_header)
2715 return BP_RESULT_BADBIOSTABLE;
2716
2717 if (get_gpio_i2c_info(bp, i2c_record, &i2c_info) !=
2718 BP_RESULT_OK)
2719 return BP_RESULT_BADBIOSTABLE;
2720
2721 if (i2c_read(bp,
2722 &i2c_info,
2723 (uint8_t *)ext_display_connection_info_tbl,
2724 sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO))) {
2725 config_tbl_present = true;
2726 }
2727 }
2728
2729
2730 if (config_tbl_present)
2731 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; i++) {
2732 if (ext_display_connection_info_tbl->ucGuid[i]
2733 != ext_display_connection_guid[i]) {
2734 config_tbl_present = false;
2735 break;
2736 }
2737 }
2738
2739
2740 if (config_tbl_present) {
2741 uint8_t check_sum = 0;
2742 uint8_t *buf =
2743 (uint8_t *)ext_display_connection_info_tbl;
2744
2745 for (i = 0; i < sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO);
2746 i++) {
2747 check_sum += buf[i];
2748 }
2749
2750 if (check_sum != 0)
2751 config_tbl_present = false;
2752 }
2753
2754 if (config_tbl_present)
2755 return BP_RESULT_OK;
2756 else
2757 return BP_RESULT_FAILURE;
2758}
2759
2760
2761
2762
2763
2764
2765
2766
2767static uint32_t enum_first_device_id(uint32_t dev_id)
2768{
2769
2770 if (dev_id & ATOM_DEVICE_CRT_SUPPORT)
2771 return ATOM_DEVICE_CRT1_SUPPORT;
2772 else if (dev_id & ATOM_DEVICE_DFP_SUPPORT)
2773 return ATOM_DEVICE_DFP1_SUPPORT;
2774 else if (dev_id & ATOM_DEVICE_LCD_SUPPORT)
2775 return ATOM_DEVICE_LCD1_SUPPORT;
2776 else if (dev_id & ATOM_DEVICE_TV_SUPPORT)
2777 return ATOM_DEVICE_TV1_SUPPORT;
2778 else if (dev_id & ATOM_DEVICE_CV_SUPPORT)
2779 return ATOM_DEVICE_CV_SUPPORT;
2780
2781
2782
2783 dm_error("%s: incorrect input %d\n", __func__, dev_id);
2784
2785 return 0;
2786}
2787
2788
2789
2790
2791
2792
2793
2794
2795static uint32_t enum_next_dev_id(uint32_t dev_id)
2796{
2797
2798 switch (dev_id) {
2799 case ATOM_DEVICE_CRT1_SUPPORT:
2800 return ATOM_DEVICE_CRT2_SUPPORT;
2801 case ATOM_DEVICE_LCD1_SUPPORT:
2802 return ATOM_DEVICE_LCD2_SUPPORT;
2803 case ATOM_DEVICE_DFP1_SUPPORT:
2804 return ATOM_DEVICE_DFP2_SUPPORT;
2805 case ATOM_DEVICE_DFP2_SUPPORT:
2806 return ATOM_DEVICE_DFP3_SUPPORT;
2807 case ATOM_DEVICE_DFP3_SUPPORT:
2808 return ATOM_DEVICE_DFP4_SUPPORT;
2809 case ATOM_DEVICE_DFP4_SUPPORT:
2810 return ATOM_DEVICE_DFP5_SUPPORT;
2811 case ATOM_DEVICE_DFP5_SUPPORT:
2812 return ATOM_DEVICE_DFP6_SUPPORT;
2813 }
2814
2815
2816 return 0;
2817}
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828static bool get_patched_device_tag(
2829 struct bios_parser *bp,
2830 EXT_DISPLAY_PATH *ext_display_path,
2831 uint32_t device_support,
2832 ATOM_CONNECTOR_DEVICE_TAG *device_tag)
2833{
2834 uint32_t dev_id;
2835
2836 if (!bp->remap_device_tags) {
2837 device_tag->ulACPIDeviceEnum =
2838 cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
2839 device_tag->usDeviceID =
2840 cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceTag));
2841 return true;
2842 }
2843
2844
2845 dev_id = enum_first_device_id(le16_to_cpu(ext_display_path->usDeviceTag));
2846 while (dev_id != 0) {
2847
2848 if ((device_support & dev_id) != 0) {
2849 device_tag->ulACPIDeviceEnum =
2850 cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
2851 device_tag->usDeviceID = cpu_to_le16((USHORT) dev_id);
2852 return true;
2853 }
2854
2855 dev_id = enum_next_dev_id(dev_id);
2856 }
2857
2858
2859 return false;
2860}
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870static void add_device_tag_from_ext_display_path(
2871 struct bios_parser *bp,
2872 ATOM_OBJECT *object,
2873 EXT_DISPLAY_PATH *ext_display_path,
2874 uint32_t *device_support)
2875{
2876
2877 ATOM_CONNECTOR_DEVICE_TAG *device_tag = NULL;
2878 ATOM_CONNECTOR_DEVICE_TAG_RECORD *device_tag_record = NULL;
2879 enum bp_result result =
2880 bios_parser_get_device_tag_record(
2881 bp, object, &device_tag_record);
2882
2883 if ((le16_to_cpu(ext_display_path->usDeviceTag) != CONNECTOR_OBJECT_ID_NONE)
2884 && (result == BP_RESULT_OK)) {
2885 uint8_t index;
2886
2887 if ((device_tag_record->ucNumberOfDevice == 1) &&
2888 (le16_to_cpu(device_tag_record->asDeviceTag[0].usDeviceID) == 0)) {
2889
2890
2891
2892
2893 device_tag_record->ucNumberOfDevice =
2894 device_tag_record->ucNumberOfDevice - 1;
2895 }
2896
2897
2898 index = device_tag_record->ucNumberOfDevice;
2899 device_tag = &device_tag_record->asDeviceTag[index];
2900 if (get_patched_device_tag(
2901 bp,
2902 ext_display_path,
2903 *device_support,
2904 device_tag)) {
2905
2906
2907 *device_support &= ~le16_to_cpu(device_tag->usDeviceID);
2908 device_tag_record->ucNumberOfDevice++;
2909 }
2910 }
2911}
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921#define INVALID_CONNECTOR 0xffff
2922
2923static EXT_DISPLAY_PATH *get_ext_display_path_entry(
2924 ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *config_table,
2925 uint32_t bios_object_id)
2926{
2927 EXT_DISPLAY_PATH *ext_display_path;
2928 uint32_t ext_display_path_index =
2929 ((bios_object_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT) - 1;
2930
2931 if (ext_display_path_index >= MAX_NUMBER_OF_EXT_DISPLAY_PATH)
2932 return NULL;
2933
2934 ext_display_path = &config_table->sPath[ext_display_path_index];
2935
2936 if (le16_to_cpu(ext_display_path->usDeviceConnector) == INVALID_CONNECTOR)
2937 ext_display_path->usDeviceConnector = cpu_to_le16(0);
2938
2939 return ext_display_path;
2940}
2941
2942
2943
2944
2945
2946
2947
2948static ATOM_CONNECTOR_AUXDDC_LUT_RECORD *get_ext_connector_aux_ddc_lut_record(
2949 struct bios_parser *bp,
2950 ATOM_OBJECT *object)
2951{
2952 uint32_t offset;
2953 ATOM_COMMON_RECORD_HEADER *header;
2954
2955 if (!object) {
2956 BREAK_TO_DEBUGGER();
2957
2958 return NULL;
2959 }
2960
2961 offset = le16_to_cpu(object->usRecordOffset)
2962 + bp->object_info_tbl_offset;
2963
2964 for (;;) {
2965 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
2966
2967 if (!header)
2968 return NULL;
2969
2970 if (LAST_RECORD_TYPE == header->ucRecordType ||
2971 0 == header->ucRecordSize)
2972 break;
2973
2974 if (ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE ==
2975 header->ucRecordType &&
2976 sizeof(ATOM_CONNECTOR_AUXDDC_LUT_RECORD) <=
2977 header->ucRecordSize)
2978 return (ATOM_CONNECTOR_AUXDDC_LUT_RECORD *)(header);
2979
2980 offset += header->ucRecordSize;
2981 }
2982
2983 return NULL;
2984}
2985
2986
2987
2988
2989
2990
2991
2992static ATOM_CONNECTOR_HPDPIN_LUT_RECORD *get_ext_connector_hpd_pin_lut_record(
2993 struct bios_parser *bp,
2994 ATOM_OBJECT *object)
2995{
2996 uint32_t offset;
2997 ATOM_COMMON_RECORD_HEADER *header;
2998
2999 if (!object) {
3000 BREAK_TO_DEBUGGER();
3001
3002 return NULL;
3003 }
3004
3005 offset = le16_to_cpu(object->usRecordOffset)
3006 + bp->object_info_tbl_offset;
3007
3008 for (;;) {
3009 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
3010
3011 if (!header)
3012 return NULL;
3013
3014 if (LAST_RECORD_TYPE == header->ucRecordType ||
3015 0 == header->ucRecordSize)
3016 break;
3017
3018 if (ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE ==
3019 header->ucRecordType &&
3020 sizeof(ATOM_CONNECTOR_HPDPIN_LUT_RECORD) <=
3021 header->ucRecordSize)
3022 return (ATOM_CONNECTOR_HPDPIN_LUT_RECORD *)header;
3023
3024 offset += header->ucRecordSize;
3025 }
3026
3027 return NULL;
3028}
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040static enum bp_result patch_bios_image_from_ext_display_connection_info(
3041 struct bios_parser *bp)
3042{
3043 ATOM_OBJECT_TABLE *connector_tbl;
3044 uint32_t connector_tbl_offset;
3045 struct graphics_object_id object_id;
3046 ATOM_OBJECT *object;
3047 ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO ext_display_connection_info_tbl;
3048 EXT_DISPLAY_PATH *ext_display_path;
3049 ATOM_CONNECTOR_AUXDDC_LUT_RECORD *aux_ddc_lut_record = NULL;
3050 ATOM_I2C_RECORD *i2c_record = NULL;
3051 ATOM_CONNECTOR_HPDPIN_LUT_RECORD *hpd_pin_lut_record = NULL;
3052 ATOM_HPD_INT_RECORD *hpd_record = NULL;
3053 ATOM_OBJECT_TABLE *encoder_table;
3054 uint32_t encoder_table_offset;
3055 ATOM_OBJECT *opm_object = NULL;
3056 uint32_t i = 0;
3057 struct graphics_object_id opm_object_id =
3058 dal_graphics_object_id_init(
3059 GENERIC_ID_MXM_OPM,
3060 ENUM_ID_1,
3061 OBJECT_TYPE_GENERIC);
3062 ATOM_CONNECTOR_DEVICE_TAG_RECORD *dev_tag_record;
3063 uint32_t cached_device_support =
3064 le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport);
3065
3066 uint32_t dst_number;
3067 uint16_t *dst_object_id_list;
3068
3069 opm_object = get_bios_object(bp, opm_object_id);
3070 if (!opm_object)
3071 return BP_RESULT_UNSUPPORTED;
3072
3073 memset(&ext_display_connection_info_tbl, 0,
3074 sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO));
3075
3076 connector_tbl_offset = bp->object_info_tbl_offset
3077 + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
3078 connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
3079
3080
3081 if (get_ext_display_connection_info(bp,
3082 opm_object,
3083 &ext_display_connection_info_tbl) != BP_RESULT_OK) {
3084
3085 DC_LOG_WARNING("%s: Failed to read Connection Info Table", __func__);
3086 return BP_RESULT_UNSUPPORTED;
3087 }
3088
3089
3090 aux_ddc_lut_record =
3091 get_ext_connector_aux_ddc_lut_record(bp, opm_object);
3092 hpd_pin_lut_record =
3093 get_ext_connector_hpd_pin_lut_record(bp, opm_object);
3094
3095 if ((aux_ddc_lut_record == NULL) || (hpd_pin_lut_record == NULL))
3096 return BP_RESULT_UNSUPPORTED;
3097
3098
3099 if (bp->remap_device_tags) {
3100 for (i = 0; i < connector_tbl->ucNumberOfObjects; ++i) {
3101 uint32_t j;
3102
3103 object = &connector_tbl->asObjects[i];
3104 object_id = object_id_from_bios_object_id(
3105 le16_to_cpu(object->usObjectID));
3106 if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
3107 (CONNECTOR_ID_MXM == object_id.id))
3108 continue;
3109
3110
3111 if (bios_parser_get_device_tag_record(
3112 bp, object, &dev_tag_record) != BP_RESULT_OK)
3113 continue;
3114
3115 for (j = 0; j < dev_tag_record->ucNumberOfDevice; ++j) {
3116 ATOM_CONNECTOR_DEVICE_TAG *device_tag =
3117 &dev_tag_record->asDeviceTag[j];
3118 cached_device_support &=
3119 ~le16_to_cpu(device_tag->usDeviceID);
3120 }
3121 }
3122 }
3123
3124
3125
3126 for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
3127 uint32_t j;
3128
3129 object = &connector_tbl->asObjects[i];
3130 object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
3131 if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
3132 (CONNECTOR_ID_MXM != object_id.id))
3133 continue;
3134
3135
3136
3137 ext_display_path = get_ext_display_path_entry(
3138 &ext_display_connection_info_tbl,
3139 le16_to_cpu(object->usObjectID));
3140 if (!ext_display_path)
3141 return BP_RESULT_FAILURE;
3142
3143
3144 object->usObjectID =
3145 cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceConnector));
3146
3147
3148 add_device_tag_from_ext_display_path(
3149 bp,
3150 object,
3151 ext_display_path,
3152 &cached_device_support);
3153
3154
3155 if (ext_display_path->ucExtHPDPINLutIndex <
3156 MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES) {
3157 hpd_record = get_hpd_record(bp, object);
3158 if (hpd_record) {
3159 uint8_t index =
3160 ext_display_path->ucExtHPDPINLutIndex;
3161 hpd_record->ucHPDIntGPIOID =
3162 hpd_pin_lut_record->ucHPDPINMap[index];
3163 } else {
3164 BREAK_TO_DEBUGGER();
3165
3166 return BP_RESULT_FAILURE;
3167 }
3168 }
3169
3170
3171 if (ext_display_path->ucExtHPDPINLutIndex <
3172 MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES) {
3173 i2c_record = get_i2c_record(bp, object);
3174 if (i2c_record) {
3175 uint8_t index =
3176 ext_display_path->ucExtAUXDDCLutIndex;
3177 i2c_record->sucI2cId =
3178 aux_ddc_lut_record->ucAUXDDCMap[index];
3179 } else {
3180 BREAK_TO_DEBUGGER();
3181
3182 return BP_RESULT_FAILURE;
3183 }
3184 }
3185
3186
3187
3188 for (j = i + 1;
3189 j < connector_tbl->ucNumberOfObjects; j++) {
3190 ATOM_OBJECT *next_object;
3191 struct graphics_object_id next_object_id;
3192 EXT_DISPLAY_PATH *next_ext_display_path;
3193
3194 next_object = &connector_tbl->asObjects[j];
3195 next_object_id = object_id_from_bios_object_id(
3196 le16_to_cpu(next_object->usObjectID));
3197
3198 if ((OBJECT_TYPE_CONNECTOR != next_object_id.type) &&
3199 (CONNECTOR_ID_MXM == next_object_id.id))
3200 continue;
3201
3202 next_ext_display_path = get_ext_display_path_entry(
3203 &ext_display_connection_info_tbl,
3204 le16_to_cpu(next_object->usObjectID));
3205
3206 if (next_ext_display_path == NULL)
3207 return BP_RESULT_FAILURE;
3208
3209
3210 if ((le16_to_cpu(next_ext_display_path->usDeviceConnector) ==
3211 le16_to_cpu(ext_display_path->usDeviceConnector)) &&
3212 (le16_to_cpu(ext_display_path->usDeviceConnector) != 0)) {
3213
3214 next_object->usObjectID = cpu_to_le16(0);
3215 add_device_tag_from_ext_display_path(
3216 bp,
3217 object,
3218 ext_display_path,
3219 &cached_device_support);
3220 }
3221 }
3222 }
3223
3224
3225
3226
3227
3228 encoder_table_offset = bp->object_info_tbl_offset
3229 + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
3230 encoder_table = GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
3231
3232 for (i = 0; i < encoder_table->ucNumberOfObjects; i++) {
3233 uint32_t j;
3234
3235 object = &encoder_table->asObjects[i];
3236
3237 dst_number = get_dest_obj_list(bp, object, &dst_object_id_list);
3238
3239 for (j = 0; j < dst_number; j++) {
3240 object_id = object_id_from_bios_object_id(
3241 dst_object_id_list[j]);
3242
3243 if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
3244 (CONNECTOR_ID_MXM != object_id.id))
3245 continue;
3246
3247
3248
3249 ext_display_path =
3250 get_ext_display_path_entry(
3251 &ext_display_connection_info_tbl,
3252 dst_object_id_list[j]);
3253
3254 if (ext_display_path == NULL)
3255 return BP_RESULT_FAILURE;
3256
3257 dst_object_id_list[j] =
3258 le16_to_cpu(ext_display_path->usDeviceConnector);
3259 }
3260 }
3261
3262 return BP_RESULT_OK;
3263}
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276static void process_ext_display_connection_info(struct bios_parser *bp)
3277{
3278 ATOM_OBJECT_TABLE *connector_tbl;
3279 uint32_t connector_tbl_offset;
3280 struct graphics_object_id object_id;
3281 ATOM_OBJECT *object;
3282 bool mxm_connector_found = false;
3283 bool null_entry_found = false;
3284 uint32_t i = 0;
3285
3286 connector_tbl_offset = bp->object_info_tbl_offset +
3287 le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
3288 connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
3289
3290
3291
3292
3293 for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
3294 object = &connector_tbl->asObjects[i];
3295 object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
3296
3297 if ((OBJECT_TYPE_CONNECTOR == object_id.type) &&
3298 (CONNECTOR_ID_MXM == object_id.id)) {
3299
3300 mxm_connector_found = true;
3301 break;
3302 } else if (OBJECT_TYPE_CONNECTOR != object_id.type) {
3303
3304
3305 null_entry_found = true;
3306 }
3307 }
3308
3309
3310 if (mxm_connector_found || null_entry_found) {
3311 uint32_t connectors_num = 0;
3312 uint8_t *original_bios;
3313
3314
3315 bp->base.bios_local_image = kzalloc(bp->base.bios_size,
3316 GFP_KERNEL);
3317 if (bp->base.bios_local_image == NULL) {
3318 BREAK_TO_DEBUGGER();
3319
3320 return;
3321 }
3322
3323 memmove(bp->base.bios_local_image, bp->base.bios, bp->base.bios_size);
3324 original_bios = bp->base.bios;
3325 bp->base.bios = bp->base.bios_local_image;
3326 connector_tbl =
3327 GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
3328
3329
3330
3331 if (mxm_connector_found &&
3332 patch_bios_image_from_ext_display_connection_info(bp) !=
3333 BP_RESULT_OK) {
3334
3335
3336
3337 memmove(
3338 bp->base.bios_local_image,
3339 original_bios,
3340 bp->base.bios_size);
3341 }
3342
3343
3344
3345 for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
3346 object = &connector_tbl->asObjects[i];
3347 object_id = object_id_from_bios_object_id(
3348 le16_to_cpu(object->usObjectID));
3349
3350 if (OBJECT_TYPE_CONNECTOR != object_id.type)
3351 continue;
3352
3353 if (i != connectors_num) {
3354 memmove(
3355 &connector_tbl->
3356 asObjects[connectors_num],
3357 object,
3358 sizeof(ATOM_OBJECT));
3359 }
3360 ++connectors_num;
3361 }
3362 connector_tbl->ucNumberOfObjects = (uint8_t)connectors_num;
3363 }
3364}
3365
3366static void bios_parser_post_init(struct dc_bios *dcb)
3367{
3368 struct bios_parser *bp = BP_FROM_DCB(dcb);
3369
3370 process_ext_display_connection_info(bp);
3371}
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382static void bios_parser_set_scratch_critical_state(
3383 struct dc_bios *dcb,
3384 bool state)
3385{
3386 bios_set_scratch_critical_state(dcb, state);
3387}
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403static enum bp_result get_integrated_info_v8(
3404 struct bios_parser *bp,
3405 struct integrated_info *info)
3406{
3407 ATOM_INTEGRATED_SYSTEM_INFO_V1_8 *info_v8;
3408 uint32_t i;
3409
3410 info_v8 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8,
3411 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
3412
3413 if (info_v8 == NULL)
3414 return BP_RESULT_BADBIOSTABLE;
3415 info->boot_up_engine_clock = le32_to_cpu(info_v8->ulBootUpEngineClock) * 10;
3416 info->dentist_vco_freq = le32_to_cpu(info_v8->ulDentistVCOFreq) * 10;
3417 info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
3418
3419 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
3420
3421 info->disp_clk_voltage[i].max_supported_clk =
3422 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].
3423 ulMaximumSupportedCLK) * 10;
3424 info->disp_clk_voltage[i].voltage_index =
3425 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
3426 }
3427
3428 info->boot_up_req_display_vector =
3429 le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
3430 info->gpu_cap_info =
3431 le32_to_cpu(info_v8->ulGPUCapInfo);
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441 info->system_config = le32_to_cpu(info_v8->ulSystemConfig);
3442 info->cpu_cap_info = le32_to_cpu(info_v8->ulCPUCapInfo);
3443 info->boot_up_nb_voltage =
3444 le16_to_cpu(info_v8->usBootUpNBVoltage);
3445 info->ext_disp_conn_info_offset =
3446 le16_to_cpu(info_v8->usExtDispConnInfoOffset);
3447 info->memory_type = info_v8->ucMemoryType;
3448 info->ma_channel_number = info_v8->ucUMAChannelNumber;
3449 info->gmc_restore_reset_time =
3450 le32_to_cpu(info_v8->ulGMCRestoreResetTime);
3451
3452 info->minimum_n_clk =
3453 le32_to_cpu(info_v8->ulNbpStateNClkFreq[0]);
3454 for (i = 1; i < 4; ++i)
3455 info->minimum_n_clk =
3456 info->minimum_n_clk < le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]) ?
3457 info->minimum_n_clk : le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]);
3458
3459 info->idle_n_clk = le32_to_cpu(info_v8->ulIdleNClk);
3460 info->ddr_dll_power_up_time =
3461 le32_to_cpu(info_v8->ulDDR_DLL_PowerUpTime);
3462 info->ddr_pll_power_up_time =
3463 le32_to_cpu(info_v8->ulDDR_PLL_PowerUpTime);
3464 info->pcie_clk_ss_type = le16_to_cpu(info_v8->usPCIEClkSSType);
3465 info->lvds_ss_percentage =
3466 le16_to_cpu(info_v8->usLvdsSSPercentage);
3467 info->lvds_sspread_rate_in_10hz =
3468 le16_to_cpu(info_v8->usLvdsSSpreadRateIn10Hz);
3469 info->hdmi_ss_percentage =
3470 le16_to_cpu(info_v8->usHDMISSPercentage);
3471 info->hdmi_sspread_rate_in_10hz =
3472 le16_to_cpu(info_v8->usHDMISSpreadRateIn10Hz);
3473 info->dvi_ss_percentage =
3474 le16_to_cpu(info_v8->usDVISSPercentage);
3475 info->dvi_sspread_rate_in_10_hz =
3476 le16_to_cpu(info_v8->usDVISSpreadRateIn10Hz);
3477
3478 info->max_lvds_pclk_freq_in_single_link =
3479 le16_to_cpu(info_v8->usMaxLVDSPclkFreqInSingleLink);
3480 info->lvds_misc = info_v8->ucLvdsMisc;
3481 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
3482 info_v8->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
3483 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
3484 info_v8->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
3485 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
3486 info_v8->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
3487 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
3488 info_v8->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
3489 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
3490 info_v8->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
3491 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
3492 info_v8->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
3493 info->lvds_off_to_on_delay_in_4ms =
3494 info_v8->ucLVDSOffToOnDelay_in4Ms;
3495 info->lvds_bit_depth_control_val =
3496 le32_to_cpu(info_v8->ulLCDBitDepthControlVal);
3497
3498 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
3499
3500 info->avail_s_clk[i].supported_s_clk =
3501 le32_to_cpu(info_v8->sAvail_SCLK[i].ulSupportedSCLK) * 10;
3502 info->avail_s_clk[i].voltage_index =
3503 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageIndex);
3504 info->avail_s_clk[i].voltage_id =
3505 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageID);
3506 }
3507
3508 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
3509 info->ext_disp_conn_info.gu_id[i] =
3510 info_v8->sExtDispConnInfo.ucGuid[i];
3511 }
3512
3513 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
3514 info->ext_disp_conn_info.path[i].device_connector_id =
3515 object_id_from_bios_object_id(
3516 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceConnector));
3517
3518 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
3519 object_id_from_bios_object_id(
3520 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
3521
3522 info->ext_disp_conn_info.path[i].device_tag =
3523 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceTag);
3524 info->ext_disp_conn_info.path[i].device_acpi_enum =
3525 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
3526 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
3527 info_v8->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
3528 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
3529 info_v8->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
3530 info->ext_disp_conn_info.path[i].channel_mapping.raw =
3531 info_v8->sExtDispConnInfo.sPath[i].ucChannelMapping;
3532 }
3533 info->ext_disp_conn_info.checksum =
3534 info_v8->sExtDispConnInfo.ucChecksum;
3535
3536 return BP_RESULT_OK;
3537}
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553static enum bp_result get_integrated_info_v9(
3554 struct bios_parser *bp,
3555 struct integrated_info *info)
3556{
3557 ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info_v9;
3558 uint32_t i;
3559
3560 info_v9 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9,
3561 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
3562
3563 if (!info_v9)
3564 return BP_RESULT_BADBIOSTABLE;
3565
3566 info->boot_up_engine_clock = le32_to_cpu(info_v9->ulBootUpEngineClock) * 10;
3567 info->dentist_vco_freq = le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
3568 info->boot_up_uma_clock = le32_to_cpu(info_v9->ulBootUpUMAClock) * 10;
3569
3570 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
3571
3572 info->disp_clk_voltage[i].max_supported_clk =
3573 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
3574 info->disp_clk_voltage[i].voltage_index =
3575 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
3576 }
3577
3578 info->boot_up_req_display_vector =
3579 le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
3580 info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590 info->system_config = le32_to_cpu(info_v9->ulSystemConfig);
3591 info->cpu_cap_info = le32_to_cpu(info_v9->ulCPUCapInfo);
3592 info->boot_up_nb_voltage = le16_to_cpu(info_v9->usBootUpNBVoltage);
3593 info->ext_disp_conn_info_offset = le16_to_cpu(info_v9->usExtDispConnInfoOffset);
3594 info->memory_type = info_v9->ucMemoryType;
3595 info->ma_channel_number = info_v9->ucUMAChannelNumber;
3596 info->gmc_restore_reset_time = le32_to_cpu(info_v9->ulGMCRestoreResetTime);
3597
3598 info->minimum_n_clk = le32_to_cpu(info_v9->ulNbpStateNClkFreq[0]);
3599 for (i = 1; i < 4; ++i)
3600 info->minimum_n_clk =
3601 info->minimum_n_clk < le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]) ?
3602 info->minimum_n_clk : le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]);
3603
3604 info->idle_n_clk = le32_to_cpu(info_v9->ulIdleNClk);
3605 info->ddr_dll_power_up_time = le32_to_cpu(info_v9->ulDDR_DLL_PowerUpTime);
3606 info->ddr_pll_power_up_time = le32_to_cpu(info_v9->ulDDR_PLL_PowerUpTime);
3607 info->pcie_clk_ss_type = le16_to_cpu(info_v9->usPCIEClkSSType);
3608 info->lvds_ss_percentage = le16_to_cpu(info_v9->usLvdsSSPercentage);
3609 info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v9->usLvdsSSpreadRateIn10Hz);
3610 info->hdmi_ss_percentage = le16_to_cpu(info_v9->usHDMISSPercentage);
3611 info->hdmi_sspread_rate_in_10hz = le16_to_cpu(info_v9->usHDMISSpreadRateIn10Hz);
3612 info->dvi_ss_percentage = le16_to_cpu(info_v9->usDVISSPercentage);
3613 info->dvi_sspread_rate_in_10_hz = le16_to_cpu(info_v9->usDVISSpreadRateIn10Hz);
3614
3615 info->max_lvds_pclk_freq_in_single_link =
3616 le16_to_cpu(info_v9->usMaxLVDSPclkFreqInSingleLink);
3617 info->lvds_misc = info_v9->ucLvdsMisc;
3618 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
3619 info_v9->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
3620 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
3621 info_v9->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
3622 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
3623 info_v9->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
3624 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
3625 info_v9->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
3626 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
3627 info_v9->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
3628 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
3629 info_v9->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
3630 info->lvds_off_to_on_delay_in_4ms =
3631 info_v9->ucLVDSOffToOnDelay_in4Ms;
3632 info->lvds_bit_depth_control_val =
3633 le32_to_cpu(info_v9->ulLCDBitDepthControlVal);
3634
3635 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
3636
3637 info->avail_s_clk[i].supported_s_clk =
3638 le32_to_cpu(info_v9->sAvail_SCLK[i].ulSupportedSCLK) * 10;
3639 info->avail_s_clk[i].voltage_index =
3640 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageIndex);
3641 info->avail_s_clk[i].voltage_id =
3642 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageID);
3643 }
3644
3645 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
3646 info->ext_disp_conn_info.gu_id[i] =
3647 info_v9->sExtDispConnInfo.ucGuid[i];
3648 }
3649
3650 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
3651 info->ext_disp_conn_info.path[i].device_connector_id =
3652 object_id_from_bios_object_id(
3653 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceConnector));
3654
3655 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
3656 object_id_from_bios_object_id(
3657 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
3658
3659 info->ext_disp_conn_info.path[i].device_tag =
3660 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceTag);
3661 info->ext_disp_conn_info.path[i].device_acpi_enum =
3662 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
3663 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
3664 info_v9->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
3665 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
3666 info_v9->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
3667 info->ext_disp_conn_info.path[i].channel_mapping.raw =
3668 info_v9->sExtDispConnInfo.sPath[i].ucChannelMapping;
3669 }
3670 info->ext_disp_conn_info.checksum =
3671 info_v9->sExtDispConnInfo.ucChecksum;
3672
3673 return BP_RESULT_OK;
3674}
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690static enum bp_result construct_integrated_info(
3691 struct bios_parser *bp,
3692 struct integrated_info *info)
3693{
3694 enum bp_result result = BP_RESULT_BADBIOSTABLE;
3695
3696 ATOM_COMMON_TABLE_HEADER *header;
3697 struct atom_data_revision revision;
3698
3699 if (bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo) {
3700 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
3701 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
3702
3703 get_atom_data_table_revision(header, &revision);
3704
3705
3706 switch (revision.minor) {
3707 case 8:
3708 result = get_integrated_info_v8(bp, info);
3709 break;
3710 case 9:
3711 result = get_integrated_info_v9(bp, info);
3712 break;
3713 default:
3714 return result;
3715
3716 }
3717 }
3718
3719
3720 if (result == BP_RESULT_OK) {
3721 struct clock_voltage_caps temp = {0, 0};
3722 uint32_t i;
3723 uint32_t j;
3724
3725 for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
3726 for (j = i; j > 0; --j) {
3727 if (
3728 info->disp_clk_voltage[j].max_supported_clk <
3729 info->disp_clk_voltage[j-1].max_supported_clk) {
3730
3731 temp = info->disp_clk_voltage[j-1];
3732 info->disp_clk_voltage[j-1] =
3733 info->disp_clk_voltage[j];
3734 info->disp_clk_voltage[j] = temp;
3735 }
3736 }
3737 }
3738
3739 }
3740
3741 return result;
3742}
3743
3744static struct integrated_info *bios_parser_create_integrated_info(
3745 struct dc_bios *dcb)
3746{
3747 struct bios_parser *bp = BP_FROM_DCB(dcb);
3748 struct integrated_info *info = NULL;
3749
3750 info = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);
3751
3752 if (info == NULL) {
3753 ASSERT_CRITICAL(0);
3754 return NULL;
3755 }
3756
3757 if (construct_integrated_info(bp, info) == BP_RESULT_OK)
3758 return info;
3759
3760 kfree(info);
3761
3762 return NULL;
3763}
3764
3765enum bp_result update_slot_layout_info(
3766 struct dc_bios *dcb,
3767 unsigned int i,
3768 struct slot_layout_info *slot_layout_info,
3769 unsigned int record_offset)
3770{
3771 unsigned int j;
3772 struct bios_parser *bp;
3773 ATOM_BRACKET_LAYOUT_RECORD *record;
3774 ATOM_COMMON_RECORD_HEADER *record_header;
3775 enum bp_result result = BP_RESULT_NORECORD;
3776
3777 bp = BP_FROM_DCB(dcb);
3778 record = NULL;
3779 record_header = NULL;
3780
3781 for (;;) {
3782
3783 record_header = (ATOM_COMMON_RECORD_HEADER *)
3784 GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
3785 if (record_header == NULL) {
3786 result = BP_RESULT_BADBIOSTABLE;
3787 break;
3788 }
3789
3790
3791 if (record_header->ucRecordType == 0xff ||
3792 record_header->ucRecordSize == 0) {
3793 break;
3794 }
3795
3796 if (record_header->ucRecordType ==
3797 ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
3798 sizeof(ATOM_BRACKET_LAYOUT_RECORD)
3799 <= record_header->ucRecordSize) {
3800 record = (ATOM_BRACKET_LAYOUT_RECORD *)
3801 (record_header);
3802 result = BP_RESULT_OK;
3803 break;
3804 }
3805
3806 record_offset += record_header->ucRecordSize;
3807 }
3808
3809
3810 if (result != BP_RESULT_OK)
3811 return result;
3812
3813
3814 slot_layout_info->length = record->ucLength;
3815 slot_layout_info->width = record->ucWidth;
3816
3817
3818 slot_layout_info->num_of_connectors = record->ucConnNum;
3819 for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
3820 slot_layout_info->connectors[j].connector_type =
3821 (enum connector_layout_type)
3822 (record->asConnInfo[j].ucConnectorType);
3823 switch (record->asConnInfo[j].ucConnectorType) {
3824 case CONNECTOR_TYPE_DVI_D:
3825 slot_layout_info->connectors[j].connector_type =
3826 CONNECTOR_LAYOUT_TYPE_DVI_D;
3827 slot_layout_info->connectors[j].length =
3828 CONNECTOR_SIZE_DVI;
3829 break;
3830
3831 case CONNECTOR_TYPE_HDMI:
3832 slot_layout_info->connectors[j].connector_type =
3833 CONNECTOR_LAYOUT_TYPE_HDMI;
3834 slot_layout_info->connectors[j].length =
3835 CONNECTOR_SIZE_HDMI;
3836 break;
3837
3838 case CONNECTOR_TYPE_DISPLAY_PORT:
3839 slot_layout_info->connectors[j].connector_type =
3840 CONNECTOR_LAYOUT_TYPE_DP;
3841 slot_layout_info->connectors[j].length =
3842 CONNECTOR_SIZE_DP;
3843 break;
3844
3845 case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
3846 slot_layout_info->connectors[j].connector_type =
3847 CONNECTOR_LAYOUT_TYPE_MINI_DP;
3848 slot_layout_info->connectors[j].length =
3849 CONNECTOR_SIZE_MINI_DP;
3850 break;
3851
3852 default:
3853 slot_layout_info->connectors[j].connector_type =
3854 CONNECTOR_LAYOUT_TYPE_UNKNOWN;
3855 slot_layout_info->connectors[j].length =
3856 CONNECTOR_SIZE_UNKNOWN;
3857 }
3858
3859 slot_layout_info->connectors[j].position =
3860 record->asConnInfo[j].ucPosition;
3861 slot_layout_info->connectors[j].connector_id =
3862 object_id_from_bios_object_id(
3863 record->asConnInfo[j].usConnectorObjectId);
3864 }
3865 return result;
3866}
3867
3868
3869enum bp_result get_bracket_layout_record(
3870 struct dc_bios *dcb,
3871 unsigned int bracket_layout_id,
3872 struct slot_layout_info *slot_layout_info)
3873{
3874 unsigned int i;
3875 unsigned int record_offset;
3876 struct bios_parser *bp;
3877 enum bp_result result;
3878 ATOM_OBJECT *object;
3879 ATOM_OBJECT_TABLE *object_table;
3880 unsigned int genericTableOffset;
3881
3882 bp = BP_FROM_DCB(dcb);
3883 object = NULL;
3884 if (slot_layout_info == NULL) {
3885 DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
3886 return BP_RESULT_BADINPUT;
3887 }
3888
3889
3890 genericTableOffset = bp->object_info_tbl_offset +
3891 bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
3892 object_table = (ATOM_OBJECT_TABLE *)
3893 GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset);
3894 if (!object_table)
3895 return BP_RESULT_FAILURE;
3896
3897 result = BP_RESULT_NORECORD;
3898 for (i = 0; i < object_table->ucNumberOfObjects; ++i) {
3899
3900 if (bracket_layout_id ==
3901 object_table->asObjects[i].usObjectID) {
3902
3903 object = &object_table->asObjects[i];
3904 record_offset = object->usRecordOffset +
3905 bp->object_info_tbl_offset;
3906
3907 result = update_slot_layout_info(dcb, i,
3908 slot_layout_info, record_offset);
3909 break;
3910 }
3911 }
3912 return result;
3913}
3914
3915static enum bp_result bios_get_board_layout_info(
3916 struct dc_bios *dcb,
3917 struct board_layout_info *board_layout_info)
3918{
3919 unsigned int i;
3920 struct bios_parser *bp;
3921 enum bp_result record_result;
3922
3923 const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
3924 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
3925 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
3926 0, 0
3927 };
3928
3929 bp = BP_FROM_DCB(dcb);
3930 if (board_layout_info == NULL) {
3931 DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
3932 return BP_RESULT_BADINPUT;
3933 }
3934
3935 board_layout_info->num_of_slots = 0;
3936
3937 for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
3938 record_result = get_bracket_layout_record(dcb,
3939 slot_index_to_vbios_id[i],
3940 &board_layout_info->slots[i]);
3941
3942 if (record_result == BP_RESULT_NORECORD && i > 0)
3943 break;
3944 else if (record_result != BP_RESULT_OK)
3945 return record_result;
3946
3947 ++board_layout_info->num_of_slots;
3948 }
3949
3950
3951 board_layout_info->is_number_of_slots_valid = 1;
3952 board_layout_info->is_slots_size_valid = 1;
3953 board_layout_info->is_connector_offsets_valid = 1;
3954 board_layout_info->is_connector_lengths_valid = 1;
3955
3956 return BP_RESULT_OK;
3957}
3958
3959
3960
3961static const struct dc_vbios_funcs vbios_funcs = {
3962 .get_connectors_number = bios_parser_get_connectors_number,
3963
3964 .get_encoder_id = bios_parser_get_encoder_id,
3965
3966 .get_connector_id = bios_parser_get_connector_id,
3967
3968 .get_dst_number = bios_parser_get_dst_number,
3969
3970 .get_src_obj = bios_parser_get_src_obj,
3971
3972 .get_dst_obj = bios_parser_get_dst_obj,
3973
3974 .get_i2c_info = bios_parser_get_i2c_info,
3975
3976 .get_voltage_ddc_info = bios_parser_get_voltage_ddc_info,
3977
3978 .get_thermal_ddc_info = bios_parser_get_thermal_ddc_info,
3979
3980 .get_hpd_info = bios_parser_get_hpd_info,
3981
3982 .get_device_tag = bios_parser_get_device_tag,
3983
3984 .get_firmware_info = bios_parser_get_firmware_info,
3985
3986 .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info,
3987
3988 .get_ss_entry_number = bios_parser_get_ss_entry_number,
3989
3990 .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
3991
3992 .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
3993
3994 .get_encoder_cap_info = bios_parser_get_encoder_cap_info,
3995
3996
3997 .is_accelerated_mode = bios_is_accelerated_mode,
3998 .get_vga_enabled_displays = bios_get_vga_enabled_displays,
3999
4000 .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
4001
4002 .is_device_id_supported = bios_parser_is_device_id_supported,
4003
4004
4005 .encoder_control = bios_parser_encoder_control,
4006
4007 .transmitter_control = bios_parser_transmitter_control,
4008
4009 .crt_control = bios_parser_crt_control,
4010
4011 .enable_crtc = bios_parser_enable_crtc,
4012
4013 .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
4014
4015 .set_pixel_clock = bios_parser_set_pixel_clock,
4016
4017 .set_dce_clock = bios_parser_set_dce_clock,
4018
4019 .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
4020
4021 .program_crtc_timing = bios_parser_program_crtc_timing,
4022
4023 .crtc_source_select = bios_parser_crtc_source_select,
4024
4025 .program_display_engine_pll = bios_parser_program_display_engine_pll,
4026
4027 .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
4028
4029
4030 .post_init = bios_parser_post_init,
4031
4032 .bios_parser_destroy = bios_parser_destroy,
4033
4034 .get_board_layout_info = bios_get_board_layout_info,
4035};
4036
4037static bool bios_parser_construct(
4038 struct bios_parser *bp,
4039 struct bp_init_data *init,
4040 enum dce_version dce_version)
4041{
4042 uint16_t *rom_header_offset = NULL;
4043 ATOM_ROM_HEADER *rom_header = NULL;
4044 ATOM_OBJECT_HEADER *object_info_tbl;
4045 struct atom_data_revision tbl_rev = {0};
4046
4047 if (!init)
4048 return false;
4049
4050 if (!init->bios)
4051 return false;
4052
4053 bp->base.funcs = &vbios_funcs;
4054 bp->base.bios = init->bios;
4055 bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
4056
4057 bp->base.ctx = init->ctx;
4058 bp->base.bios_local_image = NULL;
4059
4060 rom_header_offset =
4061 GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
4062
4063 if (!rom_header_offset)
4064 return false;
4065
4066 rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
4067
4068 if (!rom_header)
4069 return false;
4070
4071 get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev);
4072 if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
4073 return false;
4074
4075 bp->master_data_tbl =
4076 GET_IMAGE(ATOM_MASTER_DATA_TABLE,
4077 rom_header->usMasterDataTableOffset);
4078
4079 if (!bp->master_data_tbl)
4080 return false;
4081
4082 bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
4083
4084 if (!bp->object_info_tbl_offset)
4085 return false;
4086
4087 object_info_tbl =
4088 GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
4089
4090 if (!object_info_tbl)
4091 return false;
4092
4093 get_atom_data_table_revision(&object_info_tbl->sHeader,
4094 &bp->object_info_tbl.revision);
4095
4096 if (bp->object_info_tbl.revision.major == 1
4097 && bp->object_info_tbl.revision.minor >= 3) {
4098 ATOM_OBJECT_HEADER_V3 *tbl_v3;
4099
4100 tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
4101 bp->object_info_tbl_offset);
4102 if (!tbl_v3)
4103 return false;
4104
4105 bp->object_info_tbl.v1_3 = tbl_v3;
4106 } else if (bp->object_info_tbl.revision.major == 1
4107 && bp->object_info_tbl.revision.minor >= 1)
4108 bp->object_info_tbl.v1_1 = object_info_tbl;
4109 else
4110 return false;
4111
4112 dal_bios_parser_init_cmd_tbl(bp);
4113 dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
4114
4115 bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base);
4116
4117 return true;
4118}
4119
4120
4121