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