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