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