cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bios_parser.c (84746B)


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