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
update_slot_layout_info(struct dc_bios * dcb,unsigned int i,struct slot_layout_info * slot_layout_info,unsigned int record_offset)3765 enum bp_result update_slot_layout_info(
3766 struct dc_bios *dcb,
3767 unsigned int i,
3768 struct slot_layout_info *slot_layout_info,
3769 unsigned int record_offset)
3770 {
3771 unsigned int j;
3772 struct bios_parser *bp;
3773 ATOM_BRACKET_LAYOUT_RECORD *record;
3774 ATOM_COMMON_RECORD_HEADER *record_header;
3775 enum bp_result result = BP_RESULT_NORECORD;
3776
3777 bp = BP_FROM_DCB(dcb);
3778 record = NULL;
3779 record_header = NULL;
3780
3781 for (;;) {
3782
3783 record_header = (ATOM_COMMON_RECORD_HEADER *)
3784 GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
3785 if (record_header == NULL) {
3786 result = BP_RESULT_BADBIOSTABLE;
3787 break;
3788 }
3789
3790 /* the end of the list */
3791 if (record_header->ucRecordType == 0xff ||
3792 record_header->ucRecordSize == 0) {
3793 break;
3794 }
3795
3796 if (record_header->ucRecordType ==
3797 ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
3798 sizeof(ATOM_BRACKET_LAYOUT_RECORD)
3799 <= record_header->ucRecordSize) {
3800 record = (ATOM_BRACKET_LAYOUT_RECORD *)
3801 (record_header);
3802 result = BP_RESULT_OK;
3803 break;
3804 }
3805
3806 record_offset += record_header->ucRecordSize;
3807 }
3808
3809 /* return if the record not found */
3810 if (result != BP_RESULT_OK)
3811 return result;
3812
3813 /* get slot sizes */
3814 slot_layout_info->length = record->ucLength;
3815 slot_layout_info->width = record->ucWidth;
3816
3817 /* get info for each connector in the slot */
3818 slot_layout_info->num_of_connectors = record->ucConnNum;
3819 for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
3820 slot_layout_info->connectors[j].connector_type =
3821 (enum connector_layout_type)
3822 (record->asConnInfo[j].ucConnectorType);
3823 switch (record->asConnInfo[j].ucConnectorType) {
3824 case CONNECTOR_TYPE_DVI_D:
3825 slot_layout_info->connectors[j].connector_type =
3826 CONNECTOR_LAYOUT_TYPE_DVI_D;
3827 slot_layout_info->connectors[j].length =
3828 CONNECTOR_SIZE_DVI;
3829 break;
3830
3831 case CONNECTOR_TYPE_HDMI:
3832 slot_layout_info->connectors[j].connector_type =
3833 CONNECTOR_LAYOUT_TYPE_HDMI;
3834 slot_layout_info->connectors[j].length =
3835 CONNECTOR_SIZE_HDMI;
3836 break;
3837
3838 case CONNECTOR_TYPE_DISPLAY_PORT:
3839 slot_layout_info->connectors[j].connector_type =
3840 CONNECTOR_LAYOUT_TYPE_DP;
3841 slot_layout_info->connectors[j].length =
3842 CONNECTOR_SIZE_DP;
3843 break;
3844
3845 case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
3846 slot_layout_info->connectors[j].connector_type =
3847 CONNECTOR_LAYOUT_TYPE_MINI_DP;
3848 slot_layout_info->connectors[j].length =
3849 CONNECTOR_SIZE_MINI_DP;
3850 break;
3851
3852 default:
3853 slot_layout_info->connectors[j].connector_type =
3854 CONNECTOR_LAYOUT_TYPE_UNKNOWN;
3855 slot_layout_info->connectors[j].length =
3856 CONNECTOR_SIZE_UNKNOWN;
3857 }
3858
3859 slot_layout_info->connectors[j].position =
3860 record->asConnInfo[j].ucPosition;
3861 slot_layout_info->connectors[j].connector_id =
3862 object_id_from_bios_object_id(
3863 record->asConnInfo[j].usConnectorObjectId);
3864 }
3865 return result;
3866 }
3867
3868
get_bracket_layout_record(struct dc_bios * dcb,unsigned int bracket_layout_id,struct slot_layout_info * slot_layout_info)3869 enum bp_result get_bracket_layout_record(
3870 struct dc_bios *dcb,
3871 unsigned int bracket_layout_id,
3872 struct slot_layout_info *slot_layout_info)
3873 {
3874 unsigned int i;
3875 unsigned int record_offset;
3876 struct bios_parser *bp;
3877 enum bp_result result;
3878 ATOM_OBJECT *object;
3879 ATOM_OBJECT_TABLE *object_table;
3880 unsigned int genericTableOffset;
3881
3882 bp = BP_FROM_DCB(dcb);
3883 object = NULL;
3884 if (slot_layout_info == NULL) {
3885 DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
3886 return BP_RESULT_BADINPUT;
3887 }
3888
3889
3890 genericTableOffset = bp->object_info_tbl_offset +
3891 bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
3892 object_table = (ATOM_OBJECT_TABLE *)
3893 GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset);
3894 if (!object_table)
3895 return BP_RESULT_FAILURE;
3896
3897 result = BP_RESULT_NORECORD;
3898 for (i = 0; i < object_table->ucNumberOfObjects; ++i) {
3899
3900 if (bracket_layout_id ==
3901 object_table->asObjects[i].usObjectID) {
3902
3903 object = &object_table->asObjects[i];
3904 record_offset = object->usRecordOffset +
3905 bp->object_info_tbl_offset;
3906
3907 result = update_slot_layout_info(dcb, i,
3908 slot_layout_info, record_offset);
3909 break;
3910 }
3911 }
3912 return result;
3913 }
3914
bios_get_board_layout_info(struct dc_bios * dcb,struct board_layout_info * board_layout_info)3915 static enum bp_result bios_get_board_layout_info(
3916 struct dc_bios *dcb,
3917 struct board_layout_info *board_layout_info)
3918 {
3919 unsigned int i;
3920 struct bios_parser *bp;
3921 enum bp_result record_result;
3922
3923 const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
3924 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
3925 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
3926 0, 0
3927 };
3928
3929 bp = BP_FROM_DCB(dcb);
3930 if (board_layout_info == NULL) {
3931 DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
3932 return BP_RESULT_BADINPUT;
3933 }
3934
3935 board_layout_info->num_of_slots = 0;
3936
3937 for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
3938 record_result = get_bracket_layout_record(dcb,
3939 slot_index_to_vbios_id[i],
3940 &board_layout_info->slots[i]);
3941
3942 if (record_result == BP_RESULT_NORECORD && i > 0)
3943 break; /* no more slots present in bios */
3944 else if (record_result != BP_RESULT_OK)
3945 return record_result; /* fail */
3946
3947 ++board_layout_info->num_of_slots;
3948 }
3949
3950 /* all data is valid */
3951 board_layout_info->is_number_of_slots_valid = 1;
3952 board_layout_info->is_slots_size_valid = 1;
3953 board_layout_info->is_connector_offsets_valid = 1;
3954 board_layout_info->is_connector_lengths_valid = 1;
3955
3956 return BP_RESULT_OK;
3957 }
3958
3959 /******************************************************************************/
3960
3961 static const struct dc_vbios_funcs vbios_funcs = {
3962 .get_connectors_number = bios_parser_get_connectors_number,
3963
3964 .get_encoder_id = bios_parser_get_encoder_id,
3965
3966 .get_connector_id = bios_parser_get_connector_id,
3967
3968 .get_dst_number = bios_parser_get_dst_number,
3969
3970 .get_src_obj = bios_parser_get_src_obj,
3971
3972 .get_dst_obj = bios_parser_get_dst_obj,
3973
3974 .get_i2c_info = bios_parser_get_i2c_info,
3975
3976 .get_voltage_ddc_info = bios_parser_get_voltage_ddc_info,
3977
3978 .get_thermal_ddc_info = bios_parser_get_thermal_ddc_info,
3979
3980 .get_hpd_info = bios_parser_get_hpd_info,
3981
3982 .get_device_tag = bios_parser_get_device_tag,
3983
3984 .get_firmware_info = bios_parser_get_firmware_info,
3985
3986 .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info,
3987
3988 .get_ss_entry_number = bios_parser_get_ss_entry_number,
3989
3990 .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
3991
3992 .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
3993
3994 .get_encoder_cap_info = bios_parser_get_encoder_cap_info,
3995
3996 /* bios scratch register communication */
3997 .is_accelerated_mode = bios_is_accelerated_mode,
3998 .get_vga_enabled_displays = bios_get_vga_enabled_displays,
3999
4000 .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
4001
4002 .is_device_id_supported = bios_parser_is_device_id_supported,
4003
4004 /* COMMANDS */
4005 .encoder_control = bios_parser_encoder_control,
4006
4007 .transmitter_control = bios_parser_transmitter_control,
4008
4009 .crt_control = bios_parser_crt_control, /* not used in DAL3. keep for now in case we need to support VGA on Bonaire */
4010
4011 .enable_crtc = bios_parser_enable_crtc,
4012
4013 .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
4014
4015 .set_pixel_clock = bios_parser_set_pixel_clock,
4016
4017 .set_dce_clock = bios_parser_set_dce_clock,
4018
4019 .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
4020
4021 .program_crtc_timing = bios_parser_program_crtc_timing, /* still use. should probably retire and program directly */
4022
4023 .crtc_source_select = bios_parser_crtc_source_select, /* still use. should probably retire and program directly */
4024
4025 .program_display_engine_pll = bios_parser_program_display_engine_pll,
4026
4027 .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
4028
4029 /* SW init and patch */
4030 .post_init = bios_parser_post_init, /* patch vbios table for mxm module by reading i2c */
4031
4032 .bios_parser_destroy = bios_parser_destroy,
4033
4034 .get_board_layout_info = bios_get_board_layout_info,
4035 };
4036
bios_parser_construct(struct bios_parser * bp,struct bp_init_data * init,enum dce_version dce_version)4037 static bool bios_parser_construct(
4038 struct bios_parser *bp,
4039 struct bp_init_data *init,
4040 enum dce_version dce_version)
4041 {
4042 uint16_t *rom_header_offset = NULL;
4043 ATOM_ROM_HEADER *rom_header = NULL;
4044 ATOM_OBJECT_HEADER *object_info_tbl;
4045 struct atom_data_revision tbl_rev = {0};
4046
4047 if (!init)
4048 return false;
4049
4050 if (!init->bios)
4051 return false;
4052
4053 bp->base.funcs = &vbios_funcs;
4054 bp->base.bios = init->bios;
4055 bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
4056
4057 bp->base.ctx = init->ctx;
4058 bp->base.bios_local_image = NULL;
4059
4060 rom_header_offset =
4061 GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
4062
4063 if (!rom_header_offset)
4064 return false;
4065
4066 rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
4067
4068 if (!rom_header)
4069 return false;
4070
4071 get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev);
4072 if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
4073 return false;
4074
4075 bp->master_data_tbl =
4076 GET_IMAGE(ATOM_MASTER_DATA_TABLE,
4077 rom_header->usMasterDataTableOffset);
4078
4079 if (!bp->master_data_tbl)
4080 return false;
4081
4082 bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
4083
4084 if (!bp->object_info_tbl_offset)
4085 return false;
4086
4087 object_info_tbl =
4088 GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
4089
4090 if (!object_info_tbl)
4091 return false;
4092
4093 get_atom_data_table_revision(&object_info_tbl->sHeader,
4094 &bp->object_info_tbl.revision);
4095
4096 if (bp->object_info_tbl.revision.major == 1
4097 && bp->object_info_tbl.revision.minor >= 3) {
4098 ATOM_OBJECT_HEADER_V3 *tbl_v3;
4099
4100 tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
4101 bp->object_info_tbl_offset);
4102 if (!tbl_v3)
4103 return false;
4104
4105 bp->object_info_tbl.v1_3 = tbl_v3;
4106 } else if (bp->object_info_tbl.revision.major == 1
4107 && bp->object_info_tbl.revision.minor >= 1)
4108 bp->object_info_tbl.v1_1 = object_info_tbl;
4109 else
4110 return false;
4111
4112 dal_bios_parser_init_cmd_tbl(bp);
4113 dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
4114
4115 bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base);
4116
4117 return true;
4118 }
4119
4120 /******************************************************************************/
4121