xref: /dragonfly/sys/dev/drm/amd/display/dc/bios/bios_parser.c (revision 789731325bde747251c28a37e0a00ed4efb88c46)
1 /*
2  * Copyright 2012-15 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
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 /* TODO remove - only needed for default i2c speed */
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 /* GUID to validate external display connection info table (aka OPM module) */
56 static 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 
64 static void get_atom_data_table_revision(
65           ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
66           struct atom_data_revision *tbl_revision);
67 static uint32_t get_dst_number_from_object(struct bios_parser *bp,
68           ATOM_OBJECT *object);
69 static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
70           uint16_t **id_list);
71 static uint32_t get_dest_obj_list(struct bios_parser *bp,
72           ATOM_OBJECT *object, uint16_t **id_list);
73 static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
74           struct graphics_object_id id);
75 static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
76           ATOM_I2C_RECORD *record,
77           struct graphics_object_i2c_info *info);
78 static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
79           ATOM_OBJECT *object);
80 static struct device_id device_type_from_device_id(uint16_t device_id);
81 static uint32_t signal_to_ss_id(enum as_signal_type signal);
82 static uint32_t get_support_mask_for_device_id(struct device_id device_id);
83 static 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 /*****************************************************************************/
91 static bool bios_parser_construct(
92           struct bios_parser *bp,
93           struct bp_init_data *init,
94           enum dce_version dce_version);
95 
96 static uint8_t bios_parser_get_connectors_number(
97           struct dc_bios *dcb);
98 
99 static enum bp_result bios_parser_get_embedded_panel_info(
100           struct dc_bios *dcb,
101           struct embedded_panel_info *info);
102 
103 /*****************************************************************************/
104 
bios_parser_create(struct bp_init_data * init,enum dce_version dce_version)105 struct 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 
destruct(struct bios_parser * bp)123 static void destruct(struct bios_parser *bp)
124 {
125           kfree(bp->base.bios_local_image);
126           kfree(bp->base.integrated_info);
127 }
128 
bios_parser_destroy(struct dc_bios ** dcb)129 static 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 
get_number_of_objects(struct bios_parser * bp,uint32_t offset)144 static 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 
bios_parser_get_connectors_number(struct dc_bios * dcb)158 static 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 
bios_parser_get_encoder_id(struct dc_bios * dcb,uint32_t i)166 static 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 
bios_parser_get_connector_id(struct dc_bios * dcb,uint8_t i)189 static 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 
bios_parser_get_dst_number(struct dc_bios * dcb,struct graphics_object_id id)220 static 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 
bios_parser_get_src_obj(struct dc_bios * dcb,struct graphics_object_id object_id,uint32_t index,struct graphics_object_id * src_object_id)229 static 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(); /* Invalid object id */
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 
bios_parser_get_dst_obj(struct dc_bios * dcb,struct graphics_object_id object_id,uint32_t index,struct graphics_object_id * dest_object_id)258 static 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 
bios_parser_get_i2c_info(struct dc_bios * dcb,struct graphics_object_id id,struct graphics_object_i2c_info * info)282 static 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                               /* get the I2C info */
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 
get_voltage_ddc_info_v1(uint8_t * i2c_line,ATOM_COMMON_TABLE_HEADER * header,uint8_t * address)328 static 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 
get_voltage_ddc_info_v3(uint8_t * i2c_line,uint32_t index,ATOM_COMMON_TABLE_HEADER * header,uint8_t * address)357 static 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 
bios_parser_get_thermal_ddc_info(struct dc_bios * dcb,uint32_t i2c_channel_id,struct graphics_object_i2c_info * info)388 static 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 
bios_parser_get_voltage_ddc_info(struct dc_bios * dcb,uint32_t index,struct graphics_object_i2c_info * info)409 static 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 /* TODO: temporary commented out to suppress 'defined but not used' warning */
451 #if 0
452 static 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(); /* Invalid object id */
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                                         /* get the I2C info */
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 
bios_parser_get_hpd_info(struct dc_bios * dcb,struct graphics_object_id id,struct graphics_object_hpd_info * info)518 static 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 
bios_parser_get_device_tag_record(struct bios_parser * bp,ATOM_OBJECT * object,ATOM_CONNECTOR_DEVICE_TAG_RECORD ** record)545 static 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 
bios_parser_get_device_tag(struct dc_bios * dcb,struct graphics_object_id connector_object_id,uint32_t device_tag_index,struct connector_device_tag_info * info)582 static 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           /* getBiosObject will return MXM object */
597           object = get_bios_object(bp, connector_object_id);
598 
599           if (!object) {
600                     BREAK_TO_DEBUGGER(); /* Invalid object id */
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 
620 static enum bp_result get_firmware_info_v1_4(
621           struct bios_parser *bp,
622           struct dc_firmware_info *info);
623 static enum bp_result get_firmware_info_v2_1(
624           struct bios_parser *bp,
625           struct dc_firmware_info *info);
626 static enum bp_result get_firmware_info_v2_2(
627           struct bios_parser *bp,
628           struct dc_firmware_info *info);
629 
bios_parser_get_firmware_info(struct dc_bios * dcb,struct dc_firmware_info * info)630 static 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 
get_firmware_info_v1_4(struct bios_parser * bp,struct dc_firmware_info * info)674 static 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           /* Pixel clock pll information. We need to convert from 10KHz units into
691            * KHz units */
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                     /* Since there is no information on the SS, report conservative
705                      * value 3% for bandwidth calculation */
706                     /* unit of 0.01% */
707                     info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
708 
709           if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
710                     /* Since there is no information on the SS,report conservative
711                      * value 3% for bandwidth calculation */
712                     /* unit of 0.01% */
713                     info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
714 
715           return BP_RESULT_OK;
716 }
717 
718 static 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 
get_firmware_info_v2_1(struct bios_parser * bp,struct dc_firmware_info * info)724 static 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           /* Pixel clock pll information. We need to convert from 10KHz units into
742            * KHz units */
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           /* There should be only one entry in the SS info table for Memory Clock
760            */
761           index = 0;
762           if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
763                     /* Since there is no information for external SS, report
764                      *  conservative value 3% for bandwidth calculation */
765                     /* unit of 0.01% */
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                                         /* if it is centermode, the exact SS Percentage
774                                          * will be round up of half of the percentage
775                                          * reported in the SS table */
776                                         ++info->feature.memory_clk_ss_percentage;
777                                         info->feature.memory_clk_ss_percentage /= 2;
778                               }
779                     }
780           }
781 
782           /* There should be only one entry in the SS info table for Engine Clock
783            */
784           index = 1;
785           if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
786                     /* Since there is no information for external SS, report
787                      * conservative value 3% for bandwidth calculation */
788                     /* unit of 0.01% */
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                                         /* if it is centermode, the exact SS Percentage
797                                          * will be round up of half of the percentage
798                                          * reported in the SS table */
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 
get_firmware_info_v2_2(struct bios_parser * bp,struct dc_firmware_info * info)808 static 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           /* Pixel clock pll information. We need to convert from 10KHz units into
828            * KHz units */
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           /* There should be only one entry in the SS info table for Memory Clock
845            */
846           index = 0;
847           if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
848                     /* Since there is no information for external SS, report
849                      *  conservative value 3% for bandwidth calculation */
850                     /* unit of 0.01% */
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                                         /* if it is centermode, the exact SS Percentage
859                                          * will be round up of half of the percentage
860                                          * reported in the SS table */
861                                         ++info->feature.memory_clk_ss_percentage;
862                                         info->feature.memory_clk_ss_percentage /= 2;
863                               }
864                     }
865           }
866 
867           /* There should be only one entry in the SS info table for Engine Clock
868            */
869           index = 1;
870           if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
871                     /* Since there is no information for external SS, report
872                      * conservative value 3% for bandwidth calculation */
873                     /* unit of 0.01% */
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                                         /* if it is centermode, the exact SS Percentage
882                                          * will be round up of half of the percentage
883                                          * reported in the SS table */
884                                         ++info->feature.engine_clk_ss_percentage;
885                                         info->feature.engine_clk_ss_percentage /= 2;
886                               }
887                     }
888           }
889 
890           /* Remote Display */
891           info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
892 
893           /* Is allowed minimum BL level */
894           info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
895           /* Used starting from CI */
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 
get_ss_info_v3_1(struct bios_parser * bp,uint32_t id,uint32_t index,struct spread_spectrum_info * ss_info)902 static 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                     /* VBIOS introduced new defines for Version 3, same values as
941                      *  before, so now use these new ones for Version 3.
942                      * Shouldn't affect field VBIOS's V3 as define values are still
943                      *  same.
944                      * #define SS_MODE_V3_CENTRE_SPREAD_MASK                0x01
945                      * #define SS_MODE_V3_EXTERNAL_SS_MASK                  0x02
946 
947                      * Old VBIOS defines:
948                      * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK        0x00000001
949                      * #define ATOM_EXTERNAL_SS_MASK                  0x00000002
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                     /* Older VBIOS (in field) always provides SS percentage in 0.01%
959                      * units set Divider to 100 */
960                     ss_info->spread_percentage_divider = 100;
961 
962                     /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
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                     /* convert [10KHz] into [KHz] */
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 
bios_parser_transmitter_control(struct dc_bios * dcb,struct bp_transmitter_control * cntl)981 static 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 
bios_parser_encoder_control(struct dc_bios * dcb,struct bp_encoder_control * cntl)993 static 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 
bios_parser_adjust_pixel_clock(struct dc_bios * dcb,struct bp_adjust_pixel_clock_parameters * bp_params)1005 static 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 
bios_parser_set_pixel_clock(struct dc_bios * dcb,struct bp_pixel_clock_parameters * bp_params)1017 static 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 
bios_parser_set_dce_clock(struct dc_bios * dcb,struct bp_set_dce_clock_parameters * bp_params)1029 static 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 
bios_parser_enable_spread_spectrum_on_ppll(struct dc_bios * dcb,struct bp_spread_spectrum_parameters * bp_params,bool enable)1041 static 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 
bios_parser_program_crtc_timing(struct dc_bios * dcb,struct bp_hw_crtc_timing_parameters * bp_params)1056 static 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 
bios_parser_program_display_engine_pll(struct dc_bios * dcb,struct bp_pixel_clock_parameters * bp_params)1068 static 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 
bios_parser_enable_crtc(struct dc_bios * dcb,enum controller_id id,bool enable)1082 static 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 
bios_parser_crtc_source_select(struct dc_bios * dcb,struct bp_crtc_source_select * bp_params)1095 static 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 
bios_parser_enable_disp_power_gating(struct dc_bios * dcb,enum controller_id controller_id,enum bp_pipe_control_action action)1107 static 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 
bios_parser_is_device_id_supported(struct dc_bios * dcb,struct device_id id)1121 static 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 
bios_parser_crt_control(struct dc_bios * dcb,enum engine_id engine_id,bool enable,uint32_t pixel_clock)1132 static 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           /* validate params */
1148           switch (engine_id) {
1149           case ENGINE_ID_DACA:
1150           case ENGINE_ID_DACB:
1151                     break;
1152           default:
1153                     /* unsupported engine */
1154                     return BP_RESULT_FAILURE;
1155           }
1156 
1157           standard = ATOM_DAC1_PS2; /* == ATOM_DAC2_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 
get_hpd_record(struct bios_parser * bp,ATOM_OBJECT * object)1188 static 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(); /* Invalid object */
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  * Get I2C information of input object id
1224  *
1225  * search all records to find the ATOM_I2C_RECORD_TYPE record IR
1226  */
get_i2c_record(struct bios_parser * bp,ATOM_OBJECT * object)1227 static 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                     /* Invalid object */
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 
1265 static 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);
1269 static 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  * bios_parser_get_spread_spectrum_info
1275  * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or
1276  * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info
1277  * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ver 3.1,
1278  * there is only one entry for each signal /ss id.  However, there is
1279  * no planning of supporting multiple spread Sprectum entry for EverGreen
1280  * @param [in] this
1281  * @param [in] signal, ASSignalType to be converted to info index
1282  * @param [in] index, number of entries that match the converted info index
1283  * @param [out] ss_info, sprectrum information structure,
1284  * @return Bios parser result code
1285  */
bios_parser_get_spread_spectrum_info(struct dc_bios * dcb,enum as_signal_type signal,uint32_t index,struct spread_spectrum_info * ss_info)1286 static 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) /* check for bad input */
1299                     return BP_RESULT_BADINPUT;
1300           /* signal translation */
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                               /* there can not be more then one entry for Internal
1317                                * SS Info table version 2.1 */
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           /* there can not be more then one entry for SS Info table */
1339           return result;
1340 }
1341 
1342 static 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  * get_ss_info_from_table
1349  * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
1350  * SS_Info table from the VBIOS
1351  * There can not be more than 1 entry for  ASIC_InternalSS_Info Ver 2.1 or
1352  * SS_Info.
1353  *
1354  * @param this
1355  * @param id, spread sprectrum info index
1356  * @param pSSinfo, sprectrum information structure,
1357  * @return Bios parser result code
1358  */
get_ss_info_from_tbl(struct bios_parser * bp,uint32_t id,struct spread_spectrum_info * ss_info)1359 static 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) /* check for bad input, if ss_info is not NULL */
1365                     return BP_RESULT_BADINPUT;
1366           /* for SS_Info table only support DP and LVDS */
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  * get_ss_info_from_internal_ss_info_tbl_V2_1
1376  * Get spread sprectrum information from the ASIC_InternalSS_Info table Ver 2.1
1377  * from the VBIOS
1378  * There will not be multiple entry for Ver 2.1
1379  *
1380  * @param id, spread sprectrum info index
1381  * @param pSSinfo, sprectrum information structure,
1382  * @return Bios parser result code
1383  */
get_ss_info_from_internal_ss_info_tbl_V2_1(struct bios_parser * bp,uint32_t id,struct spread_spectrum_info * info)1384 static 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                     /* convert [10KHz] into [KHz] */
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  * get_ss_info_from_ss_info_table
1440  * Get spread sprectrum information from the SS_Info table from the VBIOS
1441  * if the pointer to info is NULL, indicate the caller what to know the number
1442  * of entries that matches the id
1443  * for, the SS_Info table, there should not be more than 1 entry match.
1444  *
1445  * @param [in] id, spread sprectrum id
1446  * @param [out] pSSinfo, sprectrum information structure,
1447  * @return Bios parser result code
1448  */
get_ss_info_from_ss_info_table(struct bios_parser * bp,uint32_t id,struct spread_spectrum_info * ss_info)1449 static 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           /* exist of the SS_Info table */
1463           /* check for bad input, pSSinfo can not be NULL */
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           /* have to convert from Internal_SS format to SS_Info format */
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                     /* there will be only one entry for each display type in SS_info
1526                      * table */
1527                     result = BP_RESULT_OK;
1528                     break;
1529           }
1530 
1531           return result;
1532 }
1533 static enum bp_result get_embedded_panel_info_v1_2(
1534           struct bios_parser *bp,
1535           struct embedded_panel_info *info);
1536 static enum bp_result get_embedded_panel_info_v1_3(
1537           struct bios_parser *bp,
1538           struct embedded_panel_info *info);
1539 
bios_parser_get_embedded_panel_info(struct dc_bios * dcb,struct embedded_panel_info * info)1540 static 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 
get_embedded_panel_info_v1_2(struct bios_parser * bp,struct embedded_panel_info * info)1574 static 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           /* We need to convert from 10KHz units into KHz units*/
1599           info->lcd_timing.pixel_clk =
1600                     le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1601           /* usHActive does not include borders, according to VBIOS team*/
1602           info->lcd_timing.horizontal_addressable =
1603                     le16_to_cpu(lvds->sLCDTiming.usHActive);
1604           /* usHBlanking_Time includes borders, so we should really be subtracting
1605            * borders duing this translation, but LVDS generally*/
1606           /* doesn't have borders, so we should be okay leaving this as is for
1607            * now.  May need to revisit if we ever have LVDS with borders*/
1608           info->lcd_timing.horizontal_blanking_time =
1609                               le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1610           /* usVActive does not include borders, according to VBIOS team*/
1611           info->lcd_timing.vertical_addressable =
1612                               le16_to_cpu(lvds->sLCDTiming.usVActive);
1613           /* usVBlanking_Time includes borders, so we should really be subtracting
1614            * borders duing this translation, but LVDS generally*/
1615           /* doesn't have borders, so we should be okay leaving this as is for
1616            * now. May need to revisit if we ever have LVDS with borders*/
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                     /* Get minimum supported refresh rate*/
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           /*Drr panel support can be reported by VBIOS*/
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 
get_embedded_panel_info_v1_3(struct bios_parser * bp,struct embedded_panel_info * info)1693 static 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           /* We need to convert from 10KHz units into KHz units */
1717           info->lcd_timing.pixel_clk =
1718                               le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1719           /* usHActive does not include borders, according to VBIOS team */
1720           info->lcd_timing.horizontal_addressable =
1721                               le16_to_cpu(lvds->sLCDTiming.usHActive);
1722           /* usHBlanking_Time includes borders, so we should really be subtracting
1723            * borders duing this translation, but LVDS generally*/
1724           /* doesn't have borders, so we should be okay leaving this as is for
1725            * now.  May need to revisit if we ever have LVDS with borders*/
1726           info->lcd_timing.horizontal_blanking_time =
1727                     le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1728           /* usVActive does not include borders, according to VBIOS team*/
1729           info->lcd_timing.vertical_addressable =
1730                     le16_to_cpu(lvds->sLCDTiming.usVActive);
1731           /* usVBlanking_Time includes borders, so we should really be subtracting
1732            * borders duing this translation, but LVDS generally*/
1733           /* doesn't have borders, so we should be okay leaving this as is for
1734            * now. May need to revisit if we ever have LVDS with borders*/
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           /* Drr panel support can be reported by VBIOS*/
1770           if (LCDPANEL_CAP_V13_DRR_SUPPORTED
1771                               & lvds->ucLCDPanel_SpecialHandlingCap)
1772                     info->drr_enabled = 1;
1773 
1774           /* Get supported refresh rate*/
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  * bios_parser_get_encoder_cap_info
1820  *
1821  * @brief
1822  *  Get encoder capability information of input object id
1823  *
1824  * @param object_id, Object id
1825  * @param object_id, encoder cap information structure
1826  *
1827  * @return Bios parser result code
1828  *
1829  */
bios_parser_get_encoder_cap_info(struct dc_bios * dcb,struct graphics_object_id object_id,struct bp_encoder_cap_info * info)1830 static 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  * get_encoder_cap_record
1859  *
1860  * @brief
1861  *  Get encoder cap record for the object
1862  *
1863  * @param object, ATOM object
1864  *
1865  * @return atom encoder cap record
1866  *
1867  * @note
1868  *  search all records to find the ATOM_ENCODER_CAP_RECORD_V2 record
1869  */
get_encoder_cap_record(struct bios_parser * bp,ATOM_OBJECT * object)1870 static 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(); /* Invalid object */
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 
1907 static uint32_t get_ss_entry_number(
1908           struct bios_parser *bp,
1909           uint32_t id);
1910 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1911           struct bios_parser *bp,
1912           uint32_t id);
1913 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1914           struct bios_parser *bp,
1915           uint32_t id);
1916 static uint32_t get_ss_entry_number_from_ss_info_tbl(
1917           struct bios_parser *bp,
1918           uint32_t id);
1919 
1920 /**
1921  * BiosParserObject::GetNumberofSpreadSpectrumEntry
1922  * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
1923  * the VBIOS that match the SSid (to be converted from signal)
1924  *
1925  * @param[in] signal, ASSignalType to be converted to SSid
1926  * @return number of SS Entry that match the signal
1927  */
bios_parser_get_ss_entry_number(struct dc_bios * dcb,enum as_signal_type signal)1928 static 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  * get_ss_entry_number_from_ss_info_tbl
1974  * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
1975  *
1976  * @note There can only be one entry for each id for SS_Info Table
1977  *
1978  * @param [in] id, spread spectrum id
1979  * @return number of SS Entry that match the id
1980  */
get_ss_entry_number_from_ss_info_tbl(struct bios_parser * bp,uint32_t id)1981 static 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           /* SS_Info table exist */
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           /* have to convert from Internal_SS format to SS_Info format */
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  * get_ss_entry_number
2042  * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
2043  * SS_Info table from the VBIOS
2044  * There can not be more than 1 entry for  ASIC_InternalSS_Info Ver 2.1 or
2045  * SS_Info.
2046  *
2047  * @param id, spread sprectrum info index
2048  * @return Bios parser result code
2049  */
get_ss_entry_number(struct bios_parser * bp,uint32_t id)2050 static 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  * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
2060  * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
2061  * Ver 2.1 from the VBIOS
2062  * There will not be multiple entry for Ver 2.1
2063  *
2064  * @param id, spread sprectrum info index
2065  * @return number of SS Entry that match the id
2066  */
get_ss_entry_number_from_internal_ss_info_tbl_v2_1(struct bios_parser * bp,uint32_t id)2067 static 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  * get_ss_entry_number_from_internal_ss_info_table_V3_1
2096  * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
2097  * the VBIOS that matches id
2098  *
2099  * @param[in]  id, spread sprectrum id
2100  * @return number of SS Entry that match the id
2101  */
get_ss_entry_number_from_internal_ss_info_tbl_V3_1(struct bios_parser * bp,uint32_t id)2102 static 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  * bios_parser_get_gpio_pin_info
2133  * Get GpioPin information of input gpio id
2134  *
2135  * @param gpio_id, GPIO ID
2136  * @param info, GpioPin information structure
2137  * @return Bios parser result code
2138  * @note
2139  *  to get the GPIO PIN INFO, we need:
2140  *  1. get the GPIO_ID from other object table, see GetHPDInfo()
2141  *  2. in DATA_TABLE.GPIO_Pin_LUT, search all records, to get the registerA
2142  *  offset/mask
2143  */
bios_parser_get_gpio_pin_info(struct dc_bios * dcb,uint32_t gpio_id,struct gpio_pin_info * info)2144 static 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 
get_gpio_i2c_info(struct bios_parser * bp,ATOM_I2C_RECORD * record,struct graphics_object_i2c_info * info)2193 static 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           /* get the GPIO_I2C info */
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           /* get data count */
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           /* get the GPIO_I2C_INFO */
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 
dal_graphics_object_id_is_valid(struct graphics_object_id id)2268 static 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                     /* do NOT check for id.id == 0 */
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 
dal_graphics_object_id_is_equal(struct graphics_object_id id1,struct graphics_object_id id2)2291 static 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 
get_bios_object(struct bios_parser * bp,struct graphics_object_id id)2314 static 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 
get_dest_obj_list(struct bios_parser * bp,ATOM_OBJECT * object,uint16_t ** id_list)2359 static 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(); /* Invalid object id */
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 
get_src_obj_list(struct bios_parser * bp,ATOM_OBJECT * object,uint16_t ** id_list)2393 static 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(); /* Invalid object id */
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 
get_dst_number_from_object(struct bios_parser * bp,ATOM_OBJECT * object)2420 static 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(); /* Invalid encoder object id*/
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 
device_type_from_device_id(uint16_t device_id)2449 static 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(); /* Invalid device Id */
2507                     result_device_id.device_type = DEVICE_TYPE_UNKNOWN;
2508                     result_device_id.enum_id = 0;
2509           }
2510           return result_device_id;
2511 }
2512 
get_atom_data_table_revision(ATOM_COMMON_TABLE_HEADER * atom_data_tbl,struct atom_data_revision * tbl_revision)2513 static 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           /* initialize the revision to 0 which is invalid revision */
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 
signal_to_ss_id(enum as_signal_type signal)2533 static 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 
get_support_mask_for_device_id(struct device_id device_id)2559 static 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           /* Unidentified device ID, return empty support mask. */
2624           return 0;
2625 }
2626 
2627 /**
2628  *  HwContext interface for writing MM registers
2629  */
2630 
i2c_read(struct bios_parser * bp,struct graphics_object_i2c_info * i2c_info,uint8_t * buffer,uint32_t length)2631 static 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           /*Using SW engine */
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                     /* TODO route this through drm i2c_adapter */
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  * Read external display connection info table through i2c.
2689  * validate the GUID and checksum.
2690  *
2691  * @return enum bp_result whether all data was sucessfully read
2692  */
get_ext_display_connection_info(struct bios_parser * bp,ATOM_OBJECT * opm_object,ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO * ext_display_connection_info_tbl)2693 static 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           /* Validate GUID */
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           /* Validate checksum */
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  * Gets the first device ID in the same group as the given ID for enumerating.
2762  * For instance, if any DFP device ID is passed, returns the device ID for DFP1.
2763  *
2764  * The first device ID in the same group as the passed device ID, or 0 if no
2765  * matching device group found.
2766  */
enum_first_device_id(uint32_t dev_id)2767 static uint32_t enum_first_device_id(uint32_t dev_id)
2768 {
2769           /* Return the first in the group that this ID belongs to. */
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           /* No group found for this device ID. */
2782 
2783           dm_error("%s: incorrect input %d\n", __func__, dev_id);
2784           /* No matching support flag for given device ID */
2785           return 0;
2786 }
2787 
2788 /*
2789  * Gets the next device ID in the group for a given device ID.
2790  *
2791  * The current device ID being enumerated on.
2792  *
2793  * The next device ID in the group, or 0 if no device exists.
2794  */
enum_next_dev_id(uint32_t dev_id)2795 static uint32_t enum_next_dev_id(uint32_t dev_id)
2796 {
2797           /* Get next device ID in the group. */
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           /* Done enumerating through devices. */
2816           return 0;
2817 }
2818 
2819 /*
2820  * Returns the new device tag record for patched BIOS object.
2821  *
2822  * [IN] pExtDisplayPath - External display path to copy device tag from.
2823  * [IN] deviceSupport - Bit vector for device ID support flags.
2824  * [OUT] pDeviceTag - Device tag structure to fill with patched data.
2825  *
2826  * True if a compatible device ID was found, false otherwise.
2827  */
get_patched_device_tag(struct bios_parser * bp,EXT_DISPLAY_PATH * ext_display_path,uint32_t device_support,ATOM_CONNECTOR_DEVICE_TAG * device_tag)2828 static 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           /* Use fallback behaviour if not supported. */
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           /* Find the first unused in the same group. */
2845           dev_id = enum_first_device_id(le16_to_cpu(ext_display_path->usDeviceTag));
2846           while (dev_id != 0) {
2847                     /* Assign this device ID if supported. */
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           /* No compatible device ID found. */
2859           return false;
2860 }
2861 
2862 /*
2863  * Adds a device tag to a BIOS object's device tag record if there is
2864  * matching device ID supported.
2865  *
2866  * pObject - Pointer to the BIOS object to add the device tag to.
2867  * pExtDisplayPath - Display path to retrieve base device ID from.
2868  * pDeviceSupport - Pointer to bit vector for supported device IDs.
2869  */
add_device_tag_from_ext_display_path(struct bios_parser * bp,ATOM_OBJECT * object,EXT_DISPLAY_PATH * ext_display_path,uint32_t * device_support)2870 static 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           /* Get device tag record for object. */
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                               /*Workaround bug in current VBIOS releases where
2890                                * ucNumberOfDevice = 1 but there is no actual device
2891                                * tag data. This w/a is temporary until the updated
2892                                * VBIOS is distributed. */
2893                               device_tag_record->ucNumberOfDevice =
2894                                                   device_tag_record->ucNumberOfDevice - 1;
2895                     }
2896 
2897                     /* Attempt to find a matching device ID. */
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                               /* Update cached device support to remove assigned ID.
2906                                */
2907                               *device_support &= ~le16_to_cpu(device_tag->usDeviceID);
2908                               device_tag_record->ucNumberOfDevice++;
2909                     }
2910           }
2911 }
2912 
2913 /*
2914  * Read out a single EXT_DISPLAY_PATH from the external display connection info
2915  * table. The specific entry in the table is determined by the enum_id passed
2916  * in.
2917  *
2918  * EXT_DISPLAY_PATH describing a single Configuration table entry
2919  */
2920 
2921 #define INVALID_CONNECTOR 0xffff
2922 
get_ext_display_path_entry(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO * config_table,uint32_t bios_object_id)2923 static 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  * Get AUX/DDC information of input object id
2944  *
2945  * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
2946  * IR
2947  */
get_ext_connector_aux_ddc_lut_record(struct bios_parser * bp,ATOM_OBJECT * object)2948 static 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                     /* Invalid object */
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  * Get AUX/DDC information of input object id
2988  *
2989  * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
2990  * IR
2991  */
get_ext_connector_hpd_pin_lut_record(struct bios_parser * bp,ATOM_OBJECT * object)2992 static 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                     /* Invalid object */
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  * Check whether we need to patch the VBIOS connector info table with
3032  * data from an external display connection info table.  This is
3033  * necessary to support MXM boards with an OPM (output personality
3034  * module).  With these designs, the VBIOS connector info table
3035  * specifies an MXM_CONNECTOR with a unique ID.  The driver retrieves
3036  * the external connection info table through i2c and then looks up the
3037  * connector ID to find the real connector type (e.g. DFP1).
3038  *
3039  */
patch_bios_image_from_ext_display_connection_info(struct bios_parser * bp)3040 static 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           /* Read Connector info table from EEPROM through i2c */
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           /* Get pointer to AUX/DDC and HPD LUTs */
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           /* Cache support bits for currently unmapped device types. */
3099           if (bp->remap_device_tags) {
3100                     for (i = 0; i < connector_tbl->ucNumberOfObjects; ++i) {
3101                               uint32_t j;
3102                               /* Remove support for all non-MXM connectors. */
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                               /* Remove support for all device tags. */
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           /* Find all MXM connector objects and patch them with connector info
3125            * from the external display connection info table. */
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                     /* Get the correct connection info table entry based on the enum
3136                      * id. */
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                     /* Patch device connector ID */
3144                     object->usObjectID =
3145                                         cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceConnector));
3146 
3147                     /* Patch device tag, ulACPIDeviceEnum. */
3148                     add_device_tag_from_ext_display_path(
3149                                         bp,
3150                                         object,
3151                                         ext_display_path,
3152                                         &cached_device_support);
3153 
3154                     /* Patch HPD info */
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                                         /* Invalid hpd record */
3166                                         return BP_RESULT_FAILURE;
3167                               }
3168                     }
3169 
3170                     /* Patch I2C/AUX info */
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                                         /* Invalid I2C record */
3182                                         return BP_RESULT_FAILURE;
3183                               }
3184                     }
3185 
3186                     /* Merge with other MXM connectors that map to the same physical
3187                      * connector. */
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                               /* Merge if using same connector. */
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                                         /* Clear duplicate connector from table. */
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           /* Find all encoders which have an MXM object as their destination.
3225            *  Replace the MXM object with the real connector Id from the external
3226            *  display connection info table */
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                               /* Get the correct connection info table entry based on
3248                                * the enum id. */
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  * Check whether we need to patch the VBIOS connector info table with
3267  * data from an external display connection info table.  This is
3268  * necessary to support MXM boards with an OPM (output personality
3269  * module).  With these designs, the VBIOS connector info table
3270  * specifies an MXM_CONNECTOR with a unique ID.  The driver retrieves
3271  * the external connection info table through i2c and then looks up the
3272  * connector ID to find the real connector type (e.g. DFP1).
3273  *
3274  */
3275 
process_ext_display_connection_info(struct bios_parser * bp)3276 static 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           /* Look for MXM connectors to determine whether we need patch the VBIOS
3291            * connector info table. Look for null entries to determine whether we
3292            * need to compact connector table. */
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                               /* Once we found MXM connector - we can break */
3300                               mxm_connector_found = true;
3301                               break;
3302                     } else if (OBJECT_TYPE_CONNECTOR != object_id.type) {
3303                               /* We need to continue looping - to check if MXM
3304                                * connector present */
3305                               null_entry_found = true;
3306                     }
3307           }
3308 
3309           /* Patch BIOS image */
3310           if (mxm_connector_found || null_entry_found) {
3311                     uint32_t connectors_num = 0;
3312                     uint8_t *original_bios;
3313                     /* Step 1: Replace bios image with the new copy which will be
3314                      * patched */
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                               /* Failed to alloc bp->base.bios_local_image */
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                     /* Step 2: (only if MXM connector found) Patch BIOS image with
3330                      * info from external module */
3331                     if (mxm_connector_found &&
3332                         patch_bios_image_from_ext_display_connection_info(bp) !=
3333                                                             BP_RESULT_OK) {
3334                               /* Patching the bios image has failed. We will copy
3335                                * again original image provided and afterwards
3336                                * only remove null entries */
3337                               memmove(
3338                                                   bp->base.bios_local_image,
3339                                                   original_bios,
3340                                                   bp->base.bios_size);
3341                     }
3342 
3343                     /* Step 3: Compact connector table (remove null entries, valid
3344                      * entries moved to beginning) */
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 
bios_parser_post_init(struct dc_bios * dcb)3366 static 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  * bios_parser_set_scratch_critical_state
3375  *
3376  * @brief
3377  *  update critical state bit in VBIOS scratch register
3378  *
3379  * @param
3380  *  bool - to set or reset state
3381  */
bios_parser_set_scratch_critical_state(struct dc_bios * dcb,bool state)3382 static 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  * get_integrated_info_v8
3391  *
3392  * @brief
3393  * Get V8 integrated BIOS information
3394  *
3395  * @param
3396  * bios_parser *bp - [in]BIOS parser handler to get master data table
3397  * integrated_info *info - [out] store and output integrated info
3398  *
3399  * @return
3400  * enum bp_result - BP_RESULT_OK if information is available,
3401  *                  BP_RESULT_BADBIOSTABLE otherwise.
3402  */
get_integrated_info_v8(struct bios_parser * bp,struct integrated_info * info)3403 static 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                     /* Convert [10KHz] into [KHz] */
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            * system_config: Bit[0] = 0 : PCIE power gating disabled
3435            *                       = 1 : PCIE power gating enabled
3436            *                Bit[1] = 0 : DDR-PLL shut down disabled
3437            *                       = 1 : DDR-PLL shut down enabled
3438            *                Bit[2] = 0 : DDR-PLL power down disabled
3439            *                       = 1 : DDR-PLL power down enabled
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                     /* Convert [10KHz] into [KHz] */
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  * get_integrated_info_v8
3541  *
3542  * @brief
3543  * Get V8 integrated BIOS information
3544  *
3545  * @param
3546  * bios_parser *bp - [in]BIOS parser handler to get master data table
3547  * integrated_info *info - [out] store and output integrated info
3548  *
3549  * @return
3550  * enum bp_result - BP_RESULT_OK if information is available,
3551  *                  BP_RESULT_BADBIOSTABLE otherwise.
3552  */
get_integrated_info_v9(struct bios_parser * bp,struct integrated_info * info)3553 static 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                     /* Convert [10KHz] into [KHz] */
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            * system_config: Bit[0] = 0 : PCIE power gating disabled
3584            *                       = 1 : PCIE power gating enabled
3585            *                Bit[1] = 0 : DDR-PLL shut down disabled
3586            *                       = 1 : DDR-PLL shut down enabled
3587            *                Bit[2] = 0 : DDR-PLL power down disabled
3588            *                       = 1 : DDR-PLL power down enabled
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                     /* Convert [10KHz] into [KHz] */
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  * construct_integrated_info
3678  *
3679  * @brief
3680  * Get integrated BIOS information based on table revision
3681  *
3682  * @param
3683  * bios_parser *bp - [in]BIOS parser handler to get master data table
3684  * integrated_info *info - [out] store and output integrated info
3685  *
3686  * @return
3687  * enum bp_result - BP_RESULT_OK if information is available,
3688  *                  BP_RESULT_BADBIOSTABLE otherwise.
3689  */
construct_integrated_info(struct bios_parser * bp,struct integrated_info * info)3690 static 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                     /* Don't need to check major revision as they are all 1 */
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           /* Sort voltage table from low to high*/
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                                                   /* swap j and j - 1*/
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 
bios_parser_create_integrated_info(struct dc_bios * dcb)3744 static 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 
3765 static
update_slot_layout_info(struct dc_bios * dcb,unsigned int i,struct slot_layout_info * slot_layout_info,unsigned int record_offset)3766 enum bp_result update_slot_layout_info(
3767           struct dc_bios *dcb,
3768           unsigned int i,
3769           struct slot_layout_info *slot_layout_info,
3770           unsigned int record_offset)
3771 {
3772           unsigned int j;
3773           struct bios_parser *bp;
3774           ATOM_BRACKET_LAYOUT_RECORD *record;
3775           ATOM_COMMON_RECORD_HEADER *record_header;
3776           enum bp_result result = BP_RESULT_NORECORD;
3777 
3778           bp = BP_FROM_DCB(dcb);
3779           record = NULL;
3780           record_header = NULL;
3781 
3782           for (;;) {
3783 
3784                     record_header = (ATOM_COMMON_RECORD_HEADER *)
3785                               GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
3786                     if (record_header == NULL) {
3787                               result = BP_RESULT_BADBIOSTABLE;
3788                               break;
3789                     }
3790 
3791                     /* the end of the list */
3792                     if (record_header->ucRecordType == 0xff ||
3793                               record_header->ucRecordSize == 0)       {
3794                               break;
3795                     }
3796 
3797                     if (record_header->ucRecordType ==
3798                               ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
3799                               sizeof(ATOM_BRACKET_LAYOUT_RECORD)
3800                               <= record_header->ucRecordSize) {
3801                               record = (ATOM_BRACKET_LAYOUT_RECORD *)
3802                                         (record_header);
3803                               result = BP_RESULT_OK;
3804                               break;
3805                     }
3806 
3807                     record_offset += record_header->ucRecordSize;
3808           }
3809 
3810           /* return if the record not found */
3811           if (result != BP_RESULT_OK)
3812                     return result;
3813 
3814           /* get slot sizes */
3815           slot_layout_info->length = record->ucLength;
3816           slot_layout_info->width = record->ucWidth;
3817 
3818           /* get info for each connector in the slot */
3819           slot_layout_info->num_of_connectors = record->ucConnNum;
3820           for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
3821                     slot_layout_info->connectors[j].connector_type =
3822                               (enum connector_layout_type)
3823                               (record->asConnInfo[j].ucConnectorType);
3824                     switch (record->asConnInfo[j].ucConnectorType) {
3825                     case CONNECTOR_TYPE_DVI_D:
3826                               slot_layout_info->connectors[j].connector_type =
3827                                         CONNECTOR_LAYOUT_TYPE_DVI_D;
3828                               slot_layout_info->connectors[j].length =
3829                                         CONNECTOR_SIZE_DVI;
3830                               break;
3831 
3832                     case CONNECTOR_TYPE_HDMI:
3833                               slot_layout_info->connectors[j].connector_type =
3834                                         CONNECTOR_LAYOUT_TYPE_HDMI;
3835                               slot_layout_info->connectors[j].length =
3836                                         CONNECTOR_SIZE_HDMI;
3837                               break;
3838 
3839                     case CONNECTOR_TYPE_DISPLAY_PORT:
3840                               slot_layout_info->connectors[j].connector_type =
3841                                         CONNECTOR_LAYOUT_TYPE_DP;
3842                               slot_layout_info->connectors[j].length =
3843                                         CONNECTOR_SIZE_DP;
3844                               break;
3845 
3846                     case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
3847                               slot_layout_info->connectors[j].connector_type =
3848                                         CONNECTOR_LAYOUT_TYPE_MINI_DP;
3849                               slot_layout_info->connectors[j].length =
3850                                         CONNECTOR_SIZE_MINI_DP;
3851                               break;
3852 
3853                     default:
3854                               slot_layout_info->connectors[j].connector_type =
3855                                         CONNECTOR_LAYOUT_TYPE_UNKNOWN;
3856                               slot_layout_info->connectors[j].length =
3857                                         CONNECTOR_SIZE_UNKNOWN;
3858                     }
3859 
3860                     slot_layout_info->connectors[j].position =
3861                               record->asConnInfo[j].ucPosition;
3862                     slot_layout_info->connectors[j].connector_id =
3863                               object_id_from_bios_object_id(
3864                                         record->asConnInfo[j].usConnectorObjectId);
3865           }
3866           return result;
3867 }
3868 
3869 
3870 static
get_bracket_layout_record(struct dc_bios * dcb,unsigned int bracket_layout_id,struct slot_layout_info * slot_layout_info)3871 enum bp_result get_bracket_layout_record(
3872           struct dc_bios *dcb,
3873           unsigned int bracket_layout_id,
3874           struct slot_layout_info *slot_layout_info)
3875 {
3876           unsigned int i;
3877           unsigned int record_offset;
3878           struct bios_parser *bp;
3879           enum bp_result result;
3880           ATOM_OBJECT *object;
3881           ATOM_OBJECT_TABLE *object_table;
3882           unsigned int genericTableOffset;
3883 
3884           bp = BP_FROM_DCB(dcb);
3885           object = NULL;
3886           if (slot_layout_info == NULL) {
3887                     DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
3888                     return BP_RESULT_BADINPUT;
3889           }
3890 
3891 
3892           genericTableOffset = bp->object_info_tbl_offset +
3893                     bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
3894           object_table = (ATOM_OBJECT_TABLE *)
3895                     GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset);
3896           if (!object_table)
3897                     return BP_RESULT_FAILURE;
3898 
3899           result = BP_RESULT_NORECORD;
3900           for (i = 0; i < object_table->ucNumberOfObjects; ++i) {
3901 
3902                     if (bracket_layout_id ==
3903                               object_table->asObjects[i].usObjectID) {
3904 
3905                               object = &object_table->asObjects[i];
3906                               record_offset = object->usRecordOffset +
3907                                         bp->object_info_tbl_offset;
3908 
3909                               result = update_slot_layout_info(dcb, i,
3910                                         slot_layout_info, record_offset);
3911                               break;
3912                     }
3913           }
3914           return result;
3915 }
3916 
bios_get_board_layout_info(struct dc_bios * dcb,struct board_layout_info * board_layout_info)3917 static enum bp_result bios_get_board_layout_info(
3918           struct dc_bios *dcb,
3919           struct board_layout_info *board_layout_info)
3920 {
3921           unsigned int i;
3922           struct bios_parser *bp;
3923           enum bp_result record_result;
3924 
3925           const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
3926                     GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
3927                     GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
3928                     0, 0
3929           };
3930 
3931           bp = BP_FROM_DCB(dcb);
3932           if (board_layout_info == NULL) {
3933                     DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
3934                     return BP_RESULT_BADINPUT;
3935           }
3936 
3937           board_layout_info->num_of_slots = 0;
3938 
3939           for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
3940                     record_result = get_bracket_layout_record(dcb,
3941                               slot_index_to_vbios_id[i],
3942                               &board_layout_info->slots[i]);
3943 
3944                     if (record_result == BP_RESULT_NORECORD && i > 0)
3945                               break; /* no more slots present in bios */
3946                     else if (record_result != BP_RESULT_OK)
3947                               return record_result;  /* fail */
3948 
3949                     ++board_layout_info->num_of_slots;
3950           }
3951 
3952           /* all data is valid */
3953           board_layout_info->is_number_of_slots_valid = 1;
3954           board_layout_info->is_slots_size_valid = 1;
3955           board_layout_info->is_connector_offsets_valid = 1;
3956           board_layout_info->is_connector_lengths_valid = 1;
3957 
3958           return BP_RESULT_OK;
3959 }
3960 
3961 /******************************************************************************/
3962 
3963 static const struct dc_vbios_funcs vbios_funcs = {
3964           .get_connectors_number = bios_parser_get_connectors_number,
3965 
3966           .get_encoder_id = bios_parser_get_encoder_id,
3967 
3968           .get_connector_id = bios_parser_get_connector_id,
3969 
3970           .get_dst_number = bios_parser_get_dst_number,
3971 
3972           .get_src_obj = bios_parser_get_src_obj,
3973 
3974           .get_dst_obj = bios_parser_get_dst_obj,
3975 
3976           .get_i2c_info = bios_parser_get_i2c_info,
3977 
3978           .get_voltage_ddc_info = bios_parser_get_voltage_ddc_info,
3979 
3980           .get_thermal_ddc_info = bios_parser_get_thermal_ddc_info,
3981 
3982           .get_hpd_info = bios_parser_get_hpd_info,
3983 
3984           .get_device_tag = bios_parser_get_device_tag,
3985 
3986           .get_firmware_info = bios_parser_get_firmware_info,
3987 
3988           .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info,
3989 
3990           .get_ss_entry_number = bios_parser_get_ss_entry_number,
3991 
3992           .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
3993 
3994           .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
3995 
3996           .get_encoder_cap_info = bios_parser_get_encoder_cap_info,
3997 
3998           /* bios scratch register communication */
3999           .is_accelerated_mode = bios_is_accelerated_mode,
4000           .get_vga_enabled_displays = bios_get_vga_enabled_displays,
4001 
4002           .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
4003 
4004           .is_device_id_supported = bios_parser_is_device_id_supported,
4005 
4006           /* COMMANDS */
4007           .encoder_control = bios_parser_encoder_control,
4008 
4009           .transmitter_control = bios_parser_transmitter_control,
4010 
4011           .crt_control = bios_parser_crt_control,  /* not used in DAL3.  keep for now in case we need to support VGA on Bonaire */
4012 
4013           .enable_crtc = bios_parser_enable_crtc,
4014 
4015           .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
4016 
4017           .set_pixel_clock = bios_parser_set_pixel_clock,
4018 
4019           .set_dce_clock = bios_parser_set_dce_clock,
4020 
4021           .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
4022 
4023           .program_crtc_timing = bios_parser_program_crtc_timing, /* still use.  should probably retire and program directly */
4024 
4025           .crtc_source_select = bios_parser_crtc_source_select,  /* still use.  should probably retire and program directly */
4026 
4027           .program_display_engine_pll = bios_parser_program_display_engine_pll,
4028 
4029           .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
4030 
4031           /* SW init and patch */
4032           .post_init = bios_parser_post_init,  /* patch vbios table for mxm module by reading i2c */
4033 
4034           .bios_parser_destroy = bios_parser_destroy,
4035 
4036           .get_board_layout_info = bios_get_board_layout_info,
4037 };
4038 
bios_parser_construct(struct bios_parser * bp,struct bp_init_data * init,enum dce_version dce_version)4039 static bool bios_parser_construct(
4040           struct bios_parser *bp,
4041           struct bp_init_data *init,
4042           enum dce_version dce_version)
4043 {
4044           uint16_t *rom_header_offset = NULL;
4045           ATOM_ROM_HEADER *rom_header = NULL;
4046           ATOM_OBJECT_HEADER *object_info_tbl;
4047           struct atom_data_revision tbl_rev = {0};
4048 
4049           if (!init)
4050                     return false;
4051 
4052           if (!init->bios)
4053                     return false;
4054 
4055           bp->base.funcs = &vbios_funcs;
4056           bp->base.bios = init->bios;
4057           bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
4058 
4059           bp->base.ctx = init->ctx;
4060           bp->base.bios_local_image = NULL;
4061 
4062           rom_header_offset =
4063           GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
4064 
4065           if (!rom_header_offset)
4066                     return false;
4067 
4068           rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
4069 
4070           if (!rom_header)
4071                     return false;
4072 
4073           get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev);
4074           if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
4075                     return false;
4076 
4077           bp->master_data_tbl =
4078           GET_IMAGE(ATOM_MASTER_DATA_TABLE,
4079                     rom_header->usMasterDataTableOffset);
4080 
4081           if (!bp->master_data_tbl)
4082                     return false;
4083 
4084           bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
4085 
4086           if (!bp->object_info_tbl_offset)
4087                     return false;
4088 
4089           object_info_tbl =
4090           GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
4091 
4092           if (!object_info_tbl)
4093                     return false;
4094 
4095           get_atom_data_table_revision(&object_info_tbl->sHeader,
4096                     &bp->object_info_tbl.revision);
4097 
4098           if (bp->object_info_tbl.revision.major == 1
4099                     && bp->object_info_tbl.revision.minor >= 3) {
4100                     ATOM_OBJECT_HEADER_V3 *tbl_v3;
4101 
4102                     tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
4103                               bp->object_info_tbl_offset);
4104                     if (!tbl_v3)
4105                               return false;
4106 
4107                     bp->object_info_tbl.v1_3 = tbl_v3;
4108           } else if (bp->object_info_tbl.revision.major == 1
4109                     && bp->object_info_tbl.revision.minor >= 1)
4110                     bp->object_info_tbl.v1_1 = object_info_tbl;
4111           else
4112                     return false;
4113 
4114           dal_bios_parser_init_cmd_tbl(bp);
4115           dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
4116 
4117           bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base);
4118 
4119           return true;
4120 }
4121 
4122 /******************************************************************************/
4123