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