Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012-15 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include <linux/slab.h>
0027 
0028 #include "dm_services.h"
0029 
0030 #include "atom.h"
0031 
0032 #include "dc_bios_types.h"
0033 #include "include/gpio_service_interface.h"
0034 #include "include/grph_object_ctrl_defs.h"
0035 #include "include/bios_parser_interface.h"
0036 #include "include/i2caux_interface.h"
0037 #include "include/logger_interface.h"
0038 
0039 #include "command_table.h"
0040 #include "bios_parser_helper.h"
0041 #include "command_table_helper.h"
0042 #include "bios_parser.h"
0043 #include "bios_parser_types_internal.h"
0044 #include "bios_parser_interface.h"
0045 
0046 #include "bios_parser_common.h"
0047 
0048 #include "dc.h"
0049 
0050 #define THREE_PERCENT_OF_10000 300
0051 
0052 #define LAST_RECORD_TYPE 0xff
0053 
0054 #define DC_LOGGER \
0055     bp->base.ctx->logger
0056 
0057 #define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
0058 
0059 static void get_atom_data_table_revision(
0060     ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
0061     struct atom_data_revision *tbl_revision);
0062 static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
0063     uint16_t **id_list);
0064 static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
0065     struct graphics_object_id id);
0066 static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
0067     ATOM_I2C_RECORD *record,
0068     struct graphics_object_i2c_info *info);
0069 static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
0070     ATOM_OBJECT *object);
0071 static struct device_id device_type_from_device_id(uint16_t device_id);
0072 static uint32_t signal_to_ss_id(enum as_signal_type signal);
0073 static uint32_t get_support_mask_for_device_id(struct device_id device_id);
0074 static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
0075     struct bios_parser *bp,
0076     ATOM_OBJECT *object);
0077 
0078 #define BIOS_IMAGE_SIZE_OFFSET 2
0079 #define BIOS_IMAGE_SIZE_UNIT 512
0080 
0081 /*****************************************************************************/
0082 static bool bios_parser_construct(
0083     struct bios_parser *bp,
0084     struct bp_init_data *init,
0085     enum dce_version dce_version);
0086 
0087 static uint8_t bios_parser_get_connectors_number(
0088     struct dc_bios *dcb);
0089 
0090 static enum bp_result bios_parser_get_embedded_panel_info(
0091     struct dc_bios *dcb,
0092     struct embedded_panel_info *info);
0093 
0094 /*****************************************************************************/
0095 
0096 struct dc_bios *bios_parser_create(
0097     struct bp_init_data *init,
0098     enum dce_version dce_version)
0099 {
0100     struct bios_parser *bp = NULL;
0101 
0102     bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
0103     if (!bp)
0104         return NULL;
0105 
0106     if (bios_parser_construct(bp, init, dce_version))
0107         return &bp->base;
0108 
0109     kfree(bp);
0110     BREAK_TO_DEBUGGER();
0111     return NULL;
0112 }
0113 
0114 static void bios_parser_destruct(struct bios_parser *bp)
0115 {
0116     kfree(bp->base.bios_local_image);
0117     kfree(bp->base.integrated_info);
0118 }
0119 
0120 static void bios_parser_destroy(struct dc_bios **dcb)
0121 {
0122     struct bios_parser *bp = BP_FROM_DCB(*dcb);
0123 
0124     if (!bp) {
0125         BREAK_TO_DEBUGGER();
0126         return;
0127     }
0128 
0129     bios_parser_destruct(bp);
0130 
0131     kfree(bp);
0132     *dcb = NULL;
0133 }
0134 
0135 static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
0136 {
0137     ATOM_OBJECT_TABLE *table;
0138 
0139     uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
0140 
0141     table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
0142 
0143     if (!table)
0144         return 0;
0145     else
0146         return table->ucNumberOfObjects;
0147 }
0148 
0149 static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb)
0150 {
0151     struct bios_parser *bp = BP_FROM_DCB(dcb);
0152 
0153     return get_number_of_objects(bp,
0154         le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
0155 }
0156 
0157 static struct graphics_object_id bios_parser_get_connector_id(
0158     struct dc_bios *dcb,
0159     uint8_t i)
0160 {
0161     struct bios_parser *bp = BP_FROM_DCB(dcb);
0162     struct graphics_object_id object_id = dal_graphics_object_id_init(
0163         0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
0164     uint16_t id;
0165 
0166     uint32_t connector_table_offset = bp->object_info_tbl_offset
0167         + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
0168 
0169     ATOM_OBJECT_TABLE *tbl =
0170         GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
0171 
0172     if (!tbl) {
0173         dm_error("Can't get connector table from atom bios.\n");
0174         return object_id;
0175     }
0176 
0177     if (tbl->ucNumberOfObjects <= i) {
0178         dm_error("Can't find connector id %d in connector table of size %d.\n",
0179              i, tbl->ucNumberOfObjects);
0180         return object_id;
0181     }
0182 
0183     id = le16_to_cpu(tbl->asObjects[i].usObjectID);
0184     object_id = object_id_from_bios_object_id(id);
0185     return object_id;
0186 }
0187 
0188 static enum bp_result bios_parser_get_src_obj(struct dc_bios *dcb,
0189     struct graphics_object_id object_id, uint32_t index,
0190     struct graphics_object_id *src_object_id)
0191 {
0192     uint32_t number;
0193     uint16_t *id;
0194     ATOM_OBJECT *object;
0195     struct bios_parser *bp = BP_FROM_DCB(dcb);
0196 
0197     if (!src_object_id)
0198         return BP_RESULT_BADINPUT;
0199 
0200     object = get_bios_object(bp, object_id);
0201 
0202     if (!object) {
0203         BREAK_TO_DEBUGGER(); /* Invalid object id */
0204         return BP_RESULT_BADINPUT;
0205     }
0206 
0207     number = get_src_obj_list(bp, object, &id);
0208 
0209     if (number <= index)
0210         return BP_RESULT_BADINPUT;
0211 
0212     *src_object_id = object_id_from_bios_object_id(id[index]);
0213 
0214     return BP_RESULT_OK;
0215 }
0216 
0217 static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
0218     struct graphics_object_id id,
0219     struct graphics_object_i2c_info *info)
0220 {
0221     uint32_t offset;
0222     ATOM_OBJECT *object;
0223     ATOM_COMMON_RECORD_HEADER *header;
0224     ATOM_I2C_RECORD *record;
0225     struct bios_parser *bp = BP_FROM_DCB(dcb);
0226 
0227     if (!info)
0228         return BP_RESULT_BADINPUT;
0229 
0230     object = get_bios_object(bp, id);
0231 
0232     if (!object)
0233         return BP_RESULT_BADINPUT;
0234 
0235     offset = le16_to_cpu(object->usRecordOffset)
0236             + bp->object_info_tbl_offset;
0237 
0238     for (;;) {
0239         header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
0240 
0241         if (!header)
0242             return BP_RESULT_BADBIOSTABLE;
0243 
0244         if (LAST_RECORD_TYPE == header->ucRecordType ||
0245             !header->ucRecordSize)
0246             break;
0247 
0248         if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
0249             && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
0250             /* get the I2C info */
0251             record = (ATOM_I2C_RECORD *) header;
0252 
0253             if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
0254                 return BP_RESULT_OK;
0255         }
0256 
0257         offset += header->ucRecordSize;
0258     }
0259 
0260     return BP_RESULT_NORECORD;
0261 }
0262 
0263 static enum bp_result bios_parser_get_hpd_info(struct dc_bios *dcb,
0264     struct graphics_object_id id,
0265     struct graphics_object_hpd_info *info)
0266 {
0267     struct bios_parser *bp = BP_FROM_DCB(dcb);
0268     ATOM_OBJECT *object;
0269     ATOM_HPD_INT_RECORD *record = NULL;
0270 
0271     if (!info)
0272         return BP_RESULT_BADINPUT;
0273 
0274     object = get_bios_object(bp, id);
0275 
0276     if (!object)
0277         return BP_RESULT_BADINPUT;
0278 
0279     record = get_hpd_record(bp, object);
0280 
0281     if (record != NULL) {
0282         info->hpd_int_gpio_uid = record->ucHPDIntGPIOID;
0283         info->hpd_active = record->ucPlugged_PinState;
0284         return BP_RESULT_OK;
0285     }
0286 
0287     return BP_RESULT_NORECORD;
0288 }
0289 
0290 static enum bp_result bios_parser_get_device_tag_record(
0291     struct bios_parser *bp,
0292     ATOM_OBJECT *object,
0293     ATOM_CONNECTOR_DEVICE_TAG_RECORD **record)
0294 {
0295     ATOM_COMMON_RECORD_HEADER *header;
0296     uint32_t offset;
0297 
0298     offset = le16_to_cpu(object->usRecordOffset)
0299             + bp->object_info_tbl_offset;
0300 
0301     for (;;) {
0302         header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
0303 
0304         if (!header)
0305             return BP_RESULT_BADBIOSTABLE;
0306 
0307         offset += header->ucRecordSize;
0308 
0309         if (LAST_RECORD_TYPE == header->ucRecordType ||
0310             !header->ucRecordSize)
0311             break;
0312 
0313         if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
0314             header->ucRecordType)
0315             continue;
0316 
0317         if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
0318             continue;
0319 
0320         *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
0321         return BP_RESULT_OK;
0322     }
0323 
0324     return BP_RESULT_NORECORD;
0325 }
0326 
0327 static enum bp_result bios_parser_get_device_tag(
0328     struct dc_bios *dcb,
0329     struct graphics_object_id connector_object_id,
0330     uint32_t device_tag_index,
0331     struct connector_device_tag_info *info)
0332 {
0333     struct bios_parser *bp = BP_FROM_DCB(dcb);
0334     ATOM_OBJECT *object;
0335     ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
0336     ATOM_CONNECTOR_DEVICE_TAG *device_tag;
0337 
0338     if (!info)
0339         return BP_RESULT_BADINPUT;
0340 
0341     /* getBiosObject will return MXM object */
0342     object = get_bios_object(bp, connector_object_id);
0343 
0344     if (!object) {
0345         BREAK_TO_DEBUGGER(); /* Invalid object id */
0346         return BP_RESULT_BADINPUT;
0347     }
0348 
0349     if (bios_parser_get_device_tag_record(bp, object, &record)
0350         != BP_RESULT_OK)
0351         return BP_RESULT_NORECORD;
0352 
0353     if (device_tag_index >= record->ucNumberOfDevice)
0354         return BP_RESULT_NORECORD;
0355 
0356     device_tag = &record->asDeviceTag[device_tag_index];
0357 
0358     info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
0359     info->dev_id =
0360         device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
0361 
0362     return BP_RESULT_OK;
0363 }
0364 
0365 static enum bp_result get_firmware_info_v1_4(
0366     struct bios_parser *bp,
0367     struct dc_firmware_info *info);
0368 static enum bp_result get_firmware_info_v2_1(
0369     struct bios_parser *bp,
0370     struct dc_firmware_info *info);
0371 static enum bp_result get_firmware_info_v2_2(
0372     struct bios_parser *bp,
0373     struct dc_firmware_info *info);
0374 
0375 static enum bp_result bios_parser_get_firmware_info(
0376     struct dc_bios *dcb,
0377     struct dc_firmware_info *info)
0378 {
0379     struct bios_parser *bp = BP_FROM_DCB(dcb);
0380     enum bp_result result = BP_RESULT_BADBIOSTABLE;
0381     ATOM_COMMON_TABLE_HEADER *header;
0382     struct atom_data_revision revision;
0383 
0384     if (info && DATA_TABLES(FirmwareInfo)) {
0385         header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
0386             DATA_TABLES(FirmwareInfo));
0387         get_atom_data_table_revision(header, &revision);
0388         switch (revision.major) {
0389         case 1:
0390             switch (revision.minor) {
0391             case 4:
0392                 result = get_firmware_info_v1_4(bp, info);
0393                 break;
0394             default:
0395                 break;
0396             }
0397             break;
0398 
0399         case 2:
0400             switch (revision.minor) {
0401             case 1:
0402                 result = get_firmware_info_v2_1(bp, info);
0403                 break;
0404             case 2:
0405                 result = get_firmware_info_v2_2(bp, info);
0406                 break;
0407             default:
0408                 break;
0409             }
0410             break;
0411         default:
0412             break;
0413         }
0414     }
0415 
0416     return result;
0417 }
0418 
0419 static enum bp_result get_firmware_info_v1_4(
0420     struct bios_parser *bp,
0421     struct dc_firmware_info *info)
0422 {
0423     ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
0424         GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
0425             DATA_TABLES(FirmwareInfo));
0426 
0427     if (!info)
0428         return BP_RESULT_BADINPUT;
0429 
0430     if (!firmware_info)
0431         return BP_RESULT_BADBIOSTABLE;
0432 
0433     memset(info, 0, sizeof(*info));
0434 
0435     /* Pixel clock pll information. We need to convert from 10KHz units into
0436      * KHz units */
0437     info->pll_info.crystal_frequency =
0438         le16_to_cpu(firmware_info->usReferenceClock) * 10;
0439     info->pll_info.min_input_pxl_clk_pll_frequency =
0440         le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
0441     info->pll_info.max_input_pxl_clk_pll_frequency =
0442         le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
0443     info->pll_info.min_output_pxl_clk_pll_frequency =
0444         le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
0445     info->pll_info.max_output_pxl_clk_pll_frequency =
0446         le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
0447 
0448     if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
0449         /* Since there is no information on the SS, report conservative
0450          * value 3% for bandwidth calculation */
0451         /* unit of 0.01% */
0452         info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
0453 
0454     if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
0455         /* Since there is no information on the SS,report conservative
0456          * value 3% for bandwidth calculation */
0457         /* unit of 0.01% */
0458         info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
0459 
0460     return BP_RESULT_OK;
0461 }
0462 
0463 static enum bp_result get_ss_info_v3_1(
0464     struct bios_parser *bp,
0465     uint32_t id,
0466     uint32_t index,
0467     struct spread_spectrum_info *ss_info);
0468 
0469 static enum bp_result get_firmware_info_v2_1(
0470     struct bios_parser *bp,
0471     struct dc_firmware_info *info)
0472 {
0473     ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
0474         GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
0475     struct spread_spectrum_info internalSS;
0476     uint32_t index;
0477 
0478     if (!info)
0479         return BP_RESULT_BADINPUT;
0480 
0481     if (!firmwareInfo)
0482         return BP_RESULT_BADBIOSTABLE;
0483 
0484     memset(info, 0, sizeof(*info));
0485 
0486     /* Pixel clock pll information. We need to convert from 10KHz units into
0487      * KHz units */
0488     info->pll_info.crystal_frequency =
0489         le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
0490     info->pll_info.min_input_pxl_clk_pll_frequency =
0491         le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
0492     info->pll_info.max_input_pxl_clk_pll_frequency =
0493         le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
0494     info->pll_info.min_output_pxl_clk_pll_frequency =
0495         le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
0496     info->pll_info.max_output_pxl_clk_pll_frequency =
0497         le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
0498     info->default_display_engine_pll_frequency =
0499         le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
0500     info->external_clock_source_frequency_for_dp =
0501         le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
0502     info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
0503 
0504     /* There should be only one entry in the SS info table for Memory Clock
0505      */
0506     index = 0;
0507     if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
0508         /* Since there is no information for external SS, report
0509          *  conservative value 3% for bandwidth calculation */
0510         /* unit of 0.01% */
0511         info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
0512     else if (get_ss_info_v3_1(bp,
0513         ASIC_INTERNAL_MEMORY_SS, index, &internalSS) == BP_RESULT_OK) {
0514         if (internalSS.spread_spectrum_percentage) {
0515             info->feature.memory_clk_ss_percentage =
0516                 internalSS.spread_spectrum_percentage;
0517             if (internalSS.type.CENTER_MODE) {
0518                 /* if it is centermode, the exact SS Percentage
0519                  * will be round up of half of the percentage
0520                  * reported in the SS table */
0521                 ++info->feature.memory_clk_ss_percentage;
0522                 info->feature.memory_clk_ss_percentage /= 2;
0523             }
0524         }
0525     }
0526 
0527     /* There should be only one entry in the SS info table for Engine Clock
0528      */
0529     index = 1;
0530     if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
0531         /* Since there is no information for external SS, report
0532          * conservative value 3% for bandwidth calculation */
0533         /* unit of 0.01% */
0534         info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
0535     else if (get_ss_info_v3_1(bp,
0536         ASIC_INTERNAL_ENGINE_SS, index, &internalSS) == BP_RESULT_OK) {
0537         if (internalSS.spread_spectrum_percentage) {
0538             info->feature.engine_clk_ss_percentage =
0539                 internalSS.spread_spectrum_percentage;
0540             if (internalSS.type.CENTER_MODE) {
0541                 /* if it is centermode, the exact SS Percentage
0542                  * will be round up of half of the percentage
0543                  * reported in the SS table */
0544                 ++info->feature.engine_clk_ss_percentage;
0545                 info->feature.engine_clk_ss_percentage /= 2;
0546             }
0547         }
0548     }
0549 
0550     return BP_RESULT_OK;
0551 }
0552 
0553 static enum bp_result get_firmware_info_v2_2(
0554     struct bios_parser *bp,
0555     struct dc_firmware_info *info)
0556 {
0557     ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
0558     struct spread_spectrum_info internal_ss;
0559     uint32_t index;
0560 
0561     if (!info)
0562         return BP_RESULT_BADINPUT;
0563 
0564     firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
0565         DATA_TABLES(FirmwareInfo));
0566 
0567     if (!firmware_info)
0568         return BP_RESULT_BADBIOSTABLE;
0569 
0570     memset(info, 0, sizeof(*info));
0571 
0572     /* Pixel clock pll information. We need to convert from 10KHz units into
0573      * KHz units */
0574     info->pll_info.crystal_frequency =
0575         le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
0576     info->pll_info.min_input_pxl_clk_pll_frequency =
0577         le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
0578     info->pll_info.max_input_pxl_clk_pll_frequency =
0579         le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
0580     info->pll_info.min_output_pxl_clk_pll_frequency =
0581         le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
0582     info->pll_info.max_output_pxl_clk_pll_frequency =
0583         le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
0584     info->default_display_engine_pll_frequency =
0585         le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
0586     info->external_clock_source_frequency_for_dp =
0587         le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
0588 
0589     /* There should be only one entry in the SS info table for Memory Clock
0590      */
0591     index = 0;
0592     if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
0593         /* Since there is no information for external SS, report
0594          *  conservative value 3% for bandwidth calculation */
0595         /* unit of 0.01% */
0596         info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
0597     else if (get_ss_info_v3_1(bp,
0598             ASIC_INTERNAL_MEMORY_SS, index, &internal_ss) == BP_RESULT_OK) {
0599         if (internal_ss.spread_spectrum_percentage) {
0600             info->feature.memory_clk_ss_percentage =
0601                     internal_ss.spread_spectrum_percentage;
0602             if (internal_ss.type.CENTER_MODE) {
0603                 /* if it is centermode, the exact SS Percentage
0604                  * will be round up of half of the percentage
0605                  * reported in the SS table */
0606                 ++info->feature.memory_clk_ss_percentage;
0607                 info->feature.memory_clk_ss_percentage /= 2;
0608             }
0609         }
0610     }
0611 
0612     /* There should be only one entry in the SS info table for Engine Clock
0613      */
0614     index = 1;
0615     if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
0616         /* Since there is no information for external SS, report
0617          * conservative value 3% for bandwidth calculation */
0618         /* unit of 0.01% */
0619         info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
0620     else if (get_ss_info_v3_1(bp,
0621             ASIC_INTERNAL_ENGINE_SS, index, &internal_ss) == BP_RESULT_OK) {
0622         if (internal_ss.spread_spectrum_percentage) {
0623             info->feature.engine_clk_ss_percentage =
0624                     internal_ss.spread_spectrum_percentage;
0625             if (internal_ss.type.CENTER_MODE) {
0626                 /* if it is centermode, the exact SS Percentage
0627                  * will be round up of half of the percentage
0628                  * reported in the SS table */
0629                 ++info->feature.engine_clk_ss_percentage;
0630                 info->feature.engine_clk_ss_percentage /= 2;
0631             }
0632         }
0633     }
0634 
0635     /* Remote Display */
0636     info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
0637 
0638     /* Is allowed minimum BL level */
0639     info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
0640     /* Used starting from CI */
0641     info->smu_gpu_pll_output_freq =
0642             (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
0643 
0644     return BP_RESULT_OK;
0645 }
0646 
0647 static enum bp_result get_ss_info_v3_1(
0648     struct bios_parser *bp,
0649     uint32_t id,
0650     uint32_t index,
0651     struct spread_spectrum_info *ss_info)
0652 {
0653     ATOM_ASIC_INTERNAL_SS_INFO_V3 *ss_table_header_include;
0654     ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
0655     uint32_t table_size;
0656     uint32_t i;
0657     uint32_t table_index = 0;
0658 
0659     if (!ss_info)
0660         return BP_RESULT_BADINPUT;
0661 
0662     if (!DATA_TABLES(ASIC_InternalSS_Info))
0663         return BP_RESULT_UNSUPPORTED;
0664 
0665     ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
0666         DATA_TABLES(ASIC_InternalSS_Info));
0667     table_size =
0668         (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
0669                 - sizeof(ATOM_COMMON_TABLE_HEADER))
0670                 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
0671 
0672     tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
0673                 &ss_table_header_include->asSpreadSpectrum[0];
0674 
0675     memset(ss_info, 0, sizeof(struct spread_spectrum_info));
0676 
0677     for (i = 0; i < table_size; i++) {
0678         if (tbl[i].ucClockIndication != (uint8_t) id)
0679             continue;
0680 
0681         if (table_index != index) {
0682             table_index++;
0683             continue;
0684         }
0685         /* VBIOS introduced new defines for Version 3, same values as
0686          *  before, so now use these new ones for Version 3.
0687          * Shouldn't affect field VBIOS's V3 as define values are still
0688          *  same.
0689          * #define SS_MODE_V3_CENTRE_SPREAD_MASK                0x01
0690          * #define SS_MODE_V3_EXTERNAL_SS_MASK                  0x02
0691 
0692          * Old VBIOS defines:
0693          * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK        0x00000001
0694          * #define ATOM_EXTERNAL_SS_MASK                  0x00000002
0695          */
0696 
0697         if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
0698             ss_info->type.EXTERNAL = true;
0699 
0700         if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
0701             ss_info->type.CENTER_MODE = true;
0702 
0703         /* Older VBIOS (in field) always provides SS percentage in 0.01%
0704          * units set Divider to 100 */
0705         ss_info->spread_percentage_divider = 100;
0706 
0707         /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
0708         if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
0709                 & tbl[i].ucSpreadSpectrumMode)
0710             ss_info->spread_percentage_divider = 1000;
0711 
0712         ss_info->type.STEP_AND_DELAY_INFO = false;
0713         /* convert [10KHz] into [KHz] */
0714         ss_info->target_clock_range =
0715                 le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
0716         ss_info->spread_spectrum_percentage =
0717                 (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
0718         ss_info->spread_spectrum_range =
0719                 (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
0720 
0721         return BP_RESULT_OK;
0722     }
0723     return BP_RESULT_NORECORD;
0724 }
0725 
0726 static enum bp_result bios_parser_transmitter_control(
0727     struct dc_bios *dcb,
0728     struct bp_transmitter_control *cntl)
0729 {
0730     struct bios_parser *bp = BP_FROM_DCB(dcb);
0731 
0732     if (!bp->cmd_tbl.transmitter_control)
0733         return BP_RESULT_FAILURE;
0734 
0735     return bp->cmd_tbl.transmitter_control(bp, cntl);
0736 }
0737 
0738 static enum bp_result bios_parser_encoder_control(
0739     struct dc_bios *dcb,
0740     struct bp_encoder_control *cntl)
0741 {
0742     struct bios_parser *bp = BP_FROM_DCB(dcb);
0743 
0744     if (!bp->cmd_tbl.dig_encoder_control)
0745         return BP_RESULT_FAILURE;
0746 
0747     return bp->cmd_tbl.dig_encoder_control(bp, cntl);
0748 }
0749 
0750 static enum bp_result bios_parser_adjust_pixel_clock(
0751     struct dc_bios *dcb,
0752     struct bp_adjust_pixel_clock_parameters *bp_params)
0753 {
0754     struct bios_parser *bp = BP_FROM_DCB(dcb);
0755 
0756     if (!bp->cmd_tbl.adjust_display_pll)
0757         return BP_RESULT_FAILURE;
0758 
0759     return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
0760 }
0761 
0762 static enum bp_result bios_parser_set_pixel_clock(
0763     struct dc_bios *dcb,
0764     struct bp_pixel_clock_parameters *bp_params)
0765 {
0766     struct bios_parser *bp = BP_FROM_DCB(dcb);
0767 
0768     if (!bp->cmd_tbl.set_pixel_clock)
0769         return BP_RESULT_FAILURE;
0770 
0771     return bp->cmd_tbl.set_pixel_clock(bp, bp_params);
0772 }
0773 
0774 static enum bp_result bios_parser_set_dce_clock(
0775     struct dc_bios *dcb,
0776     struct bp_set_dce_clock_parameters *bp_params)
0777 {
0778     struct bios_parser *bp = BP_FROM_DCB(dcb);
0779 
0780     if (!bp->cmd_tbl.set_dce_clock)
0781         return BP_RESULT_FAILURE;
0782 
0783     return bp->cmd_tbl.set_dce_clock(bp, bp_params);
0784 }
0785 
0786 static enum bp_result bios_parser_enable_spread_spectrum_on_ppll(
0787     struct dc_bios *dcb,
0788     struct bp_spread_spectrum_parameters *bp_params,
0789     bool enable)
0790 {
0791     struct bios_parser *bp = BP_FROM_DCB(dcb);
0792 
0793     if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
0794         return BP_RESULT_FAILURE;
0795 
0796     return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
0797             bp, bp_params, enable);
0798 
0799 }
0800 
0801 static enum bp_result bios_parser_program_crtc_timing(
0802     struct dc_bios *dcb,
0803     struct bp_hw_crtc_timing_parameters *bp_params)
0804 {
0805     struct bios_parser *bp = BP_FROM_DCB(dcb);
0806 
0807     if (!bp->cmd_tbl.set_crtc_timing)
0808         return BP_RESULT_FAILURE;
0809 
0810     return bp->cmd_tbl.set_crtc_timing(bp, bp_params);
0811 }
0812 
0813 static enum bp_result bios_parser_program_display_engine_pll(
0814     struct dc_bios *dcb,
0815     struct bp_pixel_clock_parameters *bp_params)
0816 {
0817     struct bios_parser *bp = BP_FROM_DCB(dcb);
0818 
0819     if (!bp->cmd_tbl.program_clock)
0820         return BP_RESULT_FAILURE;
0821 
0822     return bp->cmd_tbl.program_clock(bp, bp_params);
0823 
0824 }
0825 
0826 
0827 static enum bp_result bios_parser_enable_crtc(
0828     struct dc_bios *dcb,
0829     enum controller_id id,
0830     bool enable)
0831 {
0832     struct bios_parser *bp = BP_FROM_DCB(dcb);
0833 
0834     if (!bp->cmd_tbl.enable_crtc)
0835         return BP_RESULT_FAILURE;
0836 
0837     return bp->cmd_tbl.enable_crtc(bp, id, enable);
0838 }
0839 
0840 static enum bp_result bios_parser_enable_disp_power_gating(
0841     struct dc_bios *dcb,
0842     enum controller_id controller_id,
0843     enum bp_pipe_control_action action)
0844 {
0845     struct bios_parser *bp = BP_FROM_DCB(dcb);
0846 
0847     if (!bp->cmd_tbl.enable_disp_power_gating)
0848         return BP_RESULT_FAILURE;
0849 
0850     return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id,
0851         action);
0852 }
0853 
0854 static bool bios_parser_is_device_id_supported(
0855     struct dc_bios *dcb,
0856     struct device_id id)
0857 {
0858     struct bios_parser *bp = BP_FROM_DCB(dcb);
0859 
0860     uint32_t mask = get_support_mask_for_device_id(id);
0861 
0862     return (le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport) & mask) != 0;
0863 }
0864 
0865 static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
0866     ATOM_OBJECT *object)
0867 {
0868     ATOM_COMMON_RECORD_HEADER *header;
0869     uint32_t offset;
0870 
0871     if (!object) {
0872         BREAK_TO_DEBUGGER(); /* Invalid object */
0873         return NULL;
0874     }
0875 
0876     offset = le16_to_cpu(object->usRecordOffset)
0877             + bp->object_info_tbl_offset;
0878 
0879     for (;;) {
0880         header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
0881 
0882         if (!header)
0883             return NULL;
0884 
0885         if (LAST_RECORD_TYPE == header->ucRecordType ||
0886             !header->ucRecordSize)
0887             break;
0888 
0889         if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
0890             && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
0891             return (ATOM_HPD_INT_RECORD *) header;
0892 
0893         offset += header->ucRecordSize;
0894     }
0895 
0896     return NULL;
0897 }
0898 
0899 static enum bp_result get_ss_info_from_ss_info_table(
0900     struct bios_parser *bp,
0901     uint32_t id,
0902     struct spread_spectrum_info *ss_info);
0903 static enum bp_result get_ss_info_from_tbl(
0904     struct bios_parser *bp,
0905     uint32_t id,
0906     struct spread_spectrum_info *ss_info);
0907 /**
0908  * bios_parser_get_spread_spectrum_info
0909  * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or
0910  * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info
0911  * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ver 3.1,
0912  * there is only one entry for each signal /ss id.  However, there is
0913  * no planning of supporting multiple spread Sprectum entry for EverGreen
0914  * @dcb:     pointer to the DC BIOS
0915  * @signal:  ASSignalType to be converted to info index
0916  * @index:   number of entries that match the converted info index
0917  * @ss_info: sprectrum information structure,
0918  * return:   Bios parser result code
0919  */
0920 static enum bp_result bios_parser_get_spread_spectrum_info(
0921     struct dc_bios *dcb,
0922     enum as_signal_type signal,
0923     uint32_t index,
0924     struct spread_spectrum_info *ss_info)
0925 {
0926     struct bios_parser *bp = BP_FROM_DCB(dcb);
0927     enum bp_result result = BP_RESULT_UNSUPPORTED;
0928     uint32_t clk_id_ss = 0;
0929     ATOM_COMMON_TABLE_HEADER *header;
0930     struct atom_data_revision tbl_revision;
0931 
0932     if (!ss_info) /* check for bad input */
0933         return BP_RESULT_BADINPUT;
0934     /* signal translation */
0935     clk_id_ss = signal_to_ss_id(signal);
0936 
0937     if (!DATA_TABLES(ASIC_InternalSS_Info))
0938         if (!index)
0939             return get_ss_info_from_ss_info_table(bp, clk_id_ss,
0940                 ss_info);
0941 
0942     header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
0943         DATA_TABLES(ASIC_InternalSS_Info));
0944     get_atom_data_table_revision(header, &tbl_revision);
0945 
0946     switch (tbl_revision.major) {
0947     case 2:
0948         switch (tbl_revision.minor) {
0949         case 1:
0950             /* there can not be more then one entry for Internal
0951              * SS Info table version 2.1 */
0952             if (!index)
0953                 return get_ss_info_from_tbl(bp, clk_id_ss,
0954                         ss_info);
0955             break;
0956         default:
0957             break;
0958         }
0959         break;
0960 
0961     case 3:
0962         switch (tbl_revision.minor) {
0963         case 1:
0964             return get_ss_info_v3_1(bp, clk_id_ss, index, ss_info);
0965         default:
0966             break;
0967         }
0968         break;
0969     default:
0970         break;
0971     }
0972     /* there can not be more then one entry for SS Info table */
0973     return result;
0974 }
0975 
0976 static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
0977     struct bios_parser *bp,
0978     uint32_t id,
0979     struct spread_spectrum_info *info);
0980 
0981 /**
0982  * get_ss_info_from_tbl
0983  * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
0984  * SS_Info table from the VBIOS
0985  * There can not be more than 1 entry for  ASIC_InternalSS_Info Ver 2.1 or
0986  * SS_Info.
0987  *
0988  * @bp:      pointer to the BIOS parser
0989  * @id:      spread sprectrum info index
0990  * @ss_info: sprectrum information structure,
0991  * return:   BIOS parser result code
0992  */
0993 static enum bp_result get_ss_info_from_tbl(
0994     struct bios_parser *bp,
0995     uint32_t id,
0996     struct spread_spectrum_info *ss_info)
0997 {
0998     if (!ss_info) /* check for bad input, if ss_info is not NULL */
0999         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  */
1019 static 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  */
1085 static 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 }
1169 static enum bp_result get_embedded_panel_info_v1_2(
1170     struct bios_parser *bp,
1171     struct embedded_panel_info *info);
1172 static enum bp_result get_embedded_panel_info_v1_3(
1173     struct bios_parser *bp,
1174     struct embedded_panel_info *info);
1175 
1176 static 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 
1211 static 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 
1330 static 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  */
1465 static 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  */
1500 static 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 
1537 static uint32_t get_ss_entry_number(
1538     struct bios_parser *bp,
1539     uint32_t id);
1540 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1541     struct bios_parser *bp,
1542     uint32_t id);
1543 static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1544     struct bios_parser *bp,
1545     uint32_t id);
1546 static 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  */
1559 static 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  */
1612 static 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  */
1682 static 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  */
1700 static 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  */
1736 static 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  */
1779 static 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 
1828 static 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 
1903 static 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 
1926 static 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 
1949 static 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 
1994 static 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 
2021 static 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 
2085 static 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 
2105 static 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 
2131 static 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  */
2205 static 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  */
2226 static 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  */
2376 static 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  */
2513 static 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 
2564 static 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 
2585 static 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 
2689 static 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 
2735 static 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 
2779 static 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 
2839 static 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 /******************************************************************************/