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