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 <linux/slab.h>
27
28#include "dm_services.h"
29
30#include "atom.h"
31
32#include "dc_bios_types.h"
33#include "include/gpio_service_interface.h"
34#include "include/grph_object_ctrl_defs.h"
35#include "include/bios_parser_interface.h"
36#include "include/logger_interface.h"
37
38#include "command_table.h"
39#include "bios_parser_helper.h"
40#include "command_table_helper.h"
41#include "bios_parser.h"
42#include "bios_parser_types_internal.h"
43#include "bios_parser_interface.h"
44
45#include "bios_parser_common.h"
46
47#include "dc.h"
48
49#define THREE_PERCENT_OF_10000 300
50
51#define LAST_RECORD_TYPE 0xff
52
53#define DC_LOGGER \
54 bp->base.ctx->logger
55
56#define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
57
58static void get_atom_data_table_revision(
59 ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
60 struct atom_data_revision *tbl_revision);
61static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
62 uint16_t **id_list);
63static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
64 struct graphics_object_id id);
65static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
66 ATOM_I2C_RECORD *record,
67 struct graphics_object_i2c_info *info);
68static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
69 ATOM_OBJECT *object);
70static struct device_id device_type_from_device_id(uint16_t device_id);
71static uint32_t signal_to_ss_id(enum as_signal_type signal);
72static uint32_t get_support_mask_for_device_id(struct device_id device_id);
73static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
74 struct bios_parser *bp,
75 ATOM_OBJECT *object);
76
77#define BIOS_IMAGE_SIZE_OFFSET 2
78#define BIOS_IMAGE_SIZE_UNIT 512
79
80/*****************************************************************************/
81static bool bios_parser_construct(
82 struct bios_parser *bp,
83 struct bp_init_data *init,
84 enum dce_version dce_version);
85
86static uint8_t bios_parser_get_connectors_number(
87 struct dc_bios *dcb);
88
89static enum bp_result bios_parser_get_embedded_panel_info(
90 struct dc_bios *dcb,
91 struct embedded_panel_info *info);
92
93/*****************************************************************************/
94
95struct dc_bios *bios_parser_create(
96 struct bp_init_data *init,
97 enum dce_version dce_version)
98{
99 struct bios_parser *bp;
100
101 bp = kzalloc(size: sizeof(struct bios_parser), GFP_KERNEL);
102 if (!bp)
103 return NULL;
104
105 if (bios_parser_construct(bp, init, dce_version))
106 return &bp->base;
107
108 kfree(objp: bp);
109 BREAK_TO_DEBUGGER();
110 return NULL;
111}
112
113static void bios_parser_destruct(struct bios_parser *bp)
114{
115 kfree(objp: bp->base.bios_local_image);
116 kfree(objp: bp->base.integrated_info);
117}
118
119static void bios_parser_destroy(struct dc_bios **dcb)
120{
121 struct bios_parser *bp = BP_FROM_DCB(*dcb);
122
123 if (!bp) {
124 BREAK_TO_DEBUGGER();
125 return;
126 }
127
128 bios_parser_destruct(bp);
129
130 kfree(objp: bp);
131 *dcb = NULL;
132}
133
134static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
135{
136 ATOM_OBJECT_TABLE *table;
137
138 uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
139
140 table = ((ATOM_OBJECT_TABLE *) bios_get_image(bp: &bp->base,
141 offset: object_table_offset,
142 struct_size(table, asObjects, 1)));
143
144 if (!table)
145 return 0;
146 else
147 return table->ucNumberOfObjects;
148}
149
150static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb)
151{
152 struct bios_parser *bp = BP_FROM_DCB(dcb);
153
154 return get_number_of_objects(bp,
155 le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
156}
157
158static struct graphics_object_id bios_parser_get_connector_id(
159 struct dc_bios *dcb,
160 uint8_t i)
161{
162 struct bios_parser *bp = BP_FROM_DCB(dcb);
163 struct graphics_object_id object_id = dal_graphics_object_id_init(
164 id: 0, enum_id: ENUM_ID_UNKNOWN, type: OBJECT_TYPE_UNKNOWN);
165 uint16_t id;
166
167 uint32_t connector_table_offset = bp->object_info_tbl_offset
168 + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
169
170 ATOM_OBJECT_TABLE *tbl = ((ATOM_OBJECT_TABLE *) bios_get_image(bp: &bp->base,
171 offset: connector_table_offset,
172 struct_size(tbl, asObjects, 1)));
173
174 if (!tbl) {
175 dm_error("Can't get connector table from atom bios.\n");
176 return object_id;
177 }
178
179 if (tbl->ucNumberOfObjects <= i) {
180 dm_error("Can't find connector id %d in connector table of size %d.\n",
181 i, tbl->ucNumberOfObjects);
182 return object_id;
183 }
184
185 id = le16_to_cpu(tbl->asObjects[i].usObjectID);
186 object_id = object_id_from_bios_object_id(bios_object_id: id);
187 return object_id;
188}
189
190static enum bp_result bios_parser_get_src_obj(struct dc_bios *dcb,
191 struct graphics_object_id object_id, uint32_t index,
192 struct graphics_object_id *src_object_id)
193{
194 uint32_t number;
195 uint16_t *id;
196 ATOM_OBJECT *object;
197 struct bios_parser *bp = BP_FROM_DCB(dcb);
198
199 if (!src_object_id)
200 return BP_RESULT_BADINPUT;
201
202 object = get_bios_object(bp, id: object_id);
203
204 if (!object) {
205 BREAK_TO_DEBUGGER(); /* Invalid object id */
206 return BP_RESULT_BADINPUT;
207 }
208
209 number = get_src_obj_list(bp, object, id_list: &id);
210
211 if (number <= index)
212 return BP_RESULT_BADINPUT;
213
214 *src_object_id = object_id_from_bios_object_id(bios_object_id: id[index]);
215
216 return BP_RESULT_OK;
217}
218
219static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
220 struct graphics_object_id id,
221 struct graphics_object_i2c_info *info)
222{
223 uint32_t offset;
224 ATOM_OBJECT *object;
225 ATOM_COMMON_RECORD_HEADER *header;
226 ATOM_I2C_RECORD *record;
227 struct bios_parser *bp = BP_FROM_DCB(dcb);
228
229 if (!info)
230 return BP_RESULT_BADINPUT;
231
232 object = get_bios_object(bp, id);
233
234 if (!object)
235 return BP_RESULT_BADINPUT;
236
237 offset = le16_to_cpu(object->usRecordOffset)
238 + bp->object_info_tbl_offset;
239
240 for (;;) {
241 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
242
243 if (!header)
244 return BP_RESULT_BADBIOSTABLE;
245
246 if (LAST_RECORD_TYPE == header->ucRecordType ||
247 !header->ucRecordSize)
248 break;
249
250 if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
251 && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
252 /* get the I2C info */
253 record = (ATOM_I2C_RECORD *) header;
254
255 if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
256 return BP_RESULT_OK;
257 }
258
259 offset += header->ucRecordSize;
260 }
261
262 return BP_RESULT_NORECORD;
263}
264
265static enum bp_result bios_parser_get_hpd_info(struct dc_bios *dcb,
266 struct graphics_object_id id,
267 struct graphics_object_hpd_info *info)
268{
269 struct bios_parser *bp = BP_FROM_DCB(dcb);
270 ATOM_OBJECT *object;
271 ATOM_HPD_INT_RECORD *record = NULL;
272
273 if (!info)
274 return BP_RESULT_BADINPUT;
275
276 object = get_bios_object(bp, id);
277
278 if (!object)
279 return BP_RESULT_BADINPUT;
280
281 record = get_hpd_record(bp, object);
282
283 if (record != NULL) {
284 info->hpd_int_gpio_uid = record->ucHPDIntGPIOID;
285 info->hpd_active = record->ucPlugged_PinState;
286 return BP_RESULT_OK;
287 }
288
289 return BP_RESULT_NORECORD;
290}
291
292static enum bp_result bios_parser_get_device_tag_record(
293 struct bios_parser *bp,
294 ATOM_OBJECT *object,
295 ATOM_CONNECTOR_DEVICE_TAG_RECORD **record)
296{
297 ATOM_COMMON_RECORD_HEADER *header;
298 uint32_t offset;
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 offset += header->ucRecordSize;
310
311 if (LAST_RECORD_TYPE == header->ucRecordType ||
312 !header->ucRecordSize)
313 break;
314
315 if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
316 header->ucRecordType)
317 continue;
318
319 if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
320 continue;
321
322 *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
323 return BP_RESULT_OK;
324 }
325
326 return BP_RESULT_NORECORD;
327}
328
329static enum bp_result bios_parser_get_device_tag(
330 struct dc_bios *dcb,
331 struct graphics_object_id connector_object_id,
332 uint32_t device_tag_index,
333 struct connector_device_tag_info *info)
334{
335 struct bios_parser *bp = BP_FROM_DCB(dcb);
336 ATOM_OBJECT *object;
337 ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
338 ATOM_CONNECTOR_DEVICE_TAG *device_tag;
339
340 if (!info)
341 return BP_RESULT_BADINPUT;
342
343 /* getBiosObject will return MXM object */
344 object = get_bios_object(bp, id: connector_object_id);
345
346 if (!object) {
347 BREAK_TO_DEBUGGER(); /* Invalid object id */
348 return BP_RESULT_BADINPUT;
349 }
350
351 if (bios_parser_get_device_tag_record(bp, object, record: &record)
352 != BP_RESULT_OK)
353 return BP_RESULT_NORECORD;
354
355 if (device_tag_index >= record->ucNumberOfDevice)
356 return BP_RESULT_NORECORD;
357
358 device_tag = &record->asDeviceTag[device_tag_index];
359
360 info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
361 info->dev_id =
362 device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
363
364 return BP_RESULT_OK;
365}
366
367static enum bp_result get_firmware_info_v1_4(
368 struct bios_parser *bp,
369 struct dc_firmware_info *info);
370static enum bp_result get_firmware_info_v2_1(
371 struct bios_parser *bp,
372 struct dc_firmware_info *info);
373static enum bp_result get_firmware_info_v2_2(
374 struct bios_parser *bp,
375 struct dc_firmware_info *info);
376
377static enum bp_result bios_parser_get_firmware_info(
378 struct dc_bios *dcb,
379 struct dc_firmware_info *info)
380{
381 struct bios_parser *bp = BP_FROM_DCB(dcb);
382 enum bp_result result = BP_RESULT_BADBIOSTABLE;
383 ATOM_COMMON_TABLE_HEADER *header;
384 struct atom_data_revision revision;
385
386 if (info && DATA_TABLES(FirmwareInfo)) {
387 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
388 DATA_TABLES(FirmwareInfo));
389 get_atom_data_table_revision(atom_data_tbl: header, tbl_revision: &revision);
390 switch (revision.major) {
391 case 1:
392 switch (revision.minor) {
393 case 4:
394 result = get_firmware_info_v1_4(bp, info);
395 break;
396 default:
397 break;
398 }
399 break;
400
401 case 2:
402 switch (revision.minor) {
403 case 1:
404 result = get_firmware_info_v2_1(bp, info);
405 break;
406 case 2:
407 result = get_firmware_info_v2_2(bp, info);
408 break;
409 default:
410 break;
411 }
412 break;
413 default:
414 break;
415 }
416 }
417
418 return result;
419}
420
421static enum bp_result get_firmware_info_v1_4(
422 struct bios_parser *bp,
423 struct dc_firmware_info *info)
424{
425 ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
426 GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
427 DATA_TABLES(FirmwareInfo));
428
429 if (!info)
430 return BP_RESULT_BADINPUT;
431
432 if (!firmware_info)
433 return BP_RESULT_BADBIOSTABLE;
434
435 memset(info, 0, sizeof(*info));
436
437 /* Pixel clock pll information. We need to convert from 10KHz units into
438 * KHz units */
439 info->pll_info.crystal_frequency =
440 le16_to_cpu(firmware_info->usReferenceClock) * 10;
441 info->pll_info.min_input_pxl_clk_pll_frequency =
442 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
443 info->pll_info.max_input_pxl_clk_pll_frequency =
444 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
445 info->pll_info.min_output_pxl_clk_pll_frequency =
446 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
447 info->pll_info.max_output_pxl_clk_pll_frequency =
448 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
449
450 if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
451 /* Since there is no information on the SS, report conservative
452 * value 3% for bandwidth calculation */
453 /* unit of 0.01% */
454 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
455
456 if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
457 /* Since there is no information on the SS,report conservative
458 * value 3% for bandwidth calculation */
459 /* unit of 0.01% */
460 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
461
462 return BP_RESULT_OK;
463}
464
465static enum bp_result get_ss_info_v3_1(
466 struct bios_parser *bp,
467 uint32_t id,
468 uint32_t index,
469 struct spread_spectrum_info *ss_info);
470
471static enum bp_result get_firmware_info_v2_1(
472 struct bios_parser *bp,
473 struct dc_firmware_info *info)
474{
475 ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
476 GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
477 struct spread_spectrum_info internalSS;
478 uint32_t index;
479
480 if (!info)
481 return BP_RESULT_BADINPUT;
482
483 if (!firmwareInfo)
484 return BP_RESULT_BADBIOSTABLE;
485
486 memset(info, 0, sizeof(*info));
487
488 /* Pixel clock pll information. We need to convert from 10KHz units into
489 * KHz units */
490 info->pll_info.crystal_frequency =
491 le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
492 info->pll_info.min_input_pxl_clk_pll_frequency =
493 le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
494 info->pll_info.max_input_pxl_clk_pll_frequency =
495 le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
496 info->pll_info.min_output_pxl_clk_pll_frequency =
497 le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
498 info->pll_info.max_output_pxl_clk_pll_frequency =
499 le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
500 info->default_display_engine_pll_frequency =
501 le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
502 info->external_clock_source_frequency_for_dp =
503 le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
504 info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
505
506 /* There should be only one entry in the SS info table for Memory Clock
507 */
508 index = 0;
509 if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
510 /* Since there is no information for external SS, report
511 * conservative value 3% for bandwidth calculation */
512 /* unit of 0.01% */
513 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
514 else if (get_ss_info_v3_1(bp,
515 ASIC_INTERNAL_MEMORY_SS, index, ss_info: &internalSS) == BP_RESULT_OK) {
516 if (internalSS.spread_spectrum_percentage) {
517 info->feature.memory_clk_ss_percentage =
518 internalSS.spread_spectrum_percentage;
519 if (internalSS.type.CENTER_MODE) {
520 /* if it is centermode, the exact SS Percentage
521 * will be round up of half of the percentage
522 * reported in the SS table */
523 ++info->feature.memory_clk_ss_percentage;
524 info->feature.memory_clk_ss_percentage /= 2;
525 }
526 }
527 }
528
529 /* There should be only one entry in the SS info table for Engine Clock
530 */
531 index = 1;
532 if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
533 /* Since there is no information for external SS, report
534 * conservative value 3% for bandwidth calculation */
535 /* unit of 0.01% */
536 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
537 else if (get_ss_info_v3_1(bp,
538 ASIC_INTERNAL_ENGINE_SS, index, ss_info: &internalSS) == BP_RESULT_OK) {
539 if (internalSS.spread_spectrum_percentage) {
540 info->feature.engine_clk_ss_percentage =
541 internalSS.spread_spectrum_percentage;
542 if (internalSS.type.CENTER_MODE) {
543 /* if it is centermode, the exact SS Percentage
544 * will be round up of half of the percentage
545 * reported in the SS table */
546 ++info->feature.engine_clk_ss_percentage;
547 info->feature.engine_clk_ss_percentage /= 2;
548 }
549 }
550 }
551
552 return BP_RESULT_OK;
553}
554
555static enum bp_result get_firmware_info_v2_2(
556 struct bios_parser *bp,
557 struct dc_firmware_info *info)
558{
559 ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
560 struct spread_spectrum_info internal_ss;
561 uint32_t index;
562
563 if (!info)
564 return BP_RESULT_BADINPUT;
565
566 firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
567 DATA_TABLES(FirmwareInfo));
568
569 if (!firmware_info)
570 return BP_RESULT_BADBIOSTABLE;
571
572 memset(info, 0, sizeof(*info));
573
574 /* Pixel clock pll information. We need to convert from 10KHz units into
575 * KHz units */
576 info->pll_info.crystal_frequency =
577 le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
578 info->pll_info.min_input_pxl_clk_pll_frequency =
579 le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
580 info->pll_info.max_input_pxl_clk_pll_frequency =
581 le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
582 info->pll_info.min_output_pxl_clk_pll_frequency =
583 le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
584 info->pll_info.max_output_pxl_clk_pll_frequency =
585 le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
586 info->default_display_engine_pll_frequency =
587 le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
588 info->external_clock_source_frequency_for_dp =
589 le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
590
591 /* There should be only one entry in the SS info table for Memory Clock
592 */
593 index = 0;
594 if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
595 /* Since there is no information for external SS, report
596 * conservative value 3% for bandwidth calculation */
597 /* unit of 0.01% */
598 info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
599 else if (get_ss_info_v3_1(bp,
600 ASIC_INTERNAL_MEMORY_SS, index, ss_info: &internal_ss) == BP_RESULT_OK) {
601 if (internal_ss.spread_spectrum_percentage) {
602 info->feature.memory_clk_ss_percentage =
603 internal_ss.spread_spectrum_percentage;
604 if (internal_ss.type.CENTER_MODE) {
605 /* if it is centermode, the exact SS Percentage
606 * will be round up of half of the percentage
607 * reported in the SS table */
608 ++info->feature.memory_clk_ss_percentage;
609 info->feature.memory_clk_ss_percentage /= 2;
610 }
611 }
612 }
613
614 /* There should be only one entry in the SS info table for Engine Clock
615 */
616 index = 1;
617 if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
618 /* Since there is no information for external SS, report
619 * conservative value 3% for bandwidth calculation */
620 /* unit of 0.01% */
621 info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
622 else if (get_ss_info_v3_1(bp,
623 ASIC_INTERNAL_ENGINE_SS, index, ss_info: &internal_ss) == BP_RESULT_OK) {
624 if (internal_ss.spread_spectrum_percentage) {
625 info->feature.engine_clk_ss_percentage =
626 internal_ss.spread_spectrum_percentage;
627 if (internal_ss.type.CENTER_MODE) {
628 /* if it is centermode, the exact SS Percentage
629 * will be round up of half of the percentage
630 * reported in the SS table */
631 ++info->feature.engine_clk_ss_percentage;
632 info->feature.engine_clk_ss_percentage /= 2;
633 }
634 }
635 }
636
637 /* Remote Display */
638 info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
639
640 /* Is allowed minimum BL level */
641 info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
642 /* Used starting from CI */
643 info->smu_gpu_pll_output_freq =
644 (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
645
646 return BP_RESULT_OK;
647}
648
649static enum bp_result get_ss_info_v3_1(
650 struct bios_parser *bp,
651 uint32_t id,
652 uint32_t index,
653 struct spread_spectrum_info *ss_info)
654{
655 ATOM_ASIC_INTERNAL_SS_INFO_V3 *ss_table_header_include;
656 ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
657 uint32_t table_size;
658 uint32_t i;
659 uint32_t table_index = 0;
660
661 if (!ss_info)
662 return BP_RESULT_BADINPUT;
663
664 if (!DATA_TABLES(ASIC_InternalSS_Info))
665 return BP_RESULT_UNSUPPORTED;
666
667 ss_table_header_include = ((ATOM_ASIC_INTERNAL_SS_INFO_V3 *) bios_get_image(bp: &bp->base,
668 DATA_TABLES(ASIC_InternalSS_Info),
669 struct_size(ss_table_header_include, asSpreadSpectrum, 1)));
670 table_size =
671 (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
672 - sizeof(ATOM_COMMON_TABLE_HEADER))
673 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
674
675 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
676 &ss_table_header_include->asSpreadSpectrum[0];
677
678 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
679
680 for (i = 0; i < table_size; i++) {
681 if (tbl[i].ucClockIndication != (uint8_t) id)
682 continue;
683
684 if (table_index != index) {
685 table_index++;
686 continue;
687 }
688 /* VBIOS introduced new defines for Version 3, same values as
689 * before, so now use these new ones for Version 3.
690 * Shouldn't affect field VBIOS's V3 as define values are still
691 * same.
692 * #define SS_MODE_V3_CENTRE_SPREAD_MASK 0x01
693 * #define SS_MODE_V3_EXTERNAL_SS_MASK 0x02
694
695 * Old VBIOS defines:
696 * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
697 * #define ATOM_EXTERNAL_SS_MASK 0x00000002
698 */
699
700 if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
701 ss_info->type.EXTERNAL = true;
702
703 if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
704 ss_info->type.CENTER_MODE = true;
705
706 /* Older VBIOS (in field) always provides SS percentage in 0.01%
707 * units set Divider to 100 */
708 ss_info->spread_percentage_divider = 100;
709
710 /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
711 if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
712 & tbl[i].ucSpreadSpectrumMode)
713 ss_info->spread_percentage_divider = 1000;
714
715 ss_info->type.STEP_AND_DELAY_INFO = false;
716 /* convert [10KHz] into [KHz] */
717 ss_info->target_clock_range =
718 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
719 ss_info->spread_spectrum_percentage =
720 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
721 ss_info->spread_spectrum_range =
722 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
723
724 return BP_RESULT_OK;
725 }
726 return BP_RESULT_NORECORD;
727}
728
729static enum bp_result bios_parser_transmitter_control(
730 struct dc_bios *dcb,
731 struct bp_transmitter_control *cntl)
732{
733 struct bios_parser *bp = BP_FROM_DCB(dcb);
734
735 if (!bp->cmd_tbl.transmitter_control)
736 return BP_RESULT_FAILURE;
737
738 return bp->cmd_tbl.transmitter_control(bp, cntl);
739}
740
741static enum bp_result bios_parser_encoder_control(
742 struct dc_bios *dcb,
743 struct bp_encoder_control *cntl)
744{
745 struct bios_parser *bp = BP_FROM_DCB(dcb);
746
747 if (!bp->cmd_tbl.dig_encoder_control)
748 return BP_RESULT_FAILURE;
749
750 return bp->cmd_tbl.dig_encoder_control(bp, cntl);
751}
752
753static enum bp_result bios_parser_adjust_pixel_clock(
754 struct dc_bios *dcb,
755 struct bp_adjust_pixel_clock_parameters *bp_params)
756{
757 struct bios_parser *bp = BP_FROM_DCB(dcb);
758
759 if (!bp->cmd_tbl.adjust_display_pll)
760 return BP_RESULT_FAILURE;
761
762 return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
763}
764
765static enum bp_result bios_parser_set_pixel_clock(
766 struct dc_bios *dcb,
767 struct bp_pixel_clock_parameters *bp_params)
768{
769 struct bios_parser *bp = BP_FROM_DCB(dcb);
770
771 if (!bp->cmd_tbl.set_pixel_clock)
772 return BP_RESULT_FAILURE;
773
774 return bp->cmd_tbl.set_pixel_clock(bp, bp_params);
775}
776
777static enum bp_result bios_parser_set_dce_clock(
778 struct dc_bios *dcb,
779 struct bp_set_dce_clock_parameters *bp_params)
780{
781 struct bios_parser *bp = BP_FROM_DCB(dcb);
782
783 if (!bp->cmd_tbl.set_dce_clock)
784 return BP_RESULT_FAILURE;
785
786 return bp->cmd_tbl.set_dce_clock(bp, bp_params);
787}
788
789static enum bp_result bios_parser_enable_spread_spectrum_on_ppll(
790 struct dc_bios *dcb,
791 struct bp_spread_spectrum_parameters *bp_params,
792 bool enable)
793{
794 struct bios_parser *bp = BP_FROM_DCB(dcb);
795
796 if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
797 return BP_RESULT_FAILURE;
798
799 return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
800 bp, bp_params, enable);
801
802}
803
804static enum bp_result bios_parser_program_crtc_timing(
805 struct dc_bios *dcb,
806 struct bp_hw_crtc_timing_parameters *bp_params)
807{
808 struct bios_parser *bp = BP_FROM_DCB(dcb);
809
810 if (!bp->cmd_tbl.set_crtc_timing)
811 return BP_RESULT_FAILURE;
812
813 return bp->cmd_tbl.set_crtc_timing(bp, bp_params);
814}
815
816static enum bp_result bios_parser_program_display_engine_pll(
817 struct dc_bios *dcb,
818 struct bp_pixel_clock_parameters *bp_params)
819{
820 struct bios_parser *bp = BP_FROM_DCB(dcb);
821
822 if (!bp->cmd_tbl.program_clock)
823 return BP_RESULT_FAILURE;
824
825 return bp->cmd_tbl.program_clock(bp, bp_params);
826
827}
828
829
830static enum bp_result bios_parser_enable_crtc(
831 struct dc_bios *dcb,
832 enum controller_id id,
833 bool enable)
834{
835 struct bios_parser *bp = BP_FROM_DCB(dcb);
836
837 if (!bp->cmd_tbl.enable_crtc)
838 return BP_RESULT_FAILURE;
839
840 return bp->cmd_tbl.enable_crtc(bp, id, enable);
841}
842
843static enum bp_result bios_parser_enable_disp_power_gating(
844 struct dc_bios *dcb,
845 enum controller_id controller_id,
846 enum bp_pipe_control_action action)
847{
848 struct bios_parser *bp = BP_FROM_DCB(dcb);
849
850 if (!bp->cmd_tbl.enable_disp_power_gating)
851 return BP_RESULT_FAILURE;
852
853 return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id,
854 action);
855}
856
857static bool bios_parser_is_device_id_supported(
858 struct dc_bios *dcb,
859 struct device_id id)
860{
861 struct bios_parser *bp = BP_FROM_DCB(dcb);
862
863 uint32_t mask = get_support_mask_for_device_id(device_id: id);
864
865 return (le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport) & mask) != 0;
866}
867
868static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
869 ATOM_OBJECT *object)
870{
871 ATOM_COMMON_RECORD_HEADER *header;
872 uint32_t offset;
873
874 if (!object) {
875 BREAK_TO_DEBUGGER(); /* Invalid object */
876 return NULL;
877 }
878
879 offset = le16_to_cpu(object->usRecordOffset)
880 + bp->object_info_tbl_offset;
881
882 for (;;) {
883 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
884
885 if (!header)
886 return NULL;
887
888 if (LAST_RECORD_TYPE == header->ucRecordType ||
889 !header->ucRecordSize)
890 break;
891
892 if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
893 && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
894 return (ATOM_HPD_INT_RECORD *) header;
895
896 offset += header->ucRecordSize;
897 }
898
899 return NULL;
900}
901
902static enum bp_result get_ss_info_from_ss_info_table(
903 struct bios_parser *bp,
904 uint32_t id,
905 struct spread_spectrum_info *ss_info);
906static enum bp_result get_ss_info_from_tbl(
907 struct bios_parser *bp,
908 uint32_t id,
909 struct spread_spectrum_info *ss_info);
910/**
911 * bios_parser_get_spread_spectrum_info
912 * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or
913 * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info
914 * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ver 3.1,
915 * there is only one entry for each signal /ss id. However, there is
916 * no planning of supporting multiple spread Sprectum entry for EverGreen
917 * @dcb: pointer to the DC BIOS
918 * @signal: ASSignalType to be converted to info index
919 * @index: number of entries that match the converted info index
920 * @ss_info: sprectrum information structure,
921 * return: Bios parser result code
922 */
923static enum bp_result bios_parser_get_spread_spectrum_info(
924 struct dc_bios *dcb,
925 enum as_signal_type signal,
926 uint32_t index,
927 struct spread_spectrum_info *ss_info)
928{
929 struct bios_parser *bp = BP_FROM_DCB(dcb);
930 enum bp_result result = BP_RESULT_UNSUPPORTED;
931 uint32_t clk_id_ss = 0;
932 ATOM_COMMON_TABLE_HEADER *header;
933 struct atom_data_revision tbl_revision;
934
935 if (!ss_info) /* check for bad input */
936 return BP_RESULT_BADINPUT;
937 /* signal translation */
938 clk_id_ss = signal_to_ss_id(signal);
939
940 if (!DATA_TABLES(ASIC_InternalSS_Info))
941 if (!index)
942 return get_ss_info_from_ss_info_table(bp, id: clk_id_ss,
943 ss_info);
944
945 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
946 DATA_TABLES(ASIC_InternalSS_Info));
947 get_atom_data_table_revision(atom_data_tbl: header, tbl_revision: &tbl_revision);
948
949 switch (tbl_revision.major) {
950 case 2:
951 switch (tbl_revision.minor) {
952 case 1:
953 /* there can not be more then one entry for Internal
954 * SS Info table version 2.1 */
955 if (!index)
956 return get_ss_info_from_tbl(bp, id: clk_id_ss,
957 ss_info);
958 break;
959 default:
960 break;
961 }
962 break;
963
964 case 3:
965 switch (tbl_revision.minor) {
966 case 1:
967 return get_ss_info_v3_1(bp, id: clk_id_ss, index, ss_info);
968 default:
969 break;
970 }
971 break;
972 default:
973 break;
974 }
975 /* there can not be more then one entry for SS Info table */
976 return result;
977}
978
979static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
980 struct bios_parser *bp,
981 uint32_t id,
982 struct spread_spectrum_info *info);
983
984/**
985 * get_ss_info_from_tbl
986 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
987 * SS_Info table from the VBIOS
988 * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
989 * SS_Info.
990 *
991 * @bp: pointer to the BIOS parser
992 * @id: spread sprectrum info index
993 * @ss_info: sprectrum information structure,
994 * return: BIOS parser result code
995 */
996static enum bp_result get_ss_info_from_tbl(
997 struct bios_parser *bp,
998 uint32_t id,
999 struct spread_spectrum_info *ss_info)
1000{
1001 if (!ss_info) /* check for bad input, if ss_info is not NULL */
1002 return BP_RESULT_BADINPUT;
1003 /* for SS_Info table only support DP and LVDS */
1004 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1005 return get_ss_info_from_ss_info_table(bp, id, ss_info);
1006 else
1007 return get_ss_info_from_internal_ss_info_tbl_V2_1(bp, id,
1008 info: ss_info);
1009}
1010
1011/**
1012 * get_ss_info_from_internal_ss_info_tbl_V2_1
1013 * Get spread sprectrum information from the ASIC_InternalSS_Info table Ver 2.1
1014 * from the VBIOS
1015 * There will not be multiple entry for Ver 2.1
1016 *
1017 * @bp: pointer to the Bios parser
1018 * @id: spread sprectrum info index
1019 * @info: sprectrum information structure,
1020 * return: Bios parser result code
1021 */
1022static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1023 struct bios_parser *bp,
1024 uint32_t id,
1025 struct spread_spectrum_info *info)
1026{
1027 enum bp_result result = BP_RESULT_UNSUPPORTED;
1028 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header;
1029 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1030 uint32_t tbl_size, i;
1031
1032 if (!DATA_TABLES(ASIC_InternalSS_Info))
1033 return result;
1034
1035 header = ((ATOM_ASIC_INTERNAL_SS_INFO_V2 *) bios_get_image(
1036 bp: &bp->base,
1037 DATA_TABLES(ASIC_InternalSS_Info),
1038 struct_size(header, asSpreadSpectrum, 1)));
1039
1040 memset(info, 0, sizeof(struct spread_spectrum_info));
1041
1042 tbl_size = (le16_to_cpu(header->sHeader.usStructureSize)
1043 - sizeof(ATOM_COMMON_TABLE_HEADER))
1044 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1045
1046 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1047 &(header->asSpreadSpectrum[0]);
1048 for (i = 0; i < tbl_size; i++) {
1049 result = BP_RESULT_NORECORD;
1050
1051 if (tbl[i].ucClockIndication != (uint8_t)id)
1052 continue;
1053
1054 if (ATOM_EXTERNAL_SS_MASK
1055 & tbl[i].ucSpreadSpectrumMode) {
1056 info->type.EXTERNAL = true;
1057 }
1058 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
1059 & tbl[i].ucSpreadSpectrumMode) {
1060 info->type.CENTER_MODE = true;
1061 }
1062 info->type.STEP_AND_DELAY_INFO = false;
1063 /* convert [10KHz] into [KHz] */
1064 info->target_clock_range =
1065 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
1066 info->spread_spectrum_percentage =
1067 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
1068 info->spread_spectrum_range =
1069 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
1070 result = BP_RESULT_OK;
1071 break;
1072 }
1073
1074 return result;
1075
1076}
1077
1078/**
1079 * get_ss_info_from_ss_info_table
1080 * Get spread sprectrum information from the SS_Info table from the VBIOS
1081 * if the pointer to info is NULL, indicate the caller what to know the number
1082 * of entries that matches the id
1083 * for, the SS_Info table, there should not be more than 1 entry match.
1084 *
1085 * @bp: pointer to the Bios parser
1086 * @id: spread sprectrum id
1087 * @ss_info: sprectrum information structure,
1088 * return: Bios parser result code
1089 */
1090static enum bp_result get_ss_info_from_ss_info_table(
1091 struct bios_parser *bp,
1092 uint32_t id,
1093 struct spread_spectrum_info *ss_info)
1094{
1095 enum bp_result result = BP_RESULT_UNSUPPORTED;
1096 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1097 ATOM_COMMON_TABLE_HEADER *header;
1098 uint32_t table_size;
1099 uint32_t i;
1100 uint32_t id_local = SS_ID_UNKNOWN;
1101 struct atom_data_revision revision;
1102
1103 /* exist of the SS_Info table */
1104 /* check for bad input, pSSinfo can not be NULL */
1105 if (!DATA_TABLES(SS_Info) || !ss_info)
1106 return result;
1107
1108 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(SS_Info));
1109 get_atom_data_table_revision(atom_data_tbl: header, tbl_revision: &revision);
1110
1111 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info));
1112
1113 if (1 != revision.major || 2 > revision.minor)
1114 return result;
1115
1116 /* have to convert from Internal_SS format to SS_Info format */
1117 switch (id) {
1118 case ASIC_INTERNAL_SS_ON_DP:
1119 id_local = SS_ID_DP1;
1120 break;
1121 case ASIC_INTERNAL_SS_ON_LVDS:
1122 {
1123 struct embedded_panel_info panel_info;
1124
1125 if (bios_parser_get_embedded_panel_info(dcb: &bp->base, info: &panel_info)
1126 == BP_RESULT_OK)
1127 id_local = panel_info.ss_id;
1128 break;
1129 }
1130 default:
1131 break;
1132 }
1133
1134 if (id_local == SS_ID_UNKNOWN)
1135 return result;
1136
1137 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1138 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1139 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1140
1141 for (i = 0; i < table_size; i++) {
1142 if (id_local != (uint32_t)tbl->asSS_Info[i].ucSS_Id)
1143 continue;
1144
1145 memset(ss_info, 0, sizeof(struct spread_spectrum_info));
1146
1147 if (ATOM_EXTERNAL_SS_MASK &
1148 tbl->asSS_Info[i].ucSpreadSpectrumType)
1149 ss_info->type.EXTERNAL = true;
1150
1151 if (ATOM_SS_CENTRE_SPREAD_MODE_MASK &
1152 tbl->asSS_Info[i].ucSpreadSpectrumType)
1153 ss_info->type.CENTER_MODE = true;
1154
1155 ss_info->type.STEP_AND_DELAY_INFO = true;
1156 ss_info->spread_spectrum_percentage =
1157 (uint32_t)le16_to_cpu(tbl->asSS_Info[i].usSpreadSpectrumPercentage);
1158 ss_info->step_and_delay_info.step = tbl->asSS_Info[i].ucSS_Step;
1159 ss_info->step_and_delay_info.delay =
1160 tbl->asSS_Info[i].ucSS_Delay;
1161 ss_info->step_and_delay_info.recommended_ref_div =
1162 tbl->asSS_Info[i].ucRecommendedRef_Div;
1163 ss_info->spread_spectrum_range =
1164 (uint32_t)tbl->asSS_Info[i].ucSS_Range * 10000;
1165
1166 /* there will be only one entry for each display type in SS_info
1167 * table */
1168 result = BP_RESULT_OK;
1169 break;
1170 }
1171
1172 return result;
1173}
1174static enum bp_result get_embedded_panel_info_v1_2(
1175 struct bios_parser *bp,
1176 struct embedded_panel_info *info);
1177static enum bp_result get_embedded_panel_info_v1_3(
1178 struct bios_parser *bp,
1179 struct embedded_panel_info *info);
1180
1181static enum bp_result bios_parser_get_embedded_panel_info(
1182 struct dc_bios *dcb,
1183 struct embedded_panel_info *info)
1184{
1185 struct bios_parser *bp = BP_FROM_DCB(dcb);
1186 ATOM_COMMON_TABLE_HEADER *hdr;
1187
1188 if (!DATA_TABLES(LCD_Info))
1189 return BP_RESULT_FAILURE;
1190
1191 hdr = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(LCD_Info));
1192
1193 if (!hdr)
1194 return BP_RESULT_BADBIOSTABLE;
1195
1196 switch (hdr->ucTableFormatRevision) {
1197 case 1:
1198 switch (hdr->ucTableContentRevision) {
1199 case 0:
1200 case 1:
1201 case 2:
1202 return get_embedded_panel_info_v1_2(bp, info);
1203 case 3:
1204 return get_embedded_panel_info_v1_3(bp, info);
1205 default:
1206 break;
1207 }
1208 break;
1209 default:
1210 break;
1211 }
1212
1213 return BP_RESULT_FAILURE;
1214}
1215
1216static enum bp_result get_embedded_panel_info_v1_2(
1217 struct bios_parser *bp,
1218 struct embedded_panel_info *info)
1219{
1220 ATOM_LVDS_INFO_V12 *lvds;
1221
1222 if (!info)
1223 return BP_RESULT_BADINPUT;
1224
1225 if (!DATA_TABLES(LVDS_Info))
1226 return BP_RESULT_UNSUPPORTED;
1227
1228 lvds =
1229 GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
1230
1231 if (!lvds)
1232 return BP_RESULT_BADBIOSTABLE;
1233
1234 if (1 != lvds->sHeader.ucTableFormatRevision
1235 || 2 > lvds->sHeader.ucTableContentRevision)
1236 return BP_RESULT_UNSUPPORTED;
1237
1238 memset(info, 0, sizeof(struct embedded_panel_info));
1239
1240 /* We need to convert from 10KHz units into KHz units*/
1241 info->lcd_timing.pixel_clk =
1242 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1243 /* usHActive does not include borders, according to VBIOS team*/
1244 info->lcd_timing.horizontal_addressable =
1245 le16_to_cpu(lvds->sLCDTiming.usHActive);
1246 /* usHBlanking_Time includes borders, so we should really be subtracting
1247 * borders duing this translation, but LVDS generally*/
1248 /* doesn't have borders, so we should be okay leaving this as is for
1249 * now. May need to revisit if we ever have LVDS with borders*/
1250 info->lcd_timing.horizontal_blanking_time =
1251 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1252 /* usVActive does not include borders, according to VBIOS team*/
1253 info->lcd_timing.vertical_addressable =
1254 le16_to_cpu(lvds->sLCDTiming.usVActive);
1255 /* usVBlanking_Time includes borders, so we should really be subtracting
1256 * borders duing this translation, but LVDS generally*/
1257 /* doesn't have borders, so we should be okay leaving this as is for
1258 * now. May need to revisit if we ever have LVDS with borders*/
1259 info->lcd_timing.vertical_blanking_time =
1260 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1261 info->lcd_timing.horizontal_sync_offset =
1262 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1263 info->lcd_timing.horizontal_sync_width =
1264 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1265 info->lcd_timing.vertical_sync_offset =
1266 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1267 info->lcd_timing.vertical_sync_width =
1268 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1269 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1270 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1271 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1272 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1273 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1274 ~(uint32_t)
1275 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1276 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1277 ~(uint32_t)
1278 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1279 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1280 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1281 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1282 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1283 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1284 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1285 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1286 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1287 info->lcd_timing.misc_info.INTERLACE =
1288 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1289 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1290 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1291 info->ss_id = lvds->ucSS_Id;
1292
1293 {
1294 uint8_t rr = le16_to_cpu(lvds->usSupportedRefreshRate);
1295 /* Get minimum supported refresh rate*/
1296 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1297 info->supported_rr.REFRESH_RATE_30HZ = 1;
1298 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1299 info->supported_rr.REFRESH_RATE_40HZ = 1;
1300 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1301 info->supported_rr.REFRESH_RATE_48HZ = 1;
1302 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1303 info->supported_rr.REFRESH_RATE_50HZ = 1;
1304 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1305 info->supported_rr.REFRESH_RATE_60HZ = 1;
1306 }
1307
1308 /*Drr panel support can be reported by VBIOS*/
1309 if (LCDPANEL_CAP_DRR_SUPPORTED
1310 & lvds->ucLCDPanel_SpecialHandlingCap)
1311 info->drr_enabled = 1;
1312
1313 if (ATOM_PANEL_MISC_DUAL & lvds->ucLVDS_Misc)
1314 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1315
1316 if (ATOM_PANEL_MISC_888RGB & lvds->ucLVDS_Misc)
1317 info->lcd_timing.misc_info.RGB888 = true;
1318
1319 info->lcd_timing.misc_info.GREY_LEVEL =
1320 (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL &
1321 lvds->ucLVDS_Misc) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT;
1322
1323 if (ATOM_PANEL_MISC_SPATIAL & lvds->ucLVDS_Misc)
1324 info->lcd_timing.misc_info.SPATIAL = true;
1325
1326 if (ATOM_PANEL_MISC_TEMPORAL & lvds->ucLVDS_Misc)
1327 info->lcd_timing.misc_info.TEMPORAL = true;
1328
1329 if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
1330 info->lcd_timing.misc_info.API_ENABLED = true;
1331
1332 return BP_RESULT_OK;
1333}
1334
1335static enum bp_result get_embedded_panel_info_v1_3(
1336 struct bios_parser *bp,
1337 struct embedded_panel_info *info)
1338{
1339 ATOM_LCD_INFO_V13 *lvds;
1340
1341 if (!info)
1342 return BP_RESULT_BADINPUT;
1343
1344 if (!DATA_TABLES(LCD_Info))
1345 return BP_RESULT_UNSUPPORTED;
1346
1347 lvds = GET_IMAGE(ATOM_LCD_INFO_V13, DATA_TABLES(LCD_Info));
1348
1349 if (!lvds)
1350 return BP_RESULT_BADBIOSTABLE;
1351
1352 if (!((1 == lvds->sHeader.ucTableFormatRevision)
1353 && (3 <= lvds->sHeader.ucTableContentRevision)))
1354 return BP_RESULT_UNSUPPORTED;
1355
1356 memset(info, 0, sizeof(struct embedded_panel_info));
1357
1358 /* We need to convert from 10KHz units into KHz units */
1359 info->lcd_timing.pixel_clk =
1360 le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1361 /* usHActive does not include borders, according to VBIOS team */
1362 info->lcd_timing.horizontal_addressable =
1363 le16_to_cpu(lvds->sLCDTiming.usHActive);
1364 /* usHBlanking_Time includes borders, so we should really be subtracting
1365 * borders duing this translation, but LVDS generally*/
1366 /* doesn't have borders, so we should be okay leaving this as is for
1367 * now. May need to revisit if we ever have LVDS with borders*/
1368 info->lcd_timing.horizontal_blanking_time =
1369 le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1370 /* usVActive does not include borders, according to VBIOS team*/
1371 info->lcd_timing.vertical_addressable =
1372 le16_to_cpu(lvds->sLCDTiming.usVActive);
1373 /* usVBlanking_Time includes borders, so we should really be subtracting
1374 * borders duing this translation, but LVDS generally*/
1375 /* doesn't have borders, so we should be okay leaving this as is for
1376 * now. May need to revisit if we ever have LVDS with borders*/
1377 info->lcd_timing.vertical_blanking_time =
1378 le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1379 info->lcd_timing.horizontal_sync_offset =
1380 le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1381 info->lcd_timing.horizontal_sync_width =
1382 le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1383 info->lcd_timing.vertical_sync_offset =
1384 le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1385 info->lcd_timing.vertical_sync_width =
1386 le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1387 info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1388 info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1389 info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1390 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1391 info->lcd_timing.misc_info.H_SYNC_POLARITY =
1392 ~(uint32_t)
1393 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1394 info->lcd_timing.misc_info.V_SYNC_POLARITY =
1395 ~(uint32_t)
1396 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1397 info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1398 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1399 info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1400 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1401 info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1402 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1403 info->lcd_timing.misc_info.COMPOSITE_SYNC =
1404 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1405 info->lcd_timing.misc_info.INTERLACE =
1406 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1407 info->lcd_timing.misc_info.DOUBLE_CLOCK =
1408 lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1409 info->ss_id = lvds->ucSS_Id;
1410
1411 /* Drr panel support can be reported by VBIOS*/
1412 if (LCDPANEL_CAP_V13_DRR_SUPPORTED
1413 & lvds->ucLCDPanel_SpecialHandlingCap)
1414 info->drr_enabled = 1;
1415
1416 /* Get supported refresh rate*/
1417 if (info->drr_enabled == 1) {
1418 uint8_t min_rr =
1419 lvds->sRefreshRateSupport.ucMinRefreshRateForDRR;
1420 uint8_t rr = lvds->sRefreshRateSupport.ucSupportedRefreshRate;
1421
1422 if (min_rr != 0) {
1423 if (SUPPORTED_LCD_REFRESHRATE_30Hz & min_rr)
1424 info->supported_rr.REFRESH_RATE_30HZ = 1;
1425 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & min_rr)
1426 info->supported_rr.REFRESH_RATE_40HZ = 1;
1427 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & min_rr)
1428 info->supported_rr.REFRESH_RATE_48HZ = 1;
1429 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & min_rr)
1430 info->supported_rr.REFRESH_RATE_50HZ = 1;
1431 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & min_rr)
1432 info->supported_rr.REFRESH_RATE_60HZ = 1;
1433 } else {
1434 if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1435 info->supported_rr.REFRESH_RATE_30HZ = 1;
1436 else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1437 info->supported_rr.REFRESH_RATE_40HZ = 1;
1438 else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1439 info->supported_rr.REFRESH_RATE_48HZ = 1;
1440 else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1441 info->supported_rr.REFRESH_RATE_50HZ = 1;
1442 else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1443 info->supported_rr.REFRESH_RATE_60HZ = 1;
1444 }
1445 }
1446
1447 if (ATOM_PANEL_MISC_V13_DUAL & lvds->ucLCD_Misc)
1448 info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1449
1450 if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR & lvds->ucLCD_Misc)
1451 info->lcd_timing.misc_info.RGB888 = true;
1452
1453 info->lcd_timing.misc_info.GREY_LEVEL =
1454 (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
1455 lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
1456
1457 return BP_RESULT_OK;
1458}
1459
1460/**
1461 * bios_parser_get_encoder_cap_info - get encoder capability
1462 * information of input object id
1463 *
1464 * @dcb: pointer to the DC BIOS
1465 * @object_id: object id
1466 * @info: encoder cap information structure
1467 *
1468 * return: Bios parser result code
1469 */
1470static enum bp_result bios_parser_get_encoder_cap_info(
1471 struct dc_bios *dcb,
1472 struct graphics_object_id object_id,
1473 struct bp_encoder_cap_info *info)
1474{
1475 struct bios_parser *bp = BP_FROM_DCB(dcb);
1476 ATOM_OBJECT *object;
1477 ATOM_ENCODER_CAP_RECORD_V2 *record = NULL;
1478
1479 if (!info)
1480 return BP_RESULT_BADINPUT;
1481
1482 object = get_bios_object(bp, id: object_id);
1483
1484 if (!object)
1485 return BP_RESULT_BADINPUT;
1486
1487 record = get_encoder_cap_record(bp, object);
1488 if (!record)
1489 return BP_RESULT_NORECORD;
1490
1491 info->DP_HBR2_EN = record->usHBR2En;
1492 info->DP_HBR3_EN = record->usHBR3En;
1493 info->HDMI_6GB_EN = record->usHDMI6GEn;
1494 return BP_RESULT_OK;
1495}
1496
1497/**
1498 * get_encoder_cap_record - Get encoder cap record for the object
1499 *
1500 * @bp: pointer to the BIOS parser
1501 * @object: ATOM object
1502 * return: atom encoder cap record
1503 * note: search all records to find the ATOM_ENCODER_CAP_RECORD_V2 record
1504 */
1505static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
1506 struct bios_parser *bp,
1507 ATOM_OBJECT *object)
1508{
1509 ATOM_COMMON_RECORD_HEADER *header;
1510 uint32_t offset;
1511
1512 if (!object) {
1513 BREAK_TO_DEBUGGER(); /* Invalid object */
1514 return NULL;
1515 }
1516
1517 offset = le16_to_cpu(object->usRecordOffset)
1518 + bp->object_info_tbl_offset;
1519
1520 for (;;) {
1521 header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1522
1523 if (!header)
1524 return NULL;
1525
1526 offset += header->ucRecordSize;
1527
1528 if (LAST_RECORD_TYPE == header->ucRecordType ||
1529 !header->ucRecordSize)
1530 break;
1531
1532 if (ATOM_ENCODER_CAP_RECORD_TYPE != header->ucRecordType)
1533 continue;
1534
1535 if (sizeof(ATOM_ENCODER_CAP_RECORD_V2) <= header->ucRecordSize)
1536 return (ATOM_ENCODER_CAP_RECORD_V2 *)header;
1537 }
1538
1539 return NULL;
1540}
1541
1542static uint32_t get_ss_entry_number(
1543 struct bios_parser *bp,
1544 uint32_t id);
1545static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1546 struct bios_parser *bp,
1547 uint32_t id);
1548static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1549 struct bios_parser *bp,
1550 uint32_t id);
1551static uint32_t get_ss_entry_number_from_ss_info_tbl(
1552 struct bios_parser *bp,
1553 uint32_t id);
1554
1555/**
1556 * bios_parser_get_ss_entry_number
1557 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
1558 * the VBIOS that match the SSid (to be converted from signal)
1559 *
1560 * @dcb: pointer to the DC BIOS
1561 * @signal: ASSignalType to be converted to SSid
1562 * return: number of SS Entry that match the signal
1563 */
1564static uint32_t bios_parser_get_ss_entry_number(
1565 struct dc_bios *dcb,
1566 enum as_signal_type signal)
1567{
1568 struct bios_parser *bp = BP_FROM_DCB(dcb);
1569 uint32_t ss_id = 0;
1570 ATOM_COMMON_TABLE_HEADER *header;
1571 struct atom_data_revision revision;
1572
1573 ss_id = signal_to_ss_id(signal);
1574
1575 if (!DATA_TABLES(ASIC_InternalSS_Info))
1576 return get_ss_entry_number_from_ss_info_tbl(bp, id: ss_id);
1577
1578 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1579 DATA_TABLES(ASIC_InternalSS_Info));
1580 get_atom_data_table_revision(atom_data_tbl: header, tbl_revision: &revision);
1581
1582 switch (revision.major) {
1583 case 2:
1584 switch (revision.minor) {
1585 case 1:
1586 return get_ss_entry_number(bp, id: ss_id);
1587 default:
1588 break;
1589 }
1590 break;
1591 case 3:
1592 switch (revision.minor) {
1593 case 1:
1594 return
1595 get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1596 bp, id: ss_id);
1597 default:
1598 break;
1599 }
1600 break;
1601 default:
1602 break;
1603 }
1604
1605 return 0;
1606}
1607
1608/**
1609 * get_ss_entry_number_from_ss_info_tbl
1610 * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
1611 *
1612 * @bp: pointer to the BIOS parser
1613 * @id: spread spectrum id
1614 * return: number of SS Entry that match the id
1615 * note: There can only be one entry for each id for SS_Info Table
1616 */
1617static uint32_t get_ss_entry_number_from_ss_info_tbl(
1618 struct bios_parser *bp,
1619 uint32_t id)
1620{
1621 ATOM_SPREAD_SPECTRUM_INFO *tbl;
1622 ATOM_COMMON_TABLE_HEADER *header;
1623 uint32_t table_size;
1624 uint32_t i;
1625 uint32_t number = 0;
1626 uint32_t id_local = SS_ID_UNKNOWN;
1627 struct atom_data_revision revision;
1628
1629 /* SS_Info table exist */
1630 if (!DATA_TABLES(SS_Info))
1631 return number;
1632
1633 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1634 DATA_TABLES(SS_Info));
1635 get_atom_data_table_revision(atom_data_tbl: header, tbl_revision: &revision);
1636
1637 tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO,
1638 DATA_TABLES(SS_Info));
1639
1640 if (1 != revision.major || 2 > revision.minor)
1641 return number;
1642
1643 /* have to convert from Internal_SS format to SS_Info format */
1644 switch (id) {
1645 case ASIC_INTERNAL_SS_ON_DP:
1646 id_local = SS_ID_DP1;
1647 break;
1648 case ASIC_INTERNAL_SS_ON_LVDS: {
1649 struct embedded_panel_info panel_info;
1650
1651 if (bios_parser_get_embedded_panel_info(dcb: &bp->base, info: &panel_info)
1652 == BP_RESULT_OK)
1653 id_local = panel_info.ss_id;
1654 break;
1655 }
1656 default:
1657 break;
1658 }
1659
1660 if (id_local == SS_ID_UNKNOWN)
1661 return number;
1662
1663 table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1664 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1665 sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1666
1667 for (i = 0; i < table_size; i++)
1668 if (id_local == (uint32_t)tbl->asSS_Info[i].ucSS_Id) {
1669 number = 1;
1670 break;
1671 }
1672
1673 return number;
1674}
1675
1676/**
1677 * get_ss_entry_number
1678 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
1679 * SS_Info table from the VBIOS
1680 * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
1681 * SS_Info.
1682 *
1683 * @bp: pointer to the BIOS parser
1684 * @id: spread sprectrum info index
1685 * return: Bios parser result code
1686 */
1687static uint32_t get_ss_entry_number(struct bios_parser *bp, uint32_t id)
1688{
1689 if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1690 return get_ss_entry_number_from_ss_info_tbl(bp, id);
1691
1692 return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp, id);
1693}
1694
1695/**
1696 * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
1697 * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
1698 * Ver 2.1 from the VBIOS
1699 * There will not be multiple entry for Ver 2.1
1700 *
1701 * @bp: pointer to the BIOS parser
1702 * @id: spread sprectrum info index
1703 * return: number of SS Entry that match the id
1704 */
1705static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1706 struct bios_parser *bp,
1707 uint32_t id)
1708{
1709 ATOM_ASIC_INTERNAL_SS_INFO_V2 *header_include;
1710 ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1711 uint32_t size;
1712 uint32_t i;
1713
1714 if (!DATA_TABLES(ASIC_InternalSS_Info))
1715 return 0;
1716
1717 header_include = ((ATOM_ASIC_INTERNAL_SS_INFO_V2 *) bios_get_image(
1718 bp: &bp->base,
1719 DATA_TABLES(ASIC_InternalSS_Info),
1720 struct_size(header_include, asSpreadSpectrum, 1)));
1721
1722 size = (le16_to_cpu(header_include->sHeader.usStructureSize)
1723 - sizeof(ATOM_COMMON_TABLE_HEADER))
1724 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1725
1726 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1727 &header_include->asSpreadSpectrum[0];
1728 for (i = 0; i < size; i++)
1729 if (tbl[i].ucClockIndication == (uint8_t)id)
1730 return 1;
1731
1732 return 0;
1733}
1734/**
1735 * get_ss_entry_number_from_internal_ss_info_tbl_V3_1
1736 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
1737 * the VBIOS that matches id
1738 *
1739 * @bp: pointer to the BIOS parser
1740 * @id: spread sprectrum id
1741 * return: number of SS Entry that match the id
1742 */
1743static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1744 struct bios_parser *bp,
1745 uint32_t id)
1746{
1747 uint32_t number = 0;
1748 ATOM_ASIC_INTERNAL_SS_INFO_V3 *header_include;
1749 ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
1750 uint32_t size;
1751 uint32_t i;
1752
1753 if (!DATA_TABLES(ASIC_InternalSS_Info))
1754 return number;
1755
1756 header_include = ((ATOM_ASIC_INTERNAL_SS_INFO_V3 *) bios_get_image(bp: &bp->base,
1757 DATA_TABLES(ASIC_InternalSS_Info),
1758 struct_size(header_include, asSpreadSpectrum, 1)));
1759 size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
1760 sizeof(ATOM_COMMON_TABLE_HEADER)) /
1761 sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
1762
1763 tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
1764 &header_include->asSpreadSpectrum[0];
1765
1766 for (i = 0; i < size; i++)
1767 if (tbl[i].ucClockIndication == (uint8_t)id)
1768 number++;
1769
1770 return number;
1771}
1772
1773/**
1774 * bios_parser_get_gpio_pin_info
1775 * Get GpioPin information of input gpio id
1776 *
1777 * @dcb: pointer to the DC BIOS
1778 * @gpio_id: GPIO ID
1779 * @info: GpioPin information structure
1780 * return: Bios parser result code
1781 * note:
1782 * to get the GPIO PIN INFO, we need:
1783 * 1. get the GPIO_ID from other object table, see GetHPDInfo()
1784 * 2. in DATA_TABLE.GPIO_Pin_LUT, search all records, to get the registerA
1785 * offset/mask
1786 */
1787static enum bp_result bios_parser_get_gpio_pin_info(
1788 struct dc_bios *dcb,
1789 uint32_t gpio_id,
1790 struct gpio_pin_info *info)
1791{
1792 struct bios_parser *bp = BP_FROM_DCB(dcb);
1793 ATOM_GPIO_PIN_LUT *header;
1794 uint32_t count = 0;
1795 uint32_t i = 0;
1796
1797 if (!DATA_TABLES(GPIO_Pin_LUT))
1798 return BP_RESULT_BADBIOSTABLE;
1799
1800 header = ((ATOM_GPIO_PIN_LUT *) bios_get_image(bp: &bp->base,
1801 DATA_TABLES(GPIO_Pin_LUT),
1802 struct_size(header, asGPIO_Pin, 1)));
1803 if (!header)
1804 return BP_RESULT_BADBIOSTABLE;
1805
1806 if (sizeof(ATOM_COMMON_TABLE_HEADER) + struct_size(header, asGPIO_Pin, 1)
1807 > le16_to_cpu(header->sHeader.usStructureSize))
1808 return BP_RESULT_BADBIOSTABLE;
1809
1810 if (1 != header->sHeader.ucTableContentRevision)
1811 return BP_RESULT_UNSUPPORTED;
1812
1813 count = (le16_to_cpu(header->sHeader.usStructureSize)
1814 - sizeof(ATOM_COMMON_TABLE_HEADER))
1815 / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
1816 for (i = 0; i < count; ++i) {
1817 if (header->asGPIO_Pin[i].ucGPIO_ID != gpio_id)
1818 continue;
1819
1820 info->offset =
1821 (uint32_t) le16_to_cpu(header->asGPIO_Pin[i].usGpioPin_AIndex);
1822 info->offset_y = info->offset + 2;
1823 info->offset_en = info->offset + 1;
1824 info->offset_mask = info->offset - 1;
1825
1826 info->mask = (uint32_t) (1 <<
1827 header->asGPIO_Pin[i].ucGpioPinBitShift);
1828 info->mask_y = info->mask + 2;
1829 info->mask_en = info->mask + 1;
1830 info->mask_mask = info->mask - 1;
1831
1832 return BP_RESULT_OK;
1833 }
1834
1835 return BP_RESULT_NORECORD;
1836}
1837
1838static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
1839 ATOM_I2C_RECORD *record,
1840 struct graphics_object_i2c_info *info)
1841{
1842 ATOM_GPIO_I2C_INFO *header;
1843 uint32_t count = 0;
1844
1845 if (!info)
1846 return BP_RESULT_BADINPUT;
1847
1848 /* get the GPIO_I2C info */
1849 if (!DATA_TABLES(GPIO_I2C_Info))
1850 return BP_RESULT_BADBIOSTABLE;
1851
1852 header = GET_IMAGE(ATOM_GPIO_I2C_INFO, DATA_TABLES(GPIO_I2C_Info));
1853 if (!header)
1854 return BP_RESULT_BADBIOSTABLE;
1855
1856 if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_I2C_ASSIGMENT)
1857 > le16_to_cpu(header->sHeader.usStructureSize))
1858 return BP_RESULT_BADBIOSTABLE;
1859
1860 if (1 != header->sHeader.ucTableContentRevision)
1861 return BP_RESULT_UNSUPPORTED;
1862
1863 /* get data count */
1864 count = (le16_to_cpu(header->sHeader.usStructureSize)
1865 - sizeof(ATOM_COMMON_TABLE_HEADER))
1866 / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
1867 if (count < record->sucI2cId.bfI2C_LineMux)
1868 return BP_RESULT_BADBIOSTABLE;
1869
1870 /* get the GPIO_I2C_INFO */
1871 info->i2c_hw_assist = record->sucI2cId.bfHW_Capable;
1872 info->i2c_line = record->sucI2cId.bfI2C_LineMux;
1873 info->i2c_engine_id = record->sucI2cId.bfHW_EngineID;
1874 info->i2c_slave_address = record->ucI2CAddr;
1875
1876 info->gpio_info.clk_mask_register_index =
1877 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkMaskRegisterIndex);
1878 info->gpio_info.clk_en_register_index =
1879 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkEnRegisterIndex);
1880 info->gpio_info.clk_y_register_index =
1881 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkY_RegisterIndex);
1882 info->gpio_info.clk_a_register_index =
1883 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkA_RegisterIndex);
1884 info->gpio_info.data_mask_register_index =
1885 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataMaskRegisterIndex);
1886 info->gpio_info.data_en_register_index =
1887 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataEnRegisterIndex);
1888 info->gpio_info.data_y_register_index =
1889 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataY_RegisterIndex);
1890 info->gpio_info.data_a_register_index =
1891 le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataA_RegisterIndex);
1892
1893 info->gpio_info.clk_mask_shift =
1894 header->asGPIO_Info[info->i2c_line].ucClkMaskShift;
1895 info->gpio_info.clk_en_shift =
1896 header->asGPIO_Info[info->i2c_line].ucClkEnShift;
1897 info->gpio_info.clk_y_shift =
1898 header->asGPIO_Info[info->i2c_line].ucClkY_Shift;
1899 info->gpio_info.clk_a_shift =
1900 header->asGPIO_Info[info->i2c_line].ucClkA_Shift;
1901 info->gpio_info.data_mask_shift =
1902 header->asGPIO_Info[info->i2c_line].ucDataMaskShift;
1903 info->gpio_info.data_en_shift =
1904 header->asGPIO_Info[info->i2c_line].ucDataEnShift;
1905 info->gpio_info.data_y_shift =
1906 header->asGPIO_Info[info->i2c_line].ucDataY_Shift;
1907 info->gpio_info.data_a_shift =
1908 header->asGPIO_Info[info->i2c_line].ucDataA_Shift;
1909
1910 return BP_RESULT_OK;
1911}
1912
1913static bool dal_graphics_object_id_is_valid(struct graphics_object_id id)
1914{
1915 bool rc = true;
1916
1917 switch (id.type) {
1918 case OBJECT_TYPE_UNKNOWN:
1919 rc = false;
1920 break;
1921 case OBJECT_TYPE_GPU:
1922 case OBJECT_TYPE_ENGINE:
1923 /* do NOT check for id.id == 0 */
1924 if (id.enum_id == ENUM_ID_UNKNOWN)
1925 rc = false;
1926 break;
1927 default:
1928 if (id.id == 0 || id.enum_id == ENUM_ID_UNKNOWN)
1929 rc = false;
1930 break;
1931 }
1932
1933 return rc;
1934}
1935
1936static bool dal_graphics_object_id_is_equal(
1937 struct graphics_object_id id1,
1938 struct graphics_object_id id2)
1939{
1940 if (false == dal_graphics_object_id_is_valid(id: id1)) {
1941 dm_output_to_console(
1942 "%s: Warning: comparing invalid object 'id1'!\n", __func__);
1943 return false;
1944 }
1945
1946 if (false == dal_graphics_object_id_is_valid(id: id2)) {
1947 dm_output_to_console(
1948 "%s: Warning: comparing invalid object 'id2'!\n", __func__);
1949 return false;
1950 }
1951
1952 if (id1.id == id2.id && id1.enum_id == id2.enum_id
1953 && id1.type == id2.type)
1954 return true;
1955
1956 return false;
1957}
1958
1959static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
1960 struct graphics_object_id id)
1961{
1962 uint32_t offset;
1963 ATOM_OBJECT_TABLE *tbl;
1964 uint32_t i;
1965
1966 switch (id.type) {
1967 case OBJECT_TYPE_ENCODER:
1968 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
1969 break;
1970
1971 case OBJECT_TYPE_CONNECTOR:
1972 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
1973 break;
1974
1975 case OBJECT_TYPE_ROUTER:
1976 offset = le16_to_cpu(bp->object_info_tbl.v1_1->usRouterObjectTableOffset);
1977 break;
1978
1979 case OBJECT_TYPE_GENERIC:
1980 if (bp->object_info_tbl.revision.minor < 3)
1981 return NULL;
1982 offset = le16_to_cpu(bp->object_info_tbl.v1_3->usMiscObjectTableOffset);
1983 break;
1984
1985 default:
1986 return NULL;
1987 }
1988
1989 offset += bp->object_info_tbl_offset;
1990
1991 tbl = ((ATOM_OBJECT_TABLE *) bios_get_image(bp: &bp->base, offset,
1992 struct_size(tbl, asObjects, 1)));
1993 if (!tbl)
1994 return NULL;
1995
1996 for (i = 0; i < tbl->ucNumberOfObjects; i++)
1997 if (dal_graphics_object_id_is_equal(id1: id,
1998 id2: object_id_from_bios_object_id(
1999 le16_to_cpu(tbl->asObjects[i].usObjectID))))
2000 return &tbl->asObjects[i];
2001
2002 return NULL;
2003}
2004
2005static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
2006 uint16_t **id_list)
2007{
2008 uint32_t offset;
2009 uint8_t *number;
2010
2011 if (!object) {
2012 BREAK_TO_DEBUGGER(); /* Invalid object id */
2013 return 0;
2014 }
2015
2016 offset = le16_to_cpu(object->usSrcDstTableOffset)
2017 + bp->object_info_tbl_offset;
2018
2019 number = GET_IMAGE(uint8_t, offset);
2020 if (!number)
2021 return 0;
2022
2023 offset += sizeof(uint8_t);
2024 *id_list = (uint16_t *)bios_get_image(bp: &bp->base, offset, size: *number * sizeof(uint16_t));
2025
2026 if (!*id_list)
2027 return 0;
2028
2029 return *number;
2030}
2031
2032static struct device_id device_type_from_device_id(uint16_t device_id)
2033{
2034
2035 struct device_id result_device_id = {0};
2036
2037 switch (device_id) {
2038 case ATOM_DEVICE_LCD1_SUPPORT:
2039 result_device_id.device_type = DEVICE_TYPE_LCD;
2040 result_device_id.enum_id = 1;
2041 break;
2042
2043 case ATOM_DEVICE_LCD2_SUPPORT:
2044 result_device_id.device_type = DEVICE_TYPE_LCD;
2045 result_device_id.enum_id = 2;
2046 break;
2047
2048 case ATOM_DEVICE_CRT1_SUPPORT:
2049 result_device_id.device_type = DEVICE_TYPE_CRT;
2050 result_device_id.enum_id = 1;
2051 break;
2052
2053 case ATOM_DEVICE_CRT2_SUPPORT:
2054 result_device_id.device_type = DEVICE_TYPE_CRT;
2055 result_device_id.enum_id = 2;
2056 break;
2057
2058 case ATOM_DEVICE_DFP1_SUPPORT:
2059 result_device_id.device_type = DEVICE_TYPE_DFP;
2060 result_device_id.enum_id = 1;
2061 break;
2062
2063 case ATOM_DEVICE_DFP2_SUPPORT:
2064 result_device_id.device_type = DEVICE_TYPE_DFP;
2065 result_device_id.enum_id = 2;
2066 break;
2067
2068 case ATOM_DEVICE_DFP3_SUPPORT:
2069 result_device_id.device_type = DEVICE_TYPE_DFP;
2070 result_device_id.enum_id = 3;
2071 break;
2072
2073 case ATOM_DEVICE_DFP4_SUPPORT:
2074 result_device_id.device_type = DEVICE_TYPE_DFP;
2075 result_device_id.enum_id = 4;
2076 break;
2077
2078 case ATOM_DEVICE_DFP5_SUPPORT:
2079 result_device_id.device_type = DEVICE_TYPE_DFP;
2080 result_device_id.enum_id = 5;
2081 break;
2082
2083 case ATOM_DEVICE_DFP6_SUPPORT:
2084 result_device_id.device_type = DEVICE_TYPE_DFP;
2085 result_device_id.enum_id = 6;
2086 break;
2087
2088 default:
2089 BREAK_TO_DEBUGGER(); /* Invalid device Id */
2090 result_device_id.device_type = DEVICE_TYPE_UNKNOWN;
2091 result_device_id.enum_id = 0;
2092 }
2093 return result_device_id;
2094}
2095
2096static void get_atom_data_table_revision(
2097 ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
2098 struct atom_data_revision *tbl_revision)
2099{
2100 if (!tbl_revision)
2101 return;
2102
2103 /* initialize the revision to 0 which is invalid revision */
2104 tbl_revision->major = 0;
2105 tbl_revision->minor = 0;
2106
2107 if (!atom_data_tbl)
2108 return;
2109
2110 tbl_revision->major =
2111 (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl);
2112 tbl_revision->minor =
2113 (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl);
2114}
2115
2116static uint32_t signal_to_ss_id(enum as_signal_type signal)
2117{
2118 uint32_t clk_id_ss = 0;
2119
2120 switch (signal) {
2121 case AS_SIGNAL_TYPE_DVI:
2122 clk_id_ss = ASIC_INTERNAL_SS_ON_TMDS;
2123 break;
2124 case AS_SIGNAL_TYPE_HDMI:
2125 clk_id_ss = ASIC_INTERNAL_SS_ON_HDMI;
2126 break;
2127 case AS_SIGNAL_TYPE_LVDS:
2128 clk_id_ss = ASIC_INTERNAL_SS_ON_LVDS;
2129 break;
2130 case AS_SIGNAL_TYPE_DISPLAY_PORT:
2131 clk_id_ss = ASIC_INTERNAL_SS_ON_DP;
2132 break;
2133 case AS_SIGNAL_TYPE_GPU_PLL:
2134 clk_id_ss = ASIC_INTERNAL_GPUPLL_SS;
2135 break;
2136 default:
2137 break;
2138 }
2139 return clk_id_ss;
2140}
2141
2142static uint32_t get_support_mask_for_device_id(struct device_id device_id)
2143{
2144 enum dal_device_type device_type = device_id.device_type;
2145 uint32_t enum_id = device_id.enum_id;
2146
2147 switch (device_type) {
2148 case DEVICE_TYPE_LCD:
2149 switch (enum_id) {
2150 case 1:
2151 return ATOM_DEVICE_LCD1_SUPPORT;
2152 case 2:
2153 return ATOM_DEVICE_LCD2_SUPPORT;
2154 default:
2155 break;
2156 }
2157 break;
2158 case DEVICE_TYPE_CRT:
2159 switch (enum_id) {
2160 case 1:
2161 return ATOM_DEVICE_CRT1_SUPPORT;
2162 case 2:
2163 return ATOM_DEVICE_CRT2_SUPPORT;
2164 default:
2165 break;
2166 }
2167 break;
2168 case DEVICE_TYPE_DFP:
2169 switch (enum_id) {
2170 case 1:
2171 return ATOM_DEVICE_DFP1_SUPPORT;
2172 case 2:
2173 return ATOM_DEVICE_DFP2_SUPPORT;
2174 case 3:
2175 return ATOM_DEVICE_DFP3_SUPPORT;
2176 case 4:
2177 return ATOM_DEVICE_DFP4_SUPPORT;
2178 case 5:
2179 return ATOM_DEVICE_DFP5_SUPPORT;
2180 case 6:
2181 return ATOM_DEVICE_DFP6_SUPPORT;
2182 default:
2183 break;
2184 }
2185 break;
2186 case DEVICE_TYPE_CV:
2187 switch (enum_id) {
2188 case 1:
2189 return ATOM_DEVICE_CV_SUPPORT;
2190 default:
2191 break;
2192 }
2193 break;
2194 case DEVICE_TYPE_TV:
2195 switch (enum_id) {
2196 case 1:
2197 return ATOM_DEVICE_TV1_SUPPORT;
2198 default:
2199 break;
2200 }
2201 break;
2202 default:
2203 break;
2204 }
2205
2206 /* Unidentified device ID, return empty support mask. */
2207 return 0;
2208}
2209
2210/**
2211 * bios_parser_set_scratch_critical_state - update critical state
2212 * bit in VBIOS scratch register
2213 * @dcb: pointer to the DC BIOS
2214 * @state: set or reset state
2215 */
2216static void bios_parser_set_scratch_critical_state(
2217 struct dc_bios *dcb,
2218 bool state)
2219{
2220 bios_set_scratch_critical_state(bios: dcb, state);
2221}
2222
2223/*
2224 * get_integrated_info_v8
2225 *
2226 * @brief
2227 * Get V8 integrated BIOS information
2228 *
2229 * @param
2230 * bios_parser *bp - [in]BIOS parser handler to get master data table
2231 * integrated_info *info - [out] store and output integrated info
2232 *
2233 * return:
2234 * enum bp_result - BP_RESULT_OK if information is available,
2235 * BP_RESULT_BADBIOSTABLE otherwise.
2236 */
2237static enum bp_result get_integrated_info_v8(
2238 struct bios_parser *bp,
2239 struct integrated_info *info)
2240{
2241 ATOM_INTEGRATED_SYSTEM_INFO_V1_8 *info_v8;
2242 uint32_t i;
2243
2244 info_v8 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8,
2245 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2246
2247 if (info_v8 == NULL)
2248 return BP_RESULT_BADBIOSTABLE;
2249 info->boot_up_engine_clock = le32_to_cpu(info_v8->ulBootUpEngineClock) * 10;
2250 info->dentist_vco_freq = le32_to_cpu(info_v8->ulDentistVCOFreq) * 10;
2251 info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
2252
2253 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2254 /* Convert [10KHz] into [KHz] */
2255 info->disp_clk_voltage[i].max_supported_clk =
2256 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].
2257 ulMaximumSupportedCLK) * 10;
2258 info->disp_clk_voltage[i].voltage_index =
2259 le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
2260 }
2261
2262 info->boot_up_req_display_vector =
2263 le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
2264 info->gpu_cap_info =
2265 le32_to_cpu(info_v8->ulGPUCapInfo);
2266
2267 /*
2268 * system_config: Bit[0] = 0 : PCIE power gating disabled
2269 * = 1 : PCIE power gating enabled
2270 * Bit[1] = 0 : DDR-PLL shut down disabled
2271 * = 1 : DDR-PLL shut down enabled
2272 * Bit[2] = 0 : DDR-PLL power down disabled
2273 * = 1 : DDR-PLL power down enabled
2274 */
2275 info->system_config = le32_to_cpu(info_v8->ulSystemConfig);
2276 info->cpu_cap_info = le32_to_cpu(info_v8->ulCPUCapInfo);
2277 info->boot_up_nb_voltage =
2278 le16_to_cpu(info_v8->usBootUpNBVoltage);
2279 info->ext_disp_conn_info_offset =
2280 le16_to_cpu(info_v8->usExtDispConnInfoOffset);
2281 info->memory_type = info_v8->ucMemoryType;
2282 info->ma_channel_number = info_v8->ucUMAChannelNumber;
2283 info->gmc_restore_reset_time =
2284 le32_to_cpu(info_v8->ulGMCRestoreResetTime);
2285
2286 info->minimum_n_clk =
2287 le32_to_cpu(info_v8->ulNbpStateNClkFreq[0]);
2288 for (i = 1; i < 4; ++i)
2289 info->minimum_n_clk =
2290 info->minimum_n_clk < le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]) ?
2291 info->minimum_n_clk : le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]);
2292
2293 info->idle_n_clk = le32_to_cpu(info_v8->ulIdleNClk);
2294 info->ddr_dll_power_up_time =
2295 le32_to_cpu(info_v8->ulDDR_DLL_PowerUpTime);
2296 info->ddr_pll_power_up_time =
2297 le32_to_cpu(info_v8->ulDDR_PLL_PowerUpTime);
2298 info->pcie_clk_ss_type = le16_to_cpu(info_v8->usPCIEClkSSType);
2299 info->lvds_ss_percentage =
2300 le16_to_cpu(info_v8->usLvdsSSPercentage);
2301 info->lvds_sspread_rate_in_10hz =
2302 le16_to_cpu(info_v8->usLvdsSSpreadRateIn10Hz);
2303 info->hdmi_ss_percentage =
2304 le16_to_cpu(info_v8->usHDMISSPercentage);
2305 info->hdmi_sspread_rate_in_10hz =
2306 le16_to_cpu(info_v8->usHDMISSpreadRateIn10Hz);
2307 info->dvi_ss_percentage =
2308 le16_to_cpu(info_v8->usDVISSPercentage);
2309 info->dvi_sspread_rate_in_10_hz =
2310 le16_to_cpu(info_v8->usDVISSpreadRateIn10Hz);
2311
2312 info->max_lvds_pclk_freq_in_single_link =
2313 le16_to_cpu(info_v8->usMaxLVDSPclkFreqInSingleLink);
2314 info->lvds_misc = info_v8->ucLvdsMisc;
2315 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
2316 info_v8->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
2317 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
2318 info_v8->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
2319 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
2320 info_v8->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
2321 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
2322 info_v8->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
2323 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
2324 info_v8->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
2325 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
2326 info_v8->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
2327 info->lvds_off_to_on_delay_in_4ms =
2328 info_v8->ucLVDSOffToOnDelay_in4Ms;
2329 info->lvds_bit_depth_control_val =
2330 le32_to_cpu(info_v8->ulLCDBitDepthControlVal);
2331
2332 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
2333 /* Convert [10KHz] into [KHz] */
2334 info->avail_s_clk[i].supported_s_clk =
2335 le32_to_cpu(info_v8->sAvail_SCLK[i].ulSupportedSCLK) * 10;
2336 info->avail_s_clk[i].voltage_index =
2337 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageIndex);
2338 info->avail_s_clk[i].voltage_id =
2339 le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageID);
2340 }
2341
2342 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
2343 info->ext_disp_conn_info.gu_id[i] =
2344 info_v8->sExtDispConnInfo.ucGuid[i];
2345 }
2346
2347 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
2348 info->ext_disp_conn_info.path[i].device_connector_id =
2349 object_id_from_bios_object_id(
2350 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceConnector));
2351
2352 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
2353 object_id_from_bios_object_id(
2354 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
2355
2356 info->ext_disp_conn_info.path[i].device_tag =
2357 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceTag);
2358 info->ext_disp_conn_info.path[i].device_acpi_enum =
2359 le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
2360 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
2361 info_v8->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
2362 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
2363 info_v8->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
2364 info->ext_disp_conn_info.path[i].channel_mapping.raw =
2365 info_v8->sExtDispConnInfo.sPath[i].ucChannelMapping;
2366 }
2367 info->ext_disp_conn_info.checksum =
2368 info_v8->sExtDispConnInfo.ucChecksum;
2369
2370 return BP_RESULT_OK;
2371}
2372
2373/*
2374 * get_integrated_info_v8
2375 *
2376 * @brief
2377 * Get V8 integrated BIOS information
2378 *
2379 * @param
2380 * bios_parser *bp - [in]BIOS parser handler to get master data table
2381 * integrated_info *info - [out] store and output integrated info
2382 *
2383 * return:
2384 * enum bp_result - BP_RESULT_OK if information is available,
2385 * BP_RESULT_BADBIOSTABLE otherwise.
2386 */
2387static enum bp_result get_integrated_info_v9(
2388 struct bios_parser *bp,
2389 struct integrated_info *info)
2390{
2391 ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info_v9;
2392 uint32_t i;
2393
2394 info_v9 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9,
2395 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2396
2397 if (!info_v9)
2398 return BP_RESULT_BADBIOSTABLE;
2399
2400 info->boot_up_engine_clock = le32_to_cpu(info_v9->ulBootUpEngineClock) * 10;
2401 info->dentist_vco_freq = le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
2402 info->boot_up_uma_clock = le32_to_cpu(info_v9->ulBootUpUMAClock) * 10;
2403
2404 for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2405 /* Convert [10KHz] into [KHz] */
2406 info->disp_clk_voltage[i].max_supported_clk =
2407 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
2408 info->disp_clk_voltage[i].voltage_index =
2409 le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
2410 }
2411
2412 info->boot_up_req_display_vector =
2413 le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
2414 info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
2415
2416 /*
2417 * system_config: Bit[0] = 0 : PCIE power gating disabled
2418 * = 1 : PCIE power gating enabled
2419 * Bit[1] = 0 : DDR-PLL shut down disabled
2420 * = 1 : DDR-PLL shut down enabled
2421 * Bit[2] = 0 : DDR-PLL power down disabled
2422 * = 1 : DDR-PLL power down enabled
2423 */
2424 info->system_config = le32_to_cpu(info_v9->ulSystemConfig);
2425 info->cpu_cap_info = le32_to_cpu(info_v9->ulCPUCapInfo);
2426 info->boot_up_nb_voltage = le16_to_cpu(info_v9->usBootUpNBVoltage);
2427 info->ext_disp_conn_info_offset = le16_to_cpu(info_v9->usExtDispConnInfoOffset);
2428 info->memory_type = info_v9->ucMemoryType;
2429 info->ma_channel_number = info_v9->ucUMAChannelNumber;
2430 info->gmc_restore_reset_time = le32_to_cpu(info_v9->ulGMCRestoreResetTime);
2431
2432 info->minimum_n_clk = le32_to_cpu(info_v9->ulNbpStateNClkFreq[0]);
2433 for (i = 1; i < 4; ++i)
2434 info->minimum_n_clk =
2435 info->minimum_n_clk < le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]) ?
2436 info->minimum_n_clk : le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]);
2437
2438 info->idle_n_clk = le32_to_cpu(info_v9->ulIdleNClk);
2439 info->ddr_dll_power_up_time = le32_to_cpu(info_v9->ulDDR_DLL_PowerUpTime);
2440 info->ddr_pll_power_up_time = le32_to_cpu(info_v9->ulDDR_PLL_PowerUpTime);
2441 info->pcie_clk_ss_type = le16_to_cpu(info_v9->usPCIEClkSSType);
2442 info->lvds_ss_percentage = le16_to_cpu(info_v9->usLvdsSSPercentage);
2443 info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v9->usLvdsSSpreadRateIn10Hz);
2444 info->hdmi_ss_percentage = le16_to_cpu(info_v9->usHDMISSPercentage);
2445 info->hdmi_sspread_rate_in_10hz = le16_to_cpu(info_v9->usHDMISSpreadRateIn10Hz);
2446 info->dvi_ss_percentage = le16_to_cpu(info_v9->usDVISSPercentage);
2447 info->dvi_sspread_rate_in_10_hz = le16_to_cpu(info_v9->usDVISSpreadRateIn10Hz);
2448
2449 info->max_lvds_pclk_freq_in_single_link =
2450 le16_to_cpu(info_v9->usMaxLVDSPclkFreqInSingleLink);
2451 info->lvds_misc = info_v9->ucLvdsMisc;
2452 info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
2453 info_v9->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
2454 info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
2455 info_v9->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
2456 info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
2457 info_v9->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
2458 info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
2459 info_v9->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
2460 info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
2461 info_v9->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
2462 info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
2463 info_v9->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
2464 info->lvds_off_to_on_delay_in_4ms =
2465 info_v9->ucLVDSOffToOnDelay_in4Ms;
2466 info->lvds_bit_depth_control_val =
2467 le32_to_cpu(info_v9->ulLCDBitDepthControlVal);
2468
2469 for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
2470 /* Convert [10KHz] into [KHz] */
2471 info->avail_s_clk[i].supported_s_clk =
2472 le32_to_cpu(info_v9->sAvail_SCLK[i].ulSupportedSCLK) * 10;
2473 info->avail_s_clk[i].voltage_index =
2474 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageIndex);
2475 info->avail_s_clk[i].voltage_id =
2476 le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageID);
2477 }
2478
2479 for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
2480 info->ext_disp_conn_info.gu_id[i] =
2481 info_v9->sExtDispConnInfo.ucGuid[i];
2482 }
2483
2484 for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
2485 info->ext_disp_conn_info.path[i].device_connector_id =
2486 object_id_from_bios_object_id(
2487 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceConnector));
2488
2489 info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
2490 object_id_from_bios_object_id(
2491 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
2492
2493 info->ext_disp_conn_info.path[i].device_tag =
2494 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceTag);
2495 info->ext_disp_conn_info.path[i].device_acpi_enum =
2496 le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
2497 info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
2498 info_v9->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
2499 info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
2500 info_v9->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
2501 info->ext_disp_conn_info.path[i].channel_mapping.raw =
2502 info_v9->sExtDispConnInfo.sPath[i].ucChannelMapping;
2503 }
2504 info->ext_disp_conn_info.checksum =
2505 info_v9->sExtDispConnInfo.ucChecksum;
2506
2507 return BP_RESULT_OK;
2508}
2509
2510/*
2511 * construct_integrated_info
2512 *
2513 * @brief
2514 * Get integrated BIOS information based on table revision
2515 *
2516 * @param
2517 * bios_parser *bp - [in]BIOS parser handler to get master data table
2518 * integrated_info *info - [out] store and output integrated info
2519 *
2520 * return:
2521 * enum bp_result - BP_RESULT_OK if information is available,
2522 * BP_RESULT_BADBIOSTABLE otherwise.
2523 */
2524static enum bp_result construct_integrated_info(
2525 struct bios_parser *bp,
2526 struct integrated_info *info)
2527{
2528 enum bp_result result = BP_RESULT_BADBIOSTABLE;
2529
2530 ATOM_COMMON_TABLE_HEADER *header;
2531 struct atom_data_revision revision;
2532
2533 if (bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo) {
2534 header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
2535 bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
2536
2537 get_atom_data_table_revision(atom_data_tbl: header, tbl_revision: &revision);
2538
2539 /* Don't need to check major revision as they are all 1 */
2540 switch (revision.minor) {
2541 case 8:
2542 result = get_integrated_info_v8(bp, info);
2543 break;
2544 case 9:
2545 result = get_integrated_info_v9(bp, info);
2546 break;
2547 default:
2548 return result;
2549
2550 }
2551 }
2552
2553 /* Sort voltage table from low to high*/
2554 if (result == BP_RESULT_OK) {
2555 uint32_t i;
2556 uint32_t j;
2557
2558 for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
2559 for (j = i; j > 0; --j) {
2560 if (
2561 info->disp_clk_voltage[j].max_supported_clk <
2562 info->disp_clk_voltage[j-1].max_supported_clk) {
2563 /* swap j and j - 1*/
2564 swap(info->disp_clk_voltage[j - 1],
2565 info->disp_clk_voltage[j]);
2566 }
2567 }
2568 }
2569
2570 }
2571
2572 return result;
2573}
2574
2575static struct integrated_info *bios_parser_create_integrated_info(
2576 struct dc_bios *dcb)
2577{
2578 struct bios_parser *bp = BP_FROM_DCB(dcb);
2579 struct integrated_info *info;
2580
2581 info = kzalloc(size: sizeof(struct integrated_info), GFP_KERNEL);
2582
2583 if (info == NULL) {
2584 ASSERT_CRITICAL(0);
2585 return NULL;
2586 }
2587
2588 if (construct_integrated_info(bp, info) == BP_RESULT_OK)
2589 return info;
2590
2591 kfree(objp: info);
2592
2593 return NULL;
2594}
2595
2596static enum bp_result update_slot_layout_info(struct dc_bios *dcb,
2597 unsigned int i,
2598 struct slot_layout_info *slot_layout_info,
2599 unsigned int record_offset)
2600{
2601 unsigned int j;
2602 struct bios_parser *bp;
2603 ATOM_BRACKET_LAYOUT_RECORD *record;
2604 ATOM_COMMON_RECORD_HEADER *record_header;
2605 enum bp_result result = BP_RESULT_NORECORD;
2606
2607 bp = BP_FROM_DCB(dcb);
2608 record = NULL;
2609 record_header = NULL;
2610
2611 for (;;) {
2612
2613 record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
2614 if (record_header == NULL) {
2615 result = BP_RESULT_BADBIOSTABLE;
2616 break;
2617 }
2618
2619 /* the end of the list */
2620 if (record_header->ucRecordType == 0xff ||
2621 record_header->ucRecordSize == 0) {
2622 break;
2623 }
2624
2625 if (record_header->ucRecordType ==
2626 ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
2627 struct_size(record, asConnInfo, 1)
2628 <= record_header->ucRecordSize) {
2629 record = (ATOM_BRACKET_LAYOUT_RECORD *)
2630 (record_header);
2631 result = BP_RESULT_OK;
2632 break;
2633 }
2634
2635 record_offset += record_header->ucRecordSize;
2636 }
2637
2638 /* return if the record not found */
2639 if (result != BP_RESULT_OK)
2640 return result;
2641
2642 /* get slot sizes */
2643 slot_layout_info->length = record->ucLength;
2644 slot_layout_info->width = record->ucWidth;
2645
2646 /* get info for each connector in the slot */
2647 slot_layout_info->num_of_connectors = record->ucConnNum;
2648 for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
2649 slot_layout_info->connectors[j].connector_type =
2650 (enum connector_layout_type)
2651 (record->asConnInfo[j].ucConnectorType);
2652 switch (record->asConnInfo[j].ucConnectorType) {
2653 case CONNECTOR_TYPE_DVI_D:
2654 slot_layout_info->connectors[j].connector_type =
2655 CONNECTOR_LAYOUT_TYPE_DVI_D;
2656 slot_layout_info->connectors[j].length =
2657 CONNECTOR_SIZE_DVI;
2658 break;
2659
2660 case CONNECTOR_TYPE_HDMI:
2661 slot_layout_info->connectors[j].connector_type =
2662 CONNECTOR_LAYOUT_TYPE_HDMI;
2663 slot_layout_info->connectors[j].length =
2664 CONNECTOR_SIZE_HDMI;
2665 break;
2666
2667 case CONNECTOR_TYPE_DISPLAY_PORT:
2668 slot_layout_info->connectors[j].connector_type =
2669 CONNECTOR_LAYOUT_TYPE_DP;
2670 slot_layout_info->connectors[j].length =
2671 CONNECTOR_SIZE_DP;
2672 break;
2673
2674 case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
2675 slot_layout_info->connectors[j].connector_type =
2676 CONNECTOR_LAYOUT_TYPE_MINI_DP;
2677 slot_layout_info->connectors[j].length =
2678 CONNECTOR_SIZE_MINI_DP;
2679 break;
2680
2681 default:
2682 slot_layout_info->connectors[j].connector_type =
2683 CONNECTOR_LAYOUT_TYPE_UNKNOWN;
2684 slot_layout_info->connectors[j].length =
2685 CONNECTOR_SIZE_UNKNOWN;
2686 }
2687
2688 slot_layout_info->connectors[j].position =
2689 record->asConnInfo[j].ucPosition;
2690 slot_layout_info->connectors[j].connector_id =
2691 object_id_from_bios_object_id(
2692 bios_object_id: record->asConnInfo[j].usConnectorObjectId);
2693 }
2694 return result;
2695}
2696
2697
2698static enum bp_result get_bracket_layout_record(struct dc_bios *dcb,
2699 unsigned int bracket_layout_id,
2700 struct slot_layout_info *slot_layout_info)
2701{
2702 unsigned int i;
2703 unsigned int record_offset;
2704 struct bios_parser *bp;
2705 enum bp_result result;
2706 ATOM_OBJECT *object;
2707 ATOM_OBJECT_TABLE *object_table;
2708 unsigned int genericTableOffset;
2709
2710 bp = BP_FROM_DCB(dcb);
2711 object = NULL;
2712 if (slot_layout_info == NULL) {
2713 DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
2714 return BP_RESULT_BADINPUT;
2715 }
2716
2717
2718 genericTableOffset = bp->object_info_tbl_offset +
2719 bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
2720 object_table = ((ATOM_OBJECT_TABLE *) bios_get_image(bp: &bp->base,
2721 offset: genericTableOffset,
2722 struct_size(object_table, asObjects, 1)));
2723 if (!object_table)
2724 return BP_RESULT_FAILURE;
2725
2726 result = BP_RESULT_NORECORD;
2727 for (i = 0; i < object_table->ucNumberOfObjects; ++i) {
2728
2729 if (bracket_layout_id ==
2730 object_table->asObjects[i].usObjectID) {
2731
2732 object = &object_table->asObjects[i];
2733 record_offset = object->usRecordOffset +
2734 bp->object_info_tbl_offset;
2735
2736 result = update_slot_layout_info(dcb, i,
2737 slot_layout_info, record_offset);
2738 break;
2739 }
2740 }
2741 return result;
2742}
2743
2744static enum bp_result bios_get_board_layout_info(
2745 struct dc_bios *dcb,
2746 struct board_layout_info *board_layout_info)
2747{
2748 unsigned int i;
2749 struct bios_parser *bp;
2750 enum bp_result record_result;
2751
2752 const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
2753 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
2754 GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
2755 0, 0
2756 };
2757
2758 bp = BP_FROM_DCB(dcb);
2759
2760 if (board_layout_info == NULL) {
2761 DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
2762 return BP_RESULT_BADINPUT;
2763 }
2764
2765 board_layout_info->num_of_slots = 0;
2766
2767 for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
2768 record_result = get_bracket_layout_record(dcb,
2769 bracket_layout_id: slot_index_to_vbios_id[i],
2770 slot_layout_info: &board_layout_info->slots[i]);
2771
2772 if (record_result == BP_RESULT_NORECORD && i > 0)
2773 break; /* no more slots present in bios */
2774 else if (record_result != BP_RESULT_OK)
2775 return record_result; /* fail */
2776
2777 ++board_layout_info->num_of_slots;
2778 }
2779
2780 /* all data is valid */
2781 board_layout_info->is_number_of_slots_valid = 1;
2782 board_layout_info->is_slots_size_valid = 1;
2783 board_layout_info->is_connector_offsets_valid = 1;
2784 board_layout_info->is_connector_lengths_valid = 1;
2785
2786 return BP_RESULT_OK;
2787}
2788
2789/******************************************************************************/
2790
2791static const struct dc_vbios_funcs vbios_funcs = {
2792 .get_connectors_number = bios_parser_get_connectors_number,
2793
2794 .get_connector_id = bios_parser_get_connector_id,
2795
2796 .get_src_obj = bios_parser_get_src_obj,
2797
2798 .get_i2c_info = bios_parser_get_i2c_info,
2799
2800 .get_hpd_info = bios_parser_get_hpd_info,
2801
2802 .get_device_tag = bios_parser_get_device_tag,
2803
2804 .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info,
2805
2806 .get_ss_entry_number = bios_parser_get_ss_entry_number,
2807
2808 .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
2809
2810 .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
2811
2812 .get_encoder_cap_info = bios_parser_get_encoder_cap_info,
2813
2814 /* bios scratch register communication */
2815 .is_accelerated_mode = bios_is_accelerated_mode,
2816
2817 .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
2818
2819 .is_device_id_supported = bios_parser_is_device_id_supported,
2820
2821 /* COMMANDS */
2822 .encoder_control = bios_parser_encoder_control,
2823
2824 .transmitter_control = bios_parser_transmitter_control,
2825
2826 .enable_crtc = bios_parser_enable_crtc,
2827
2828 .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
2829
2830 .set_pixel_clock = bios_parser_set_pixel_clock,
2831
2832 .set_dce_clock = bios_parser_set_dce_clock,
2833
2834 .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
2835
2836 .program_crtc_timing = bios_parser_program_crtc_timing, /* still use. should probably retire and program directly */
2837
2838 .program_display_engine_pll = bios_parser_program_display_engine_pll,
2839
2840 .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
2841
2842 /* SW init and patch */
2843
2844 .bios_parser_destroy = bios_parser_destroy,
2845
2846 .get_board_layout_info = bios_get_board_layout_info,
2847
2848 .get_atom_dc_golden_table = NULL
2849};
2850
2851static bool bios_parser_construct(
2852 struct bios_parser *bp,
2853 struct bp_init_data *init,
2854 enum dce_version dce_version)
2855{
2856 uint16_t *rom_header_offset = NULL;
2857 ATOM_ROM_HEADER *rom_header = NULL;
2858 ATOM_OBJECT_HEADER *object_info_tbl;
2859 struct atom_data_revision tbl_rev = {0};
2860
2861 if (!init)
2862 return false;
2863
2864 if (!init->bios)
2865 return false;
2866
2867 bp->base.funcs = &vbios_funcs;
2868 bp->base.bios = init->bios;
2869 bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
2870
2871 bp->base.ctx = init->ctx;
2872 bp->base.bios_local_image = NULL;
2873
2874 rom_header_offset =
2875 GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
2876
2877 if (!rom_header_offset)
2878 return false;
2879
2880 rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
2881
2882 if (!rom_header)
2883 return false;
2884
2885 get_atom_data_table_revision(atom_data_tbl: &rom_header->sHeader, tbl_revision: &tbl_rev);
2886 if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
2887 return false;
2888
2889 bp->master_data_tbl =
2890 GET_IMAGE(ATOM_MASTER_DATA_TABLE,
2891 rom_header->usMasterDataTableOffset);
2892
2893 if (!bp->master_data_tbl)
2894 return false;
2895
2896 bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
2897
2898 if (!bp->object_info_tbl_offset)
2899 return false;
2900
2901 object_info_tbl =
2902 GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
2903
2904 if (!object_info_tbl)
2905 return false;
2906
2907 get_atom_data_table_revision(atom_data_tbl: &object_info_tbl->sHeader,
2908 tbl_revision: &bp->object_info_tbl.revision);
2909
2910 if (bp->object_info_tbl.revision.major == 1
2911 && bp->object_info_tbl.revision.minor >= 3) {
2912 ATOM_OBJECT_HEADER_V3 *tbl_v3;
2913
2914 tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
2915 bp->object_info_tbl_offset);
2916 if (!tbl_v3)
2917 return false;
2918
2919 bp->object_info_tbl.v1_3 = tbl_v3;
2920 } else if (bp->object_info_tbl.revision.major == 1
2921 && bp->object_info_tbl.revision.minor >= 1)
2922 bp->object_info_tbl.v1_1 = object_info_tbl;
2923 else
2924 return false;
2925
2926 dal_bios_parser_init_cmd_tbl(bp);
2927 dal_bios_parser_init_cmd_tbl_helper(h: &bp->cmd_helper, dce: dce_version);
2928
2929 bp->base.integrated_info = bios_parser_create_integrated_info(dcb: &bp->base);
2930 bp->base.fw_info_valid = bios_parser_get_firmware_info(dcb: &bp->base, info: &bp->base.fw_info) == BP_RESULT_OK;
2931
2932 return true;
2933}
2934
2935/******************************************************************************/
2936

source code of linux/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c