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