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 "dm_services.h"
  27
  28#include "atom.h"
  29
  30#include "dc_bios_types.h"
  31#include "include/gpio_service_interface.h"
  32#include "include/grph_object_ctrl_defs.h"
  33#include "include/bios_parser_interface.h"
  34#include "include/i2caux_interface.h"
  35#include "include/logger_interface.h"
  36
  37#include "command_table.h"
  38#include "bios_parser_helper.h"
  39#include "command_table_helper.h"
  40#include "bios_parser.h"
  41#include "bios_parser_types_internal.h"
  42#include "bios_parser_interface.h"
  43
  44#include "bios_parser_common.h"
  45/* TODO remove - only needed for default i2c speed */
  46#include "dc.h"
  47
  48#define THREE_PERCENT_OF_10000 300
  49
  50#define LAST_RECORD_TYPE 0xff
  51
  52#define DC_LOGGER \
  53        bp->base.ctx->logger
  54
  55/* GUID to validate external display connection info table (aka OPM module) */
  56static const uint8_t ext_display_connection_guid[NUMBER_OF_UCHAR_FOR_GUID] = {
  57        0x91, 0x6E, 0x57, 0x09,
  58        0x3F, 0x6D, 0xD2, 0x11,
  59        0x39, 0x8E, 0x00, 0xA0,
  60        0xC9, 0x69, 0x72, 0x3B};
  61
  62#define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
  63
  64static void get_atom_data_table_revision(
  65        ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
  66        struct atom_data_revision *tbl_revision);
  67static uint32_t get_dst_number_from_object(struct bios_parser *bp,
  68        ATOM_OBJECT *object);
  69static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
  70        uint16_t **id_list);
  71static uint32_t get_dest_obj_list(struct bios_parser *bp,
  72        ATOM_OBJECT *object, uint16_t **id_list);
  73static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
  74        struct graphics_object_id id);
  75static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
  76        ATOM_I2C_RECORD *record,
  77        struct graphics_object_i2c_info *info);
  78static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
  79        ATOM_OBJECT *object);
  80static struct device_id device_type_from_device_id(uint16_t device_id);
  81static uint32_t signal_to_ss_id(enum as_signal_type signal);
  82static uint32_t get_support_mask_for_device_id(struct device_id device_id);
  83static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
  84        struct bios_parser *bp,
  85        ATOM_OBJECT *object);
  86
  87#define BIOS_IMAGE_SIZE_OFFSET 2
  88#define BIOS_IMAGE_SIZE_UNIT 512
  89
  90/*****************************************************************************/
  91static bool bios_parser_construct(
  92        struct bios_parser *bp,
  93        struct bp_init_data *init,
  94        enum dce_version dce_version);
  95
  96static uint8_t bios_parser_get_connectors_number(
  97        struct dc_bios *dcb);
  98
  99static enum bp_result bios_parser_get_embedded_panel_info(
 100        struct dc_bios *dcb,
 101        struct embedded_panel_info *info);
 102
 103/*****************************************************************************/
 104
 105struct dc_bios *bios_parser_create(
 106        struct bp_init_data *init,
 107        enum dce_version dce_version)
 108{
 109        struct bios_parser *bp = NULL;
 110
 111        bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
 112        if (!bp)
 113                return NULL;
 114
 115        if (bios_parser_construct(bp, init, dce_version))
 116                return &bp->base;
 117
 118        kfree(bp);
 119        BREAK_TO_DEBUGGER();
 120        return NULL;
 121}
 122
 123static void destruct(struct bios_parser *bp)
 124{
 125        kfree(bp->base.bios_local_image);
 126        kfree(bp->base.integrated_info);
 127}
 128
 129static void bios_parser_destroy(struct dc_bios **dcb)
 130{
 131        struct bios_parser *bp = BP_FROM_DCB(*dcb);
 132
 133        if (!bp) {
 134                BREAK_TO_DEBUGGER();
 135                return;
 136        }
 137
 138        destruct(bp);
 139
 140        kfree(bp);
 141        *dcb = NULL;
 142}
 143
 144static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
 145{
 146        ATOM_OBJECT_TABLE *table;
 147
 148        uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
 149
 150        table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
 151
 152        if (!table)
 153                return 0;
 154        else
 155                return table->ucNumberOfObjects;
 156}
 157
 158static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb)
 159{
 160        struct bios_parser *bp = BP_FROM_DCB(dcb);
 161
 162        return get_number_of_objects(bp,
 163                le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
 164}
 165
 166static struct graphics_object_id bios_parser_get_encoder_id(
 167        struct dc_bios *dcb,
 168        uint32_t i)
 169{
 170        struct bios_parser *bp = BP_FROM_DCB(dcb);
 171        struct graphics_object_id object_id = dal_graphics_object_id_init(
 172                0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
 173
 174        uint32_t encoder_table_offset = bp->object_info_tbl_offset
 175                + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
 176
 177        ATOM_OBJECT_TABLE *tbl =
 178                GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
 179
 180        if (tbl && tbl->ucNumberOfObjects > i) {
 181                const uint16_t id = le16_to_cpu(tbl->asObjects[i].usObjectID);
 182
 183                object_id = object_id_from_bios_object_id(id);
 184        }
 185
 186        return object_id;
 187}
 188
 189static struct graphics_object_id bios_parser_get_connector_id(
 190        struct dc_bios *dcb,
 191        uint8_t i)
 192{
 193        struct bios_parser *bp = BP_FROM_DCB(dcb);
 194        struct graphics_object_id object_id = dal_graphics_object_id_init(
 195                0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
 196        uint16_t id;
 197
 198        uint32_t connector_table_offset = bp->object_info_tbl_offset
 199                + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
 200
 201        ATOM_OBJECT_TABLE *tbl =
 202                GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
 203
 204        if (!tbl) {
 205                dm_error("Can't get connector table from atom bios.\n");
 206                return object_id;
 207        }
 208
 209        if (tbl->ucNumberOfObjects <= i) {
 210                dm_error("Can't find connector id %d in connector table of size %d.\n",
 211                         i, tbl->ucNumberOfObjects);
 212                return object_id;
 213        }
 214
 215        id = le16_to_cpu(tbl->asObjects[i].usObjectID);
 216        object_id = object_id_from_bios_object_id(id);
 217        return object_id;
 218}
 219
 220static uint32_t bios_parser_get_dst_number(struct dc_bios *dcb,
 221        struct graphics_object_id id)
 222{
 223        struct bios_parser *bp = BP_FROM_DCB(dcb);
 224        ATOM_OBJECT *object = get_bios_object(bp, id);
 225
 226        return get_dst_number_from_object(bp, object);
 227}
 228
 229static enum bp_result bios_parser_get_src_obj(struct dc_bios *dcb,
 230        struct graphics_object_id object_id, uint32_t index,
 231        struct graphics_object_id *src_object_id)
 232{
 233        uint32_t number;
 234        uint16_t *id;
 235        ATOM_OBJECT *object;
 236        struct bios_parser *bp = BP_FROM_DCB(dcb);
 237
 238        if (!src_object_id)
 239                return BP_RESULT_BADINPUT;
 240
 241        object = get_bios_object(bp, object_id);
 242
 243        if (!object) {
 244                BREAK_TO_DEBUGGER(); /* Invalid object id */
 245                return BP_RESULT_BADINPUT;
 246        }
 247
 248        number = get_src_obj_list(bp, object, &id);
 249
 250        if (number <= index)
 251                return BP_RESULT_BADINPUT;
 252
 253        *src_object_id = object_id_from_bios_object_id(id[index]);
 254
 255        return BP_RESULT_OK;
 256}
 257
 258static enum bp_result bios_parser_get_dst_obj(struct dc_bios *dcb,
 259        struct graphics_object_id object_id, uint32_t index,
 260        struct graphics_object_id *dest_object_id)
 261{
 262        uint32_t number;
 263        uint16_t *id = NULL;
 264        ATOM_OBJECT *object;
 265        struct bios_parser *bp = BP_FROM_DCB(dcb);
 266
 267        if (!dest_object_id)
 268                return BP_RESULT_BADINPUT;
 269
 270        object = get_bios_object(bp, object_id);
 271
 272        number = get_dest_obj_list(bp, object, &id);
 273
 274        if (number <= index || !id)
 275                return BP_RESULT_BADINPUT;
 276
 277        *dest_object_id = object_id_from_bios_object_id(id[index]);
 278
 279        return BP_RESULT_OK;
 280}
 281
 282static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb,
 283        struct graphics_object_id id,
 284        struct graphics_object_i2c_info *info)
 285{
 286        uint32_t offset;
 287        ATOM_OBJECT *object;
 288        ATOM_COMMON_RECORD_HEADER *header;
 289        ATOM_I2C_RECORD *record;
 290        struct bios_parser *bp = BP_FROM_DCB(dcb);
 291
 292        if (!info)
 293                return BP_RESULT_BADINPUT;
 294
 295        object = get_bios_object(bp, id);
 296
 297        if (!object)
 298                return BP_RESULT_BADINPUT;
 299
 300        offset = le16_to_cpu(object->usRecordOffset)
 301                        + bp->object_info_tbl_offset;
 302
 303        for (;;) {
 304                header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
 305
 306                if (!header)
 307                        return BP_RESULT_BADBIOSTABLE;
 308
 309                if (LAST_RECORD_TYPE == header->ucRecordType ||
 310                        !header->ucRecordSize)
 311                        break;
 312
 313                if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
 314                        && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
 315                        /* get the I2C info */
 316                        record = (ATOM_I2C_RECORD *) header;
 317
 318                        if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
 319                                return BP_RESULT_OK;
 320                }
 321
 322                offset += header->ucRecordSize;
 323        }
 324
 325        return BP_RESULT_NORECORD;
 326}
 327
 328static enum bp_result get_voltage_ddc_info_v1(uint8_t *i2c_line,
 329        ATOM_COMMON_TABLE_HEADER *header,
 330        uint8_t *address)
 331{
 332        enum bp_result result = BP_RESULT_NORECORD;
 333        ATOM_VOLTAGE_OBJECT_INFO *info =
 334                (ATOM_VOLTAGE_OBJECT_INFO *) address;
 335
 336        uint8_t *voltage_current_object = (uint8_t *) &info->asVoltageObj[0];
 337
 338        while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
 339                ATOM_VOLTAGE_OBJECT *object =
 340                        (ATOM_VOLTAGE_OBJECT *) voltage_current_object;
 341
 342                if ((object->ucVoltageType == SET_VOLTAGE_INIT_MODE) &&
 343                        (object->ucVoltageType &
 344                                VOLTAGE_CONTROLLED_BY_I2C_MASK)) {
 345
 346                        *i2c_line = object->asControl.ucVoltageControlI2cLine
 347                                        ^ 0x90;
 348                        result = BP_RESULT_OK;
 349                        break;
 350                }
 351
 352                voltage_current_object += object->ucSize;
 353        }
 354        return result;
 355}
 356
 357static enum bp_result get_voltage_ddc_info_v3(uint8_t *i2c_line,
 358        uint32_t index,
 359        ATOM_COMMON_TABLE_HEADER *header,
 360        uint8_t *address)
 361{
 362        enum bp_result result = BP_RESULT_NORECORD;
 363        ATOM_VOLTAGE_OBJECT_INFO_V3_1 *info =
 364                (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *) address;
 365
 366        uint8_t *voltage_current_object =
 367                (uint8_t *) (&(info->asVoltageObj[0]));
 368
 369        while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
 370                ATOM_I2C_VOLTAGE_OBJECT_V3 *object =
 371                        (ATOM_I2C_VOLTAGE_OBJECT_V3 *) voltage_current_object;
 372
 373                if (object->sHeader.ucVoltageMode ==
 374                        ATOM_INIT_VOLTAGE_REGULATOR) {
 375                        if (object->sHeader.ucVoltageType == index) {
 376                                *i2c_line = object->ucVoltageControlI2cLine
 377                                                ^ 0x90;
 378                                result = BP_RESULT_OK;
 379                                break;
 380                        }
 381                }
 382
 383                voltage_current_object += le16_to_cpu(object->sHeader.usSize);
 384        }
 385        return result;
 386}
 387
 388static enum bp_result bios_parser_get_thermal_ddc_info(
 389        struct dc_bios *dcb,
 390        uint32_t i2c_channel_id,
 391        struct graphics_object_i2c_info *info)
 392{
 393        struct bios_parser *bp = BP_FROM_DCB(dcb);
 394        ATOM_I2C_ID_CONFIG_ACCESS *config;
 395        ATOM_I2C_RECORD record;
 396
 397        if (!info)
 398                return BP_RESULT_BADINPUT;
 399
 400        config = (ATOM_I2C_ID_CONFIG_ACCESS *) &i2c_channel_id;
 401
 402        record.sucI2cId.bfHW_Capable = config->sbfAccess.bfHW_Capable;
 403        record.sucI2cId.bfI2C_LineMux = config->sbfAccess.bfI2C_LineMux;
 404        record.sucI2cId.bfHW_EngineID = config->sbfAccess.bfHW_EngineID;
 405
 406        return get_gpio_i2c_info(bp, &record, info);
 407}
 408
 409static enum bp_result bios_parser_get_voltage_ddc_info(struct dc_bios *dcb,
 410        uint32_t index,
 411        struct graphics_object_i2c_info *info)
 412{
 413        uint8_t i2c_line = 0;
 414        enum bp_result result = BP_RESULT_NORECORD;
 415        uint8_t *voltage_info_address;
 416        ATOM_COMMON_TABLE_HEADER *header;
 417        struct atom_data_revision revision = {0};
 418        struct bios_parser *bp = BP_FROM_DCB(dcb);
 419
 420        if (!DATA_TABLES(VoltageObjectInfo))
 421                return result;
 422
 423        voltage_info_address = bios_get_image(&bp->base, DATA_TABLES(VoltageObjectInfo), sizeof(ATOM_COMMON_TABLE_HEADER));
 424
 425        header = (ATOM_COMMON_TABLE_HEADER *) voltage_info_address;
 426
 427        get_atom_data_table_revision(header, &revision);
 428
 429        switch (revision.major) {
 430        case 1:
 431        case 2:
 432                result = get_voltage_ddc_info_v1(&i2c_line, header,
 433                        voltage_info_address);
 434                break;
 435        case 3:
 436                if (revision.minor != 1)
 437                        break;
 438                result = get_voltage_ddc_info_v3(&i2c_line, index, header,
 439                        voltage_info_address);
 440                break;
 441        }
 442
 443        if (result == BP_RESULT_OK)
 444                result = bios_parser_get_thermal_ddc_info(dcb,
 445                        i2c_line, info);
 446
 447        return result;
 448}
 449
 450/* TODO: temporary commented out to suppress 'defined but not used' warning */
 451#if 0
 452static enum bp_result bios_parser_get_ddc_info_for_i2c_line(
 453        struct bios_parser *bp,
 454        uint8_t i2c_line, struct graphics_object_i2c_info *info)
 455{
 456        uint32_t offset;
 457        ATOM_OBJECT *object;
 458        ATOM_OBJECT_TABLE *table;
 459        uint32_t i;
 460
 461        if (!info)
 462                return BP_RESULT_BADINPUT;
 463
 464        offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
 465
 466        offset += bp->object_info_tbl_offset;
 467
 468        table = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
 469
 470        if (!table)
 471                return BP_RESULT_BADBIOSTABLE;
 472
 473        for (i = 0; i < table->ucNumberOfObjects; i++) {
 474                object = &table->asObjects[i];
 475
 476                if (!object) {
 477                        BREAK_TO_DEBUGGER(); /* Invalid object id */
 478                        return BP_RESULT_BADINPUT;
 479                }
 480
 481                offset = le16_to_cpu(object->usRecordOffset)
 482                                + bp->object_info_tbl_offset;
 483
 484                for (;;) {
 485                        ATOM_COMMON_RECORD_HEADER *header =
 486                                GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
 487
 488                        if (!header)
 489                                return BP_RESULT_BADBIOSTABLE;
 490
 491                        offset += header->ucRecordSize;
 492
 493                        if (LAST_RECORD_TYPE == header->ucRecordType ||
 494                                !header->ucRecordSize)
 495                                break;
 496
 497                        if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
 498                                && sizeof(ATOM_I2C_RECORD) <=
 499                                header->ucRecordSize) {
 500                                ATOM_I2C_RECORD *record =
 501                                        (ATOM_I2C_RECORD *) header;
 502
 503                                if (i2c_line != record->sucI2cId.bfI2C_LineMux)
 504                                        continue;
 505
 506                                /* get the I2C info */
 507                                if (get_gpio_i2c_info(bp, record, info) ==
 508                                        BP_RESULT_OK)
 509                                        return BP_RESULT_OK;
 510                        }
 511                }
 512        }
 513
 514        return BP_RESULT_NORECORD;
 515}
 516#endif
 517
 518static enum bp_result bios_parser_get_hpd_info(struct dc_bios *dcb,
 519        struct graphics_object_id id,
 520        struct graphics_object_hpd_info *info)
 521{
 522        struct bios_parser *bp = BP_FROM_DCB(dcb);
 523        ATOM_OBJECT *object;
 524        ATOM_HPD_INT_RECORD *record = NULL;
 525
 526        if (!info)
 527                return BP_RESULT_BADINPUT;
 528
 529        object = get_bios_object(bp, id);
 530
 531        if (!object)
 532                return BP_RESULT_BADINPUT;
 533
 534        record = get_hpd_record(bp, object);
 535
 536        if (record != NULL) {
 537                info->hpd_int_gpio_uid = record->ucHPDIntGPIOID;
 538                info->hpd_active = record->ucPlugged_PinState;
 539                return BP_RESULT_OK;
 540        }
 541
 542        return BP_RESULT_NORECORD;
 543}
 544
 545static enum bp_result bios_parser_get_device_tag_record(
 546        struct bios_parser *bp,
 547        ATOM_OBJECT *object,
 548        ATOM_CONNECTOR_DEVICE_TAG_RECORD **record)
 549{
 550        ATOM_COMMON_RECORD_HEADER *header;
 551        uint32_t offset;
 552
 553        offset = le16_to_cpu(object->usRecordOffset)
 554                        + bp->object_info_tbl_offset;
 555
 556        for (;;) {
 557                header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
 558
 559                if (!header)
 560                        return BP_RESULT_BADBIOSTABLE;
 561
 562                offset += header->ucRecordSize;
 563
 564                if (LAST_RECORD_TYPE == header->ucRecordType ||
 565                        !header->ucRecordSize)
 566                        break;
 567
 568                if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
 569                        header->ucRecordType)
 570                        continue;
 571
 572                if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
 573                        continue;
 574
 575                *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
 576                return BP_RESULT_OK;
 577        }
 578
 579        return BP_RESULT_NORECORD;
 580}
 581
 582static enum bp_result bios_parser_get_device_tag(
 583        struct dc_bios *dcb,
 584        struct graphics_object_id connector_object_id,
 585        uint32_t device_tag_index,
 586        struct connector_device_tag_info *info)
 587{
 588        struct bios_parser *bp = BP_FROM_DCB(dcb);
 589        ATOM_OBJECT *object;
 590        ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
 591        ATOM_CONNECTOR_DEVICE_TAG *device_tag;
 592
 593        if (!info)
 594                return BP_RESULT_BADINPUT;
 595
 596        /* getBiosObject will return MXM object */
 597        object = get_bios_object(bp, connector_object_id);
 598
 599        if (!object) {
 600                BREAK_TO_DEBUGGER(); /* Invalid object id */
 601                return BP_RESULT_BADINPUT;
 602        }
 603
 604        if (bios_parser_get_device_tag_record(bp, object, &record)
 605                != BP_RESULT_OK)
 606                return BP_RESULT_NORECORD;
 607
 608        if (device_tag_index >= record->ucNumberOfDevice)
 609                return BP_RESULT_NORECORD;
 610
 611        device_tag = &record->asDeviceTag[device_tag_index];
 612
 613        info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
 614        info->dev_id =
 615                device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
 616
 617        return BP_RESULT_OK;
 618}
 619
 620static enum bp_result get_firmware_info_v1_4(
 621        struct bios_parser *bp,
 622        struct dc_firmware_info *info);
 623static enum bp_result get_firmware_info_v2_1(
 624        struct bios_parser *bp,
 625        struct dc_firmware_info *info);
 626static enum bp_result get_firmware_info_v2_2(
 627        struct bios_parser *bp,
 628        struct dc_firmware_info *info);
 629
 630static enum bp_result bios_parser_get_firmware_info(
 631        struct dc_bios *dcb,
 632        struct dc_firmware_info *info)
 633{
 634        struct bios_parser *bp = BP_FROM_DCB(dcb);
 635        enum bp_result result = BP_RESULT_BADBIOSTABLE;
 636        ATOM_COMMON_TABLE_HEADER *header;
 637        struct atom_data_revision revision;
 638
 639        if (info && DATA_TABLES(FirmwareInfo)) {
 640                header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
 641                        DATA_TABLES(FirmwareInfo));
 642                get_atom_data_table_revision(header, &revision);
 643                switch (revision.major) {
 644                case 1:
 645                        switch (revision.minor) {
 646                        case 4:
 647                                result = get_firmware_info_v1_4(bp, info);
 648                                break;
 649                        default:
 650                                break;
 651                        }
 652                        break;
 653
 654                case 2:
 655                        switch (revision.minor) {
 656                        case 1:
 657                                result = get_firmware_info_v2_1(bp, info);
 658                                break;
 659                        case 2:
 660                                result = get_firmware_info_v2_2(bp, info);
 661                                break;
 662                        default:
 663                                break;
 664                        }
 665                        break;
 666                default:
 667                        break;
 668                }
 669        }
 670
 671        return result;
 672}
 673
 674static enum bp_result get_firmware_info_v1_4(
 675        struct bios_parser *bp,
 676        struct dc_firmware_info *info)
 677{
 678        ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
 679                GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
 680                        DATA_TABLES(FirmwareInfo));
 681
 682        if (!info)
 683                return BP_RESULT_BADINPUT;
 684
 685        if (!firmware_info)
 686                return BP_RESULT_BADBIOSTABLE;
 687
 688        memset(info, 0, sizeof(*info));
 689
 690        /* Pixel clock pll information. We need to convert from 10KHz units into
 691         * KHz units */
 692        info->pll_info.crystal_frequency =
 693                le16_to_cpu(firmware_info->usReferenceClock) * 10;
 694        info->pll_info.min_input_pxl_clk_pll_frequency =
 695                le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
 696        info->pll_info.max_input_pxl_clk_pll_frequency =
 697                le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
 698        info->pll_info.min_output_pxl_clk_pll_frequency =
 699                le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
 700        info->pll_info.max_output_pxl_clk_pll_frequency =
 701                le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
 702
 703        if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
 704                /* Since there is no information on the SS, report conservative
 705                 * value 3% for bandwidth calculation */
 706                /* unit of 0.01% */
 707                info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
 708
 709        if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
 710                /* Since there is no information on the SS,report conservative
 711                 * value 3% for bandwidth calculation */
 712                /* unit of 0.01% */
 713                info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
 714
 715        return BP_RESULT_OK;
 716}
 717
 718static enum bp_result get_ss_info_v3_1(
 719        struct bios_parser *bp,
 720        uint32_t id,
 721        uint32_t index,
 722        struct spread_spectrum_info *ss_info);
 723
 724static enum bp_result get_firmware_info_v2_1(
 725        struct bios_parser *bp,
 726        struct dc_firmware_info *info)
 727{
 728        ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
 729                GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
 730        struct spread_spectrum_info internalSS;
 731        uint32_t index;
 732
 733        if (!info)
 734                return BP_RESULT_BADINPUT;
 735
 736        if (!firmwareInfo)
 737                return BP_RESULT_BADBIOSTABLE;
 738
 739        memset(info, 0, sizeof(*info));
 740
 741        /* Pixel clock pll information. We need to convert from 10KHz units into
 742         * KHz units */
 743        info->pll_info.crystal_frequency =
 744                le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
 745        info->pll_info.min_input_pxl_clk_pll_frequency =
 746                le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
 747        info->pll_info.max_input_pxl_clk_pll_frequency =
 748                le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
 749        info->pll_info.min_output_pxl_clk_pll_frequency =
 750                le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
 751        info->pll_info.max_output_pxl_clk_pll_frequency =
 752                le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
 753        info->default_display_engine_pll_frequency =
 754                le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
 755        info->external_clock_source_frequency_for_dp =
 756                le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
 757        info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
 758
 759        /* There should be only one entry in the SS info table for Memory Clock
 760         */
 761        index = 0;
 762        if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
 763                /* Since there is no information for external SS, report
 764                 *  conservative value 3% for bandwidth calculation */
 765                /* unit of 0.01% */
 766                info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
 767        else if (get_ss_info_v3_1(bp,
 768                ASIC_INTERNAL_MEMORY_SS, index, &internalSS) == BP_RESULT_OK) {
 769                if (internalSS.spread_spectrum_percentage) {
 770                        info->feature.memory_clk_ss_percentage =
 771                                internalSS.spread_spectrum_percentage;
 772                        if (internalSS.type.CENTER_MODE) {
 773                                /* if it is centermode, the exact SS Percentage
 774                                 * will be round up of half of the percentage
 775                                 * reported in the SS table */
 776                                ++info->feature.memory_clk_ss_percentage;
 777                                info->feature.memory_clk_ss_percentage /= 2;
 778                        }
 779                }
 780        }
 781
 782        /* There should be only one entry in the SS info table for Engine Clock
 783         */
 784        index = 1;
 785        if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
 786                /* Since there is no information for external SS, report
 787                 * conservative value 3% for bandwidth calculation */
 788                /* unit of 0.01% */
 789                info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
 790        else if (get_ss_info_v3_1(bp,
 791                ASIC_INTERNAL_ENGINE_SS, index, &internalSS) == BP_RESULT_OK) {
 792                if (internalSS.spread_spectrum_percentage) {
 793                        info->feature.engine_clk_ss_percentage =
 794                                internalSS.spread_spectrum_percentage;
 795                        if (internalSS.type.CENTER_MODE) {
 796                                /* if it is centermode, the exact SS Percentage
 797                                 * will be round up of half of the percentage
 798                                 * reported in the SS table */
 799                                ++info->feature.engine_clk_ss_percentage;
 800                                info->feature.engine_clk_ss_percentage /= 2;
 801                        }
 802                }
 803        }
 804
 805        return BP_RESULT_OK;
 806}
 807
 808static enum bp_result get_firmware_info_v2_2(
 809        struct bios_parser *bp,
 810        struct dc_firmware_info *info)
 811{
 812        ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
 813        struct spread_spectrum_info internal_ss;
 814        uint32_t index;
 815
 816        if (!info)
 817                return BP_RESULT_BADINPUT;
 818
 819        firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
 820                DATA_TABLES(FirmwareInfo));
 821
 822        if (!firmware_info)
 823                return BP_RESULT_BADBIOSTABLE;
 824
 825        memset(info, 0, sizeof(*info));
 826
 827        /* Pixel clock pll information. We need to convert from 10KHz units into
 828         * KHz units */
 829        info->pll_info.crystal_frequency =
 830                le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
 831        info->pll_info.min_input_pxl_clk_pll_frequency =
 832                le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
 833        info->pll_info.max_input_pxl_clk_pll_frequency =
 834                le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
 835        info->pll_info.min_output_pxl_clk_pll_frequency =
 836                le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
 837        info->pll_info.max_output_pxl_clk_pll_frequency =
 838                le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
 839        info->default_display_engine_pll_frequency =
 840                le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
 841        info->external_clock_source_frequency_for_dp =
 842                le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
 843
 844        /* There should be only one entry in the SS info table for Memory Clock
 845         */
 846        index = 0;
 847        if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
 848                /* Since there is no information for external SS, report
 849                 *  conservative value 3% for bandwidth calculation */
 850                /* unit of 0.01% */
 851                info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
 852        else if (get_ss_info_v3_1(bp,
 853                        ASIC_INTERNAL_MEMORY_SS, index, &internal_ss) == BP_RESULT_OK) {
 854                if (internal_ss.spread_spectrum_percentage) {
 855                        info->feature.memory_clk_ss_percentage =
 856                                        internal_ss.spread_spectrum_percentage;
 857                        if (internal_ss.type.CENTER_MODE) {
 858                                /* if it is centermode, the exact SS Percentage
 859                                 * will be round up of half of the percentage
 860                                 * reported in the SS table */
 861                                ++info->feature.memory_clk_ss_percentage;
 862                                info->feature.memory_clk_ss_percentage /= 2;
 863                        }
 864                }
 865        }
 866
 867        /* There should be only one entry in the SS info table for Engine Clock
 868         */
 869        index = 1;
 870        if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
 871                /* Since there is no information for external SS, report
 872                 * conservative value 3% for bandwidth calculation */
 873                /* unit of 0.01% */
 874                info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
 875        else if (get_ss_info_v3_1(bp,
 876                        ASIC_INTERNAL_ENGINE_SS, index, &internal_ss) == BP_RESULT_OK) {
 877                if (internal_ss.spread_spectrum_percentage) {
 878                        info->feature.engine_clk_ss_percentage =
 879                                        internal_ss.spread_spectrum_percentage;
 880                        if (internal_ss.type.CENTER_MODE) {
 881                                /* if it is centermode, the exact SS Percentage
 882                                 * will be round up of half of the percentage
 883                                 * reported in the SS table */
 884                                ++info->feature.engine_clk_ss_percentage;
 885                                info->feature.engine_clk_ss_percentage /= 2;
 886                        }
 887                }
 888        }
 889
 890        /* Remote Display */
 891        info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
 892
 893        /* Is allowed minimum BL level */
 894        info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
 895        /* Used starting from CI */
 896        info->smu_gpu_pll_output_freq =
 897                        (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
 898
 899        return BP_RESULT_OK;
 900}
 901
 902static enum bp_result get_ss_info_v3_1(
 903        struct bios_parser *bp,
 904        uint32_t id,
 905        uint32_t index,
 906        struct spread_spectrum_info *ss_info)
 907{
 908        ATOM_ASIC_INTERNAL_SS_INFO_V3 *ss_table_header_include;
 909        ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
 910        uint32_t table_size;
 911        uint32_t i;
 912        uint32_t table_index = 0;
 913
 914        if (!ss_info)
 915                return BP_RESULT_BADINPUT;
 916
 917        if (!DATA_TABLES(ASIC_InternalSS_Info))
 918                return BP_RESULT_UNSUPPORTED;
 919
 920        ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
 921                DATA_TABLES(ASIC_InternalSS_Info));
 922        table_size =
 923                (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
 924                                - sizeof(ATOM_COMMON_TABLE_HEADER))
 925                                / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
 926
 927        tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
 928                                &ss_table_header_include->asSpreadSpectrum[0];
 929
 930        memset(ss_info, 0, sizeof(struct spread_spectrum_info));
 931
 932        for (i = 0; i < table_size; i++) {
 933                if (tbl[i].ucClockIndication != (uint8_t) id)
 934                        continue;
 935
 936                if (table_index != index) {
 937                        table_index++;
 938                        continue;
 939                }
 940                /* VBIOS introduced new defines for Version 3, same values as
 941                 *  before, so now use these new ones for Version 3.
 942                 * Shouldn't affect field VBIOS's V3 as define values are still
 943                 *  same.
 944                 * #define SS_MODE_V3_CENTRE_SPREAD_MASK                0x01
 945                 * #define SS_MODE_V3_EXTERNAL_SS_MASK                  0x02
 946
 947                 * Old VBIOS defines:
 948                 * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK        0x00000001
 949                 * #define ATOM_EXTERNAL_SS_MASK                  0x00000002
 950                 */
 951
 952                if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
 953                        ss_info->type.EXTERNAL = true;
 954
 955                if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
 956                        ss_info->type.CENTER_MODE = true;
 957
 958                /* Older VBIOS (in field) always provides SS percentage in 0.01%
 959                 * units set Divider to 100 */
 960                ss_info->spread_percentage_divider = 100;
 961
 962                /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
 963                if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
 964                                & tbl[i].ucSpreadSpectrumMode)
 965                        ss_info->spread_percentage_divider = 1000;
 966
 967                ss_info->type.STEP_AND_DELAY_INFO = false;
 968                /* convert [10KHz] into [KHz] */
 969                ss_info->target_clock_range =
 970                                le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
 971                ss_info->spread_spectrum_percentage =
 972                                (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
 973                ss_info->spread_spectrum_range =
 974                                (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
 975
 976                return BP_RESULT_OK;
 977        }
 978        return BP_RESULT_NORECORD;
 979}
 980
 981static enum bp_result bios_parser_transmitter_control(
 982        struct dc_bios *dcb,
 983        struct bp_transmitter_control *cntl)
 984{
 985        struct bios_parser *bp = BP_FROM_DCB(dcb);
 986
 987        if (!bp->cmd_tbl.transmitter_control)
 988                return BP_RESULT_FAILURE;
 989
 990        return bp->cmd_tbl.transmitter_control(bp, cntl);
 991}
 992
 993static enum bp_result bios_parser_encoder_control(
 994        struct dc_bios *dcb,
 995        struct bp_encoder_control *cntl)
 996{
 997        struct bios_parser *bp = BP_FROM_DCB(dcb);
 998
 999        if (!bp->cmd_tbl.dig_encoder_control)
1000                return BP_RESULT_FAILURE;
1001
1002        return bp->cmd_tbl.dig_encoder_control(bp, cntl);
1003}
1004
1005static enum bp_result bios_parser_adjust_pixel_clock(
1006        struct dc_bios *dcb,
1007        struct bp_adjust_pixel_clock_parameters *bp_params)
1008{
1009        struct bios_parser *bp = BP_FROM_DCB(dcb);
1010
1011        if (!bp->cmd_tbl.adjust_display_pll)
1012                return BP_RESULT_FAILURE;
1013
1014        return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
1015}
1016
1017static enum bp_result bios_parser_set_pixel_clock(
1018        struct dc_bios *dcb,
1019        struct bp_pixel_clock_parameters *bp_params)
1020{
1021        struct bios_parser *bp = BP_FROM_DCB(dcb);
1022
1023        if (!bp->cmd_tbl.set_pixel_clock)
1024                return BP_RESULT_FAILURE;
1025
1026        return bp->cmd_tbl.set_pixel_clock(bp, bp_params);
1027}
1028
1029static enum bp_result bios_parser_set_dce_clock(
1030        struct dc_bios *dcb,
1031        struct bp_set_dce_clock_parameters *bp_params)
1032{
1033        struct bios_parser *bp = BP_FROM_DCB(dcb);
1034
1035        if (!bp->cmd_tbl.set_dce_clock)
1036                return BP_RESULT_FAILURE;
1037
1038        return bp->cmd_tbl.set_dce_clock(bp, bp_params);
1039}
1040
1041static enum bp_result bios_parser_enable_spread_spectrum_on_ppll(
1042        struct dc_bios *dcb,
1043        struct bp_spread_spectrum_parameters *bp_params,
1044        bool enable)
1045{
1046        struct bios_parser *bp = BP_FROM_DCB(dcb);
1047
1048        if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
1049                return BP_RESULT_FAILURE;
1050
1051        return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
1052                        bp, bp_params, enable);
1053
1054}
1055
1056static enum bp_result bios_parser_program_crtc_timing(
1057        struct dc_bios *dcb,
1058        struct bp_hw_crtc_timing_parameters *bp_params)
1059{
1060        struct bios_parser *bp = BP_FROM_DCB(dcb);
1061
1062        if (!bp->cmd_tbl.set_crtc_timing)
1063                return BP_RESULT_FAILURE;
1064
1065        return bp->cmd_tbl.set_crtc_timing(bp, bp_params);
1066}
1067
1068static enum bp_result bios_parser_program_display_engine_pll(
1069        struct dc_bios *dcb,
1070        struct bp_pixel_clock_parameters *bp_params)
1071{
1072        struct bios_parser *bp = BP_FROM_DCB(dcb);
1073
1074        if (!bp->cmd_tbl.program_clock)
1075                return BP_RESULT_FAILURE;
1076
1077        return bp->cmd_tbl.program_clock(bp, bp_params);
1078
1079}
1080
1081
1082static enum bp_result bios_parser_enable_crtc(
1083        struct dc_bios *dcb,
1084        enum controller_id id,
1085        bool enable)
1086{
1087        struct bios_parser *bp = BP_FROM_DCB(dcb);
1088
1089        if (!bp->cmd_tbl.enable_crtc)
1090                return BP_RESULT_FAILURE;
1091
1092        return bp->cmd_tbl.enable_crtc(bp, id, enable);
1093}
1094
1095static enum bp_result bios_parser_crtc_source_select(
1096        struct dc_bios *dcb,
1097        struct bp_crtc_source_select *bp_params)
1098{
1099        struct bios_parser *bp = BP_FROM_DCB(dcb);
1100
1101        if (!bp->cmd_tbl.select_crtc_source)
1102                return BP_RESULT_FAILURE;
1103
1104        return bp->cmd_tbl.select_crtc_source(bp, bp_params);
1105}
1106
1107static enum bp_result bios_parser_enable_disp_power_gating(
1108        struct dc_bios *dcb,
1109        enum controller_id controller_id,
1110        enum bp_pipe_control_action action)
1111{
1112        struct bios_parser *bp = BP_FROM_DCB(dcb);
1113
1114        if (!bp->cmd_tbl.enable_disp_power_gating)
1115                return BP_RESULT_FAILURE;
1116
1117        return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id,
1118                action);
1119}
1120
1121static bool bios_parser_is_device_id_supported(
1122        struct dc_bios *dcb,
1123        struct device_id id)
1124{
1125        struct bios_parser *bp = BP_FROM_DCB(dcb);
1126
1127        uint32_t mask = get_support_mask_for_device_id(id);
1128
1129        return (le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport) & mask) != 0;
1130}
1131
1132static enum bp_result bios_parser_crt_control(
1133        struct dc_bios *dcb,
1134        enum engine_id engine_id,
1135        bool enable,
1136        uint32_t pixel_clock)
1137{
1138        struct bios_parser *bp = BP_FROM_DCB(dcb);
1139        uint8_t standard;
1140
1141        if (!bp->cmd_tbl.dac1_encoder_control &&
1142                engine_id == ENGINE_ID_DACA)
1143                return BP_RESULT_FAILURE;
1144        if (!bp->cmd_tbl.dac2_encoder_control &&
1145                engine_id == ENGINE_ID_DACB)
1146                return BP_RESULT_FAILURE;
1147        /* validate params */
1148        switch (engine_id) {
1149        case ENGINE_ID_DACA:
1150        case ENGINE_ID_DACB:
1151                break;
1152        default:
1153                /* unsupported engine */
1154                return BP_RESULT_FAILURE;
1155        }
1156
1157        standard = ATOM_DAC1_PS2; /* == ATOM_DAC2_PS2 */
1158
1159        if (enable) {
1160                if (engine_id == ENGINE_ID_DACA) {
1161                        bp->cmd_tbl.dac1_encoder_control(bp, enable,
1162                                pixel_clock, standard);
1163                        if (bp->cmd_tbl.dac1_output_control != NULL)
1164                                bp->cmd_tbl.dac1_output_control(bp, enable);
1165                } else {
1166                        bp->cmd_tbl.dac2_encoder_control(bp, enable,
1167                                pixel_clock, standard);
1168                        if (bp->cmd_tbl.dac2_output_control != NULL)
1169                                bp->cmd_tbl.dac2_output_control(bp, enable);
1170                }
1171        } else {
1172                if (engine_id == ENGINE_ID_DACA) {
1173                        if (bp->cmd_tbl.dac1_output_control != NULL)
1174                                bp->cmd_tbl.dac1_output_control(bp, enable);
1175                        bp->cmd_tbl.dac1_encoder_control(bp, enable,
1176                                pixel_clock, standard);
1177                } else {
1178                        if (bp->cmd_tbl.dac2_output_control != NULL)
1179                                bp->cmd_tbl.dac2_output_control(bp, enable);
1180                        bp->cmd_tbl.dac2_encoder_control(bp, enable,
1181                                pixel_clock, standard);
1182                }
1183        }
1184
1185        return BP_RESULT_OK;
1186}
1187
1188static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
1189        ATOM_OBJECT *object)
1190{
1191        ATOM_COMMON_RECORD_HEADER *header;
1192        uint32_t offset;
1193
1194        if (!object) {
1195                BREAK_TO_DEBUGGER(); /* Invalid object */
1196                return NULL;
1197        }
1198
1199        offset = le16_to_cpu(object->usRecordOffset)
1200                        + bp->object_info_tbl_offset;
1201
1202        for (;;) {
1203                header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1204
1205                if (!header)
1206                        return NULL;
1207
1208                if (LAST_RECORD_TYPE == header->ucRecordType ||
1209                        !header->ucRecordSize)
1210                        break;
1211
1212                if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
1213                        && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
1214                        return (ATOM_HPD_INT_RECORD *) header;
1215
1216                offset += header->ucRecordSize;
1217        }
1218
1219        return NULL;
1220}
1221
1222/**
1223 * Get I2C information of input object id
1224 *
1225 * search all records to find the ATOM_I2C_RECORD_TYPE record IR
1226 */
1227static ATOM_I2C_RECORD *get_i2c_record(
1228        struct bios_parser *bp,
1229        ATOM_OBJECT *object)
1230{
1231        uint32_t offset;
1232        ATOM_COMMON_RECORD_HEADER *record_header;
1233
1234        if (!object) {
1235                BREAK_TO_DEBUGGER();
1236                /* Invalid object */
1237                return NULL;
1238        }
1239
1240        offset = le16_to_cpu(object->usRecordOffset)
1241                        + bp->object_info_tbl_offset;
1242
1243        for (;;) {
1244                record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1245
1246                if (!record_header)
1247                        return NULL;
1248
1249                if (LAST_RECORD_TYPE == record_header->ucRecordType ||
1250                        0 == record_header->ucRecordSize)
1251                        break;
1252
1253                if (ATOM_I2C_RECORD_TYPE == record_header->ucRecordType &&
1254                        sizeof(ATOM_I2C_RECORD) <=
1255                        record_header->ucRecordSize) {
1256                        return (ATOM_I2C_RECORD *)record_header;
1257                }
1258
1259                offset += record_header->ucRecordSize;
1260        }
1261
1262        return NULL;
1263}
1264
1265static enum bp_result get_ss_info_from_ss_info_table(
1266        struct bios_parser *bp,
1267        uint32_t id,
1268        struct spread_spectrum_info *ss_info);
1269static enum bp_result get_ss_info_from_tbl(
1270        struct bios_parser *bp,
1271        uint32_t id,
1272        struct spread_spectrum_info *ss_info);
1273/**
1274 * bios_parser_get_spread_spectrum_info
1275 * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or
1276 * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info
1277 * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ver 3.1,
1278 * there is only one entry for each signal /ss id.  However, there is
1279 * no planning of supporting multiple spread Sprectum entry for EverGreen
1280 * @param [in] this
1281 * @param [in] signal, ASSignalType to be converted to info index
1282 * @param [in] index, number of entries that match the converted info index
1283 * @param [out] ss_info, sprectrum information structure,
1284 * @return Bios parser result code
1285 */
1286static enum bp_result bios_parser_get_spread_spectrum_info(
1287        struct dc_bios *dcb,
1288        enum as_signal_type signal,
1289        uint32_t index,
1290        struct spread_spectrum_info *ss_info)
1291{
1292        struct bios_parser *bp = BP_FROM_DCB(dcb);
1293        enum bp_result result = BP_RESULT_UNSUPPORTED;
1294        uint32_t clk_id_ss = 0;
1295        ATOM_COMMON_TABLE_HEADER *header;
1296        struct atom_data_revision tbl_revision;
1297
1298        if (!ss_info) /* check for bad input */
1299                return BP_RESULT_BADINPUT;
1300        /* signal translation */
1301        clk_id_ss = signal_to_ss_id(signal);
1302
1303        if (!DATA_TABLES(ASIC_InternalSS_Info))
1304                if (!index)
1305                        return get_ss_info_from_ss_info_table(bp, clk_id_ss,
1306                                ss_info);
1307
1308        header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1309                DATA_TABLES(ASIC_InternalSS_Info));
1310        get_atom_data_table_revision(header, &tbl_revision);
1311
1312        switch (tbl_revision.major) {
1313        case 2:
1314                switch (tbl_revision.minor) {
1315                case 1:
1316                        /* there can not be more then one entry for Internal
1317                         * SS Info table version 2.1 */
1318                        if (!index)
1319                                return get_ss_info_from_tbl(bp, clk_id_ss,
1320                                                ss_info);
1321                        break;
1322                default:
1323                        break;
1324                }
1325                break;
1326
1327        case 3:
1328                switch (tbl_revision.minor) {
1329                case 1:
1330                        return get_ss_info_v3_1(bp, clk_id_ss, index, ss_info);
1331                default:
1332                        break;
1333                }
1334                break;
1335        default:
1336                break;
1337        }
1338        /* there can not be more then one entry for SS Info table */
1339        return result;
1340}
1341
1342static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1343        struct bios_parser *bp,
1344        uint32_t id,
1345        struct spread_spectrum_info *info);
1346
1347/**
1348 * get_ss_info_from_table
1349 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
1350 * SS_Info table from the VBIOS
1351 * There can not be more than 1 entry for  ASIC_InternalSS_Info Ver 2.1 or
1352 * SS_Info.
1353 *
1354 * @param this
1355 * @param id, spread sprectrum info index
1356 * @param pSSinfo, sprectrum information structure,
1357 * @return Bios parser result code
1358 */
1359static enum bp_result get_ss_info_from_tbl(
1360        struct bios_parser *bp,
1361        uint32_t id,
1362        struct spread_spectrum_info *ss_info)
1363{
1364        if (!ss_info) /* check for bad input, if ss_info is not NULL */
1365                return BP_RESULT_BADINPUT;
1366        /* for SS_Info table only support DP and LVDS */
1367        if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
1368                return get_ss_info_from_ss_info_table(bp, id, ss_info);
1369        else
1370                return get_ss_info_from_internal_ss_info_tbl_V2_1(bp, id,
1371                        ss_info);
1372}
1373
1374/**
1375 * get_ss_info_from_internal_ss_info_tbl_V2_1
1376 * Get spread sprectrum information from the ASIC_InternalSS_Info table Ver 2.1
1377 * from the VBIOS
1378 * There will not be multiple entry for Ver 2.1
1379 *
1380 * @param id, spread sprectrum info index
1381 * @param pSSinfo, sprectrum information structure,
1382 * @return Bios parser result code
1383 */
1384static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
1385        struct bios_parser *bp,
1386        uint32_t id,
1387        struct spread_spectrum_info *info)
1388{
1389        enum bp_result result = BP_RESULT_UNSUPPORTED;
1390        ATOM_ASIC_INTERNAL_SS_INFO_V2 *header;
1391        ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
1392        uint32_t tbl_size, i;
1393
1394        if (!DATA_TABLES(ASIC_InternalSS_Info))
1395                return result;
1396
1397        header = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
1398                DATA_TABLES(ASIC_InternalSS_Info));
1399
1400        memset(info, 0, sizeof(struct spread_spectrum_info));
1401
1402        tbl_size = (le16_to_cpu(header->sHeader.usStructureSize)
1403                        - sizeof(ATOM_COMMON_TABLE_HEADER))
1404                                        / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
1405
1406        tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
1407                                        &(header->asSpreadSpectrum[0]);
1408        for (i = 0; i < tbl_size; i++) {
1409                result = BP_RESULT_NORECORD;
1410
1411                if (tbl[i].ucClockIndication != (uint8_t)id)
1412                        continue;
1413
1414                if (ATOM_EXTERNAL_SS_MASK
1415                        & tbl[i].ucSpreadSpectrumMode) {
1416                        info->type.EXTERNAL = true;
1417                }
1418                if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
1419                        & tbl[i].ucSpreadSpectrumMode) {
1420                        info->type.CENTER_MODE = true;
1421                }
1422                info->type.STEP_AND_DELAY_INFO = false;
1423                /* convert [10KHz] into [KHz] */
1424                info->target_clock_range =
1425                        le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
1426                info->spread_spectrum_percentage =
1427                        (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
1428                info->spread_spectrum_range =
1429                        (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
1430                result = BP_RESULT_OK;
1431                break;
1432        }
1433
1434        return result;
1435
1436}
1437
1438/**
1439 * get_ss_info_from_ss_info_table
1440 * Get spread sprectrum information from the SS_Info table from the VBIOS
1441 * if the pointer to info is NULL, indicate the caller what to know the number
1442 * of entries that matches the id
1443 * for, the SS_Info table, there should not be more than 1 entry match.
1444 *
1445 * @param [in] id, spread sprectrum id
1446 * @param [out] pSSinfo, sprectrum information structure,
1447 * @return Bios parser result code
1448 */
1449static enum bp_result get_ss_info_from_ss_info_table(
1450        struct bios_parser *bp,
1451        uint32_t id,
1452        struct spread_spectrum_info *ss_info)
1453{
1454        enum bp_result result = BP_RESULT_UNSUPPORTED;
1455        ATOM_SPREAD_SPECTRUM_INFO *tbl;
1456        ATOM_COMMON_TABLE_HEADER *header;
1457        uint32_t table_size;
1458        uint32_t i;
1459        uint32_t id_local = SS_ID_UNKNOWN;
1460        struct atom_data_revision revision;
1461
1462        /* exist of the SS_Info table */
1463        /* check for bad input, pSSinfo can not be NULL */
1464        if (!DATA_TABLES(SS_Info) || !ss_info)
1465                return result;
1466
1467        header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(SS_Info));
1468        get_atom_data_table_revision(header, &revision);
1469
1470        tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info));
1471
1472        if (1 != revision.major || 2 > revision.minor)
1473                return result;
1474
1475        /* have to convert from Internal_SS format to SS_Info format */
1476        switch (id) {
1477        case ASIC_INTERNAL_SS_ON_DP:
1478                id_local = SS_ID_DP1;
1479                break;
1480        case ASIC_INTERNAL_SS_ON_LVDS:
1481        {
1482                struct embedded_panel_info panel_info;
1483
1484                if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
1485                                == BP_RESULT_OK)
1486                        id_local = panel_info.ss_id;
1487                break;
1488        }
1489        default:
1490                break;
1491        }
1492
1493        if (id_local == SS_ID_UNKNOWN)
1494                return result;
1495
1496        table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
1497                        sizeof(ATOM_COMMON_TABLE_HEADER)) /
1498                                        sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
1499
1500        for (i = 0; i < table_size; i++) {
1501                if (id_local != (uint32_t)tbl->asSS_Info[i].ucSS_Id)
1502                        continue;
1503
1504                memset(ss_info, 0, sizeof(struct spread_spectrum_info));
1505
1506                if (ATOM_EXTERNAL_SS_MASK &
1507                                tbl->asSS_Info[i].ucSpreadSpectrumType)
1508                        ss_info->type.EXTERNAL = true;
1509
1510                if (ATOM_SS_CENTRE_SPREAD_MODE_MASK &
1511                                tbl->asSS_Info[i].ucSpreadSpectrumType)
1512                        ss_info->type.CENTER_MODE = true;
1513
1514                ss_info->type.STEP_AND_DELAY_INFO = true;
1515                ss_info->spread_spectrum_percentage =
1516                        (uint32_t)le16_to_cpu(tbl->asSS_Info[i].usSpreadSpectrumPercentage);
1517                ss_info->step_and_delay_info.step = tbl->asSS_Info[i].ucSS_Step;
1518                ss_info->step_and_delay_info.delay =
1519                        tbl->asSS_Info[i].ucSS_Delay;
1520                ss_info->step_and_delay_info.recommended_ref_div =
1521                        tbl->asSS_Info[i].ucRecommendedRef_Div;
1522                ss_info->spread_spectrum_range =
1523                        (uint32_t)tbl->asSS_Info[i].ucSS_Range * 10000;
1524
1525                /* there will be only one entry for each display type in SS_info
1526                 * table */
1527                result = BP_RESULT_OK;
1528                break;
1529        }
1530
1531        return result;
1532}
1533static enum bp_result get_embedded_panel_info_v1_2(
1534        struct bios_parser *bp,
1535        struct embedded_panel_info *info);
1536static enum bp_result get_embedded_panel_info_v1_3(
1537        struct bios_parser *bp,
1538        struct embedded_panel_info *info);
1539
1540static enum bp_result bios_parser_get_embedded_panel_info(
1541        struct dc_bios *dcb,
1542        struct embedded_panel_info *info)
1543{
1544        struct bios_parser *bp = BP_FROM_DCB(dcb);
1545        ATOM_COMMON_TABLE_HEADER *hdr;
1546
1547        if (!DATA_TABLES(LCD_Info))
1548                return BP_RESULT_FAILURE;
1549
1550        hdr = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(LCD_Info));
1551
1552        if (!hdr)
1553                return BP_RESULT_BADBIOSTABLE;
1554
1555        switch (hdr->ucTableFormatRevision) {
1556        case 1:
1557                switch (hdr->ucTableContentRevision) {
1558                case 0:
1559                case 1:
1560                case 2:
1561                        return get_embedded_panel_info_v1_2(bp, info);
1562                case 3:
1563                        return get_embedded_panel_info_v1_3(bp, info);
1564                default:
1565                        break;
1566                }
1567        default:
1568                break;
1569        }
1570
1571        return BP_RESULT_FAILURE;
1572}
1573
1574static enum bp_result get_embedded_panel_info_v1_2(
1575        struct bios_parser *bp,
1576        struct embedded_panel_info *info)
1577{
1578        ATOM_LVDS_INFO_V12 *lvds;
1579
1580        if (!info)
1581                return BP_RESULT_BADINPUT;
1582
1583        if (!DATA_TABLES(LVDS_Info))
1584                return BP_RESULT_UNSUPPORTED;
1585
1586        lvds =
1587                GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
1588
1589        if (!lvds)
1590                return BP_RESULT_BADBIOSTABLE;
1591
1592        if (1 != lvds->sHeader.ucTableFormatRevision
1593                || 2 > lvds->sHeader.ucTableContentRevision)
1594                return BP_RESULT_UNSUPPORTED;
1595
1596        memset(info, 0, sizeof(struct embedded_panel_info));
1597
1598        /* We need to convert from 10KHz units into KHz units*/
1599        info->lcd_timing.pixel_clk =
1600                le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1601        /* usHActive does not include borders, according to VBIOS team*/
1602        info->lcd_timing.horizontal_addressable =
1603                le16_to_cpu(lvds->sLCDTiming.usHActive);
1604        /* usHBlanking_Time includes borders, so we should really be subtracting
1605         * borders duing this translation, but LVDS generally*/
1606        /* doesn't have borders, so we should be okay leaving this as is for
1607         * now.  May need to revisit if we ever have LVDS with borders*/
1608        info->lcd_timing.horizontal_blanking_time =
1609                        le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1610        /* usVActive does not include borders, according to VBIOS team*/
1611        info->lcd_timing.vertical_addressable =
1612                        le16_to_cpu(lvds->sLCDTiming.usVActive);
1613        /* usVBlanking_Time includes borders, so we should really be subtracting
1614         * borders duing this translation, but LVDS generally*/
1615        /* doesn't have borders, so we should be okay leaving this as is for
1616         * now. May need to revisit if we ever have LVDS with borders*/
1617        info->lcd_timing.vertical_blanking_time =
1618                le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1619        info->lcd_timing.horizontal_sync_offset =
1620                le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1621        info->lcd_timing.horizontal_sync_width =
1622                le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1623        info->lcd_timing.vertical_sync_offset =
1624                le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1625        info->lcd_timing.vertical_sync_width =
1626                le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1627        info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1628        info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1629        info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1630                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1631        info->lcd_timing.misc_info.H_SYNC_POLARITY =
1632                ~(uint32_t)
1633                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1634        info->lcd_timing.misc_info.V_SYNC_POLARITY =
1635                ~(uint32_t)
1636                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1637        info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1638                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1639        info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1640                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1641        info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1642                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1643        info->lcd_timing.misc_info.COMPOSITE_SYNC =
1644                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1645        info->lcd_timing.misc_info.INTERLACE =
1646                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1647        info->lcd_timing.misc_info.DOUBLE_CLOCK =
1648                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1649        info->ss_id = lvds->ucSS_Id;
1650
1651        {
1652                uint8_t rr = le16_to_cpu(lvds->usSupportedRefreshRate);
1653                /* Get minimum supported refresh rate*/
1654                if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1655                        info->supported_rr.REFRESH_RATE_30HZ = 1;
1656                else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1657                        info->supported_rr.REFRESH_RATE_40HZ = 1;
1658                else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1659                        info->supported_rr.REFRESH_RATE_48HZ = 1;
1660                else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1661                        info->supported_rr.REFRESH_RATE_50HZ = 1;
1662                else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1663                        info->supported_rr.REFRESH_RATE_60HZ = 1;
1664        }
1665
1666        /*Drr panel support can be reported by VBIOS*/
1667        if (LCDPANEL_CAP_DRR_SUPPORTED
1668                        & lvds->ucLCDPanel_SpecialHandlingCap)
1669                info->drr_enabled = 1;
1670
1671        if (ATOM_PANEL_MISC_DUAL & lvds->ucLVDS_Misc)
1672                info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1673
1674        if (ATOM_PANEL_MISC_888RGB & lvds->ucLVDS_Misc)
1675                info->lcd_timing.misc_info.RGB888 = true;
1676
1677        info->lcd_timing.misc_info.GREY_LEVEL =
1678                (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL &
1679                        lvds->ucLVDS_Misc) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT;
1680
1681        if (ATOM_PANEL_MISC_SPATIAL & lvds->ucLVDS_Misc)
1682                info->lcd_timing.misc_info.SPATIAL = true;
1683
1684        if (ATOM_PANEL_MISC_TEMPORAL & lvds->ucLVDS_Misc)
1685                info->lcd_timing.misc_info.TEMPORAL = true;
1686
1687        if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
1688                info->lcd_timing.misc_info.API_ENABLED = true;
1689
1690        return BP_RESULT_OK;
1691}
1692
1693static enum bp_result get_embedded_panel_info_v1_3(
1694        struct bios_parser *bp,
1695        struct embedded_panel_info *info)
1696{
1697        ATOM_LCD_INFO_V13 *lvds;
1698
1699        if (!info)
1700                return BP_RESULT_BADINPUT;
1701
1702        if (!DATA_TABLES(LCD_Info))
1703                return BP_RESULT_UNSUPPORTED;
1704
1705        lvds = GET_IMAGE(ATOM_LCD_INFO_V13, DATA_TABLES(LCD_Info));
1706
1707        if (!lvds)
1708                return BP_RESULT_BADBIOSTABLE;
1709
1710        if (!((1 == lvds->sHeader.ucTableFormatRevision)
1711                        && (3 <= lvds->sHeader.ucTableContentRevision)))
1712                return BP_RESULT_UNSUPPORTED;
1713
1714        memset(info, 0, sizeof(struct embedded_panel_info));
1715
1716        /* We need to convert from 10KHz units into KHz units */
1717        info->lcd_timing.pixel_clk =
1718                        le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
1719        /* usHActive does not include borders, according to VBIOS team */
1720        info->lcd_timing.horizontal_addressable =
1721                        le16_to_cpu(lvds->sLCDTiming.usHActive);
1722        /* usHBlanking_Time includes borders, so we should really be subtracting
1723         * borders duing this translation, but LVDS generally*/
1724        /* doesn't have borders, so we should be okay leaving this as is for
1725         * now.  May need to revisit if we ever have LVDS with borders*/
1726        info->lcd_timing.horizontal_blanking_time =
1727                le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
1728        /* usVActive does not include borders, according to VBIOS team*/
1729        info->lcd_timing.vertical_addressable =
1730                le16_to_cpu(lvds->sLCDTiming.usVActive);
1731        /* usVBlanking_Time includes borders, so we should really be subtracting
1732         * borders duing this translation, but LVDS generally*/
1733        /* doesn't have borders, so we should be okay leaving this as is for
1734         * now. May need to revisit if we ever have LVDS with borders*/
1735        info->lcd_timing.vertical_blanking_time =
1736                le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
1737        info->lcd_timing.horizontal_sync_offset =
1738                le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
1739        info->lcd_timing.horizontal_sync_width =
1740                le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
1741        info->lcd_timing.vertical_sync_offset =
1742                le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
1743        info->lcd_timing.vertical_sync_width =
1744                le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
1745        info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
1746        info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
1747        info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
1748                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
1749        info->lcd_timing.misc_info.H_SYNC_POLARITY =
1750                ~(uint32_t)
1751                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
1752        info->lcd_timing.misc_info.V_SYNC_POLARITY =
1753                ~(uint32_t)
1754                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
1755        info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
1756                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
1757        info->lcd_timing.misc_info.H_REPLICATION_BY2 =
1758                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
1759        info->lcd_timing.misc_info.V_REPLICATION_BY2 =
1760                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
1761        info->lcd_timing.misc_info.COMPOSITE_SYNC =
1762                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
1763        info->lcd_timing.misc_info.INTERLACE =
1764                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
1765        info->lcd_timing.misc_info.DOUBLE_CLOCK =
1766                lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
1767        info->ss_id = lvds->ucSS_Id;
1768
1769        /* Drr panel support can be reported by VBIOS*/
1770        if (LCDPANEL_CAP_V13_DRR_SUPPORTED
1771                        & lvds->ucLCDPanel_SpecialHandlingCap)
1772                info->drr_enabled = 1;
1773
1774        /* Get supported refresh rate*/
1775        if (info->drr_enabled == 1) {
1776                uint8_t min_rr =
1777                                lvds->sRefreshRateSupport.ucMinRefreshRateForDRR;
1778                uint8_t rr = lvds->sRefreshRateSupport.ucSupportedRefreshRate;
1779
1780                if (min_rr != 0) {
1781                        if (SUPPORTED_LCD_REFRESHRATE_30Hz & min_rr)
1782                                info->supported_rr.REFRESH_RATE_30HZ = 1;
1783                        else if (SUPPORTED_LCD_REFRESHRATE_40Hz & min_rr)
1784                                info->supported_rr.REFRESH_RATE_40HZ = 1;
1785                        else if (SUPPORTED_LCD_REFRESHRATE_48Hz & min_rr)
1786                                info->supported_rr.REFRESH_RATE_48HZ = 1;
1787                        else if (SUPPORTED_LCD_REFRESHRATE_50Hz & min_rr)
1788                                info->supported_rr.REFRESH_RATE_50HZ = 1;
1789                        else if (SUPPORTED_LCD_REFRESHRATE_60Hz & min_rr)
1790                                info->supported_rr.REFRESH_RATE_60HZ = 1;
1791                } else {
1792                        if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
1793                                info->supported_rr.REFRESH_RATE_30HZ = 1;
1794                        else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
1795                                info->supported_rr.REFRESH_RATE_40HZ = 1;
1796                        else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
1797                                info->supported_rr.REFRESH_RATE_48HZ = 1;
1798                        else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
1799                                info->supported_rr.REFRESH_RATE_50HZ = 1;
1800                        else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
1801                                info->supported_rr.REFRESH_RATE_60HZ = 1;
1802                }
1803        }
1804
1805        if (ATOM_PANEL_MISC_V13_DUAL & lvds->ucLCD_Misc)
1806                info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
1807
1808        if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR & lvds->ucLCD_Misc)
1809                info->lcd_timing.misc_info.RGB888 = true;
1810
1811        info->lcd_timing.misc_info.GREY_LEVEL =
1812                        (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
1813                                lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
1814
1815        return BP_RESULT_OK;
1816}
1817
1818/**
1819 * bios_parser_get_encoder_cap_info
1820 *
1821 * @brief
1822 *  Get encoder capability information of input object id
1823 *
1824 * @param object_id, Object id
1825 * @param object_id, encoder cap information structure
1826 *
1827 * @return Bios parser result code
1828 *
1829 */
1830static enum bp_result bios_parser_get_encoder_cap_info(
1831        struct dc_bios *dcb,
1832        struct graphics_object_id object_id,
1833        struct bp_encoder_cap_info *info)
1834{
1835        struct bios_parser *bp = BP_FROM_DCB(dcb);
1836        ATOM_OBJECT *object;
1837        ATOM_ENCODER_CAP_RECORD_V2 *record = NULL;
1838
1839        if (!info)
1840                return BP_RESULT_BADINPUT;
1841
1842        object = get_bios_object(bp, object_id);
1843
1844        if (!object)
1845                return BP_RESULT_BADINPUT;
1846
1847        record = get_encoder_cap_record(bp, object);
1848        if (!record)
1849                return BP_RESULT_NORECORD;
1850
1851        info->DP_HBR2_EN = record->usHBR2En;
1852        info->DP_HBR3_EN = record->usHBR3En;
1853        info->HDMI_6GB_EN = record->usHDMI6GEn;
1854        return BP_RESULT_OK;
1855}
1856
1857/**
1858 * get_encoder_cap_record
1859 *
1860 * @brief
1861 *  Get encoder cap record for the object
1862 *
1863 * @param object, ATOM object
1864 *
1865 * @return atom encoder cap record
1866 *
1867 * @note
1868 *  search all records to find the ATOM_ENCODER_CAP_RECORD_V2 record
1869 */
1870static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
1871        struct bios_parser *bp,
1872        ATOM_OBJECT *object)
1873{
1874        ATOM_COMMON_RECORD_HEADER *header;
1875        uint32_t offset;
1876
1877        if (!object) {
1878                BREAK_TO_DEBUGGER(); /* Invalid object */
1879                return NULL;
1880        }
1881
1882        offset = le16_to_cpu(object->usRecordOffset)
1883                                        + bp->object_info_tbl_offset;
1884
1885        for (;;) {
1886                header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
1887
1888                if (!header)
1889                        return NULL;
1890
1891                offset += header->ucRecordSize;
1892
1893                if (LAST_RECORD_TYPE == header->ucRecordType ||
1894                                !header->ucRecordSize)
1895                        break;
1896
1897                if (ATOM_ENCODER_CAP_RECORD_TYPE != header->ucRecordType)
1898                        continue;
1899
1900                if (sizeof(ATOM_ENCODER_CAP_RECORD_V2) <= header->ucRecordSize)
1901                        return (ATOM_ENCODER_CAP_RECORD_V2 *)header;
1902        }
1903
1904        return NULL;
1905}
1906
1907static uint32_t get_ss_entry_number(
1908        struct bios_parser *bp,
1909        uint32_t id);
1910static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
1911        struct bios_parser *bp,
1912        uint32_t id);
1913static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1914        struct bios_parser *bp,
1915        uint32_t id);
1916static uint32_t get_ss_entry_number_from_ss_info_tbl(
1917        struct bios_parser *bp,
1918        uint32_t id);
1919
1920/**
1921 * BiosParserObject::GetNumberofSpreadSpectrumEntry
1922 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
1923 * the VBIOS that match the SSid (to be converted from signal)
1924 *
1925 * @param[in] signal, ASSignalType to be converted to SSid
1926 * @return number of SS Entry that match the signal
1927 */
1928static uint32_t bios_parser_get_ss_entry_number(
1929        struct dc_bios *dcb,
1930        enum as_signal_type signal)
1931{
1932        struct bios_parser *bp = BP_FROM_DCB(dcb);
1933        uint32_t ss_id = 0;
1934        ATOM_COMMON_TABLE_HEADER *header;
1935        struct atom_data_revision revision;
1936
1937        ss_id = signal_to_ss_id(signal);
1938
1939        if (!DATA_TABLES(ASIC_InternalSS_Info))
1940                return get_ss_entry_number_from_ss_info_tbl(bp, ss_id);
1941
1942        header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1943                        DATA_TABLES(ASIC_InternalSS_Info));
1944        get_atom_data_table_revision(header, &revision);
1945
1946        switch (revision.major) {
1947        case 2:
1948                switch (revision.minor) {
1949                case 1:
1950                        return get_ss_entry_number(bp, ss_id);
1951                default:
1952                        break;
1953                }
1954                break;
1955        case 3:
1956                switch (revision.minor) {
1957                case 1:
1958                        return
1959                                get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
1960                                                bp, ss_id);
1961                default:
1962                        break;
1963                }
1964                break;
1965        default:
1966                break;
1967        }
1968
1969        return 0;
1970}
1971
1972/**
1973 * get_ss_entry_number_from_ss_info_tbl
1974 * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
1975 *
1976 * @note There can only be one entry for each id for SS_Info Table
1977 *
1978 * @param [in] id, spread spectrum id
1979 * @return number of SS Entry that match the id
1980 */
1981static uint32_t get_ss_entry_number_from_ss_info_tbl(
1982        struct bios_parser *bp,
1983        uint32_t id)
1984{
1985        ATOM_SPREAD_SPECTRUM_INFO *tbl;
1986        ATOM_COMMON_TABLE_HEADER *header;
1987        uint32_t table_size;
1988        uint32_t i;
1989        uint32_t number = 0;
1990        uint32_t id_local = SS_ID_UNKNOWN;
1991        struct atom_data_revision revision;
1992
1993        /* SS_Info table exist */
1994        if (!DATA_TABLES(SS_Info))
1995                return number;
1996
1997        header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
1998                        DATA_TABLES(SS_Info));
1999        get_atom_data_table_revision(header, &revision);
2000
2001        tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO,
2002                        DATA_TABLES(SS_Info));
2003
2004        if (1 != revision.major || 2 > revision.minor)
2005                return number;
2006
2007        /* have to convert from Internal_SS format to SS_Info format */
2008        switch (id) {
2009        case ASIC_INTERNAL_SS_ON_DP:
2010                id_local = SS_ID_DP1;
2011                break;
2012        case ASIC_INTERNAL_SS_ON_LVDS: {
2013                struct embedded_panel_info panel_info;
2014
2015                if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
2016                                == BP_RESULT_OK)
2017                        id_local = panel_info.ss_id;
2018                break;
2019        }
2020        default:
2021                break;
2022        }
2023
2024        if (id_local == SS_ID_UNKNOWN)
2025                return number;
2026
2027        table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
2028                        sizeof(ATOM_COMMON_TABLE_HEADER)) /
2029                                        sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
2030
2031        for (i = 0; i < table_size; i++)
2032                if (id_local == (uint32_t)tbl->asSS_Info[i].ucSS_Id) {
2033                        number = 1;
2034                        break;
2035                }
2036
2037        return number;
2038}
2039
2040/**
2041 * get_ss_entry_number
2042 * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
2043 * SS_Info table from the VBIOS
2044 * There can not be more than 1 entry for  ASIC_InternalSS_Info Ver 2.1 or
2045 * SS_Info.
2046 *
2047 * @param id, spread sprectrum info index
2048 * @return Bios parser result code
2049 */
2050static uint32_t get_ss_entry_number(struct bios_parser *bp, uint32_t id)
2051{
2052        if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
2053                return get_ss_entry_number_from_ss_info_tbl(bp, id);
2054
2055        return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp, id);
2056}
2057
2058/**
2059 * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
2060 * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
2061 * Ver 2.1 from the VBIOS
2062 * There will not be multiple entry for Ver 2.1
2063 *
2064 * @param id, spread sprectrum info index
2065 * @return number of SS Entry that match the id
2066 */
2067static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
2068        struct bios_parser *bp,
2069        uint32_t id)
2070{
2071        ATOM_ASIC_INTERNAL_SS_INFO_V2 *header_include;
2072        ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
2073        uint32_t size;
2074        uint32_t i;
2075
2076        if (!DATA_TABLES(ASIC_InternalSS_Info))
2077                return 0;
2078
2079        header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
2080                        DATA_TABLES(ASIC_InternalSS_Info));
2081
2082        size = (le16_to_cpu(header_include->sHeader.usStructureSize)
2083                        - sizeof(ATOM_COMMON_TABLE_HEADER))
2084                                                / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
2085
2086        tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
2087                                &header_include->asSpreadSpectrum[0];
2088        for (i = 0; i < size; i++)
2089                if (tbl[i].ucClockIndication == (uint8_t)id)
2090                        return 1;
2091
2092        return 0;
2093}
2094/**
2095 * get_ss_entry_number_from_internal_ss_info_table_V3_1
2096 * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
2097 * the VBIOS that matches id
2098 *
2099 * @param[in]  id, spread sprectrum id
2100 * @return number of SS Entry that match the id
2101 */
2102static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
2103        struct bios_parser *bp,
2104        uint32_t id)
2105{
2106        uint32_t number = 0;
2107        ATOM_ASIC_INTERNAL_SS_INFO_V3 *header_include;
2108        ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
2109        uint32_t size;
2110        uint32_t i;
2111
2112        if (!DATA_TABLES(ASIC_InternalSS_Info))
2113                return number;
2114
2115        header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
2116                        DATA_TABLES(ASIC_InternalSS_Info));
2117        size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
2118                        sizeof(ATOM_COMMON_TABLE_HEADER)) /
2119                                        sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
2120
2121        tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
2122                                &header_include->asSpreadSpectrum[0];
2123
2124        for (i = 0; i < size; i++)
2125                if (tbl[i].ucClockIndication == (uint8_t)id)
2126                        number++;
2127
2128        return number;
2129}
2130
2131/**
2132 * bios_parser_get_gpio_pin_info
2133 * Get GpioPin information of input gpio id
2134 *
2135 * @param gpio_id, GPIO ID
2136 * @param info, GpioPin information structure
2137 * @return Bios parser result code
2138 * @note
2139 *  to get the GPIO PIN INFO, we need:
2140 *  1. get the GPIO_ID from other object table, see GetHPDInfo()
2141 *  2. in DATA_TABLE.GPIO_Pin_LUT, search all records, to get the registerA
2142 *  offset/mask
2143 */
2144static enum bp_result bios_parser_get_gpio_pin_info(
2145        struct dc_bios *dcb,
2146        uint32_t gpio_id,
2147        struct gpio_pin_info *info)
2148{
2149        struct bios_parser *bp = BP_FROM_DCB(dcb);
2150        ATOM_GPIO_PIN_LUT *header;
2151        uint32_t count = 0;
2152        uint32_t i = 0;
2153
2154        if (!DATA_TABLES(GPIO_Pin_LUT))
2155                return BP_RESULT_BADBIOSTABLE;
2156
2157        header = GET_IMAGE(ATOM_GPIO_PIN_LUT, DATA_TABLES(GPIO_Pin_LUT));
2158        if (!header)
2159                return BP_RESULT_BADBIOSTABLE;
2160
2161        if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_PIN_LUT)
2162                        > le16_to_cpu(header->sHeader.usStructureSize))
2163                return BP_RESULT_BADBIOSTABLE;
2164
2165        if (1 != header->sHeader.ucTableContentRevision)
2166                return BP_RESULT_UNSUPPORTED;
2167
2168        count = (le16_to_cpu(header->sHeader.usStructureSize)
2169                        - sizeof(ATOM_COMMON_TABLE_HEADER))
2170                                / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
2171        for (i = 0; i < count; ++i) {
2172                if (header->asGPIO_Pin[i].ucGPIO_ID != gpio_id)
2173                        continue;
2174
2175                info->offset =
2176                        (uint32_t) le16_to_cpu(header->asGPIO_Pin[i].usGpioPin_AIndex);
2177                info->offset_y = info->offset + 2;
2178                info->offset_en = info->offset + 1;
2179                info->offset_mask = info->offset - 1;
2180
2181                info->mask = (uint32_t) (1 <<
2182                        header->asGPIO_Pin[i].ucGpioPinBitShift);
2183                info->mask_y = info->mask + 2;
2184                info->mask_en = info->mask + 1;
2185                info->mask_mask = info->mask - 1;
2186
2187                return BP_RESULT_OK;
2188        }
2189
2190        return BP_RESULT_NORECORD;
2191}
2192
2193static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
2194        ATOM_I2C_RECORD *record,
2195        struct graphics_object_i2c_info *info)
2196{
2197        ATOM_GPIO_I2C_INFO *header;
2198        uint32_t count = 0;
2199
2200        if (!info)
2201                return BP_RESULT_BADINPUT;
2202
2203        /* get the GPIO_I2C info */
2204        if (!DATA_TABLES(GPIO_I2C_Info))
2205                return BP_RESULT_BADBIOSTABLE;
2206
2207        header = GET_IMAGE(ATOM_GPIO_I2C_INFO, DATA_TABLES(GPIO_I2C_Info));
2208        if (!header)
2209                return BP_RESULT_BADBIOSTABLE;
2210
2211        if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_I2C_ASSIGMENT)
2212                        > le16_to_cpu(header->sHeader.usStructureSize))
2213                return BP_RESULT_BADBIOSTABLE;
2214
2215        if (1 != header->sHeader.ucTableContentRevision)
2216                return BP_RESULT_UNSUPPORTED;
2217
2218        /* get data count */
2219        count = (le16_to_cpu(header->sHeader.usStructureSize)
2220                        - sizeof(ATOM_COMMON_TABLE_HEADER))
2221                                / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
2222        if (count < record->sucI2cId.bfI2C_LineMux)
2223                return BP_RESULT_BADBIOSTABLE;
2224
2225        /* get the GPIO_I2C_INFO */
2226        info->i2c_hw_assist = record->sucI2cId.bfHW_Capable;
2227        info->i2c_line = record->sucI2cId.bfI2C_LineMux;
2228        info->i2c_engine_id = record->sucI2cId.bfHW_EngineID;
2229        info->i2c_slave_address = record->ucI2CAddr;
2230
2231        info->gpio_info.clk_mask_register_index =
2232                        le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkMaskRegisterIndex);
2233        info->gpio_info.clk_en_register_index =
2234                        le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkEnRegisterIndex);
2235        info->gpio_info.clk_y_register_index =
2236                        le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkY_RegisterIndex);
2237        info->gpio_info.clk_a_register_index =
2238                        le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkA_RegisterIndex);
2239        info->gpio_info.data_mask_register_index =
2240                        le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataMaskRegisterIndex);
2241        info->gpio_info.data_en_register_index =
2242                        le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataEnRegisterIndex);
2243        info->gpio_info.data_y_register_index =
2244                        le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataY_RegisterIndex);
2245        info->gpio_info.data_a_register_index =
2246                        le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataA_RegisterIndex);
2247
2248        info->gpio_info.clk_mask_shift =
2249                        header->asGPIO_Info[info->i2c_line].ucClkMaskShift;
2250        info->gpio_info.clk_en_shift =
2251                        header->asGPIO_Info[info->i2c_line].ucClkEnShift;
2252        info->gpio_info.clk_y_shift =
2253                        header->asGPIO_Info[info->i2c_line].ucClkY_Shift;
2254        info->gpio_info.clk_a_shift =
2255                        header->asGPIO_Info[info->i2c_line].ucClkA_Shift;
2256        info->gpio_info.data_mask_shift =
2257                        header->asGPIO_Info[info->i2c_line].ucDataMaskShift;
2258        info->gpio_info.data_en_shift =
2259                        header->asGPIO_Info[info->i2c_line].ucDataEnShift;
2260        info->gpio_info.data_y_shift =
2261                        header->asGPIO_Info[info->i2c_line].ucDataY_Shift;
2262        info->gpio_info.data_a_shift =
2263                        header->asGPIO_Info[info->i2c_line].ucDataA_Shift;
2264
2265        return BP_RESULT_OK;
2266}
2267
2268static bool dal_graphics_object_id_is_valid(struct graphics_object_id id)
2269{
2270        bool rc = true;
2271
2272        switch (id.type) {
2273        case OBJECT_TYPE_UNKNOWN:
2274                rc = false;
2275                break;
2276        case OBJECT_TYPE_GPU:
2277        case OBJECT_TYPE_ENGINE:
2278                /* do NOT check for id.id == 0 */
2279                if (id.enum_id == ENUM_ID_UNKNOWN)
2280                        rc = false;
2281                break;
2282        default:
2283                if (id.id == 0 || id.enum_id == ENUM_ID_UNKNOWN)
2284                        rc = false;
2285                break;
2286        }
2287
2288        return rc;
2289}
2290
2291static bool dal_graphics_object_id_is_equal(
2292        struct graphics_object_id id1,
2293        struct graphics_object_id id2)
2294{
2295        if (false == dal_graphics_object_id_is_valid(id1)) {
2296                dm_output_to_console(
2297                "%s: Warning: comparing invalid object 'id1'!\n", __func__);
2298                return false;
2299        }
2300
2301        if (false == dal_graphics_object_id_is_valid(id2)) {
2302                dm_output_to_console(
2303                "%s: Warning: comparing invalid object 'id2'!\n", __func__);
2304                return false;
2305        }
2306
2307        if (id1.id == id2.id && id1.enum_id == id2.enum_id
2308                && id1.type == id2.type)
2309                return true;
2310
2311        return false;
2312}
2313
2314static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
2315        struct graphics_object_id id)
2316{
2317        uint32_t offset;
2318        ATOM_OBJECT_TABLE *tbl;
2319        uint32_t i;
2320
2321        switch (id.type) {
2322        case OBJECT_TYPE_ENCODER:
2323                offset = le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
2324                break;
2325
2326        case OBJECT_TYPE_CONNECTOR:
2327                offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
2328                break;
2329
2330        case OBJECT_TYPE_ROUTER:
2331                offset = le16_to_cpu(bp->object_info_tbl.v1_1->usRouterObjectTableOffset);
2332                break;
2333
2334        case OBJECT_TYPE_GENERIC:
2335                if (bp->object_info_tbl.revision.minor < 3)
2336                        return NULL;
2337                offset = le16_to_cpu(bp->object_info_tbl.v1_3->usMiscObjectTableOffset);
2338                break;
2339
2340        default:
2341                return NULL;
2342        }
2343
2344        offset += bp->object_info_tbl_offset;
2345
2346        tbl = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
2347        if (!tbl)
2348                return NULL;
2349
2350        for (i = 0; i < tbl->ucNumberOfObjects; i++)
2351                if (dal_graphics_object_id_is_equal(id,
2352                                object_id_from_bios_object_id(
2353                                                le16_to_cpu(tbl->asObjects[i].usObjectID))))
2354                        return &tbl->asObjects[i];
2355
2356        return NULL;
2357}
2358
2359static uint32_t get_dest_obj_list(struct bios_parser *bp,
2360        ATOM_OBJECT *object, uint16_t **id_list)
2361{
2362        uint32_t offset;
2363        uint8_t *number;
2364
2365        if (!object) {
2366                BREAK_TO_DEBUGGER(); /* Invalid object id */
2367                return 0;
2368        }
2369
2370        offset = le16_to_cpu(object->usSrcDstTableOffset)
2371                                                + bp->object_info_tbl_offset;
2372
2373        number = GET_IMAGE(uint8_t, offset);
2374        if (!number)
2375                return 0;
2376
2377        offset += sizeof(uint8_t);
2378        offset += sizeof(uint16_t) * (*number);
2379
2380        number = GET_IMAGE(uint8_t, offset);
2381        if ((!number) || (!*number))
2382                return 0;
2383
2384        offset += sizeof(uint8_t);
2385        *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
2386
2387        if (!*id_list)
2388                return 0;
2389
2390        return *number;
2391}
2392
2393static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
2394        uint16_t **id_list)
2395{
2396        uint32_t offset;
2397        uint8_t *number;
2398
2399        if (!object) {
2400                BREAK_TO_DEBUGGER(); /* Invalid object id */
2401                return 0;
2402        }
2403
2404        offset = le16_to_cpu(object->usSrcDstTableOffset)
2405                                        + bp->object_info_tbl_offset;
2406
2407        number = GET_IMAGE(uint8_t, offset);
2408        if (!number)
2409                return 0;
2410
2411        offset += sizeof(uint8_t);
2412        *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
2413
2414        if (!*id_list)
2415                return 0;
2416
2417        return *number;
2418}
2419
2420static uint32_t get_dst_number_from_object(struct bios_parser *bp,
2421        ATOM_OBJECT *object)
2422{
2423        uint32_t offset;
2424        uint8_t *number;
2425
2426        if (!object) {
2427                BREAK_TO_DEBUGGER(); /* Invalid encoder object id*/
2428                return 0;
2429        }
2430
2431        offset = le16_to_cpu(object->usSrcDstTableOffset)
2432                                        + bp->object_info_tbl_offset;
2433
2434        number = GET_IMAGE(uint8_t, offset);
2435        if (!number)
2436                return 0;
2437
2438        offset += sizeof(uint8_t);
2439        offset += sizeof(uint16_t) * (*number);
2440
2441        number = GET_IMAGE(uint8_t, offset);
2442
2443        if (!number)
2444                return 0;
2445
2446        return *number;
2447}
2448
2449static struct device_id device_type_from_device_id(uint16_t device_id)
2450{
2451
2452        struct device_id result_device_id;
2453
2454        switch (device_id) {
2455        case ATOM_DEVICE_LCD1_SUPPORT:
2456                result_device_id.device_type = DEVICE_TYPE_LCD;
2457                result_device_id.enum_id = 1;
2458                break;
2459
2460        case ATOM_DEVICE_LCD2_SUPPORT:
2461                result_device_id.device_type = DEVICE_TYPE_LCD;
2462                result_device_id.enum_id = 2;
2463                break;
2464
2465        case ATOM_DEVICE_CRT1_SUPPORT:
2466                result_device_id.device_type = DEVICE_TYPE_CRT;
2467                result_device_id.enum_id = 1;
2468                break;
2469
2470        case ATOM_DEVICE_CRT2_SUPPORT:
2471                result_device_id.device_type = DEVICE_TYPE_CRT;
2472                result_device_id.enum_id = 2;
2473                break;
2474
2475        case ATOM_DEVICE_DFP1_SUPPORT:
2476                result_device_id.device_type = DEVICE_TYPE_DFP;
2477                result_device_id.enum_id = 1;
2478                break;
2479
2480        case ATOM_DEVICE_DFP2_SUPPORT:
2481                result_device_id.device_type = DEVICE_TYPE_DFP;
2482                result_device_id.enum_id = 2;
2483                break;
2484
2485        case ATOM_DEVICE_DFP3_SUPPORT:
2486                result_device_id.device_type = DEVICE_TYPE_DFP;
2487                result_device_id.enum_id = 3;
2488                break;
2489
2490        case ATOM_DEVICE_DFP4_SUPPORT:
2491                result_device_id.device_type = DEVICE_TYPE_DFP;
2492                result_device_id.enum_id = 4;
2493                break;
2494
2495        case ATOM_DEVICE_DFP5_SUPPORT:
2496                result_device_id.device_type = DEVICE_TYPE_DFP;
2497                result_device_id.enum_id = 5;
2498                break;
2499
2500        case ATOM_DEVICE_DFP6_SUPPORT:
2501                result_device_id.device_type = DEVICE_TYPE_DFP;
2502                result_device_id.enum_id = 6;
2503                break;
2504
2505        default:
2506                BREAK_TO_DEBUGGER(); /* Invalid device Id */
2507                result_device_id.device_type = DEVICE_TYPE_UNKNOWN;
2508                result_device_id.enum_id = 0;
2509        }
2510        return result_device_id;
2511}
2512
2513static void get_atom_data_table_revision(
2514        ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
2515        struct atom_data_revision *tbl_revision)
2516{
2517        if (!tbl_revision)
2518                return;
2519
2520        /* initialize the revision to 0 which is invalid revision */
2521        tbl_revision->major = 0;
2522        tbl_revision->minor = 0;
2523
2524        if (!atom_data_tbl)
2525                return;
2526
2527        tbl_revision->major =
2528                        (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl);
2529        tbl_revision->minor =
2530                        (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl);
2531}
2532
2533static uint32_t signal_to_ss_id(enum as_signal_type signal)
2534{
2535        uint32_t clk_id_ss = 0;
2536
2537        switch (signal) {
2538        case AS_SIGNAL_TYPE_DVI:
2539                clk_id_ss = ASIC_INTERNAL_SS_ON_TMDS;
2540                break;
2541        case AS_SIGNAL_TYPE_HDMI:
2542                clk_id_ss = ASIC_INTERNAL_SS_ON_HDMI;
2543                break;
2544        case AS_SIGNAL_TYPE_LVDS:
2545                clk_id_ss = ASIC_INTERNAL_SS_ON_LVDS;
2546                break;
2547        case AS_SIGNAL_TYPE_DISPLAY_PORT:
2548                clk_id_ss = ASIC_INTERNAL_SS_ON_DP;
2549                break;
2550        case AS_SIGNAL_TYPE_GPU_PLL:
2551                clk_id_ss = ASIC_INTERNAL_GPUPLL_SS;
2552                break;
2553        default:
2554                break;
2555        }
2556        return clk_id_ss;
2557}
2558
2559static uint32_t get_support_mask_for_device_id(struct device_id device_id)
2560{
2561        enum dal_device_type device_type = device_id.device_type;
2562        uint32_t enum_id = device_id.enum_id;
2563
2564        switch (device_type) {
2565        case DEVICE_TYPE_LCD:
2566                switch (enum_id) {
2567                case 1:
2568                        return ATOM_DEVICE_LCD1_SUPPORT;
2569                case 2:
2570                        return ATOM_DEVICE_LCD2_SUPPORT;
2571                default:
2572                        break;
2573                }
2574                break;
2575        case DEVICE_TYPE_CRT:
2576                switch (enum_id) {
2577                case 1:
2578                        return ATOM_DEVICE_CRT1_SUPPORT;
2579                case 2:
2580                        return ATOM_DEVICE_CRT2_SUPPORT;
2581                default:
2582                        break;
2583                }
2584                break;
2585        case DEVICE_TYPE_DFP:
2586                switch (enum_id) {
2587                case 1:
2588                        return ATOM_DEVICE_DFP1_SUPPORT;
2589                case 2:
2590                        return ATOM_DEVICE_DFP2_SUPPORT;
2591                case 3:
2592                        return ATOM_DEVICE_DFP3_SUPPORT;
2593                case 4:
2594                        return ATOM_DEVICE_DFP4_SUPPORT;
2595                case 5:
2596                        return ATOM_DEVICE_DFP5_SUPPORT;
2597                case 6:
2598                        return ATOM_DEVICE_DFP6_SUPPORT;
2599                default:
2600                        break;
2601                }
2602                break;
2603        case DEVICE_TYPE_CV:
2604                switch (enum_id) {
2605                case 1:
2606                        return ATOM_DEVICE_CV_SUPPORT;
2607                default:
2608                        break;
2609                }
2610                break;
2611        case DEVICE_TYPE_TV:
2612                switch (enum_id) {
2613                case 1:
2614                        return ATOM_DEVICE_TV1_SUPPORT;
2615                default:
2616                        break;
2617                }
2618                break;
2619        default:
2620                break;
2621        };
2622
2623        /* Unidentified device ID, return empty support mask. */
2624        return 0;
2625}
2626
2627/**
2628 *  HwContext interface for writing MM registers
2629 */
2630
2631static bool i2c_read(
2632        struct bios_parser *bp,
2633        struct graphics_object_i2c_info *i2c_info,
2634        uint8_t *buffer,
2635        uint32_t length)
2636{
2637        struct ddc *ddc;
2638        uint8_t offset[2] = { 0, 0 };
2639        bool result = false;
2640        struct i2c_command cmd;
2641        struct gpio_ddc_hw_info hw_info = {
2642                i2c_info->i2c_hw_assist,
2643                i2c_info->i2c_line };
2644
2645        ddc = dal_gpio_create_ddc(bp->base.ctx->gpio_service,
2646                i2c_info->gpio_info.clk_a_register_index,
2647                (1 << i2c_info->gpio_info.clk_a_shift), &hw_info);
2648
2649        if (!ddc)
2650                return result;
2651
2652        /*Using SW engine */
2653        cmd.engine = I2C_COMMAND_ENGINE_SW;
2654        cmd.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
2655
2656        {
2657                struct i2c_payload payloads[] = {
2658                                {
2659                                                .address = i2c_info->i2c_slave_address >> 1,
2660                                                .data = offset,
2661                                                .length = sizeof(offset),
2662                                                .write = true
2663                                },
2664                                {
2665                                                .address = i2c_info->i2c_slave_address >> 1,
2666                                                .data = buffer,
2667                                                .length = length,
2668                                                .write = false
2669                                }
2670                };
2671
2672                cmd.payloads = payloads;
2673                cmd.number_of_payloads = ARRAY_SIZE(payloads);
2674
2675                /* TODO route this through drm i2c_adapter */
2676                result = dal_i2caux_submit_i2c_command(
2677                                ddc->ctx->i2caux,
2678                                ddc,
2679                                &cmd);
2680        }
2681
2682        dal_gpio_destroy_ddc(&ddc);
2683
2684        return result;
2685}
2686
2687/**
2688 * Read external display connection info table through i2c.
2689 * validate the GUID and checksum.
2690 *
2691 * @return enum bp_result whether all data was sucessfully read
2692 */
2693static enum bp_result get_ext_display_connection_info(
2694        struct bios_parser *bp,
2695        ATOM_OBJECT *opm_object,
2696        ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *ext_display_connection_info_tbl)
2697{
2698        bool config_tbl_present = false;
2699        ATOM_I2C_RECORD *i2c_record = NULL;
2700        uint32_t i = 0;
2701
2702        if (opm_object == NULL)
2703                return BP_RESULT_BADINPUT;
2704
2705        i2c_record = get_i2c_record(bp, opm_object);
2706
2707        if (i2c_record != NULL) {
2708                ATOM_GPIO_I2C_INFO *gpio_i2c_header;
2709                struct graphics_object_i2c_info i2c_info;
2710
2711                gpio_i2c_header = GET_IMAGE(ATOM_GPIO_I2C_INFO,
2712                                bp->master_data_tbl->ListOfDataTables.GPIO_I2C_Info);
2713
2714                if (NULL == gpio_i2c_header)
2715                        return BP_RESULT_BADBIOSTABLE;
2716
2717                if (get_gpio_i2c_info(bp, i2c_record, &i2c_info) !=
2718                                BP_RESULT_OK)
2719                        return BP_RESULT_BADBIOSTABLE;
2720
2721                if (i2c_read(bp,
2722                             &i2c_info,
2723                             (uint8_t *)ext_display_connection_info_tbl,
2724                             sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO))) {
2725                        config_tbl_present = true;
2726                }
2727        }
2728
2729        /* Validate GUID */
2730        if (config_tbl_present)
2731                for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; i++) {
2732                        if (ext_display_connection_info_tbl->ucGuid[i]
2733                            != ext_display_connection_guid[i]) {
2734                                config_tbl_present = false;
2735                                break;
2736                        }
2737                }
2738
2739        /* Validate checksum */
2740        if (config_tbl_present) {
2741                uint8_t check_sum = 0;
2742                uint8_t *buf =
2743                                (uint8_t *)ext_display_connection_info_tbl;
2744
2745                for (i = 0; i < sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO);
2746                                i++) {
2747                        check_sum += buf[i];
2748                }
2749
2750                if (check_sum != 0)
2751                        config_tbl_present = false;
2752        }
2753
2754        if (config_tbl_present)
2755                return BP_RESULT_OK;
2756        else
2757                return BP_RESULT_FAILURE;
2758}
2759
2760/*
2761 * Gets the first device ID in the same group as the given ID for enumerating.
2762 * For instance, if any DFP device ID is passed, returns the device ID for DFP1.
2763 *
2764 * The first device ID in the same group as the passed device ID, or 0 if no
2765 * matching device group found.
2766 */
2767static uint32_t enum_first_device_id(uint32_t dev_id)
2768{
2769        /* Return the first in the group that this ID belongs to. */
2770        if (dev_id & ATOM_DEVICE_CRT_SUPPORT)
2771                return ATOM_DEVICE_CRT1_SUPPORT;
2772        else if (dev_id & ATOM_DEVICE_DFP_SUPPORT)
2773                return ATOM_DEVICE_DFP1_SUPPORT;
2774        else if (dev_id & ATOM_DEVICE_LCD_SUPPORT)
2775                return ATOM_DEVICE_LCD1_SUPPORT;
2776        else if (dev_id & ATOM_DEVICE_TV_SUPPORT)
2777                return ATOM_DEVICE_TV1_SUPPORT;
2778        else if (dev_id & ATOM_DEVICE_CV_SUPPORT)
2779                return ATOM_DEVICE_CV_SUPPORT;
2780
2781        /* No group found for this device ID. */
2782
2783        dm_error("%s: incorrect input %d\n", __func__, dev_id);
2784        /* No matching support flag for given device ID */
2785        return 0;
2786}
2787
2788/*
2789 * Gets the next device ID in the group for a given device ID.
2790 *
2791 * The current device ID being enumerated on.
2792 *
2793 * The next device ID in the group, or 0 if no device exists.
2794 */
2795static uint32_t enum_next_dev_id(uint32_t dev_id)
2796{
2797        /* Get next device ID in the group. */
2798        switch (dev_id) {
2799        case ATOM_DEVICE_CRT1_SUPPORT:
2800                return ATOM_DEVICE_CRT2_SUPPORT;
2801        case ATOM_DEVICE_LCD1_SUPPORT:
2802                return ATOM_DEVICE_LCD2_SUPPORT;
2803        case ATOM_DEVICE_DFP1_SUPPORT:
2804                return ATOM_DEVICE_DFP2_SUPPORT;
2805        case ATOM_DEVICE_DFP2_SUPPORT:
2806                return ATOM_DEVICE_DFP3_SUPPORT;
2807        case ATOM_DEVICE_DFP3_SUPPORT:
2808                return ATOM_DEVICE_DFP4_SUPPORT;
2809        case ATOM_DEVICE_DFP4_SUPPORT:
2810                return ATOM_DEVICE_DFP5_SUPPORT;
2811        case ATOM_DEVICE_DFP5_SUPPORT:
2812                return ATOM_DEVICE_DFP6_SUPPORT;
2813        }
2814
2815        /* Done enumerating through devices. */
2816        return 0;
2817}
2818
2819/*
2820 * Returns the new device tag record for patched BIOS object.
2821 *
2822 * [IN] pExtDisplayPath - External display path to copy device tag from.
2823 * [IN] deviceSupport - Bit vector for device ID support flags.
2824 * [OUT] pDeviceTag - Device tag structure to fill with patched data.
2825 *
2826 * True if a compatible device ID was found, false otherwise.
2827 */
2828static bool get_patched_device_tag(
2829        struct bios_parser *bp,
2830        EXT_DISPLAY_PATH *ext_display_path,
2831        uint32_t device_support,
2832        ATOM_CONNECTOR_DEVICE_TAG *device_tag)
2833{
2834        uint32_t dev_id;
2835        /* Use fallback behaviour if not supported. */
2836        if (!bp->remap_device_tags) {
2837                device_tag->ulACPIDeviceEnum =
2838                                cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
2839                device_tag->usDeviceID =
2840                                cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceTag));
2841                return true;
2842        }
2843
2844        /* Find the first unused in the same group. */
2845        dev_id = enum_first_device_id(le16_to_cpu(ext_display_path->usDeviceTag));
2846        while (dev_id != 0) {
2847                /* Assign this device ID if supported. */
2848                if ((device_support & dev_id) != 0) {
2849                        device_tag->ulACPIDeviceEnum =
2850                                        cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
2851                        device_tag->usDeviceID = cpu_to_le16((USHORT) dev_id);
2852                        return true;
2853                }
2854
2855                dev_id = enum_next_dev_id(dev_id);
2856        }
2857
2858        /* No compatible device ID found. */
2859        return false;
2860}
2861
2862/*
2863 * Adds a device tag to a BIOS object's device tag record if there is
2864 * matching device ID supported.
2865 *
2866 * pObject - Pointer to the BIOS object to add the device tag to.
2867 * pExtDisplayPath - Display path to retrieve base device ID from.
2868 * pDeviceSupport - Pointer to bit vector for supported device IDs.
2869 */
2870static void add_device_tag_from_ext_display_path(
2871        struct bios_parser *bp,
2872        ATOM_OBJECT *object,
2873        EXT_DISPLAY_PATH *ext_display_path,
2874        uint32_t *device_support)
2875{
2876        /* Get device tag record for object. */
2877        ATOM_CONNECTOR_DEVICE_TAG *device_tag = NULL;
2878        ATOM_CONNECTOR_DEVICE_TAG_RECORD *device_tag_record = NULL;
2879        enum bp_result result =
2880                        bios_parser_get_device_tag_record(
2881                                        bp, object, &device_tag_record);
2882
2883        if ((le16_to_cpu(ext_display_path->usDeviceTag) != CONNECTOR_OBJECT_ID_NONE)
2884                        && (result == BP_RESULT_OK)) {
2885                uint8_t index;
2886
2887                if ((device_tag_record->ucNumberOfDevice == 1) &&
2888                                (le16_to_cpu(device_tag_record->asDeviceTag[0].usDeviceID) == 0)) {
2889                        /*Workaround bug in current VBIOS releases where
2890                         * ucNumberOfDevice = 1 but there is no actual device
2891                         * tag data. This w/a is temporary until the updated
2892                         * VBIOS is distributed. */
2893                        device_tag_record->ucNumberOfDevice =
2894                                        device_tag_record->ucNumberOfDevice - 1;
2895                }
2896
2897                /* Attempt to find a matching device ID. */
2898                index = device_tag_record->ucNumberOfDevice;
2899                device_tag = &device_tag_record->asDeviceTag[index];
2900                if (get_patched_device_tag(
2901                                bp,
2902                                ext_display_path,
2903                                *device_support,
2904                                device_tag)) {
2905                        /* Update cached device support to remove assigned ID.
2906                         */
2907                        *device_support &= ~le16_to_cpu(device_tag->usDeviceID);
2908                        device_tag_record->ucNumberOfDevice++;
2909                }
2910        }
2911}
2912
2913/*
2914 * Read out a single EXT_DISPLAY_PATH from the external display connection info
2915 * table. The specific entry in the table is determined by the enum_id passed
2916 * in.
2917 *
2918 * EXT_DISPLAY_PATH describing a single Configuration table entry
2919 */
2920
2921#define INVALID_CONNECTOR 0xffff
2922
2923static EXT_DISPLAY_PATH *get_ext_display_path_entry(
2924        ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *config_table,
2925        uint32_t bios_object_id)
2926{
2927        EXT_DISPLAY_PATH *ext_display_path;
2928        uint32_t ext_display_path_index =
2929                        ((bios_object_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT) - 1;
2930
2931        if (ext_display_path_index >= MAX_NUMBER_OF_EXT_DISPLAY_PATH)
2932                return NULL;
2933
2934        ext_display_path = &config_table->sPath[ext_display_path_index];
2935
2936        if (le16_to_cpu(ext_display_path->usDeviceConnector) == INVALID_CONNECTOR)
2937                ext_display_path->usDeviceConnector = cpu_to_le16(0);
2938
2939        return ext_display_path;
2940}
2941
2942/*
2943 * Get AUX/DDC information of input object id
2944 *
2945 * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
2946 * IR
2947 */
2948static ATOM_CONNECTOR_AUXDDC_LUT_RECORD *get_ext_connector_aux_ddc_lut_record(
2949        struct bios_parser *bp,
2950        ATOM_OBJECT *object)
2951{
2952        uint32_t offset;
2953        ATOM_COMMON_RECORD_HEADER *header;
2954
2955        if (!object) {
2956                BREAK_TO_DEBUGGER();
2957                /* Invalid object */
2958                return NULL;
2959        }
2960
2961        offset = le16_to_cpu(object->usRecordOffset)
2962                                        + bp->object_info_tbl_offset;
2963
2964        for (;;) {
2965                header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
2966
2967                if (!header)
2968                        return NULL;
2969
2970                if (LAST_RECORD_TYPE == header->ucRecordType ||
2971                                0 == header->ucRecordSize)
2972                        break;
2973
2974                if (ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE ==
2975                                header->ucRecordType &&
2976                                sizeof(ATOM_CONNECTOR_AUXDDC_LUT_RECORD) <=
2977                                header->ucRecordSize)
2978                        return (ATOM_CONNECTOR_AUXDDC_LUT_RECORD *)(header);
2979
2980                offset += header->ucRecordSize;
2981        }
2982
2983        return NULL;
2984}
2985
2986/*
2987 * Get AUX/DDC information of input object id
2988 *
2989 * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
2990 * IR
2991 */
2992static ATOM_CONNECTOR_HPDPIN_LUT_RECORD *get_ext_connector_hpd_pin_lut_record(
2993        struct bios_parser *bp,
2994        ATOM_OBJECT *object)
2995{
2996        uint32_t offset;
2997        ATOM_COMMON_RECORD_HEADER *header;
2998
2999        if (!object) {
3000                BREAK_TO_DEBUGGER();
3001                /* Invalid object */
3002                return NULL;
3003        }
3004
3005        offset = le16_to_cpu(object->usRecordOffset)
3006                                        + bp->object_info_tbl_offset;
3007
3008        for (;;) {
3009                header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
3010
3011                if (!header)
3012                        return NULL;
3013
3014                if (LAST_RECORD_TYPE == header->ucRecordType ||
3015                                0 == header->ucRecordSize)
3016                        break;
3017
3018                if (ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE ==
3019                                header->ucRecordType &&
3020                                sizeof(ATOM_CONNECTOR_HPDPIN_LUT_RECORD) <=
3021                                header->ucRecordSize)
3022                        return (ATOM_CONNECTOR_HPDPIN_LUT_RECORD *)header;
3023
3024                offset += header->ucRecordSize;
3025        }
3026
3027        return NULL;
3028}
3029
3030/*
3031 * Check whether we need to patch the VBIOS connector info table with
3032 * data from an external display connection info table.  This is
3033 * necessary to support MXM boards with an OPM (output personality
3034 * module).  With these designs, the VBIOS connector info table
3035 * specifies an MXM_CONNECTOR with a unique ID.  The driver retrieves
3036 * the external connection info table through i2c and then looks up the
3037 * connector ID to find the real connector type (e.g. DFP1).
3038 *
3039 */
3040static enum bp_result patch_bios_image_from_ext_display_connection_info(
3041        struct bios_parser *bp)
3042{
3043        ATOM_OBJECT_TABLE *connector_tbl;
3044        uint32_t connector_tbl_offset;
3045        struct graphics_object_id object_id;
3046        ATOM_OBJECT *object;
3047        ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO ext_display_connection_info_tbl;
3048        EXT_DISPLAY_PATH *ext_display_path;
3049        ATOM_CONNECTOR_AUXDDC_LUT_RECORD *aux_ddc_lut_record = NULL;
3050        ATOM_I2C_RECORD *i2c_record = NULL;
3051        ATOM_CONNECTOR_HPDPIN_LUT_RECORD *hpd_pin_lut_record = NULL;
3052        ATOM_HPD_INT_RECORD *hpd_record = NULL;
3053        ATOM_OBJECT_TABLE *encoder_table;
3054        uint32_t encoder_table_offset;
3055        ATOM_OBJECT *opm_object = NULL;
3056        uint32_t i = 0;
3057        struct graphics_object_id opm_object_id =
3058                        dal_graphics_object_id_init(
3059                                        GENERIC_ID_MXM_OPM,
3060                                        ENUM_ID_1,
3061                                        OBJECT_TYPE_GENERIC);
3062        ATOM_CONNECTOR_DEVICE_TAG_RECORD *dev_tag_record;
3063        uint32_t cached_device_support =
3064                        le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport);
3065
3066        uint32_t dst_number;
3067        uint16_t *dst_object_id_list;
3068
3069        opm_object = get_bios_object(bp, opm_object_id);
3070        if (!opm_object)
3071                return BP_RESULT_UNSUPPORTED;
3072
3073        memset(&ext_display_connection_info_tbl, 0,
3074                        sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO));
3075
3076        connector_tbl_offset = bp->object_info_tbl_offset
3077                        + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
3078        connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
3079
3080        /* Read Connector info table from EEPROM through i2c */
3081        if (get_ext_display_connection_info(bp,
3082                                            opm_object,
3083                                            &ext_display_connection_info_tbl) != BP_RESULT_OK) {
3084
3085                DC_LOG_WARNING("%s: Failed to read Connection Info Table", __func__);
3086                return BP_RESULT_UNSUPPORTED;
3087        }
3088
3089        /* Get pointer to AUX/DDC and HPD LUTs */
3090        aux_ddc_lut_record =
3091                        get_ext_connector_aux_ddc_lut_record(bp, opm_object);
3092        hpd_pin_lut_record =
3093                        get_ext_connector_hpd_pin_lut_record(bp, opm_object);
3094
3095        if ((aux_ddc_lut_record == NULL) || (hpd_pin_lut_record == NULL))
3096                return BP_RESULT_UNSUPPORTED;
3097
3098        /* Cache support bits for currently unmapped device types. */
3099        if (bp->remap_device_tags) {
3100                for (i = 0; i < connector_tbl->ucNumberOfObjects; ++i) {
3101                        uint32_t j;
3102                        /* Remove support for all non-MXM connectors. */
3103                        object = &connector_tbl->asObjects[i];
3104                        object_id = object_id_from_bios_object_id(
3105                                        le16_to_cpu(object->usObjectID));
3106                        if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
3107                                        (CONNECTOR_ID_MXM == object_id.id))
3108                                continue;
3109
3110                        /* Remove support for all device tags. */
3111                        if (bios_parser_get_device_tag_record(
3112                                        bp, object, &dev_tag_record) != BP_RESULT_OK)
3113                                continue;
3114
3115                        for (j = 0; j < dev_tag_record->ucNumberOfDevice; ++j) {
3116                                ATOM_CONNECTOR_DEVICE_TAG *device_tag =
3117                                                &dev_tag_record->asDeviceTag[j];
3118                                cached_device_support &=
3119                                                ~le16_to_cpu(device_tag->usDeviceID);
3120                        }
3121                }
3122        }
3123
3124        /* Find all MXM connector objects and patch them with connector info
3125         * from the external display connection info table. */
3126        for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
3127                uint32_t j;
3128
3129                object = &connector_tbl->asObjects[i];
3130                object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
3131                if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
3132                                (CONNECTOR_ID_MXM != object_id.id))
3133                        continue;
3134
3135                /* Get the correct connection info table entry based on the enum
3136                 * id. */
3137                ext_display_path = get_ext_display_path_entry(
3138                                &ext_display_connection_info_tbl,
3139                                le16_to_cpu(object->usObjectID));
3140                if (!ext_display_path)
3141                        return BP_RESULT_FAILURE;
3142
3143                /* Patch device connector ID */
3144                object->usObjectID =
3145                                cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceConnector));
3146
3147                /* Patch device tag, ulACPIDeviceEnum. */
3148                add_device_tag_from_ext_display_path(
3149                                bp,
3150                                object,
3151                                ext_display_path,
3152                                &cached_device_support);
3153
3154                /* Patch HPD info */
3155                if (ext_display_path->ucExtHPDPINLutIndex <
3156                                MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES) {
3157                        hpd_record = get_hpd_record(bp, object);
3158                        if (hpd_record) {
3159                                uint8_t index =
3160                                                ext_display_path->ucExtHPDPINLutIndex;
3161                                hpd_record->ucHPDIntGPIOID =
3162                                                hpd_pin_lut_record->ucHPDPINMap[index];
3163                        } else {
3164                                BREAK_TO_DEBUGGER();
3165                                /* Invalid hpd record */
3166                                return BP_RESULT_FAILURE;
3167                        }
3168                }
3169
3170                /* Patch I2C/AUX info */
3171                if (ext_display_path->ucExtHPDPINLutIndex <
3172                                MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES) {
3173                        i2c_record = get_i2c_record(bp, object);
3174                        if (i2c_record) {
3175                                uint8_t index =
3176                                                ext_display_path->ucExtAUXDDCLutIndex;
3177                                i2c_record->sucI2cId =
3178                                                aux_ddc_lut_record->ucAUXDDCMap[index];
3179                        } else {
3180                                BREAK_TO_DEBUGGER();
3181                                /* Invalid I2C record */
3182                                return BP_RESULT_FAILURE;
3183                        }
3184                }
3185
3186                /* Merge with other MXM connectors that map to the same physical
3187                 * connector. */
3188                for (j = i + 1;
3189                                j < connector_tbl->ucNumberOfObjects; j++) {
3190                        ATOM_OBJECT *next_object;
3191                        struct graphics_object_id next_object_id;
3192                        EXT_DISPLAY_PATH *next_ext_display_path;
3193
3194                        next_object = &connector_tbl->asObjects[j];
3195                        next_object_id = object_id_from_bios_object_id(
3196                                        le16_to_cpu(next_object->usObjectID));
3197
3198                        if ((OBJECT_TYPE_CONNECTOR != next_object_id.type) &&
3199                                        (CONNECTOR_ID_MXM == next_object_id.id))
3200                                continue;
3201
3202                        next_ext_display_path = get_ext_display_path_entry(
3203                                        &ext_display_connection_info_tbl,
3204                                        le16_to_cpu(next_object->usObjectID));
3205
3206                        if (next_ext_display_path == NULL)
3207                                return BP_RESULT_FAILURE;
3208
3209                        /* Merge if using same connector. */
3210                        if ((le16_to_cpu(next_ext_display_path->usDeviceConnector) ==
3211                                        le16_to_cpu(ext_display_path->usDeviceConnector)) &&
3212                                        (le16_to_cpu(ext_display_path->usDeviceConnector) != 0)) {
3213                                /* Clear duplicate connector from table. */
3214                                next_object->usObjectID = cpu_to_le16(0);
3215                                add_device_tag_from_ext_display_path(
3216                                                bp,
3217                                                object,
3218                                                ext_display_path,
3219                                                &cached_device_support);
3220                        }
3221                }
3222        }
3223
3224        /* Find all encoders which have an MXM object as their destination.
3225         *  Replace the MXM object with the real connector Id from the external
3226         *  display connection info table */
3227
3228        encoder_table_offset = bp->object_info_tbl_offset
3229                        + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
3230        encoder_table = GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
3231
3232        for (i = 0; i < encoder_table->ucNumberOfObjects; i++) {
3233                uint32_t j;
3234
3235                object = &encoder_table->asObjects[i];
3236
3237                dst_number = get_dest_obj_list(bp, object, &dst_object_id_list);
3238
3239                for (j = 0; j < dst_number; j++) {
3240                        object_id = object_id_from_bios_object_id(
3241                                        dst_object_id_list[j]);
3242
3243                        if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
3244                                        (CONNECTOR_ID_MXM != object_id.id))
3245                                continue;
3246
3247                        /* Get the correct connection info table entry based on
3248                         * the enum id. */
3249                        ext_display_path =
3250                                        get_ext_display_path_entry(
3251                                                        &ext_display_connection_info_tbl,
3252                                                        dst_object_id_list[j]);
3253
3254                        if (ext_display_path == NULL)
3255                                return BP_RESULT_FAILURE;
3256
3257                        dst_object_id_list[j] =
3258                                        le16_to_cpu(ext_display_path->usDeviceConnector);
3259                }
3260        }
3261
3262        return BP_RESULT_OK;
3263}
3264
3265/*
3266 * Check whether we need to patch the VBIOS connector info table with
3267 * data from an external display connection info table.  This is
3268 * necessary to support MXM boards with an OPM (output personality
3269 * module).  With these designs, the VBIOS connector info table
3270 * specifies an MXM_CONNECTOR with a unique ID.  The driver retrieves
3271 * the external connection info table through i2c and then looks up the
3272 * connector ID to find the real connector type (e.g. DFP1).
3273 *
3274 */
3275
3276static void process_ext_display_connection_info(struct bios_parser *bp)
3277{
3278        ATOM_OBJECT_TABLE *connector_tbl;
3279        uint32_t connector_tbl_offset;
3280        struct graphics_object_id object_id;
3281        ATOM_OBJECT *object;
3282        bool mxm_connector_found = false;
3283        bool null_entry_found = false;
3284        uint32_t i = 0;
3285
3286        connector_tbl_offset = bp->object_info_tbl_offset +
3287                        le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
3288        connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
3289
3290        /* Look for MXM connectors to determine whether we need patch the VBIOS
3291         * connector info table. Look for null entries to determine whether we
3292         * need to compact connector table. */
3293        for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
3294                object = &connector_tbl->asObjects[i];
3295                object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
3296
3297                if ((OBJECT_TYPE_CONNECTOR == object_id.type) &&
3298                                (CONNECTOR_ID_MXM == object_id.id)) {
3299                        /* Once we found MXM connector - we can break */
3300                        mxm_connector_found = true;
3301                        break;
3302                } else if (OBJECT_TYPE_CONNECTOR != object_id.type) {
3303                        /* We need to continue looping - to check if MXM
3304                         * connector present */
3305                        null_entry_found = true;
3306                }
3307        }
3308
3309        /* Patch BIOS image */
3310        if (mxm_connector_found || null_entry_found) {
3311                uint32_t connectors_num = 0;
3312                uint8_t *original_bios;
3313                /* Step 1: Replace bios image with the new copy which will be
3314                 * patched */
3315                bp->base.bios_local_image = kzalloc(bp->base.bios_size,
3316                                                    GFP_KERNEL);
3317                if (bp->base.bios_local_image == NULL) {
3318                        BREAK_TO_DEBUGGER();
3319                        /* Failed to alloc bp->base.bios_local_image */
3320                        return;
3321                }
3322
3323                memmove(bp->base.bios_local_image, bp->base.bios, bp->base.bios_size);
3324                original_bios = bp->base.bios;
3325                bp->base.bios = bp->base.bios_local_image;
3326                connector_tbl =
3327                                GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
3328
3329                /* Step 2: (only if MXM connector found) Patch BIOS image with
3330                 * info from external module */
3331                if (mxm_connector_found &&
3332                    patch_bios_image_from_ext_display_connection_info(bp) !=
3333                                                BP_RESULT_OK) {
3334                        /* Patching the bios image has failed. We will copy
3335                         * again original image provided and afterwards
3336                         * only remove null entries */
3337                        memmove(
3338                                        bp->base.bios_local_image,
3339                                        original_bios,
3340                                        bp->base.bios_size);
3341                }
3342
3343                /* Step 3: Compact connector table (remove null entries, valid
3344                 * entries moved to beginning) */
3345                for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
3346                        object = &connector_tbl->asObjects[i];
3347                        object_id = object_id_from_bios_object_id(
3348                                        le16_to_cpu(object->usObjectID));
3349
3350                        if (OBJECT_TYPE_CONNECTOR != object_id.type)
3351                                continue;
3352
3353                        if (i != connectors_num) {
3354                                memmove(
3355                                                &connector_tbl->
3356                                                asObjects[connectors_num],
3357                                                object,
3358                                                sizeof(ATOM_OBJECT));
3359                        }
3360                        ++connectors_num;
3361                }
3362                connector_tbl->ucNumberOfObjects = (uint8_t)connectors_num;
3363        }
3364}
3365
3366static void bios_parser_post_init(struct dc_bios *dcb)
3367{
3368        struct bios_parser *bp = BP_FROM_DCB(dcb);
3369
3370        process_ext_display_connection_info(bp);
3371}
3372
3373/**
3374 * bios_parser_set_scratch_critical_state
3375 *
3376 * @brief
3377 *  update critical state bit in VBIOS scratch register
3378 *
3379 * @param
3380 *  bool - to set or reset state
3381 */
3382static void bios_parser_set_scratch_critical_state(
3383        struct dc_bios *dcb,
3384        bool state)
3385{
3386        bios_set_scratch_critical_state(dcb, state);
3387}
3388
3389/*
3390 * get_integrated_info_v8
3391 *
3392 * @brief
3393 * Get V8 integrated BIOS information
3394 *
3395 * @param
3396 * bios_parser *bp - [in]BIOS parser handler to get master data table
3397 * integrated_info *info - [out] store and output integrated info
3398 *
3399 * @return
3400 * enum bp_result - BP_RESULT_OK if information is available,
3401 *                  BP_RESULT_BADBIOSTABLE otherwise.
3402 */
3403static enum bp_result get_integrated_info_v8(
3404        struct bios_parser *bp,
3405        struct integrated_info *info)
3406{
3407        ATOM_INTEGRATED_SYSTEM_INFO_V1_8 *info_v8;
3408        uint32_t i;
3409
3410        info_v8 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8,
3411                        bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
3412
3413        if (info_v8 == NULL)
3414                return BP_RESULT_BADBIOSTABLE;
3415        info->boot_up_engine_clock = le32_to_cpu(info_v8->ulBootUpEngineClock) * 10;
3416        info->dentist_vco_freq = le32_to_cpu(info_v8->ulDentistVCOFreq) * 10;
3417        info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
3418
3419        for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
3420                /* Convert [10KHz] into [KHz] */
3421                info->disp_clk_voltage[i].max_supported_clk =
3422                        le32_to_cpu(info_v8->sDISPCLK_Voltage[i].
3423                                    ulMaximumSupportedCLK) * 10;
3424                info->disp_clk_voltage[i].voltage_index =
3425                        le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
3426        }
3427
3428        info->boot_up_req_display_vector =
3429                le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
3430        info->gpu_cap_info =
3431                le32_to_cpu(info_v8->ulGPUCapInfo);
3432
3433        /*
3434         * system_config: Bit[0] = 0 : PCIE power gating disabled
3435         *                       = 1 : PCIE power gating enabled
3436         *                Bit[1] = 0 : DDR-PLL shut down disabled
3437         *                       = 1 : DDR-PLL shut down enabled
3438         *                Bit[2] = 0 : DDR-PLL power down disabled
3439         *                       = 1 : DDR-PLL power down enabled
3440         */
3441        info->system_config = le32_to_cpu(info_v8->ulSystemConfig);
3442        info->cpu_cap_info = le32_to_cpu(info_v8->ulCPUCapInfo);
3443        info->boot_up_nb_voltage =
3444                le16_to_cpu(info_v8->usBootUpNBVoltage);
3445        info->ext_disp_conn_info_offset =
3446                le16_to_cpu(info_v8->usExtDispConnInfoOffset);
3447        info->memory_type = info_v8->ucMemoryType;
3448        info->ma_channel_number = info_v8->ucUMAChannelNumber;
3449        info->gmc_restore_reset_time =
3450                le32_to_cpu(info_v8->ulGMCRestoreResetTime);
3451
3452        info->minimum_n_clk =
3453                le32_to_cpu(info_v8->ulNbpStateNClkFreq[0]);
3454        for (i = 1; i < 4; ++i)
3455                info->minimum_n_clk =
3456                        info->minimum_n_clk < le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]) ?
3457                        info->minimum_n_clk : le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]);
3458
3459        info->idle_n_clk = le32_to_cpu(info_v8->ulIdleNClk);
3460        info->ddr_dll_power_up_time =
3461                le32_to_cpu(info_v8->ulDDR_DLL_PowerUpTime);
3462        info->ddr_pll_power_up_time =
3463                le32_to_cpu(info_v8->ulDDR_PLL_PowerUpTime);
3464        info->pcie_clk_ss_type = le16_to_cpu(info_v8->usPCIEClkSSType);
3465        info->lvds_ss_percentage =
3466                le16_to_cpu(info_v8->usLvdsSSPercentage);
3467        info->lvds_sspread_rate_in_10hz =
3468                le16_to_cpu(info_v8->usLvdsSSpreadRateIn10Hz);
3469        info->hdmi_ss_percentage =
3470                le16_to_cpu(info_v8->usHDMISSPercentage);
3471        info->hdmi_sspread_rate_in_10hz =
3472                le16_to_cpu(info_v8->usHDMISSpreadRateIn10Hz);
3473        info->dvi_ss_percentage =
3474                le16_to_cpu(info_v8->usDVISSPercentage);
3475        info->dvi_sspread_rate_in_10_hz =
3476                le16_to_cpu(info_v8->usDVISSpreadRateIn10Hz);
3477
3478        info->max_lvds_pclk_freq_in_single_link =
3479                le16_to_cpu(info_v8->usMaxLVDSPclkFreqInSingleLink);
3480        info->lvds_misc = info_v8->ucLvdsMisc;
3481        info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
3482                info_v8->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
3483        info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
3484                info_v8->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
3485        info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
3486                info_v8->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
3487        info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
3488                info_v8->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
3489        info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
3490                info_v8->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
3491        info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
3492                info_v8->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
3493        info->lvds_off_to_on_delay_in_4ms =
3494                info_v8->ucLVDSOffToOnDelay_in4Ms;
3495        info->lvds_bit_depth_control_val =
3496                le32_to_cpu(info_v8->ulLCDBitDepthControlVal);
3497
3498        for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
3499                /* Convert [10KHz] into [KHz] */
3500                info->avail_s_clk[i].supported_s_clk =
3501                        le32_to_cpu(info_v8->sAvail_SCLK[i].ulSupportedSCLK) * 10;
3502                info->avail_s_clk[i].voltage_index =
3503                        le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageIndex);
3504                info->avail_s_clk[i].voltage_id =
3505                        le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageID);
3506        }
3507
3508        for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
3509                info->ext_disp_conn_info.gu_id[i] =
3510                        info_v8->sExtDispConnInfo.ucGuid[i];
3511        }
3512
3513        for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
3514                info->ext_disp_conn_info.path[i].device_connector_id =
3515                        object_id_from_bios_object_id(
3516                                le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceConnector));
3517
3518                info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
3519                        object_id_from_bios_object_id(
3520                                le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
3521
3522                info->ext_disp_conn_info.path[i].device_tag =
3523                        le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceTag);
3524                info->ext_disp_conn_info.path[i].device_acpi_enum =
3525                        le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
3526                info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
3527                        info_v8->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
3528                info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
3529                        info_v8->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
3530                info->ext_disp_conn_info.path[i].channel_mapping.raw =
3531                        info_v8->sExtDispConnInfo.sPath[i].ucChannelMapping;
3532        }
3533        info->ext_disp_conn_info.checksum =
3534                info_v8->sExtDispConnInfo.ucChecksum;
3535
3536        return BP_RESULT_OK;
3537}
3538
3539/*
3540 * get_integrated_info_v8
3541 *
3542 * @brief
3543 * Get V8 integrated BIOS information
3544 *
3545 * @param
3546 * bios_parser *bp - [in]BIOS parser handler to get master data table
3547 * integrated_info *info - [out] store and output integrated info
3548 *
3549 * @return
3550 * enum bp_result - BP_RESULT_OK if information is available,
3551 *                  BP_RESULT_BADBIOSTABLE otherwise.
3552 */
3553static enum bp_result get_integrated_info_v9(
3554        struct bios_parser *bp,
3555        struct integrated_info *info)
3556{
3557        ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info_v9;
3558        uint32_t i;
3559
3560        info_v9 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9,
3561                        bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
3562
3563        if (!info_v9)
3564                return BP_RESULT_BADBIOSTABLE;
3565
3566        info->boot_up_engine_clock = le32_to_cpu(info_v9->ulBootUpEngineClock) * 10;
3567        info->dentist_vco_freq = le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
3568        info->boot_up_uma_clock = le32_to_cpu(info_v9->ulBootUpUMAClock) * 10;
3569
3570        for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
3571                /* Convert [10KHz] into [KHz] */
3572                info->disp_clk_voltage[i].max_supported_clk =
3573                        le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
3574                info->disp_clk_voltage[i].voltage_index =
3575                        le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
3576        }
3577
3578        info->boot_up_req_display_vector =
3579                le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
3580        info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
3581
3582        /*
3583         * system_config: Bit[0] = 0 : PCIE power gating disabled
3584         *                       = 1 : PCIE power gating enabled
3585         *                Bit[1] = 0 : DDR-PLL shut down disabled
3586         *                       = 1 : DDR-PLL shut down enabled
3587         *                Bit[2] = 0 : DDR-PLL power down disabled
3588         *                       = 1 : DDR-PLL power down enabled
3589         */
3590        info->system_config = le32_to_cpu(info_v9->ulSystemConfig);
3591        info->cpu_cap_info = le32_to_cpu(info_v9->ulCPUCapInfo);
3592        info->boot_up_nb_voltage = le16_to_cpu(info_v9->usBootUpNBVoltage);
3593        info->ext_disp_conn_info_offset = le16_to_cpu(info_v9->usExtDispConnInfoOffset);
3594        info->memory_type = info_v9->ucMemoryType;
3595        info->ma_channel_number = info_v9->ucUMAChannelNumber;
3596        info->gmc_restore_reset_time = le32_to_cpu(info_v9->ulGMCRestoreResetTime);
3597
3598        info->minimum_n_clk = le32_to_cpu(info_v9->ulNbpStateNClkFreq[0]);
3599        for (i = 1; i < 4; ++i)
3600                info->minimum_n_clk =
3601                        info->minimum_n_clk < le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]) ?
3602                        info->minimum_n_clk : le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]);
3603
3604        info->idle_n_clk = le32_to_cpu(info_v9->ulIdleNClk);
3605        info->ddr_dll_power_up_time = le32_to_cpu(info_v9->ulDDR_DLL_PowerUpTime);
3606        info->ddr_pll_power_up_time = le32_to_cpu(info_v9->ulDDR_PLL_PowerUpTime);
3607        info->pcie_clk_ss_type = le16_to_cpu(info_v9->usPCIEClkSSType);
3608        info->lvds_ss_percentage = le16_to_cpu(info_v9->usLvdsSSPercentage);
3609        info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v9->usLvdsSSpreadRateIn10Hz);
3610        info->hdmi_ss_percentage = le16_to_cpu(info_v9->usHDMISSPercentage);
3611        info->hdmi_sspread_rate_in_10hz = le16_to_cpu(info_v9->usHDMISSpreadRateIn10Hz);
3612        info->dvi_ss_percentage = le16_to_cpu(info_v9->usDVISSPercentage);
3613        info->dvi_sspread_rate_in_10_hz = le16_to_cpu(info_v9->usDVISSpreadRateIn10Hz);
3614
3615        info->max_lvds_pclk_freq_in_single_link =
3616                le16_to_cpu(info_v9->usMaxLVDSPclkFreqInSingleLink);
3617        info->lvds_misc = info_v9->ucLvdsMisc;
3618        info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
3619                info_v9->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
3620        info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
3621                info_v9->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
3622        info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
3623                info_v9->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
3624        info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
3625                info_v9->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
3626        info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
3627                info_v9->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
3628        info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
3629                info_v9->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
3630        info->lvds_off_to_on_delay_in_4ms =
3631                info_v9->ucLVDSOffToOnDelay_in4Ms;
3632        info->lvds_bit_depth_control_val =
3633                le32_to_cpu(info_v9->ulLCDBitDepthControlVal);
3634
3635        for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
3636                /* Convert [10KHz] into [KHz] */
3637                info->avail_s_clk[i].supported_s_clk =
3638                        le32_to_cpu(info_v9->sAvail_SCLK[i].ulSupportedSCLK) * 10;
3639                info->avail_s_clk[i].voltage_index =
3640                        le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageIndex);
3641                info->avail_s_clk[i].voltage_id =
3642                        le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageID);
3643        }
3644
3645        for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
3646                info->ext_disp_conn_info.gu_id[i] =
3647                        info_v9->sExtDispConnInfo.ucGuid[i];
3648        }
3649
3650        for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
3651                info->ext_disp_conn_info.path[i].device_connector_id =
3652                        object_id_from_bios_object_id(
3653                                le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceConnector));
3654
3655                info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
3656                        object_id_from_bios_object_id(
3657                                le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
3658
3659                info->ext_disp_conn_info.path[i].device_tag =
3660                        le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceTag);
3661                info->ext_disp_conn_info.path[i].device_acpi_enum =
3662                        le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
3663                info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
3664                        info_v9->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
3665                info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
3666                        info_v9->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
3667                info->ext_disp_conn_info.path[i].channel_mapping.raw =
3668                        info_v9->sExtDispConnInfo.sPath[i].ucChannelMapping;
3669        }
3670        info->ext_disp_conn_info.checksum =
3671                info_v9->sExtDispConnInfo.ucChecksum;
3672
3673        return BP_RESULT_OK;
3674}
3675
3676/*
3677 * construct_integrated_info
3678 *
3679 * @brief
3680 * Get integrated BIOS information based on table revision
3681 *
3682 * @param
3683 * bios_parser *bp - [in]BIOS parser handler to get master data table
3684 * integrated_info *info - [out] store and output integrated info
3685 *
3686 * @return
3687 * enum bp_result - BP_RESULT_OK if information is available,
3688 *                  BP_RESULT_BADBIOSTABLE otherwise.
3689 */
3690static enum bp_result construct_integrated_info(
3691        struct bios_parser *bp,
3692        struct integrated_info *info)
3693{
3694        enum bp_result result = BP_RESULT_BADBIOSTABLE;
3695
3696        ATOM_COMMON_TABLE_HEADER *header;
3697        struct atom_data_revision revision;
3698
3699        if (bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo) {
3700                header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
3701                                bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
3702
3703                get_atom_data_table_revision(header, &revision);
3704
3705                /* Don't need to check major revision as they are all 1 */
3706                switch (revision.minor) {
3707                case 8:
3708                        result = get_integrated_info_v8(bp, info);
3709                        break;
3710                case 9:
3711                        result = get_integrated_info_v9(bp, info);
3712                        break;
3713                default:
3714                        return result;
3715
3716                }
3717        }
3718
3719        /* Sort voltage table from low to high*/
3720        if (result == BP_RESULT_OK) {
3721                struct clock_voltage_caps temp = {0, 0};
3722                uint32_t i;
3723                uint32_t j;
3724
3725                for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
3726                        for (j = i; j > 0; --j) {
3727                                if (
3728                                                info->disp_clk_voltage[j].max_supported_clk <
3729                                                info->disp_clk_voltage[j-1].max_supported_clk) {
3730                                        /* swap j and j - 1*/
3731                                        temp = info->disp_clk_voltage[j-1];
3732                                        info->disp_clk_voltage[j-1] =
3733                                                        info->disp_clk_voltage[j];
3734                                        info->disp_clk_voltage[j] = temp;
3735                                }
3736                        }
3737                }
3738
3739        }
3740
3741        return result;
3742}
3743
3744static struct integrated_info *bios_parser_create_integrated_info(
3745        struct dc_bios *dcb)
3746{
3747        struct bios_parser *bp = BP_FROM_DCB(dcb);
3748        struct integrated_info *info = NULL;
3749
3750        info = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);
3751
3752        if (info == NULL) {
3753                ASSERT_CRITICAL(0);
3754                return NULL;
3755        }
3756
3757        if (construct_integrated_info(bp, info) == BP_RESULT_OK)
3758                return info;
3759
3760        kfree(info);
3761
3762        return NULL;
3763}
3764
3765enum bp_result update_slot_layout_info(
3766        struct dc_bios *dcb,
3767        unsigned int i,
3768        struct slot_layout_info *slot_layout_info,
3769        unsigned int record_offset)
3770{
3771        unsigned int j;
3772        struct bios_parser *bp;
3773        ATOM_BRACKET_LAYOUT_RECORD *record;
3774        ATOM_COMMON_RECORD_HEADER *record_header;
3775        enum bp_result result = BP_RESULT_NORECORD;
3776
3777        bp = BP_FROM_DCB(dcb);
3778        record = NULL;
3779        record_header = NULL;
3780
3781        for (;;) {
3782
3783                record_header = (ATOM_COMMON_RECORD_HEADER *)
3784                        GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
3785                if (record_header == NULL) {
3786                        result = BP_RESULT_BADBIOSTABLE;
3787                        break;
3788                }
3789
3790                /* the end of the list */
3791                if (record_header->ucRecordType == 0xff ||
3792                        record_header->ucRecordSize == 0)       {
3793                        break;
3794                }
3795
3796                if (record_header->ucRecordType ==
3797                        ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
3798                        sizeof(ATOM_BRACKET_LAYOUT_RECORD)
3799                        <= record_header->ucRecordSize) {
3800                        record = (ATOM_BRACKET_LAYOUT_RECORD *)
3801                                (record_header);
3802                        result = BP_RESULT_OK;
3803                        break;
3804                }
3805
3806                record_offset += record_header->ucRecordSize;
3807        }
3808
3809        /* return if the record not found */
3810        if (result != BP_RESULT_OK)
3811                return result;
3812
3813        /* get slot sizes */
3814        slot_layout_info->length = record->ucLength;
3815        slot_layout_info->width = record->ucWidth;
3816
3817        /* get info for each connector in the slot */
3818        slot_layout_info->num_of_connectors = record->ucConnNum;
3819        for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
3820                slot_layout_info->connectors[j].connector_type =
3821                        (enum connector_layout_type)
3822                        (record->asConnInfo[j].ucConnectorType);
3823                switch (record->asConnInfo[j].ucConnectorType) {
3824                case CONNECTOR_TYPE_DVI_D:
3825                        slot_layout_info->connectors[j].connector_type =
3826                                CONNECTOR_LAYOUT_TYPE_DVI_D;
3827                        slot_layout_info->connectors[j].length =
3828                                CONNECTOR_SIZE_DVI;
3829                        break;
3830
3831                case CONNECTOR_TYPE_HDMI:
3832                        slot_layout_info->connectors[j].connector_type =
3833                                CONNECTOR_LAYOUT_TYPE_HDMI;
3834                        slot_layout_info->connectors[j].length =
3835                                CONNECTOR_SIZE_HDMI;
3836                        break;
3837
3838                case CONNECTOR_TYPE_DISPLAY_PORT:
3839                        slot_layout_info->connectors[j].connector_type =
3840                                CONNECTOR_LAYOUT_TYPE_DP;
3841                        slot_layout_info->connectors[j].length =
3842                                CONNECTOR_SIZE_DP;
3843                        break;
3844
3845                case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
3846                        slot_layout_info->connectors[j].connector_type =
3847                                CONNECTOR_LAYOUT_TYPE_MINI_DP;
3848                        slot_layout_info->connectors[j].length =
3849                                CONNECTOR_SIZE_MINI_DP;
3850                        break;
3851
3852                default:
3853                        slot_layout_info->connectors[j].connector_type =
3854                                CONNECTOR_LAYOUT_TYPE_UNKNOWN;
3855                        slot_layout_info->connectors[j].length =
3856                                CONNECTOR_SIZE_UNKNOWN;
3857                }
3858
3859                slot_layout_info->connectors[j].position =
3860                        record->asConnInfo[j].ucPosition;
3861                slot_layout_info->connectors[j].connector_id =
3862                        object_id_from_bios_object_id(
3863                                record->asConnInfo[j].usConnectorObjectId);
3864        }
3865        return result;
3866}
3867
3868
3869enum bp_result get_bracket_layout_record(
3870        struct dc_bios *dcb,
3871        unsigned int bracket_layout_id,
3872        struct slot_layout_info *slot_layout_info)
3873{
3874        unsigned int i;
3875        unsigned int record_offset;
3876        struct bios_parser *bp;
3877        enum bp_result result;
3878        ATOM_OBJECT *object;
3879        ATOM_OBJECT_TABLE *object_table;
3880        unsigned int genericTableOffset;
3881
3882        bp = BP_FROM_DCB(dcb);
3883        object = NULL;
3884        if (slot_layout_info == NULL) {
3885                DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
3886                return BP_RESULT_BADINPUT;
3887        }
3888
3889
3890        genericTableOffset = bp->object_info_tbl_offset +
3891                bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
3892        object_table = (ATOM_OBJECT_TABLE *)
3893                GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset);
3894        if (!object_table)
3895                return BP_RESULT_FAILURE;
3896
3897        result = BP_RESULT_NORECORD;
3898        for (i = 0; i < object_table->ucNumberOfObjects; ++i) {
3899
3900                if (bracket_layout_id ==
3901                        object_table->asObjects[i].usObjectID) {
3902
3903                        object = &object_table->asObjects[i];
3904                        record_offset = object->usRecordOffset +
3905                                bp->object_info_tbl_offset;
3906
3907                        result = update_slot_layout_info(dcb, i,
3908                                slot_layout_info, record_offset);
3909                        break;
3910                }
3911        }
3912        return result;
3913}
3914
3915static enum bp_result bios_get_board_layout_info(
3916        struct dc_bios *dcb,
3917        struct board_layout_info *board_layout_info)
3918{
3919        unsigned int i;
3920        struct bios_parser *bp;
3921        enum bp_result record_result;
3922
3923        const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
3924                GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
3925                GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
3926                0, 0
3927        };
3928
3929        bp = BP_FROM_DCB(dcb);
3930        if (board_layout_info == NULL) {
3931                DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
3932                return BP_RESULT_BADINPUT;
3933        }
3934
3935        board_layout_info->num_of_slots = 0;
3936
3937        for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
3938                record_result = get_bracket_layout_record(dcb,
3939                        slot_index_to_vbios_id[i],
3940                        &board_layout_info->slots[i]);
3941
3942                if (record_result == BP_RESULT_NORECORD && i > 0)
3943                        break; /* no more slots present in bios */
3944                else if (record_result != BP_RESULT_OK)
3945                        return record_result;  /* fail */
3946
3947                ++board_layout_info->num_of_slots;
3948        }
3949
3950        /* all data is valid */
3951        board_layout_info->is_number_of_slots_valid = 1;
3952        board_layout_info->is_slots_size_valid = 1;
3953        board_layout_info->is_connector_offsets_valid = 1;
3954        board_layout_info->is_connector_lengths_valid = 1;
3955
3956        return BP_RESULT_OK;
3957}
3958
3959/******************************************************************************/
3960
3961static const struct dc_vbios_funcs vbios_funcs = {
3962        .get_connectors_number = bios_parser_get_connectors_number,
3963
3964        .get_encoder_id = bios_parser_get_encoder_id,
3965
3966        .get_connector_id = bios_parser_get_connector_id,
3967
3968        .get_dst_number = bios_parser_get_dst_number,
3969
3970        .get_src_obj = bios_parser_get_src_obj,
3971
3972        .get_dst_obj = bios_parser_get_dst_obj,
3973
3974        .get_i2c_info = bios_parser_get_i2c_info,
3975
3976        .get_voltage_ddc_info = bios_parser_get_voltage_ddc_info,
3977
3978        .get_thermal_ddc_info = bios_parser_get_thermal_ddc_info,
3979
3980        .get_hpd_info = bios_parser_get_hpd_info,
3981
3982        .get_device_tag = bios_parser_get_device_tag,
3983
3984        .get_firmware_info = bios_parser_get_firmware_info,
3985
3986        .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info,
3987
3988        .get_ss_entry_number = bios_parser_get_ss_entry_number,
3989
3990        .get_embedded_panel_info = bios_parser_get_embedded_panel_info,
3991
3992        .get_gpio_pin_info = bios_parser_get_gpio_pin_info,
3993
3994        .get_encoder_cap_info = bios_parser_get_encoder_cap_info,
3995
3996        /* bios scratch register communication */
3997        .is_accelerated_mode = bios_is_accelerated_mode,
3998        .get_vga_enabled_displays = bios_get_vga_enabled_displays,
3999
4000        .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
4001
4002        .is_device_id_supported = bios_parser_is_device_id_supported,
4003
4004        /* COMMANDS */
4005        .encoder_control = bios_parser_encoder_control,
4006
4007        .transmitter_control = bios_parser_transmitter_control,
4008
4009        .crt_control = bios_parser_crt_control,  /* not used in DAL3.  keep for now in case we need to support VGA on Bonaire */
4010
4011        .enable_crtc = bios_parser_enable_crtc,
4012
4013        .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
4014
4015        .set_pixel_clock = bios_parser_set_pixel_clock,
4016
4017        .set_dce_clock = bios_parser_set_dce_clock,
4018
4019        .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
4020
4021        .program_crtc_timing = bios_parser_program_crtc_timing, /* still use.  should probably retire and program directly */
4022
4023        .crtc_source_select = bios_parser_crtc_source_select,  /* still use.  should probably retire and program directly */
4024
4025        .program_display_engine_pll = bios_parser_program_display_engine_pll,
4026
4027        .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
4028
4029        /* SW init and patch */
4030        .post_init = bios_parser_post_init,  /* patch vbios table for mxm module by reading i2c */
4031
4032        .bios_parser_destroy = bios_parser_destroy,
4033
4034        .get_board_layout_info = bios_get_board_layout_info,
4035};
4036
4037static bool bios_parser_construct(
4038        struct bios_parser *bp,
4039        struct bp_init_data *init,
4040        enum dce_version dce_version)
4041{
4042        uint16_t *rom_header_offset = NULL;
4043        ATOM_ROM_HEADER *rom_header = NULL;
4044        ATOM_OBJECT_HEADER *object_info_tbl;
4045        struct atom_data_revision tbl_rev = {0};
4046
4047        if (!init)
4048                return false;
4049
4050        if (!init->bios)
4051                return false;
4052
4053        bp->base.funcs = &vbios_funcs;
4054        bp->base.bios = init->bios;
4055        bp->base.bios_size = bp->base.bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
4056
4057        bp->base.ctx = init->ctx;
4058        bp->base.bios_local_image = NULL;
4059
4060        rom_header_offset =
4061        GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
4062
4063        if (!rom_header_offset)
4064                return false;
4065
4066        rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
4067
4068        if (!rom_header)
4069                return false;
4070
4071        get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev);
4072        if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
4073                return false;
4074
4075        bp->master_data_tbl =
4076        GET_IMAGE(ATOM_MASTER_DATA_TABLE,
4077                rom_header->usMasterDataTableOffset);
4078
4079        if (!bp->master_data_tbl)
4080                return false;
4081
4082        bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
4083
4084        if (!bp->object_info_tbl_offset)
4085                return false;
4086
4087        object_info_tbl =
4088        GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
4089
4090        if (!object_info_tbl)
4091                return false;
4092
4093        get_atom_data_table_revision(&object_info_tbl->sHeader,
4094                &bp->object_info_tbl.revision);
4095
4096        if (bp->object_info_tbl.revision.major == 1
4097                && bp->object_info_tbl.revision.minor >= 3) {
4098                ATOM_OBJECT_HEADER_V3 *tbl_v3;
4099
4100                tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
4101                        bp->object_info_tbl_offset);
4102                if (!tbl_v3)
4103                        return false;
4104
4105                bp->object_info_tbl.v1_3 = tbl_v3;
4106        } else if (bp->object_info_tbl.revision.major == 1
4107                && bp->object_info_tbl.revision.minor >= 1)
4108                bp->object_info_tbl.v1_1 = object_info_tbl;
4109        else
4110                return false;
4111
4112        dal_bios_parser_init_cmd_tbl(bp);
4113        dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
4114
4115        bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base);
4116
4117        return true;
4118}
4119
4120/******************************************************************************/
4121