diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0272-drm-amd-display-Add-DCE12-bios-parser-support.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0272-drm-amd-display-Add-DCE12-bios-parser-support.patch | 3989 |
1 files changed, 3989 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0272-drm-amd-display-Add-DCE12-bios-parser-support.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0272-drm-amd-display-Add-DCE12-bios-parser-support.patch new file mode 100644 index 00000000..db5f644f --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/0272-drm-amd-display-Add-DCE12-bios-parser-support.patch @@ -0,0 +1,3989 @@ +From 4be1f3c0a235197dba29743dcbb84a34ae9101c3 Mon Sep 17 00:00:00 2001 +From: Harry Wentland <harry.wentland@amd.com> +Date: Mon, 6 Mar 2017 14:29:52 -0500 +Subject: [PATCH 0272/4131] drm/amd/display: Add DCE12 bios parser support + +Signed-off-by: Harry Wentland <harry.wentland@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 2085 ++++++++++++++++++++ + drivers/gpu/drm/amd/display/dc/bios/bios_parser2.h | 33 + + .../display/dc/bios/bios_parser_types_internal2.h | 74 + + .../gpu/drm/amd/display/dc/bios/command_table2.c | 813 ++++++++ + .../gpu/drm/amd/display/dc/bios/command_table2.h | 105 + + .../amd/display/dc/bios/command_table_helper2.c | 260 +++ + .../amd/display/dc/bios/command_table_helper2.h | 82 + + .../dc/bios/dce112/command_table_helper2_dce112.c | 418 ++++ + .../dc/bios/dce112/command_table_helper2_dce112.h | 34 + + 9 files changed, 3904 insertions(+) + create mode 100644 drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c + create mode 100644 drivers/gpu/drm/amd/display/dc/bios/bios_parser2.h + create mode 100644 drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal2.h + create mode 100644 drivers/gpu/drm/amd/display/dc/bios/command_table2.c + create mode 100644 drivers/gpu/drm/amd/display/dc/bios/command_table2.h + create mode 100644 drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c + create mode 100644 drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h + create mode 100644 drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c + create mode 100644 drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.h + +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +new file mode 100644 +index 0000000..f6e77da +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +@@ -0,0 +1,2085 @@ ++/* ++ * Copyright 2012-15 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#include "dm_services.h" ++ ++#define _BIOS_PARSER_2_ ++ ++#include "ObjectID.h" ++#include "atomfirmware.h" ++#include "atomfirmwareid.h" ++ ++#include "dc_bios_types.h" ++#include "include/grph_object_ctrl_defs.h" ++#include "include/bios_parser_interface.h" ++#include "include/i2caux_interface.h" ++#include "include/logger_interface.h" ++ ++#include "command_table2.h" ++ ++#include "bios_parser_helper.h" ++#include "command_table_helper2.h" ++#include "bios_parser2.h" ++#include "bios_parser_types_internal2.h" ++#include "bios_parser_interface.h" ++ ++#define LAST_RECORD_TYPE 0xff ++ ++ ++struct i2c_id_config_access { ++ uint8_t bfI2C_LineMux:4; ++ uint8_t bfHW_EngineID:3; ++ uint8_t bfHW_Capable:1; ++ uint8_t ucAccess; ++}; ++ ++static enum object_type object_type_from_bios_object_id( ++ uint32_t bios_object_id); ++ ++static enum object_enum_id enum_id_from_bios_object_id(uint32_t bios_object_id); ++ ++static struct graphics_object_id object_id_from_bios_object_id( ++ uint32_t bios_object_id); ++ ++static uint32_t id_from_bios_object_id(enum object_type type, ++ uint32_t bios_object_id); ++ ++static uint32_t gpu_id_from_bios_object_id(uint32_t bios_object_id); ++ ++static enum encoder_id encoder_id_from_bios_object_id(uint32_t bios_object_id); ++ ++static enum connector_id connector_id_from_bios_object_id( ++ uint32_t bios_object_id); ++ ++static enum generic_id generic_id_from_bios_object_id(uint32_t bios_object_id); ++ ++static enum bp_result get_gpio_i2c_info(struct bios_parser *bp, ++ struct atom_i2c_record *record, ++ struct graphics_object_i2c_info *info); ++ ++static enum bp_result bios_parser_get_firmware_info( ++ struct dc_bios *dcb, ++ struct firmware_info *info); ++ ++static enum bp_result bios_parser_get_encoder_cap_info( ++ struct dc_bios *dcb, ++ struct graphics_object_id object_id, ++ struct bp_encoder_cap_info *info); ++ ++static enum bp_result get_firmware_info_v3_1( ++ struct bios_parser *bp, ++ struct firmware_info *info); ++ ++static struct atom_hpd_int_record *get_hpd_record(struct bios_parser *bp, ++ struct atom_display_object_path_v2 *object); ++ ++static struct atom_encoder_caps_record *get_encoder_cap_record( ++ struct bios_parser *bp, ++ struct atom_display_object_path_v2 *object); ++ ++#define BIOS_IMAGE_SIZE_OFFSET 2 ++#define BIOS_IMAGE_SIZE_UNIT 512 ++ ++#define DATA_TABLES(table) (bp->master_data_tbl->listOfdatatables.table) ++ ++ ++static void destruct(struct bios_parser *bp) ++{ ++ if (bp->base.bios_local_image) ++ dm_free(bp->base.bios_local_image); ++ ++ if (bp->base.integrated_info) ++ dm_free(bp->base.integrated_info); ++} ++ ++static void firmware_parser_destroy(struct dc_bios **dcb) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(*dcb); ++ ++ if (!bp) { ++ BREAK_TO_DEBUGGER(); ++ return; ++ } ++ ++ destruct(bp); ++ ++ dm_free(bp); ++ *dcb = NULL; ++} ++ ++static void get_atom_data_table_revision( ++ struct atom_common_table_header *atom_data_tbl, ++ struct atom_data_revision *tbl_revision) ++{ ++ if (!tbl_revision) ++ return; ++ ++ /* initialize the revision to 0 which is invalid revision */ ++ tbl_revision->major = 0; ++ tbl_revision->minor = 0; ++ ++ if (!atom_data_tbl) ++ return; ++ ++ tbl_revision->major = ++ (uint32_t) atom_data_tbl->format_revision & 0x3f; ++ tbl_revision->minor = ++ (uint32_t) atom_data_tbl->content_revision & 0x3f; ++} ++ ++static struct graphics_object_id object_id_from_bios_object_id( ++ uint32_t bios_object_id) ++{ ++ enum object_type type; ++ enum object_enum_id enum_id; ++ struct graphics_object_id go_id = { 0 }; ++ ++ type = object_type_from_bios_object_id(bios_object_id); ++ ++ if (type == OBJECT_TYPE_UNKNOWN) ++ return go_id; ++ ++ enum_id = enum_id_from_bios_object_id(bios_object_id); ++ ++ if (enum_id == ENUM_ID_UNKNOWN) ++ return go_id; ++ ++ go_id = dal_graphics_object_id_init( ++ id_from_bios_object_id(type, bios_object_id), ++ enum_id, type); ++ ++ return go_id; ++} ++ ++static enum object_type object_type_from_bios_object_id(uint32_t bios_object_id) ++{ ++ uint32_t bios_object_type = (bios_object_id & OBJECT_TYPE_MASK) ++ >> OBJECT_TYPE_SHIFT; ++ enum object_type object_type; ++ ++ switch (bios_object_type) { ++ case GRAPH_OBJECT_TYPE_GPU: ++ object_type = OBJECT_TYPE_GPU; ++ break; ++ case GRAPH_OBJECT_TYPE_ENCODER: ++ object_type = OBJECT_TYPE_ENCODER; ++ break; ++ case GRAPH_OBJECT_TYPE_CONNECTOR: ++ object_type = OBJECT_TYPE_CONNECTOR; ++ break; ++ case GRAPH_OBJECT_TYPE_ROUTER: ++ object_type = OBJECT_TYPE_ROUTER; ++ break; ++ case GRAPH_OBJECT_TYPE_GENERIC: ++ object_type = OBJECT_TYPE_GENERIC; ++ break; ++ default: ++ object_type = OBJECT_TYPE_UNKNOWN; ++ break; ++ } ++ ++ return object_type; ++} ++ ++static enum object_enum_id enum_id_from_bios_object_id(uint32_t bios_object_id) ++{ ++ uint32_t bios_enum_id = ++ (bios_object_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT; ++ enum object_enum_id id; ++ ++ switch (bios_enum_id) { ++ case GRAPH_OBJECT_ENUM_ID1: ++ id = ENUM_ID_1; ++ break; ++ case GRAPH_OBJECT_ENUM_ID2: ++ id = ENUM_ID_2; ++ break; ++ case GRAPH_OBJECT_ENUM_ID3: ++ id = ENUM_ID_3; ++ break; ++ case GRAPH_OBJECT_ENUM_ID4: ++ id = ENUM_ID_4; ++ break; ++ case GRAPH_OBJECT_ENUM_ID5: ++ id = ENUM_ID_5; ++ break; ++ case GRAPH_OBJECT_ENUM_ID6: ++ id = ENUM_ID_6; ++ break; ++ case GRAPH_OBJECT_ENUM_ID7: ++ id = ENUM_ID_7; ++ break; ++ default: ++ id = ENUM_ID_UNKNOWN; ++ break; ++ } ++ ++ return id; ++} ++ ++static uint32_t id_from_bios_object_id(enum object_type type, ++ uint32_t bios_object_id) ++{ ++ switch (type) { ++ case OBJECT_TYPE_GPU: ++ return gpu_id_from_bios_object_id(bios_object_id); ++ case OBJECT_TYPE_ENCODER: ++ return (uint32_t)encoder_id_from_bios_object_id(bios_object_id); ++ case OBJECT_TYPE_CONNECTOR: ++ return (uint32_t)connector_id_from_bios_object_id( ++ bios_object_id); ++ case OBJECT_TYPE_GENERIC: ++ return generic_id_from_bios_object_id(bios_object_id); ++ default: ++ return 0; ++ } ++} ++ ++uint32_t gpu_id_from_bios_object_id(uint32_t bios_object_id) ++{ ++ return (bios_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; ++} ++ ++static enum encoder_id encoder_id_from_bios_object_id(uint32_t bios_object_id) ++{ ++ uint32_t bios_encoder_id = gpu_id_from_bios_object_id(bios_object_id); ++ enum encoder_id id; ++ ++ switch (bios_encoder_id) { ++ case ENCODER_OBJECT_ID_INTERNAL_LVDS: ++ id = ENCODER_ID_INTERNAL_LVDS; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_TMDS1: ++ id = ENCODER_ID_INTERNAL_TMDS1; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_TMDS2: ++ id = ENCODER_ID_INTERNAL_TMDS2; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_DAC1: ++ id = ENCODER_ID_INTERNAL_DAC1; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_DAC2: ++ id = ENCODER_ID_INTERNAL_DAC2; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_LVTM1: ++ id = ENCODER_ID_INTERNAL_LVTM1; ++ break; ++ case ENCODER_OBJECT_ID_HDMI_INTERNAL: ++ id = ENCODER_ID_INTERNAL_HDMI; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: ++ id = ENCODER_ID_INTERNAL_KLDSCP_TMDS1; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: ++ id = ENCODER_ID_INTERNAL_KLDSCP_DAC1; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: ++ id = ENCODER_ID_INTERNAL_KLDSCP_DAC2; ++ break; ++ case ENCODER_OBJECT_ID_MVPU_FPGA: ++ id = ENCODER_ID_EXTERNAL_MVPU_FPGA; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_DDI: ++ id = ENCODER_ID_INTERNAL_DDI; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: ++ id = ENCODER_ID_INTERNAL_UNIPHY; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: ++ id = ENCODER_ID_INTERNAL_KLDSCP_LVTMA; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: ++ id = ENCODER_ID_INTERNAL_UNIPHY1; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: ++ id = ENCODER_ID_INTERNAL_UNIPHY2; ++ break; ++ case ENCODER_OBJECT_ID_ALMOND: /* ENCODER_OBJECT_ID_NUTMEG */ ++ id = ENCODER_ID_EXTERNAL_NUTMEG; ++ break; ++ case ENCODER_OBJECT_ID_TRAVIS: ++ id = ENCODER_ID_EXTERNAL_TRAVIS; ++ break; ++ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: ++ id = ENCODER_ID_INTERNAL_UNIPHY3; ++ break; ++ default: ++ id = ENCODER_ID_UNKNOWN; ++ ASSERT(0); ++ break; ++ } ++ ++ return id; ++} ++ ++static enum connector_id connector_id_from_bios_object_id( ++ uint32_t bios_object_id) ++{ ++ uint32_t bios_connector_id = gpu_id_from_bios_object_id(bios_object_id); ++ ++ enum connector_id id; ++ ++ switch (bios_connector_id) { ++ case CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I: ++ id = CONNECTOR_ID_SINGLE_LINK_DVII; ++ break; ++ case CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I: ++ id = CONNECTOR_ID_DUAL_LINK_DVII; ++ break; ++ case CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D: ++ id = CONNECTOR_ID_SINGLE_LINK_DVID; ++ break; ++ case CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D: ++ id = CONNECTOR_ID_DUAL_LINK_DVID; ++ break; ++ case CONNECTOR_OBJECT_ID_VGA: ++ id = CONNECTOR_ID_VGA; ++ break; ++ case CONNECTOR_OBJECT_ID_HDMI_TYPE_A: ++ id = CONNECTOR_ID_HDMI_TYPE_A; ++ break; ++ case CONNECTOR_OBJECT_ID_LVDS: ++ id = CONNECTOR_ID_LVDS; ++ break; ++ case CONNECTOR_OBJECT_ID_PCIE_CONNECTOR: ++ id = CONNECTOR_ID_PCIE; ++ break; ++ case CONNECTOR_OBJECT_ID_HARDCODE_DVI: ++ id = CONNECTOR_ID_HARDCODE_DVI; ++ break; ++ case CONNECTOR_OBJECT_ID_DISPLAYPORT: ++ id = CONNECTOR_ID_DISPLAY_PORT; ++ break; ++ case CONNECTOR_OBJECT_ID_eDP: ++ id = CONNECTOR_ID_EDP; ++ break; ++ case CONNECTOR_OBJECT_ID_MXM: ++ id = CONNECTOR_ID_MXM; ++ break; ++ default: ++ id = CONNECTOR_ID_UNKNOWN; ++ break; ++ } ++ ++ return id; ++} ++ ++enum generic_id generic_id_from_bios_object_id(uint32_t bios_object_id) ++{ ++ uint32_t bios_generic_id = gpu_id_from_bios_object_id(bios_object_id); ++ ++ enum generic_id id; ++ ++ switch (bios_generic_id) { ++ case GENERIC_OBJECT_ID_MXM_OPM: ++ id = GENERIC_ID_MXM_OPM; ++ break; ++ case GENERIC_OBJECT_ID_GLSYNC: ++ id = GENERIC_ID_GLSYNC; ++ break; ++ case GENERIC_OBJECT_ID_STEREO_PIN: ++ id = GENERIC_ID_STEREO; ++ break; ++ default: ++ id = GENERIC_ID_UNKNOWN; ++ break; ++ } ++ ++ return id; ++} ++ ++static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ unsigned int count = 0; ++ unsigned int i; ++ ++ for (i = 0; i < bp->object_info_tbl.v1_4->number_of_path; i++) { ++ if (bp->object_info_tbl.v1_4->display_path[i].encoderobjid != 0 ++ && ++ bp->object_info_tbl.v1_4->display_path[i].display_objid != 0) ++ count++; ++ } ++ return count; ++} ++ ++static struct graphics_object_id bios_parser_get_encoder_id( ++ struct dc_bios *dcb, ++ uint32_t i) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ struct graphics_object_id object_id = dal_graphics_object_id_init( ++ 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN); ++ ++ if (bp->object_info_tbl.v1_4->number_of_path > i) ++ object_id = object_id_from_bios_object_id( ++ bp->object_info_tbl.v1_4->display_path[i].encoderobjid); ++ ++ return object_id; ++} ++ ++static struct graphics_object_id bios_parser_get_connector_id( ++ struct dc_bios *dcb, ++ uint8_t i) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ struct graphics_object_id object_id = dal_graphics_object_id_init( ++ 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN); ++ struct object_info_table *tbl = &bp->object_info_tbl; ++ struct display_object_info_table_v1_4 *v1_4 = tbl->v1_4; ++ ++ if (v1_4->number_of_path > i) { ++ /* If display_objid is generic object id, the encoderObj ++ * /extencoderobjId should be 0 ++ */ ++ if (v1_4->display_path[i].encoderobjid != 0 && ++ v1_4->display_path[i].display_objid != 0) ++ object_id = object_id_from_bios_object_id( ++ v1_4->display_path[i].display_objid); ++ } ++ ++ return object_id; ++} ++ ++ ++/* TODO: GetNumberOfSrc*/ ++ ++static uint32_t bios_parser_get_dst_number(struct dc_bios *dcb, ++ struct graphics_object_id id) ++{ ++ /* connector has 1 Dest, encoder has 0 Dest */ ++ switch (id.type) { ++ case OBJECT_TYPE_ENCODER: ++ return 0; ++ case OBJECT_TYPE_CONNECTOR: ++ return 1; ++ default: ++ return 0; ++ } ++} ++ ++/* removed getSrcObjList, getDestObjList*/ ++ ++ ++static enum bp_result bios_parser_get_src_obj(struct dc_bios *dcb, ++ struct graphics_object_id object_id, uint32_t index, ++ struct graphics_object_id *src_object_id) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ unsigned int i; ++ enum bp_result bp_result = BP_RESULT_BADINPUT; ++ struct graphics_object_id obj_id = {0}; ++ struct object_info_table *tbl = &bp->object_info_tbl; ++ ++ if (!src_object_id) ++ return bp_result; ++ ++ switch (object_id.type) { ++ /* Encoder's Source is GPU. BIOS does not provide GPU, since all ++ * displaypaths point to same GPU (0x1100). Hardcode GPU object type ++ */ ++ case OBJECT_TYPE_ENCODER: ++ /* TODO: since num of src must be less than 2. ++ * If found in for loop, should break. ++ * DAL2 implementation may be changed too ++ */ ++ for (i = 0; i < tbl->v1_4->number_of_path; i++) { ++ obj_id = object_id_from_bios_object_id( ++ tbl->v1_4->display_path[i].encoderobjid); ++ if (object_id.type == obj_id.type && ++ object_id.id == obj_id.id && ++ object_id.enum_id == ++ obj_id.enum_id) { ++ *src_object_id = ++ object_id_from_bios_object_id(0x1100); ++ /* break; */ ++ } ++ } ++ bp_result = BP_RESULT_OK; ++ break; ++ case OBJECT_TYPE_CONNECTOR: ++ for (i = 0; i < tbl->v1_4->number_of_path; i++) { ++ obj_id = object_id_from_bios_object_id( ++ tbl->v1_4->display_path[i].display_objid); ++ ++ if (object_id.type == obj_id.type && ++ object_id.id == obj_id.id && ++ object_id.enum_id == obj_id.enum_id) { ++ *src_object_id = ++ object_id_from_bios_object_id( ++ tbl->v1_4->display_path[i].encoderobjid); ++ /* break; */ ++ } ++ } ++ bp_result = BP_RESULT_OK; ++ break; ++ default: ++ break; ++ } ++ ++ return bp_result; ++} ++ ++static enum bp_result bios_parser_get_dst_obj(struct dc_bios *dcb, ++ struct graphics_object_id object_id, uint32_t index, ++ struct graphics_object_id *dest_object_id) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ unsigned int i; ++ enum bp_result bp_result = BP_RESULT_BADINPUT; ++ struct graphics_object_id obj_id = {0}; ++ struct object_info_table *tbl = &bp->object_info_tbl; ++ ++ if (!dest_object_id) ++ return BP_RESULT_BADINPUT; ++ ++ switch (object_id.type) { ++ case OBJECT_TYPE_ENCODER: ++ /* TODO: since num of src must be less than 2. ++ * If found in for loop, should break. ++ * DAL2 implementation may be changed too ++ */ ++ for (i = 0; i < tbl->v1_4->number_of_path; i++) { ++ obj_id = object_id_from_bios_object_id( ++ tbl->v1_4->display_path[i].encoderobjid); ++ if (object_id.type == obj_id.type && ++ object_id.id == obj_id.id && ++ object_id.enum_id == ++ obj_id.enum_id) { ++ *dest_object_id = ++ object_id_from_bios_object_id( ++ tbl->v1_4->display_path[i].display_objid); ++ /* break; */ ++ } ++ } ++ bp_result = BP_RESULT_OK; ++ break; ++ default: ++ break; ++ } ++ ++ return bp_result; ++} ++ ++ ++/* from graphics_object_id, find display path which includes the object_id */ ++static struct atom_display_object_path_v2 *get_bios_object( ++ struct bios_parser *bp, ++ struct graphics_object_id id) ++{ ++ unsigned int i; ++ struct graphics_object_id obj_id = {0}; ++ ++ switch (id.type) { ++ case OBJECT_TYPE_ENCODER: ++ for (i = 0; i < bp->object_info_tbl.v1_4->number_of_path; i++) { ++ obj_id = object_id_from_bios_object_id( ++ bp->object_info_tbl.v1_4->display_path[i].encoderobjid); ++ if (id.type == obj_id.type && ++ id.id == obj_id.id && ++ id.enum_id == obj_id.enum_id) ++ return ++ &bp->object_info_tbl.v1_4->display_path[i]; ++ } ++ case OBJECT_TYPE_CONNECTOR: ++ case OBJECT_TYPE_GENERIC: ++ /* Both Generic and Connector Object ID ++ * will be stored on display_objid ++ */ ++ for (i = 0; i < bp->object_info_tbl.v1_4->number_of_path; i++) { ++ obj_id = object_id_from_bios_object_id( ++ bp->object_info_tbl.v1_4->display_path[i].display_objid ++ ); ++ if (id.type == obj_id.type && ++ id.id == obj_id.id && ++ id.enum_id == obj_id.enum_id) ++ return ++ &bp->object_info_tbl.v1_4->display_path[i]; ++ } ++ default: ++ return NULL; ++ } ++} ++ ++static enum bp_result bios_parser_get_i2c_info(struct dc_bios *dcb, ++ struct graphics_object_id id, ++ struct graphics_object_i2c_info *info) ++{ ++ uint32_t offset; ++ struct atom_display_object_path_v2 *object; ++ struct atom_common_record_header *header; ++ struct atom_i2c_record *record; ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!info) ++ return BP_RESULT_BADINPUT; ++ ++ object = get_bios_object(bp, id); ++ ++ if (!object) ++ return BP_RESULT_BADINPUT; ++ ++ offset = object->disp_recordoffset + bp->object_info_tbl_offset; ++ ++ for (;;) { ++ header = GET_IMAGE(struct atom_common_record_header, offset); ++ ++ if (!header) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ if (header->record_type == LAST_RECORD_TYPE || ++ !header->record_size) ++ break; ++ ++ if (header->record_type == ATOM_I2C_RECORD_TYPE ++ && sizeof(struct atom_i2c_record) <= ++ header->record_size) { ++ /* get the I2C info */ ++ record = (struct atom_i2c_record *) header; ++ ++ if (get_gpio_i2c_info(bp, record, info) == ++ BP_RESULT_OK) ++ return BP_RESULT_OK; ++ } ++ ++ offset += header->record_size; ++ } ++ ++ return BP_RESULT_NORECORD; ++} ++ ++static enum bp_result get_gpio_i2c_info( ++ struct bios_parser *bp, ++ struct atom_i2c_record *record, ++ struct graphics_object_i2c_info *info) ++{ ++ struct atom_gpio_pin_lut_v2_1 *header; ++ uint32_t count = 0; ++ unsigned int table_index = 0; ++ ++ if (!info) ++ return BP_RESULT_BADINPUT; ++ ++ /* get the GPIO_I2C info */ ++ if (!DATA_TABLES(gpio_pin_lut)) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ header = GET_IMAGE(struct atom_gpio_pin_lut_v2_1, ++ DATA_TABLES(gpio_pin_lut)); ++ if (!header) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ if (sizeof(struct atom_common_table_header) + ++ sizeof(struct atom_gpio_pin_assignment) > ++ le16_to_cpu(header->table_header.structuresize)) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ /* TODO: is version change? */ ++ if (header->table_header.content_revision != 1) ++ return BP_RESULT_UNSUPPORTED; ++ ++ /* get data count */ ++ count = (le16_to_cpu(header->table_header.structuresize) ++ - sizeof(struct atom_common_table_header)) ++ / sizeof(struct atom_gpio_pin_assignment); ++ ++ table_index = record->i2c_id & I2C_HW_LANE_MUX; ++ ++ if (count < table_index) { ++ bool find_valid = false; ++ ++ for (table_index = 0; table_index < count; table_index++) { ++ if (((record->i2c_id & I2C_HW_CAP) == ( ++ header->gpio_pin[table_index].gpio_id & ++ I2C_HW_CAP)) && ++ ((record->i2c_id & I2C_HW_ENGINE_ID_MASK) == ++ (header->gpio_pin[table_index].gpio_id & ++ I2C_HW_ENGINE_ID_MASK)) && ++ ((record->i2c_id & I2C_HW_LANE_MUX) == ++ (header->gpio_pin[table_index].gpio_id & ++ I2C_HW_LANE_MUX))) { ++ /* still valid */ ++ find_valid = true; ++ break; ++ } ++ } ++ /* If we don't find the entry that we are looking for then ++ * we will return BP_Result_BadBiosTable. ++ */ ++ if (find_valid == false) ++ return BP_RESULT_BADBIOSTABLE; ++ } ++ ++ /* get the GPIO_I2C_INFO */ ++ info->i2c_hw_assist = (record->i2c_id & I2C_HW_CAP) ? true : false; ++ info->i2c_line = record->i2c_id & I2C_HW_LANE_MUX; ++ info->i2c_engine_id = (record->i2c_id & I2C_HW_ENGINE_ID_MASK) >> 4; ++ info->i2c_slave_address = record->i2c_slave_addr; ++ ++ /* TODO: check how to get register offset for en, Y, etc. */ ++ info->gpio_info.clk_a_register_index = ++ le16_to_cpu( ++ header->gpio_pin[table_index].data_a_reg_index); ++ info->gpio_info.clk_a_shift = ++ header->gpio_pin[table_index].gpio_bitshift; ++ ++ return BP_RESULT_OK; ++} ++ ++static enum bp_result get_voltage_ddc_info_v4( ++ uint8_t *i2c_line, ++ uint32_t index, ++ struct atom_common_table_header *header, ++ uint8_t *address) ++{ ++ enum bp_result result = BP_RESULT_NORECORD; ++ struct atom_voltage_objects_info_v4_1 *info = ++ (struct atom_voltage_objects_info_v4_1 *) address; ++ ++ uint8_t *voltage_current_object = ++ (uint8_t *) (&(info->voltage_object[0])); ++ ++ while ((address + le16_to_cpu(header->structuresize)) > ++ voltage_current_object) { ++ struct atom_i2c_voltage_object_v4 *object = ++ (struct atom_i2c_voltage_object_v4 *) ++ voltage_current_object; ++ ++ if (object->header.voltage_mode == ++ ATOM_INIT_VOLTAGE_REGULATOR) { ++ if (object->header.voltage_type == index) { ++ *i2c_line = object->i2c_id ^ 0x90; ++ result = BP_RESULT_OK; ++ break; ++ } ++ } ++ ++ voltage_current_object += ++ le16_to_cpu(object->header.object_size); ++ } ++ return result; ++} ++ ++static enum bp_result bios_parser_get_thermal_ddc_info( ++ struct dc_bios *dcb, ++ uint32_t i2c_channel_id, ++ struct graphics_object_i2c_info *info) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ struct i2c_id_config_access *config; ++ struct atom_i2c_record record; ++ ++ if (!info) ++ return BP_RESULT_BADINPUT; ++ ++ config = (struct i2c_id_config_access *) &i2c_channel_id; ++ ++ record.i2c_id = config->bfHW_Capable; ++ record.i2c_id |= config->bfI2C_LineMux; ++ record.i2c_id |= config->bfHW_EngineID; ++ ++ return get_gpio_i2c_info(bp, &record, info); ++} ++ ++static enum bp_result bios_parser_get_voltage_ddc_info(struct dc_bios *dcb, ++ uint32_t index, ++ struct graphics_object_i2c_info *info) ++{ ++ uint8_t i2c_line = 0; ++ enum bp_result result = BP_RESULT_NORECORD; ++ uint8_t *voltage_info_address; ++ struct atom_common_table_header *header; ++ struct atom_data_revision revision = {0}; ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!DATA_TABLES(voltageobject_info)) ++ return result; ++ ++ voltage_info_address = get_image(&bp->base, ++ DATA_TABLES(voltageobject_info), ++ sizeof(struct atom_common_table_header)); ++ ++ header = (struct atom_common_table_header *) voltage_info_address; ++ ++ get_atom_data_table_revision(header, &revision); ++ ++ switch (revision.major) { ++ case 4: ++ if (revision.minor != 1) ++ break; ++ result = get_voltage_ddc_info_v4(&i2c_line, index, header, ++ voltage_info_address); ++ break; ++ } ++ ++ if (result == BP_RESULT_OK) ++ result = bios_parser_get_thermal_ddc_info(dcb, ++ i2c_line, info); ++ ++ return result; ++} ++ ++static enum bp_result bios_parser_get_hpd_info( ++ struct dc_bios *dcb, ++ struct graphics_object_id id, ++ struct graphics_object_hpd_info *info) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ struct atom_display_object_path_v2 *object; ++ struct atom_hpd_int_record *record = NULL; ++ ++ if (!info) ++ return BP_RESULT_BADINPUT; ++ ++ object = get_bios_object(bp, id); ++ ++ if (!object) ++ return BP_RESULT_BADINPUT; ++ ++ record = get_hpd_record(bp, object); ++ ++ if (record != NULL) { ++ info->hpd_int_gpio_uid = record->pin_id; ++ info->hpd_active = record->plugin_pin_state; ++ return BP_RESULT_OK; ++ } ++ ++ return BP_RESULT_NORECORD; ++} ++ ++static struct atom_hpd_int_record *get_hpd_record( ++ struct bios_parser *bp, ++ struct atom_display_object_path_v2 *object) ++{ ++ struct atom_common_record_header *header; ++ uint32_t offset; ++ ++ if (!object) { ++ BREAK_TO_DEBUGGER(); /* Invalid object */ ++ return NULL; ++ } ++ ++ offset = le16_to_cpu(object->disp_recordoffset) ++ + bp->object_info_tbl_offset; ++ ++ for (;;) { ++ header = GET_IMAGE(struct atom_common_record_header, offset); ++ ++ if (!header) ++ return NULL; ++ ++ if (header->record_type == LAST_RECORD_TYPE || ++ !header->record_size) ++ break; ++ ++ if (header->record_type == ATOM_HPD_INT_RECORD_TYPE ++ && sizeof(struct atom_hpd_int_record) <= ++ header->record_size) ++ return (struct atom_hpd_int_record *) header; ++ ++ offset += header->record_size; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * bios_parser_get_gpio_pin_info ++ * Get GpioPin information of input gpio id ++ * ++ * @param gpio_id, GPIO ID ++ * @param info, GpioPin information structure ++ * @return Bios parser result code ++ * @note ++ * to get the GPIO PIN INFO, we need: ++ * 1. get the GPIO_ID from other object table, see GetHPDInfo() ++ * 2. in DATA_TABLE.GPIO_Pin_LUT, search all records, ++ * to get the registerA offset/mask ++ */ ++static enum bp_result bios_parser_get_gpio_pin_info( ++ struct dc_bios *dcb, ++ uint32_t gpio_id, ++ struct gpio_pin_info *info) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ struct atom_gpio_pin_lut_v2_1 *header; ++ uint32_t count = 0; ++ uint32_t i = 0; ++ ++ if (!DATA_TABLES(gpio_pin_lut)) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ header = GET_IMAGE(struct atom_gpio_pin_lut_v2_1, ++ DATA_TABLES(gpio_pin_lut)); ++ if (!header) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ if (sizeof(struct atom_common_table_header) + ++ sizeof(struct atom_gpio_pin_lut_v2_1) ++ > le16_to_cpu(header->table_header.structuresize)) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ if (header->table_header.content_revision != 1) ++ return BP_RESULT_UNSUPPORTED; ++ ++ /* Temporary hard code gpio pin info */ ++#if defined(FOR_SIMNOW_BOOT) ++ { ++ struct atom_gpio_pin_assignment gpio_pin[8] = { ++ {0x5db5, 0, 0, 1, 0}, ++ {0x5db5, 8, 8, 2, 0}, ++ {0x5db5, 0x10, 0x10, 3, 0}, ++ {0x5db5, 0x18, 0x14, 4, 0}, ++ {0x5db5, 0x1A, 0x18, 5, 0}, ++ {0x5db5, 0x1C, 0x1C, 6, 0}, ++ }; ++ ++ count = 6; ++ memmove(header->gpio_pin, gpio_pin, sizeof(gpio_pin)); ++ } ++#else ++ count = (le16_to_cpu(header->table_header.structuresize) ++ - sizeof(struct atom_common_table_header)) ++ / sizeof(struct atom_gpio_pin_assignment); ++#endif ++ for (i = 0; i < count; ++i) { ++ if (header->gpio_pin[i].gpio_id != gpio_id) ++ continue; ++ ++ info->offset = ++ (uint32_t) le16_to_cpu( ++ header->gpio_pin[i].data_a_reg_index); ++ info->offset_y = info->offset + 2; ++ info->offset_en = info->offset + 1; ++ info->offset_mask = info->offset - 1; ++ ++ info->mask = (uint32_t) (1 << ++ header->gpio_pin[i].gpio_bitshift); ++ info->mask_y = info->mask + 2; ++ info->mask_en = info->mask + 1; ++ info->mask_mask = info->mask - 1; ++ ++ return BP_RESULT_OK; ++ } ++ ++ return BP_RESULT_NORECORD; ++} ++ ++static struct device_id device_type_from_device_id(uint16_t device_id) ++{ ++ ++ struct device_id result_device_id; ++ ++ switch (device_id) { ++ case ATOM_DISPLAY_LCD1_SUPPORT: ++ result_device_id.device_type = DEVICE_TYPE_LCD; ++ result_device_id.enum_id = 1; ++ break; ++ ++ case ATOM_DISPLAY_DFP1_SUPPORT: ++ result_device_id.device_type = DEVICE_TYPE_DFP; ++ result_device_id.enum_id = 1; ++ break; ++ ++ case ATOM_DISPLAY_DFP2_SUPPORT: ++ result_device_id.device_type = DEVICE_TYPE_DFP; ++ result_device_id.enum_id = 2; ++ break; ++ ++ case ATOM_DISPLAY_DFP3_SUPPORT: ++ result_device_id.device_type = DEVICE_TYPE_DFP; ++ result_device_id.enum_id = 3; ++ break; ++ ++ case ATOM_DISPLAY_DFP4_SUPPORT: ++ result_device_id.device_type = DEVICE_TYPE_DFP; ++ result_device_id.enum_id = 4; ++ break; ++ ++ case ATOM_DISPLAY_DFP5_SUPPORT: ++ result_device_id.device_type = DEVICE_TYPE_DFP; ++ result_device_id.enum_id = 5; ++ break; ++ ++ case ATOM_DISPLAY_DFP6_SUPPORT: ++ result_device_id.device_type = DEVICE_TYPE_DFP; ++ result_device_id.enum_id = 6; ++ break; ++ ++ default: ++ BREAK_TO_DEBUGGER(); /* Invalid device Id */ ++ result_device_id.device_type = DEVICE_TYPE_UNKNOWN; ++ result_device_id.enum_id = 0; ++ } ++ return result_device_id; ++} ++ ++static enum bp_result bios_parser_get_device_tag( ++ struct dc_bios *dcb, ++ struct graphics_object_id connector_object_id, ++ uint32_t device_tag_index, ++ struct connector_device_tag_info *info) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ struct atom_display_object_path_v2 *object; ++ ++ if (!info) ++ return BP_RESULT_BADINPUT; ++ ++ /* getBiosObject will return MXM object */ ++ object = get_bios_object(bp, connector_object_id); ++ ++ if (!object) { ++ BREAK_TO_DEBUGGER(); /* Invalid object id */ ++ return BP_RESULT_BADINPUT; ++ } ++ ++ info->acpi_device = 0; /* BIOS no longer provides this */ ++ info->dev_id = device_type_from_device_id(object->device_tag); ++ ++ return BP_RESULT_OK; ++} ++ ++static enum bp_result get_ss_info_v4_1( ++ struct bios_parser *bp, ++ uint32_t id, ++ uint32_t index, ++ struct spread_spectrum_info *ss_info) ++{ ++ enum bp_result result = BP_RESULT_OK; ++ struct atom_display_controller_info_v4_1 *disp_cntl_tbl = NULL; ++ struct atom_smu_info_v3_1 *smu_tbl = NULL; ++ ++ if (!ss_info) ++ return BP_RESULT_BADINPUT; ++ ++ if (!DATA_TABLES(dce_info)) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ if (!DATA_TABLES(smu_info)) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ disp_cntl_tbl = GET_IMAGE(struct atom_display_controller_info_v4_1, ++ DATA_TABLES(dce_info)); ++ if (!disp_cntl_tbl) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ smu_tbl = GET_IMAGE(struct atom_smu_info_v3_1, DATA_TABLES(smu_info)); ++ if (!smu_tbl) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ ++ ss_info->type.STEP_AND_DELAY_INFO = false; ++ ss_info->spread_percentage_divider = 1000; ++ /* BIOS no longer uses target clock. Always enable for now */ ++ ss_info->target_clock_range = 0xffffffff; ++ ++ switch (id) { ++ case AS_SIGNAL_TYPE_DVI: ++ ss_info->spread_spectrum_percentage = ++ disp_cntl_tbl->dvi_ss_percentage; ++ ss_info->spread_spectrum_range = ++ disp_cntl_tbl->dvi_ss_rate_10hz * 10; ++ if (disp_cntl_tbl->dvi_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ++ ss_info->type.CENTER_MODE = true; ++ break; ++ case AS_SIGNAL_TYPE_HDMI: ++ ss_info->spread_spectrum_percentage = ++ disp_cntl_tbl->hdmi_ss_percentage; ++ ss_info->spread_spectrum_range = ++ disp_cntl_tbl->hdmi_ss_rate_10hz * 10; ++ if (disp_cntl_tbl->hdmi_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ++ ss_info->type.CENTER_MODE = true; ++ break; ++ /* TODO LVDS not support anymore? */ ++ case AS_SIGNAL_TYPE_DISPLAY_PORT: ++ ss_info->spread_spectrum_percentage = ++ disp_cntl_tbl->dp_ss_percentage; ++ ss_info->spread_spectrum_range = ++ disp_cntl_tbl->dp_ss_rate_10hz * 10; ++ if (disp_cntl_tbl->dp_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ++ ss_info->type.CENTER_MODE = true; ++ break; ++ case AS_SIGNAL_TYPE_GPU_PLL: ++ ss_info->spread_spectrum_percentage = ++ smu_tbl->gpuclk_ss_percentage; ++ ss_info->spread_spectrum_range = ++ smu_tbl->gpuclk_ss_rate_10hz * 10; ++ if (smu_tbl->gpuclk_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE) ++ ss_info->type.CENTER_MODE = true; ++ break; ++ default: ++ result = BP_RESULT_UNSUPPORTED; ++ } ++ ++ return result; ++} ++ ++/** ++ * bios_parser_get_spread_spectrum_info ++ * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or ++ * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info ++ * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ++ * ver 3.1, ++ * there is only one entry for each signal /ss id. However, there is ++ * no planning of supporting multiple spread Sprectum entry for EverGreen ++ * @param [in] this ++ * @param [in] signal, ASSignalType to be converted to info index ++ * @param [in] index, number of entries that match the converted info index ++ * @param [out] ss_info, sprectrum information structure, ++ * @return Bios parser result code ++ */ ++static enum bp_result bios_parser_get_spread_spectrum_info( ++ struct dc_bios *dcb, ++ enum as_signal_type signal, ++ uint32_t index, ++ struct spread_spectrum_info *ss_info) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ enum bp_result result = BP_RESULT_UNSUPPORTED; ++ struct atom_common_table_header *header; ++ struct atom_data_revision tbl_revision; ++ ++ if (!ss_info) /* check for bad input */ ++ return BP_RESULT_BADINPUT; ++ ++ if (!DATA_TABLES(dce_info)) ++ return BP_RESULT_UNSUPPORTED; ++ ++ header = GET_IMAGE(struct atom_common_table_header, ++ DATA_TABLES(dce_info)); ++ get_atom_data_table_revision(header, &tbl_revision); ++ ++ switch (tbl_revision.major) { ++ case 4: ++ switch (tbl_revision.minor) { ++ case 1: ++ return get_ss_info_v4_1(bp, signal, index, ss_info); ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ /* there can not be more then one entry for SS Info table */ ++ return result; ++} ++ ++static enum bp_result get_embedded_panel_info_v2_1( ++ struct bios_parser *bp, ++ struct embedded_panel_info *info) ++{ ++ struct lcd_info_v2_1 *lvds; ++ ++ if (!info) ++ return BP_RESULT_BADINPUT; ++ ++ if (!DATA_TABLES(lcd_info)) ++ return BP_RESULT_UNSUPPORTED; ++ ++ lvds = GET_IMAGE(struct lcd_info_v2_1, DATA_TABLES(lcd_info)); ++ ++ if (!lvds) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ /* TODO: previous vv1_3, should v2_1 */ ++ if (!((lvds->table_header.format_revision == 2) ++ && (lvds->table_header.content_revision >= 1))) ++ return BP_RESULT_UNSUPPORTED; ++ ++ memset(info, 0, sizeof(struct embedded_panel_info)); ++ ++ /* We need to convert from 10KHz units into KHz units */ ++ info->lcd_timing.pixel_clk = ++ le16_to_cpu(lvds->lcd_timing.pixclk) * 10; ++ /* usHActive does not include borders, according to VBIOS team */ ++ info->lcd_timing.horizontal_addressable = ++ le16_to_cpu(lvds->lcd_timing.h_active); ++ /* usHBlanking_Time includes borders, so we should really be ++ * subtractingborders duing this translation, but LVDS generally ++ * doesn't have borders, so we should be okay leaving this as is for ++ * now. May need to revisit if we ever have LVDS with borders ++ */ ++ info->lcd_timing.horizontal_blanking_time = ++ le16_to_cpu(lvds->lcd_timing.h_blanking_time); ++ /* usVActive does not include borders, according to VBIOS team*/ ++ info->lcd_timing.vertical_addressable = ++ le16_to_cpu(lvds->lcd_timing.v_active); ++ /* usVBlanking_Time includes borders, so we should really be ++ * subtracting borders duing this translation, but LVDS generally ++ * doesn't have borders, so we should be okay leaving this as is for ++ * now. May need to revisit if we ever have LVDS with borders ++ */ ++ info->lcd_timing.vertical_blanking_time = ++ le16_to_cpu(lvds->lcd_timing.v_blanking_time); ++ info->lcd_timing.horizontal_sync_offset = ++ le16_to_cpu(lvds->lcd_timing.h_sync_offset); ++ info->lcd_timing.horizontal_sync_width = ++ le16_to_cpu(lvds->lcd_timing.h_sync_width); ++ info->lcd_timing.vertical_sync_offset = ++ le16_to_cpu(lvds->lcd_timing.v_sync_offset); ++ info->lcd_timing.vertical_sync_width = ++ le16_to_cpu(lvds->lcd_timing.v_syncwidth); ++ info->lcd_timing.horizontal_border = lvds->lcd_timing.h_border; ++ info->lcd_timing.vertical_border = lvds->lcd_timing.v_border; ++ ++ /* not provided by VBIOS */ ++ info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF = 0; ++ ++ info->lcd_timing.misc_info.H_SYNC_POLARITY = ++ ~(uint32_t) ++ (lvds->lcd_timing.miscinfo & ATOM_HSYNC_POLARITY); ++ info->lcd_timing.misc_info.V_SYNC_POLARITY = ++ ~(uint32_t) ++ (lvds->lcd_timing.miscinfo & ATOM_VSYNC_POLARITY); ++ ++ /* not provided by VBIOS */ ++ info->lcd_timing.misc_info.VERTICAL_CUT_OFF = 0; ++ ++ info->lcd_timing.misc_info.H_REPLICATION_BY2 = ++ lvds->lcd_timing.miscinfo & ATOM_H_REPLICATIONBY2; ++ info->lcd_timing.misc_info.V_REPLICATION_BY2 = ++ lvds->lcd_timing.miscinfo & ATOM_V_REPLICATIONBY2; ++ info->lcd_timing.misc_info.COMPOSITE_SYNC = ++ lvds->lcd_timing.miscinfo & ATOM_COMPOSITESYNC; ++ info->lcd_timing.misc_info.INTERLACE = ++ lvds->lcd_timing.miscinfo & ATOM_INTERLACE; ++ ++ /* not provided by VBIOS*/ ++ info->lcd_timing.misc_info.DOUBLE_CLOCK = 0; ++ /* not provided by VBIOS*/ ++ info->ss_id = 0; ++ ++ info->realtek_eDPToLVDS = ++ (lvds->dplvdsrxid == eDP_TO_LVDS_REALTEK_ID ? 1:0); ++ ++ return BP_RESULT_OK; ++} ++ ++static enum bp_result bios_parser_get_embedded_panel_info( ++ struct dc_bios *dcb, ++ struct embedded_panel_info *info) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ struct atom_common_table_header *header; ++ struct atom_data_revision tbl_revision; ++ ++ if (!DATA_TABLES(lcd_info)) ++ return BP_RESULT_FAILURE; ++ ++ header = GET_IMAGE(struct atom_common_table_header, ++ DATA_TABLES(lcd_info)); ++ ++ if (!header) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ get_atom_data_table_revision(header, &tbl_revision); ++ ++ ++ switch (tbl_revision.major) { ++ case 2: ++ switch (tbl_revision.minor) { ++ case 1: ++ return get_embedded_panel_info_v2_1(bp, info); ++ default: ++ break; ++ } ++ default: ++ break; ++ } ++ ++ return BP_RESULT_FAILURE; ++} ++ ++static uint32_t get_support_mask_for_device_id(struct device_id device_id) ++{ ++ enum dal_device_type device_type = device_id.device_type; ++ uint32_t enum_id = device_id.enum_id; ++ ++ switch (device_type) { ++ case DEVICE_TYPE_LCD: ++ switch (enum_id) { ++ case 1: ++ return ATOM_DISPLAY_LCD1_SUPPORT; ++ default: ++ break; ++ } ++ break; ++ case DEVICE_TYPE_DFP: ++ switch (enum_id) { ++ case 1: ++ return ATOM_DISPLAY_DFP1_SUPPORT; ++ case 2: ++ return ATOM_DISPLAY_DFP2_SUPPORT; ++ case 3: ++ return ATOM_DISPLAY_DFP3_SUPPORT; ++ case 4: ++ return ATOM_DISPLAY_DFP4_SUPPORT; ++ case 5: ++ return ATOM_DISPLAY_DFP5_SUPPORT; ++ case 6: ++ return ATOM_DISPLAY_DFP6_SUPPORT; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ }; ++ ++ /* Unidentified device ID, return empty support mask. */ ++ return 0; ++} ++ ++static bool bios_parser_is_device_id_supported( ++ struct dc_bios *dcb, ++ struct device_id id) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ uint32_t mask = get_support_mask_for_device_id(id); ++ ++ return (le16_to_cpu(bp->object_info_tbl.v1_4->supporteddevices) & ++ mask) != 0; ++} ++ ++static void bios_parser_post_init( ++ struct dc_bios *dcb) ++{ ++ /* TODO for OPM module. Need implement later */ ++} ++ ++static uint32_t bios_parser_get_ss_entry_number( ++ struct dc_bios *dcb, ++ enum as_signal_type signal) ++{ ++ /* TODO: DAL2 atomfirmware implementation does not need this. ++ * why DAL3 need this? ++ */ ++ return 1; ++} ++ ++static enum bp_result bios_parser_transmitter_control( ++ struct dc_bios *dcb, ++ struct bp_transmitter_control *cntl) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!bp->cmd_tbl.transmitter_control) ++ return BP_RESULT_FAILURE; ++ ++ return bp->cmd_tbl.transmitter_control(bp, cntl); ++} ++ ++static enum bp_result bios_parser_encoder_control( ++ struct dc_bios *dcb, ++ struct bp_encoder_control *cntl) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!bp->cmd_tbl.dig_encoder_control) ++ return BP_RESULT_FAILURE; ++ ++ return bp->cmd_tbl.dig_encoder_control(bp, cntl); ++} ++ ++static enum bp_result bios_parser_set_pixel_clock( ++ struct dc_bios *dcb, ++ struct bp_pixel_clock_parameters *bp_params) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!bp->cmd_tbl.set_pixel_clock) ++ return BP_RESULT_FAILURE; ++ ++ return bp->cmd_tbl.set_pixel_clock(bp, bp_params); ++} ++ ++static enum bp_result bios_parser_set_dce_clock( ++ struct dc_bios *dcb, ++ struct bp_set_dce_clock_parameters *bp_params) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!bp->cmd_tbl.set_dce_clock) ++ return BP_RESULT_FAILURE; ++ ++ return bp->cmd_tbl.set_dce_clock(bp, bp_params); ++} ++ ++static unsigned int bios_parser_get_smu_clock_info( ++ struct dc_bios *dcb) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!bp->cmd_tbl.get_smu_clock_info) ++ return BP_RESULT_FAILURE; ++ ++ return bp->cmd_tbl.get_smu_clock_info(bp); ++} ++ ++static enum bp_result bios_parser_program_crtc_timing( ++ struct dc_bios *dcb, ++ struct bp_hw_crtc_timing_parameters *bp_params) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!bp->cmd_tbl.set_crtc_timing) ++ return BP_RESULT_FAILURE; ++ ++ return bp->cmd_tbl.set_crtc_timing(bp, bp_params); ++} ++ ++static enum bp_result bios_parser_enable_crtc( ++ struct dc_bios *dcb, ++ enum controller_id id, ++ bool enable) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!bp->cmd_tbl.enable_crtc) ++ return BP_RESULT_FAILURE; ++ ++ return bp->cmd_tbl.enable_crtc(bp, id, enable); ++} ++ ++static enum bp_result bios_parser_crtc_source_select( ++ struct dc_bios *dcb, ++ struct bp_crtc_source_select *bp_params) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!bp->cmd_tbl.select_crtc_source) ++ return BP_RESULT_FAILURE; ++ ++ return bp->cmd_tbl.select_crtc_source(bp, bp_params); ++} ++ ++static enum bp_result bios_parser_enable_disp_power_gating( ++ struct dc_bios *dcb, ++ enum controller_id controller_id, ++ enum bp_pipe_control_action action) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ ++ if (!bp->cmd_tbl.enable_disp_power_gating) ++ return BP_RESULT_FAILURE; ++ ++ return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id, ++ action); ++} ++ ++static bool bios_parser_is_accelerated_mode( ++ struct dc_bios *dcb) ++{ ++ return bios_is_accelerated_mode(dcb); ++} ++ ++ ++/** ++ * bios_parser_set_scratch_critical_state ++ * ++ * @brief ++ * update critical state bit in VBIOS scratch register ++ * ++ * @param ++ * bool - to set or reset state ++ */ ++static void bios_parser_set_scratch_critical_state( ++ struct dc_bios *dcb, ++ bool state) ++{ ++ bios_set_scratch_critical_state(dcb, state); ++} ++ ++static enum bp_result bios_parser_get_firmware_info( ++ struct dc_bios *dcb, ++ struct firmware_info *info) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ enum bp_result result = BP_RESULT_BADBIOSTABLE; ++ struct atom_common_table_header *header; ++ ++ struct atom_data_revision revision; ++ ++ if (info && DATA_TABLES(firmwareinfo)) { ++ header = GET_IMAGE(struct atom_common_table_header, ++ DATA_TABLES(firmwareinfo)); ++ get_atom_data_table_revision(header, &revision); ++ switch (revision.major) { ++ case 3: ++ switch (revision.minor) { ++ case 1: ++ result = get_firmware_info_v3_1(bp, info); ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return result; ++} ++ ++static enum bp_result get_firmware_info_v3_1( ++ struct bios_parser *bp, ++ struct firmware_info *info) ++{ ++ struct atom_firmware_info_v3_1 *firmware_info; ++ struct atom_display_controller_info_v4_1 *dce_info = NULL; ++ ++ if (!info) ++ return BP_RESULT_BADINPUT; ++ ++ firmware_info = GET_IMAGE(struct atom_firmware_info_v3_1, ++ DATA_TABLES(firmwareinfo)); ++ ++ dce_info = GET_IMAGE(struct atom_display_controller_info_v4_1, ++ DATA_TABLES(dce_info)); ++ ++ if (!firmware_info || !dce_info) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ memset(info, 0, sizeof(*info)); ++ ++ /* Pixel clock pll information. */ ++ /* We need to convert from 10KHz units into KHz units */ ++ info->default_memory_clk = firmware_info->bootup_mclk_in10khz * 10; ++ info->default_engine_clk = firmware_info->bootup_sclk_in10khz * 10; ++ ++ /* 27MHz for Vega10: */ ++ info->pll_info.crystal_frequency = dce_info->dce_refclk_10khz * 10; ++ ++ /* Hardcode frequency if BIOS gives no DCE Ref Clk */ ++ if (info->pll_info.crystal_frequency == 0) ++ info->pll_info.crystal_frequency = 27000; ++ ++ info->dp_phy_ref_clk = dce_info->dpphy_refclk_10khz * 10; ++ info->i2c_engine_ref_clk = dce_info->i2c_engine_refclk_10khz * 10; ++ ++ /* Get GPU PLL VCO Clock */ ++ ++ if (bp->cmd_tbl.get_smu_clock_info != NULL) { ++ /* VBIOS gives in 10KHz */ ++ info->smu_gpu_pll_output_freq = ++ bp->cmd_tbl.get_smu_clock_info(bp) * 10; ++ } ++ ++ return BP_RESULT_OK; ++} ++ ++static enum bp_result bios_parser_get_encoder_cap_info( ++ struct dc_bios *dcb, ++ struct graphics_object_id object_id, ++ struct bp_encoder_cap_info *info) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ struct atom_display_object_path_v2 *object; ++ struct atom_encoder_caps_record *record = NULL; ++ ++ if (!info) ++ return BP_RESULT_BADINPUT; ++ ++ object = get_bios_object(bp, object_id); ++ ++ if (!object) ++ return BP_RESULT_BADINPUT; ++ ++ record = get_encoder_cap_record(bp, object); ++ if (!record) ++ return BP_RESULT_NORECORD; ++ ++ info->DP_HBR2_CAP = (record->encodercaps & ++ ATOM_ENCODER_CAP_RECORD_HBR2) ? 1 : 0; ++ info->DP_HBR2_EN = (record->encodercaps & ++ ATOM_ENCODER_CAP_RECORD_HBR2_EN) ? 1 : 0; ++ info->DP_HBR3_EN = (record->encodercaps & ++ ATOM_ENCODER_CAP_RECORD_HBR3_EN) ? 1 : 0; ++ info->HDMI_6GB_EN = (record->encodercaps & ++ ATOM_ENCODER_CAP_RECORD_HDMI6Gbps_EN) ? 1 : 0; ++ ++ return BP_RESULT_OK; ++} ++ ++ ++static struct atom_encoder_caps_record *get_encoder_cap_record( ++ struct bios_parser *bp, ++ struct atom_display_object_path_v2 *object) ++{ ++ struct atom_common_record_header *header; ++ uint32_t offset; ++ ++ if (!object) { ++ BREAK_TO_DEBUGGER(); /* Invalid object */ ++ return NULL; ++ } ++ ++ offset = object->encoder_recordoffset + bp->object_info_tbl_offset; ++ ++ for (;;) { ++ header = GET_IMAGE(struct atom_common_record_header, offset); ++ ++ if (!header) ++ return NULL; ++ ++ offset += header->record_size; ++ ++ if (header->record_type == LAST_RECORD_TYPE || ++ !header->record_size) ++ break; ++ ++ if (header->record_type != ATOM_ENCODER_CAP_RECORD_TYPE) ++ continue; ++ ++ if (sizeof(struct atom_encoder_caps_record) <= ++ header->record_size) ++ return (struct atom_encoder_caps_record *)header; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * get_integrated_info_v11 ++ * ++ * @brief ++ * Get V8 integrated BIOS information ++ * ++ * @param ++ * bios_parser *bp - [in]BIOS parser handler to get master data table ++ * integrated_info *info - [out] store and output integrated info ++ * ++ * @return ++ * enum bp_result - BP_RESULT_OK if information is available, ++ * BP_RESULT_BADBIOSTABLE otherwise. ++ */ ++static enum bp_result get_integrated_info_v11( ++ struct bios_parser *bp, ++ struct integrated_info *info) ++{ ++ struct atom_integrated_system_info_v1_11 *info_v11; ++ uint32_t i; ++ ++ info_v11 = GET_IMAGE(struct atom_integrated_system_info_v1_11, ++ DATA_TABLES(integratedsysteminfo)); ++ ++ if (info_v11 == NULL) ++ return BP_RESULT_BADBIOSTABLE; ++ ++ info->gpu_cap_info = ++ le32_to_cpu(info_v11->gpucapinfo); ++ /* ++ * system_config: Bit[0] = 0 : PCIE power gating disabled ++ * = 1 : PCIE power gating enabled ++ * Bit[1] = 0 : DDR-PLL shut down disabled ++ * = 1 : DDR-PLL shut down enabled ++ * Bit[2] = 0 : DDR-PLL power down disabled ++ * = 1 : DDR-PLL power down enabled ++ */ ++ info->system_config = le32_to_cpu(info_v11->system_config); ++ info->cpu_cap_info = le32_to_cpu(info_v11->cpucapinfo); ++ info->memory_type = info_v11->memorytype; ++ info->ma_channel_number = info_v11->umachannelnumber; ++ info->lvds_ss_percentage = ++ le16_to_cpu(info_v11->lvds_ss_percentage); ++ info->lvds_sspread_rate_in_10hz = ++ le16_to_cpu(info_v11->lvds_ss_rate_10hz); ++ info->hdmi_ss_percentage = ++ le16_to_cpu(info_v11->hdmi_ss_percentage); ++ info->hdmi_sspread_rate_in_10hz = ++ le16_to_cpu(info_v11->hdmi_ss_rate_10hz); ++ info->dvi_ss_percentage = ++ le16_to_cpu(info_v11->dvi_ss_percentage); ++ info->dvi_sspread_rate_in_10_hz = ++ le16_to_cpu(info_v11->dvi_ss_rate_10hz); ++ info->lvds_misc = info_v11->lvds_misc; ++ for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) { ++ info->ext_disp_conn_info.gu_id[i] = ++ info_v11->extdispconninfo.guid[i]; ++ } ++ ++ for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) { ++ info->ext_disp_conn_info.path[i].device_connector_id = ++ object_id_from_bios_object_id( ++ le16_to_cpu(info_v11->extdispconninfo.path[i].connectorobjid)); ++ ++ info->ext_disp_conn_info.path[i].ext_encoder_obj_id = ++ object_id_from_bios_object_id( ++ le16_to_cpu( ++ info_v11->extdispconninfo.path[i].ext_encoder_objid)); ++ ++ info->ext_disp_conn_info.path[i].device_tag = ++ le16_to_cpu( ++ info_v11->extdispconninfo.path[i].device_tag); ++ info->ext_disp_conn_info.path[i].device_acpi_enum = ++ le16_to_cpu( ++ info_v11->extdispconninfo.path[i].device_acpi_enum); ++ info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index = ++ info_v11->extdispconninfo.path[i].auxddclut_index; ++ info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index = ++ info_v11->extdispconninfo.path[i].hpdlut_index; ++ info->ext_disp_conn_info.path[i].channel_mapping.raw = ++ info_v11->extdispconninfo.path[i].channelmapping; ++ } ++ info->ext_disp_conn_info.checksum = ++ info_v11->extdispconninfo.checksum; ++ ++ /** TODO - review **/ ++ #if 0 ++ info->boot_up_engine_clock = le32_to_cpu(info_v11->ulBootUpEngineClock) ++ * 10; ++ info->dentist_vco_freq = le32_to_cpu(info_v11->ulDentistVCOFreq) * 10; ++ info->boot_up_uma_clock = le32_to_cpu(info_v8->ulBootUpUMAClock) * 10; ++ ++ for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) { ++ /* Convert [10KHz] into [KHz] */ ++ info->disp_clk_voltage[i].max_supported_clk = ++ le32_to_cpu(info_v11->sDISPCLK_Voltage[i]. ++ ulMaximumSupportedCLK) * 10; ++ info->disp_clk_voltage[i].voltage_index = ++ le32_to_cpu(info_v11->sDISPCLK_Voltage[i].ulVoltageIndex); ++ } ++ ++ info->boot_up_req_display_vector = ++ le32_to_cpu(info_v11->ulBootUpReqDisplayVector); ++ info->boot_up_nb_voltage = ++ le16_to_cpu(info_v11->usBootUpNBVoltage); ++ info->ext_disp_conn_info_offset = ++ le16_to_cpu(info_v11->usExtDispConnInfoOffset); ++ info->gmc_restore_reset_time = ++ le32_to_cpu(info_v11->ulGMCRestoreResetTime); ++ info->minimum_n_clk = ++ le32_to_cpu(info_v11->ulNbpStateNClkFreq[0]); ++ for (i = 1; i < 4; ++i) ++ info->minimum_n_clk = ++ info->minimum_n_clk < ++ le32_to_cpu(info_v11->ulNbpStateNClkFreq[i]) ? ++ info->minimum_n_clk : le32_to_cpu( ++ info_v11->ulNbpStateNClkFreq[i]); ++ ++ info->idle_n_clk = le32_to_cpu(info_v11->ulIdleNClk); ++ info->ddr_dll_power_up_time = ++ le32_to_cpu(info_v11->ulDDR_DLL_PowerUpTime); ++ info->ddr_pll_power_up_time = ++ le32_to_cpu(info_v11->ulDDR_PLL_PowerUpTime); ++ info->pcie_clk_ss_type = le16_to_cpu(info_v11->usPCIEClkSSType); ++ info->max_lvds_pclk_freq_in_single_link = ++ le16_to_cpu(info_v11->usMaxLVDSPclkFreqInSingleLink); ++ info->max_lvds_pclk_freq_in_single_link = ++ le16_to_cpu(info_v11->usMaxLVDSPclkFreqInSingleLink); ++ info->lvds_pwr_on_seq_dig_on_to_de_in_4ms = ++ info_v11->ucLVDSPwrOnSeqDIGONtoDE_in4Ms; ++ info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms = ++ info_v11->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms; ++ info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms = ++ info_v11->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms; ++ info->lvds_pwr_off_seq_vary_bl_to_de_in4ms = ++ info_v11->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms; ++ info->lvds_pwr_off_seq_de_to_dig_on_in4ms = ++ info_v11->ucLVDSPwrOffSeqDEtoDIGON_in4Ms; ++ info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms = ++ info_v11->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms; ++ info->lvds_off_to_on_delay_in_4ms = ++ info_v11->ucLVDSOffToOnDelay_in4Ms; ++ info->lvds_bit_depth_control_val = ++ le32_to_cpu(info_v11->ulLCDBitDepthControlVal); ++ ++ for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) { ++ /* Convert [10KHz] into [KHz] */ ++ info->avail_s_clk[i].supported_s_clk = ++ le32_to_cpu(info_v11->sAvail_SCLK[i].ulSupportedSCLK) ++ * 10; ++ info->avail_s_clk[i].voltage_index = ++ le16_to_cpu(info_v11->sAvail_SCLK[i].usVoltageIndex); ++ info->avail_s_clk[i].voltage_id = ++ le16_to_cpu(info_v11->sAvail_SCLK[i].usVoltageID); ++ } ++ #endif /* TODO*/ ++ ++ return BP_RESULT_OK; ++} ++ ++ ++/* ++ * construct_integrated_info ++ * ++ * @brief ++ * Get integrated BIOS information based on table revision ++ * ++ * @param ++ * bios_parser *bp - [in]BIOS parser handler to get master data table ++ * integrated_info *info - [out] store and output integrated info ++ * ++ * @return ++ * enum bp_result - BP_RESULT_OK if information is available, ++ * BP_RESULT_BADBIOSTABLE otherwise. ++ */ ++static enum bp_result construct_integrated_info( ++ struct bios_parser *bp, ++ struct integrated_info *info) ++{ ++ enum bp_result result = BP_RESULT_BADBIOSTABLE; ++ ++ struct atom_common_table_header *header; ++ struct atom_data_revision revision; ++ ++ struct clock_voltage_caps temp = {0, 0}; ++ uint32_t i; ++ uint32_t j; ++ ++ if (info && DATA_TABLES(integratedsysteminfo)) { ++ header = GET_IMAGE(struct atom_common_table_header, ++ DATA_TABLES(integratedsysteminfo)); ++ ++ get_atom_data_table_revision(header, &revision); ++ ++ /* Don't need to check major revision as they are all 1 */ ++ switch (revision.minor) { ++ case 11: ++ result = get_integrated_info_v11(bp, info); ++ break; ++ default: ++ return result; ++ } ++ } ++ ++ if (result != BP_RESULT_OK) ++ return result; ++ ++ /* Sort voltage table from low to high*/ ++ for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) { ++ for (j = i; j > 0; --j) { ++ if (info->disp_clk_voltage[j].max_supported_clk < ++ info->disp_clk_voltage[j-1].max_supported_clk ++ ) { ++ /* swap j and j - 1*/ ++ temp = info->disp_clk_voltage[j-1]; ++ info->disp_clk_voltage[j-1] = ++ info->disp_clk_voltage[j]; ++ info->disp_clk_voltage[j] = temp; ++ } ++ } ++ } ++ ++ return result; ++} ++ ++static struct integrated_info *bios_parser_create_integrated_info( ++ struct dc_bios *dcb) ++{ ++ struct bios_parser *bp = BP_FROM_DCB(dcb); ++ struct integrated_info *info = NULL; ++ ++ info = dm_alloc(sizeof(struct integrated_info)); ++ ++ if (info == NULL) { ++ ASSERT_CRITICAL(0); ++ return NULL; ++ } ++ ++ if (construct_integrated_info(bp, info) == BP_RESULT_OK) ++ return info; ++ ++ dm_free(info); ++ ++ return NULL; ++} ++ ++static const struct dc_vbios_funcs vbios_funcs = { ++ .get_connectors_number = bios_parser_get_connectors_number, ++ ++ .get_encoder_id = bios_parser_get_encoder_id, ++ ++ .get_connector_id = bios_parser_get_connector_id, ++ ++ .get_dst_number = bios_parser_get_dst_number, ++ ++ .get_src_obj = bios_parser_get_src_obj, ++ ++ .get_dst_obj = bios_parser_get_dst_obj, ++ ++ .get_i2c_info = bios_parser_get_i2c_info, ++ ++ .get_voltage_ddc_info = bios_parser_get_voltage_ddc_info, ++ ++ .get_thermal_ddc_info = bios_parser_get_thermal_ddc_info, ++ ++ .get_hpd_info = bios_parser_get_hpd_info, ++ ++ .get_device_tag = bios_parser_get_device_tag, ++ ++ .get_firmware_info = bios_parser_get_firmware_info, ++ ++ .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info, ++ ++ .get_ss_entry_number = bios_parser_get_ss_entry_number, ++ ++ .get_embedded_panel_info = bios_parser_get_embedded_panel_info, ++ ++ .get_gpio_pin_info = bios_parser_get_gpio_pin_info, ++ ++ .get_encoder_cap_info = bios_parser_get_encoder_cap_info, ++ ++ .is_device_id_supported = bios_parser_is_device_id_supported, ++ ++ ++ ++ .is_accelerated_mode = bios_parser_is_accelerated_mode, ++ ++ .set_scratch_critical_state = bios_parser_set_scratch_critical_state, ++ ++ ++/* COMMANDS */ ++ .encoder_control = bios_parser_encoder_control, ++ ++ .transmitter_control = bios_parser_transmitter_control, ++ ++ .enable_crtc = bios_parser_enable_crtc, ++ ++ .set_pixel_clock = bios_parser_set_pixel_clock, ++ ++ .set_dce_clock = bios_parser_set_dce_clock, ++ ++ .program_crtc_timing = bios_parser_program_crtc_timing, ++ ++ /* .blank_crtc = bios_parser_blank_crtc, */ ++ ++ .crtc_source_select = bios_parser_crtc_source_select, ++ ++ /* .external_encoder_control = bios_parser_external_encoder_control, */ ++ ++ .enable_disp_power_gating = bios_parser_enable_disp_power_gating, ++ ++ .post_init = bios_parser_post_init, ++ ++ .bios_parser_destroy = firmware_parser_destroy, ++ ++ .get_smu_clock_info = bios_parser_get_smu_clock_info, ++}; ++ ++static bool bios_parser_construct( ++ struct bios_parser *bp, ++ struct bp_init_data *init, ++ enum dce_version dce_version) ++{ ++ uint16_t *rom_header_offset = NULL; ++ struct atom_rom_header_v2_2 *rom_header = NULL; ++ struct display_object_info_table_v1_4 *object_info_tbl; ++ struct atom_data_revision tbl_rev = {0}; ++ ++ if (!init) ++ return false; ++ ++ if (!init->bios) ++ return false; ++ ++ bp->base.funcs = &vbios_funcs; ++ bp->base.bios = init->bios; ++ bp->base.bios_size = bp->base.bios[OFFSET_TO_ATOM_ROM_IMAGE_SIZE] * BIOS_IMAGE_SIZE_UNIT; ++ ++ bp->base.ctx = init->ctx; ++ ++ bp->base.bios_local_image = NULL; ++ ++ rom_header_offset = ++ GET_IMAGE(uint16_t, OFFSET_TO_ATOM_ROM_HEADER_POINTER); ++ ++ if (!rom_header_offset) ++ return false; ++ ++ rom_header = GET_IMAGE(struct atom_rom_header_v2_2, *rom_header_offset); ++ ++ if (!rom_header) ++ return false; ++ ++ get_atom_data_table_revision(&rom_header->table_header, &tbl_rev); ++ if (!(tbl_rev.major >= 2 && tbl_rev.minor >= 2)) ++ return false; ++ ++ bp->master_data_tbl = ++ GET_IMAGE(struct atom_master_data_table_v2_1, ++ rom_header->masterdatatable_offset); ++ ++ if (!bp->master_data_tbl) ++ return false; ++ ++ bp->object_info_tbl_offset = DATA_TABLES(displayobjectinfo); ++ ++ if (!bp->object_info_tbl_offset) ++ return false; ++ ++ object_info_tbl = ++ GET_IMAGE(struct display_object_info_table_v1_4, ++ bp->object_info_tbl_offset); ++ ++ if (!object_info_tbl) ++ return false; ++ ++ get_atom_data_table_revision(&object_info_tbl->table_header, ++ &bp->object_info_tbl.revision); ++ ++ if (bp->object_info_tbl.revision.major == 1 ++ && bp->object_info_tbl.revision.minor >= 4) { ++ struct display_object_info_table_v1_4 *tbl_v1_4; ++ ++ tbl_v1_4 = GET_IMAGE(struct display_object_info_table_v1_4, ++ bp->object_info_tbl_offset); ++ if (!tbl_v1_4) ++ return false; ++ ++ bp->object_info_tbl.v1_4 = tbl_v1_4; ++ } else ++ return false; ++ ++ dal_firmware_parser_init_cmd_tbl(bp); ++ dal_bios_parser_init_cmd_tbl_helper2(&bp->cmd_helper, dce_version); ++ ++ bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base); ++ ++ return true; ++} ++ ++struct dc_bios *firmware_parser_create( ++ struct bp_init_data *init, ++ enum dce_version dce_version) ++{ ++ struct bios_parser *bp = NULL; ++ ++ bp = dm_alloc(sizeof(struct bios_parser)); ++ if (!bp) ++ return NULL; ++ ++ if (bios_parser_construct(bp, init, dce_version)) ++ return &bp->base; ++ ++ dm_free(bp); ++ return NULL; ++} ++ ++ +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.h +new file mode 100644 +index 0000000..cb40546 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.h +@@ -0,0 +1,33 @@ ++/* ++ * Copyright 2012-15 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#ifndef __DAL_BIOS_PARSER2_H__ ++#define __DAL_BIOS_PARSER2_H__ ++ ++struct dc_bios *firmware_parser_create( ++ struct bp_init_data *init, ++ enum dce_version dce_version); ++ ++#endif +diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal2.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal2.h +new file mode 100644 +index 0000000..bf1f5c8 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal2.h +@@ -0,0 +1,74 @@ ++/* ++ * Copyright 2012-15 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#ifndef __DAL_BIOS_PARSER_TYPES_BIOS2_H__ ++#define __DAL_BIOS_PARSER_TYPES_BIOS2_H__ ++ ++#include "dc_bios_types.h" ++#include "bios_parser_helper.h" ++ ++/* use atomfirmware_bringup.h only. Not atombios.h anymore */ ++ ++struct atom_data_revision { ++ uint32_t major; ++ uint32_t minor; ++}; ++ ++struct object_info_table { ++ struct atom_data_revision revision; ++ union { ++ struct display_object_info_table_v1_4 *v1_4; ++ }; ++}; ++ ++enum spread_spectrum_id { ++ SS_ID_UNKNOWN = 0, ++ SS_ID_DP1 = 0xf1, ++ SS_ID_DP2 = 0xf2, ++ SS_ID_LVLINK_2700MHZ = 0xf3, ++ SS_ID_LVLINK_1620MHZ = 0xf4 ++}; ++ ++struct bios_parser { ++ struct dc_bios base; ++ ++ struct object_info_table object_info_tbl; ++ uint32_t object_info_tbl_offset; ++ struct atom_master_data_table_v2_1 *master_data_tbl; ++ ++ ++ const struct bios_parser_helper *bios_helper; ++ ++ const struct command_table_helper *cmd_helper; ++ struct cmd_tbl cmd_tbl; ++ ++ bool remap_device_tags; ++}; ++ ++/* Bios Parser from DC Bios */ ++#define BP_FROM_DCB(dc_bios) \ ++ container_of(dc_bios, struct bios_parser, base) ++ ++#endif +diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +new file mode 100644 +index 0000000..36d1582 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +@@ -0,0 +1,813 @@ ++/* ++ * Copyright 2012-15 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#include "dm_services.h" ++ ++#include "ObjectID.h" ++#include "atomfirmware.h" ++#include "atomfirmwareid.h" ++ ++#include "include/bios_parser_interface.h" ++ ++#include "command_table2.h" ++#include "command_table_helper2.h" ++#include "bios_parser_helper.h" ++#include "bios_parser_types_internal2.h" ++ ++#define GET_INDEX_INTO_MASTER_TABLE(MasterOrData, FieldName)\ ++ (((char *)(&((\ ++ struct atom_master_list_of_##MasterOrData##_functions_v2_1 *)0)\ ++ ->FieldName)-(char *)0)/sizeof(uint16_t)) ++ ++#define EXEC_BIOS_CMD_TABLE(fname, params)\ ++ (cgs_atom_exec_cmd_table(bp->base.ctx->cgs_device, \ ++ GET_INDEX_INTO_MASTER_TABLE(command, fname), \ ++ ¶ms) == 0) ++ ++#define BIOS_CMD_TABLE_REVISION(fname, frev, crev)\ ++ cgs_atom_get_cmd_table_revs(bp->base.ctx->cgs_device, \ ++ GET_INDEX_INTO_MASTER_TABLE(command, fname), &frev, &crev) ++ ++#define BIOS_CMD_TABLE_PARA_REVISION(fname)\ ++ bios_cmd_table_para_revision(bp->base.ctx->cgs_device, \ ++ GET_INDEX_INTO_MASTER_TABLE(command, fname)) ++ ++static void init_dig_encoder_control(struct bios_parser *bp); ++static void init_transmitter_control(struct bios_parser *bp); ++static void init_set_pixel_clock(struct bios_parser *bp); ++ ++static void init_set_crtc_timing(struct bios_parser *bp); ++ ++static void init_select_crtc_source(struct bios_parser *bp); ++static void init_enable_crtc(struct bios_parser *bp); ++ ++static void init_external_encoder_control(struct bios_parser *bp); ++static void init_enable_disp_power_gating(struct bios_parser *bp); ++static void init_set_dce_clock(struct bios_parser *bp); ++static void init_get_smu_clock_info(struct bios_parser *bp); ++ ++void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp) ++{ ++ init_dig_encoder_control(bp); ++ init_transmitter_control(bp); ++ init_set_pixel_clock(bp); ++ ++ init_set_crtc_timing(bp); ++ ++ init_select_crtc_source(bp); ++ init_enable_crtc(bp); ++ ++ init_external_encoder_control(bp); ++ init_enable_disp_power_gating(bp); ++ init_set_dce_clock(bp); ++ init_get_smu_clock_info(bp); ++} ++ ++static uint32_t bios_cmd_table_para_revision(void *cgs_device, ++ uint32_t index) ++{ ++ uint8_t frev, crev; ++ ++ if (cgs_atom_get_cmd_table_revs(cgs_device, ++ index, ++ &frev, &crev) != 0) ++ return 0; ++ return crev; ++} ++ ++/****************************************************************************** ++ ****************************************************************************** ++ ** ++ ** D I G E N C O D E R C O N T R O L ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++static enum bp_result encoder_control_digx_v1_5( ++ struct bios_parser *bp, ++ struct bp_encoder_control *cntl); ++ ++static void init_dig_encoder_control(struct bios_parser *bp) ++{ ++ uint32_t version = ++ BIOS_CMD_TABLE_PARA_REVISION(digxencodercontrol); ++ ++ switch (version) { ++ case 5: ++ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v1_5; ++ break; ++ default: ++ bp->cmd_tbl.dig_encoder_control = NULL; ++ break; ++ } ++} ++ ++static enum bp_result encoder_control_digx_v1_5( ++ struct bios_parser *bp, ++ struct bp_encoder_control *cntl) ++{ ++ enum bp_result result = BP_RESULT_FAILURE; ++ struct dig_encoder_stream_setup_parameters_v1_5 params = {0}; ++ ++ params.digid = (uint8_t)(cntl->engine_id); ++ params.action = bp->cmd_helper->encoder_action_to_atom(cntl->action); ++ ++ params.pclk_10khz = cntl->pixel_clock / 10; ++ params.digmode = ++ (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom( ++ cntl->signal, ++ cntl->enable_dp_audio)); ++ params.lanenum = (uint8_t)(cntl->lanes_number); ++ ++ switch (cntl->color_depth) { ++ case COLOR_DEPTH_888: ++ params.bitpercolor = PANEL_8BIT_PER_COLOR; ++ break; ++ case COLOR_DEPTH_101010: ++ params.bitpercolor = PANEL_10BIT_PER_COLOR; ++ break; ++ case COLOR_DEPTH_121212: ++ params.bitpercolor = PANEL_12BIT_PER_COLOR; ++ break; ++ case COLOR_DEPTH_161616: ++ params.bitpercolor = PANEL_16BIT_PER_COLOR; ++ break; ++ default: ++ break; ++ } ++ ++ if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A) ++ switch (cntl->color_depth) { ++ case COLOR_DEPTH_101010: ++ params.pclk_10khz = ++ (params.pclk_10khz * 30) / 24; ++ break; ++ case COLOR_DEPTH_121212: ++ params.pclk_10khz = ++ (params.pclk_10khz * 36) / 24; ++ break; ++ case COLOR_DEPTH_161616: ++ params.pclk_10khz = ++ (params.pclk_10khz * 48) / 24; ++ break; ++ default: ++ break; ++ } ++ ++ if (EXEC_BIOS_CMD_TABLE(digxencodercontrol, params)) ++ result = BP_RESULT_OK; ++ ++ return result; ++} ++ ++/***************************************************************************** ++ ****************************************************************************** ++ ** ++ ** TRANSMITTER CONTROL ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++static enum bp_result transmitter_control_v1_6( ++ struct bios_parser *bp, ++ struct bp_transmitter_control *cntl); ++ ++static void init_transmitter_control(struct bios_parser *bp) ++{ ++ uint8_t frev; ++ uint8_t crev; ++ ++ if (BIOS_CMD_TABLE_REVISION(dig1transmittercontrol, frev, crev) != 0) ++ BREAK_TO_DEBUGGER(); ++ switch (crev) { ++ case 6: ++ bp->cmd_tbl.transmitter_control = transmitter_control_v1_6; ++ break; ++ default: ++ bp->cmd_tbl.transmitter_control = NULL; ++ break; ++ } ++} ++ ++static enum bp_result transmitter_control_v1_6( ++ struct bios_parser *bp, ++ struct bp_transmitter_control *cntl) ++{ ++ enum bp_result result = BP_RESULT_FAILURE; ++ const struct command_table_helper *cmd = bp->cmd_helper; ++ struct dig_transmitter_control_ps_allocation_v1_6 ps = { { 0 } }; ++ ++ ps.param.phyid = cmd->phy_id_to_atom(cntl->transmitter); ++ ps.param.action = (uint8_t)cntl->action; ++ ++ if (cntl->action == TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS) ++ ps.param.mode_laneset.dplaneset = (uint8_t)cntl->lane_settings; ++ else ++ ps.param.mode_laneset.digmode = ++ cmd->signal_type_to_atom_dig_mode(cntl->signal); ++ ++ ps.param.lanenum = (uint8_t)cntl->lanes_number; ++ ps.param.hpdsel = cmd->hpd_sel_to_atom(cntl->hpd_sel); ++ ps.param.digfe_sel = cmd->dig_encoder_sel_to_atom(cntl->engine_id); ++ ps.param.connobj_id = (uint8_t)cntl->connector_obj_id.id; ++ ps.param.symclk_10khz = cntl->pixel_clock/10; ++ ++ ++ if (cntl->action == TRANSMITTER_CONTROL_ENABLE || ++ cntl->action == TRANSMITTER_CONTROL_ACTIAVATE || ++ cntl->action == TRANSMITTER_CONTROL_DEACTIVATE) { ++ dm_logger_write(bp->base.ctx->logger, LOG_HW_SET_MODE,\ ++ "************************%s:ps.param.symclk_10khz = %d\n",\ ++ __func__, ps.param.symclk_10khz); ++ } ++ ++ ++/*color_depth not used any more, driver has deep color factor in the Phyclk*/ ++ if (EXEC_BIOS_CMD_TABLE(dig1transmittercontrol, ps)) ++ result = BP_RESULT_OK; ++ return result; ++} ++ ++/****************************************************************************** ++ ****************************************************************************** ++ ** ++ ** SET PIXEL CLOCK ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++static enum bp_result set_pixel_clock_v7( ++ struct bios_parser *bp, ++ struct bp_pixel_clock_parameters *bp_params); ++ ++static void init_set_pixel_clock(struct bios_parser *bp) ++{ ++ switch (BIOS_CMD_TABLE_PARA_REVISION(setpixelclock)) { ++ case 7: ++ bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v7; ++ break; ++ default: ++ bp->cmd_tbl.set_pixel_clock = NULL; ++ break; ++ } ++} ++ ++ ++ ++static enum bp_result set_pixel_clock_v7( ++ struct bios_parser *bp, ++ struct bp_pixel_clock_parameters *bp_params) ++{ ++ enum bp_result result = BP_RESULT_FAILURE; ++ struct set_pixel_clock_parameter_v1_7 clk; ++ uint8_t controller_id; ++ uint32_t pll_id; ++ ++ memset(&clk, 0, sizeof(clk)); ++ ++ if (bp->cmd_helper->clock_source_id_to_atom(bp_params->pll_id, &pll_id) ++ && bp->cmd_helper->controller_id_to_atom(bp_params-> ++ controller_id, &controller_id)) { ++ /* Note: VBIOS still wants to use ucCRTC name which is now ++ * 1 byte in ULONG ++ *typedef struct _CRTC_PIXEL_CLOCK_FREQ ++ *{ ++ * target the pixel clock to drive the CRTC timing. ++ * ULONG ulPixelClock:24; ++ * 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to ++ * previous version. ++ * ATOM_CRTC1~6, indicate the CRTC controller to ++ * ULONG ucCRTC:8; ++ * drive the pixel clock. not used for DCPLL case. ++ *}CRTC_PIXEL_CLOCK_FREQ; ++ *union ++ *{ ++ * pixel clock and CRTC id frequency ++ * CRTC_PIXEL_CLOCK_FREQ ulCrtcPclkFreq; ++ * ULONG ulDispEngClkFreq; dispclk frequency ++ *}; ++ */ ++ clk.crtc_id = controller_id; ++ clk.pll_id = (uint8_t) pll_id; ++ clk.encoderobjid = ++ bp->cmd_helper->encoder_id_to_atom( ++ dal_graphics_object_id_get_encoder_id( ++ bp_params->encoder_object_id)); ++ ++ clk.encoder_mode = (uint8_t) bp-> ++ cmd_helper->encoder_mode_bp_to_atom( ++ bp_params->signal_type, false); ++ ++ /* We need to convert from KHz units into 10KHz units */ ++ clk.pixclk_100hz = cpu_to_le32(bp_params->target_pixel_clock * ++ 10); ++ ++ clk.deep_color_ratio = ++ (uint8_t) bp->cmd_helper-> ++ transmitter_color_depth_to_atom( ++ bp_params->color_depth); ++ dm_logger_write(bp->base.ctx->logger, LOG_HW_SET_MODE,\ ++ "************************%s:program display clock = %d"\ ++ "colorDepth = %d\n", __func__,\ ++ bp_params->target_pixel_clock, bp_params->color_depth); ++ ++ if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) ++ clk.miscinfo |= PIXEL_CLOCK_V7_MISC_FORCE_PROG_PPLL; ++ ++ if (bp_params->flags.PROGRAM_PHY_PLL_ONLY) ++ clk.miscinfo |= PIXEL_CLOCK_V7_MISC_PROG_PHYPLL; ++ ++ if (bp_params->flags.SUPPORT_YUV_420) ++ clk.miscinfo |= PIXEL_CLOCK_V7_MISC_YUV420_MODE; ++ ++ if (bp_params->flags.SET_XTALIN_REF_SRC) ++ clk.miscinfo |= PIXEL_CLOCK_V7_MISC_REF_DIV_SRC_XTALIN; ++ ++ if (bp_params->flags.SET_GENLOCK_REF_DIV_SRC) ++ clk.miscinfo |= PIXEL_CLOCK_V7_MISC_REF_DIV_SRC_GENLK; ++ ++ if (bp_params->signal_type == SIGNAL_TYPE_DVI_DUAL_LINK) ++ clk.miscinfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN; ++ ++ if (EXEC_BIOS_CMD_TABLE(setpixelclock, clk)) ++ result = BP_RESULT_OK; ++ } ++ return result; ++} ++ ++/****************************************************************************** ++ ****************************************************************************** ++ ** ++ ** SET CRTC TIMING ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++static enum bp_result set_crtc_using_dtd_timing_v3( ++ struct bios_parser *bp, ++ struct bp_hw_crtc_timing_parameters *bp_params); ++ ++static void init_set_crtc_timing(struct bios_parser *bp) ++{ ++ uint32_t dtd_version = ++ BIOS_CMD_TABLE_PARA_REVISION(setcrtc_usingdtdtiming); ++ ++ switch (dtd_version) { ++ case 3: ++ bp->cmd_tbl.set_crtc_timing = ++ set_crtc_using_dtd_timing_v3; ++ break; ++ default: ++ bp->cmd_tbl.set_crtc_timing = NULL; ++ break; ++ } ++} ++ ++static enum bp_result set_crtc_using_dtd_timing_v3( ++ struct bios_parser *bp, ++ struct bp_hw_crtc_timing_parameters *bp_params) ++{ ++ enum bp_result result = BP_RESULT_FAILURE; ++ struct set_crtc_using_dtd_timing_parameters params = {0}; ++ uint8_t atom_controller_id; ++ ++ if (bp->cmd_helper->controller_id_to_atom( ++ bp_params->controller_id, &atom_controller_id)) ++ params.crtc_id = atom_controller_id; ++ ++ /* bios usH_Size wants h addressable size */ ++ params.h_size = cpu_to_le16((uint16_t)bp_params->h_addressable); ++ /* bios usH_Blanking_Time wants borders included in blanking */ ++ params.h_blanking_time = ++ cpu_to_le16((uint16_t)(bp_params->h_total - ++ bp_params->h_addressable)); ++ /* bios usV_Size wants v addressable size */ ++ params.v_size = cpu_to_le16((uint16_t)bp_params->v_addressable); ++ /* bios usV_Blanking_Time wants borders included in blanking */ ++ params.v_blanking_time = ++ cpu_to_le16((uint16_t)(bp_params->v_total - ++ bp_params->v_addressable)); ++ /* bios usHSyncOffset is the offset from the end of h addressable, ++ * our horizontalSyncStart is the offset from the beginning ++ * of h addressable ++ */ ++ params.h_syncoffset = ++ cpu_to_le16((uint16_t)(bp_params->h_sync_start - ++ bp_params->h_addressable)); ++ params.h_syncwidth = cpu_to_le16((uint16_t)bp_params->h_sync_width); ++ /* bios usHSyncOffset is the offset from the end of v addressable, ++ * our verticalSyncStart is the offset from the beginning of ++ * v addressable ++ */ ++ params.v_syncoffset = ++ cpu_to_le16((uint16_t)(bp_params->v_sync_start - ++ bp_params->v_addressable)); ++ params.v_syncwidth = cpu_to_le16((uint16_t)bp_params->v_sync_width); ++ ++ /* we assume that overscan from original timing does not get bigger ++ * than 255 ++ * we will program all the borders in the Set CRTC Overscan call below ++ */ ++ ++ if (bp_params->flags.HSYNC_POSITIVE_POLARITY == 0) ++ params.modemiscinfo = ++ cpu_to_le16(le16_to_cpu(params.modemiscinfo) | ++ ATOM_HSYNC_POLARITY); ++ ++ if (bp_params->flags.VSYNC_POSITIVE_POLARITY == 0) ++ params.modemiscinfo = ++ cpu_to_le16(le16_to_cpu(params.modemiscinfo) | ++ ATOM_VSYNC_POLARITY); ++ ++ if (bp_params->flags.INTERLACE) { ++ params.modemiscinfo = ++ cpu_to_le16(le16_to_cpu(params.modemiscinfo) | ++ ATOM_INTERLACE); ++ ++ /* original DAL code has this condition to apply this ++ * for non-TV/CV only ++ * due to complex MV testing for possible impact ++ * if ( pACParameters->signal != SignalType_YPbPr && ++ * pACParameters->signal != SignalType_Composite && ++ * pACParameters->signal != SignalType_SVideo) ++ */ ++ { ++ /* HW will deduct 0.5 line from 2nd feild. ++ * i.e. for 1080i, it is 2 lines for 1st field, ++ * 2.5 lines for the 2nd feild. we need input as 5 ++ * instead of 4. ++ * but it is 4 either from Edid data (spec CEA 861) ++ * or CEA timing table. ++ */ ++ params.v_syncoffset = ++ cpu_to_le16(le16_to_cpu(params.v_syncoffset) + ++ 1); ++ ++ } ++ } ++ ++ if (bp_params->flags.HORZ_COUNT_BY_TWO) ++ params.modemiscinfo = ++ cpu_to_le16(le16_to_cpu(params.modemiscinfo) | ++ 0x100); /* ATOM_DOUBLE_CLOCK_MODE */ ++ ++ if (EXEC_BIOS_CMD_TABLE(setcrtc_usingdtdtiming, params)) ++ result = BP_RESULT_OK; ++ ++ return result; ++} ++ ++/****************************************************************************** ++ ****************************************************************************** ++ ** ++ ** SELECT CRTC SOURCE ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++ ++static enum bp_result select_crtc_source_v3( ++ struct bios_parser *bp, ++ struct bp_crtc_source_select *bp_params); ++ ++static void init_select_crtc_source(struct bios_parser *bp) ++{ ++ switch (BIOS_CMD_TABLE_PARA_REVISION(selectcrtc_source)) { ++ case 3: ++ bp->cmd_tbl.select_crtc_source = select_crtc_source_v3; ++ break; ++ default: ++ bp->cmd_tbl.select_crtc_source = NULL; ++ break; ++ } ++} ++ ++ ++static enum bp_result select_crtc_source_v3( ++ struct bios_parser *bp, ++ struct bp_crtc_source_select *bp_params) ++{ ++ bool result = BP_RESULT_FAILURE; ++ struct select_crtc_source_parameters_v2_3 params; ++ uint8_t atom_controller_id; ++ uint32_t atom_engine_id; ++ enum signal_type s = bp_params->signal; ++ ++ memset(¶ms, 0, sizeof(params)); ++ ++ if (bp->cmd_helper->controller_id_to_atom(bp_params->controller_id, ++ &atom_controller_id)) ++ params.crtc_id = atom_controller_id; ++ else ++ return result; ++ ++ if (bp->cmd_helper->engine_bp_to_atom(bp_params->engine_id, ++ &atom_engine_id)) ++ params.encoder_id = (uint8_t)atom_engine_id; ++ else ++ return result; ++ ++ if (s == SIGNAL_TYPE_EDP || ++ (s == SIGNAL_TYPE_DISPLAY_PORT && bp_params->sink_signal == ++ SIGNAL_TYPE_LVDS)) ++ s = SIGNAL_TYPE_LVDS; ++ ++ params.encode_mode = ++ bp->cmd_helper->encoder_mode_bp_to_atom( ++ s, bp_params->enable_dp_audio); ++ /* Needed for VBIOS Random Spatial Dithering feature */ ++ params.dst_bpc = (uint8_t)(bp_params->display_output_bit_depth); ++ ++ if (EXEC_BIOS_CMD_TABLE(selectcrtc_source, params)) ++ result = BP_RESULT_OK; ++ ++ return result; ++} ++ ++/****************************************************************************** ++ ****************************************************************************** ++ ** ++ ** ENABLE CRTC ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++static enum bp_result enable_crtc_v1( ++ struct bios_parser *bp, ++ enum controller_id controller_id, ++ bool enable); ++ ++static void init_enable_crtc(struct bios_parser *bp) ++{ ++ switch (BIOS_CMD_TABLE_PARA_REVISION(enablecrtc)) { ++ case 1: ++ bp->cmd_tbl.enable_crtc = enable_crtc_v1; ++ break; ++ default: ++ bp->cmd_tbl.enable_crtc = NULL; ++ break; ++ } ++} ++ ++static enum bp_result enable_crtc_v1( ++ struct bios_parser *bp, ++ enum controller_id controller_id, ++ bool enable) ++{ ++ bool result = BP_RESULT_FAILURE; ++ struct enable_crtc_parameters params = {0}; ++ uint8_t id; ++ ++ if (bp->cmd_helper->controller_id_to_atom(controller_id, &id)) ++ params.crtc_id = id; ++ else ++ return BP_RESULT_BADINPUT; ++ ++ if (enable) ++ params.enable = ATOM_ENABLE; ++ else ++ params.enable = ATOM_DISABLE; ++ ++ if (EXEC_BIOS_CMD_TABLE(enablecrtc, params)) ++ result = BP_RESULT_OK; ++ ++ return result; ++} ++ ++/****************************************************************************** ++ ****************************************************************************** ++ ** ++ ** DISPLAY PLL ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++ ++ ++/****************************************************************************** ++ ****************************************************************************** ++ ** ++ ** EXTERNAL ENCODER CONTROL ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++static enum bp_result external_encoder_control_v3( ++ struct bios_parser *bp, ++ struct bp_external_encoder_control *cntl); ++ ++static void init_external_encoder_control( ++ struct bios_parser *bp) ++{ ++ switch (BIOS_CMD_TABLE_PARA_REVISION(externalencodercontrol)) { ++ case 3: ++ bp->cmd_tbl.external_encoder_control = ++ external_encoder_control_v3; ++ break; ++ default: ++ bp->cmd_tbl.external_encoder_control = NULL; ++ break; ++ } ++} ++ ++static enum bp_result external_encoder_control_v3( ++ struct bios_parser *bp, ++ struct bp_external_encoder_control *cntl) ++{ ++ /* TODO */ ++ return BP_RESULT_OK; ++} ++ ++/****************************************************************************** ++ ****************************************************************************** ++ ** ++ ** ENABLE DISPLAY POWER GATING ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++static enum bp_result enable_disp_power_gating_v2_1( ++ struct bios_parser *bp, ++ enum controller_id crtc_id, ++ enum bp_pipe_control_action action); ++ ++static void init_enable_disp_power_gating( ++ struct bios_parser *bp) ++{ ++ switch (BIOS_CMD_TABLE_PARA_REVISION(enabledisppowergating)) { ++ case 1: ++ bp->cmd_tbl.enable_disp_power_gating = ++ enable_disp_power_gating_v2_1; ++ break; ++ default: ++ bp->cmd_tbl.enable_disp_power_gating = NULL; ++ break; ++ } ++} ++ ++static enum bp_result enable_disp_power_gating_v2_1( ++ struct bios_parser *bp, ++ enum controller_id crtc_id, ++ enum bp_pipe_control_action action) ++{ ++ enum bp_result result = BP_RESULT_FAILURE; ++ ++ ++ struct enable_disp_power_gating_ps_allocation ps = { { 0 } }; ++ uint8_t atom_crtc_id; ++ ++ if (bp->cmd_helper->controller_id_to_atom(crtc_id, &atom_crtc_id)) ++ ps.param.disp_pipe_id = atom_crtc_id; ++ else ++ return BP_RESULT_BADINPUT; ++ ++ ps.param.enable = ++ bp->cmd_helper->disp_power_gating_action_to_atom(action); ++ ++ if (EXEC_BIOS_CMD_TABLE(enabledisppowergating, ps.param)) ++ result = BP_RESULT_OK; ++ ++ return result; ++} ++ ++/****************************************************************************** ++******************************************************************************* ++ ** ++ ** SET DCE CLOCK ++ ** ++******************************************************************************* ++*******************************************************************************/ ++ ++static enum bp_result set_dce_clock_v2_1( ++ struct bios_parser *bp, ++ struct bp_set_dce_clock_parameters *bp_params); ++ ++static void init_set_dce_clock(struct bios_parser *bp) ++{ ++ switch (BIOS_CMD_TABLE_PARA_REVISION(setdceclock)) { ++ case 1: ++ bp->cmd_tbl.set_dce_clock = set_dce_clock_v2_1; ++ break; ++ default: ++ bp->cmd_tbl.set_dce_clock = NULL; ++ break; ++ } ++} ++ ++static enum bp_result set_dce_clock_v2_1( ++ struct bios_parser *bp, ++ struct bp_set_dce_clock_parameters *bp_params) ++{ ++ enum bp_result result = BP_RESULT_FAILURE; ++ ++ struct set_dce_clock_ps_allocation_v2_1 params; ++ uint32_t atom_pll_id; ++ uint32_t atom_clock_type; ++ const struct command_table_helper *cmd = bp->cmd_helper; ++ ++ memset(¶ms, 0, sizeof(params)); ++ ++ if (!cmd->clock_source_id_to_atom(bp_params->pll_id, &atom_pll_id) || ++ !cmd->dc_clock_type_to_atom(bp_params->clock_type, ++ &atom_clock_type)) ++ return BP_RESULT_BADINPUT; ++ ++ params.param.dceclksrc = atom_pll_id; ++ params.param.dceclktype = atom_clock_type; ++ ++ if (bp_params->clock_type == DCECLOCK_TYPE_DPREFCLK) { ++ if (bp_params->flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK) ++ params.param.dceclkflag |= ++ DCE_CLOCK_FLAG_PLL_REFCLK_SRC_GENLK; ++ ++ if (bp_params->flags.USE_PCIE_AS_SOURCE_FOR_DPREFCLK) ++ params.param.dceclkflag |= ++ DCE_CLOCK_FLAG_PLL_REFCLK_SRC_PCIE; ++ ++ if (bp_params->flags.USE_XTALIN_AS_SOURCE_FOR_DPREFCLK) ++ params.param.dceclkflag |= ++ DCE_CLOCK_FLAG_PLL_REFCLK_SRC_XTALIN; ++ ++ if (bp_params->flags.USE_GENERICA_AS_SOURCE_FOR_DPREFCLK) ++ params.param.dceclkflag |= ++ DCE_CLOCK_FLAG_PLL_REFCLK_SRC_GENERICA; ++ } else ++ /* only program clock frequency if display clock is used; ++ * VBIOS will program DPREFCLK ++ * We need to convert from KHz units into 10KHz units ++ */ ++ params.param.dceclk_10khz = cpu_to_le32( ++ bp_params->target_clock_frequency / 10); ++ dm_logger_write(bp->base.ctx->logger, LOG_HW_SET_MODE, ++ "************************%s:target_clock_frequency = %d"\ ++ "clock_type = %d \n", __func__,\ ++ bp_params->target_clock_frequency,\ ++ bp_params->clock_type); ++ ++ if (EXEC_BIOS_CMD_TABLE(setdceclock, params)) { ++ /* Convert from 10KHz units back to KHz */ ++ bp_params->target_clock_frequency = le32_to_cpu( ++ params.param.dceclk_10khz) * 10; ++ result = BP_RESULT_OK; ++ } ++ ++ return result; ++} ++ ++ ++/****************************************************************************** ++ ****************************************************************************** ++ ** ++ ** GET SMU CLOCK INFO ++ ** ++ ****************************************************************************** ++ *****************************************************************************/ ++ ++static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp); ++ ++static void init_get_smu_clock_info(struct bios_parser *bp) ++{ ++ /* TODO add switch for table vrsion */ ++ bp->cmd_tbl.get_smu_clock_info = get_smu_clock_info_v3_1; ++ ++} ++ ++static unsigned int get_smu_clock_info_v3_1(struct bios_parser *bp) ++{ ++ struct atom_get_smu_clock_info_parameters_v3_1 smu_input = {0}; ++ struct atom_get_smu_clock_info_output_parameters_v3_1 smu_output; ++ ++ smu_input.command = GET_SMU_CLOCK_INFO_V3_1_GET_PLLVCO_FREQ; ++ ++ /* Get Specific Clock */ ++ if (EXEC_BIOS_CMD_TABLE(getsmuclockinfo, smu_input)) { ++ memmove(&smu_output, &smu_input, sizeof( ++ struct atom_get_smu_clock_info_parameters_v3_1)); ++ return smu_output.atom_smu_outputclkfreq.syspllvcofreq_10khz; ++ } ++ ++ return 0; ++} ++ +diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h +new file mode 100644 +index 0000000..59061b8 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright 2012-15 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#ifndef __DAL_COMMAND_TABLE2_H__ ++#define __DAL_COMMAND_TABLE2_H__ ++ ++struct bios_parser; ++struct bp_encoder_control; ++ ++struct cmd_tbl { ++ enum bp_result (*dig_encoder_control)( ++ struct bios_parser *bp, ++ struct bp_encoder_control *control); ++ enum bp_result (*encoder_control_dig1)( ++ struct bios_parser *bp, ++ struct bp_encoder_control *control); ++ enum bp_result (*encoder_control_dig2)( ++ struct bios_parser *bp, ++ struct bp_encoder_control *control); ++ enum bp_result (*transmitter_control)( ++ struct bios_parser *bp, ++ struct bp_transmitter_control *control); ++ enum bp_result (*set_pixel_clock)( ++ struct bios_parser *bp, ++ struct bp_pixel_clock_parameters *bp_params); ++ enum bp_result (*enable_spread_spectrum_on_ppll)( ++ struct bios_parser *bp, ++ struct bp_spread_spectrum_parameters *bp_params, ++ bool enable); ++ enum bp_result (*adjust_display_pll)( ++ struct bios_parser *bp, ++ struct bp_adjust_pixel_clock_parameters *bp_params); ++ enum bp_result (*dac1_encoder_control)( ++ struct bios_parser *bp, ++ bool enable, ++ uint32_t pixel_clock, ++ uint8_t dac_standard); ++ enum bp_result (*dac2_encoder_control)( ++ struct bios_parser *bp, ++ bool enable, ++ uint32_t pixel_clock, ++ uint8_t dac_standard); ++ enum bp_result (*dac1_output_control)( ++ struct bios_parser *bp, ++ bool enable); ++ enum bp_result (*dac2_output_control)( ++ struct bios_parser *bp, ++ bool enable); ++ enum bp_result (*set_crtc_timing)( ++ struct bios_parser *bp, ++ struct bp_hw_crtc_timing_parameters *bp_params); ++ enum bp_result (*select_crtc_source)( ++ struct bios_parser *bp, ++ struct bp_crtc_source_select *bp_params); ++ enum bp_result (*enable_crtc)( ++ struct bios_parser *bp, ++ enum controller_id controller_id, ++ bool enable); ++ enum bp_result (*enable_crtc_mem_req)( ++ struct bios_parser *bp, ++ enum controller_id controller_id, ++ bool enable); ++ enum bp_result (*program_clock)( ++ struct bios_parser *bp, ++ struct bp_pixel_clock_parameters *bp_params); ++ enum bp_result (*external_encoder_control)( ++ struct bios_parser *bp, ++ struct bp_external_encoder_control *cntl); ++ enum bp_result (*enable_disp_power_gating)( ++ struct bios_parser *bp, ++ enum controller_id crtc_id, ++ enum bp_pipe_control_action action); ++ enum bp_result (*set_dce_clock)( ++ struct bios_parser *bp, ++ struct bp_set_dce_clock_parameters *bp_params); ++ unsigned int (*get_smu_clock_info)( ++ struct bios_parser *bp); ++ ++}; ++ ++void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp); ++ ++#endif +diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c +new file mode 100644 +index 0000000..b0dcad2 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c +@@ -0,0 +1,260 @@ ++/* ++ * Copyright 2012-15 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#include "dm_services.h" ++ ++#include "ObjectID.h" ++#include "atomfirmware.h" ++#include "atomfirmwareid.h" ++ ++#include "include/bios_parser_types.h" ++ ++#include "command_table_helper2.h" ++ ++bool dal_bios_parser_init_cmd_tbl_helper2( ++ const struct command_table_helper **h, ++ enum dce_version dce) ++{ ++ switch (dce) { ++ case DCE_VERSION_8_0: ++ *h = dal_cmd_tbl_helper_dce80_get_table(); ++ return true; ++ ++ case DCE_VERSION_10_0: ++ *h = dal_cmd_tbl_helper_dce110_get_table(); ++ return true; ++ ++ case DCE_VERSION_11_0: ++ *h = dal_cmd_tbl_helper_dce110_get_table(); ++ return true; ++ ++ case DCE_VERSION_11_2: ++ *h = dal_cmd_tbl_helper_dce112_get_table2(); ++ return true; ++#if defined(CONFIG_DRM_AMD_DC_DCE12_0) ++ case DCE_VERSION_12_0: ++ *h = dal_cmd_tbl_helper_dce112_get_table2(); ++ return true; ++#endif ++ ++ default: ++ /* Unsupported DCE */ ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++} ++ ++/* real implementations */ ++ ++bool dal_cmd_table_helper_controller_id_to_atom2( ++ enum controller_id id, ++ uint8_t *atom_id) ++{ ++ if (atom_id == NULL) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ switch (id) { ++ case CONTROLLER_ID_D0: ++ *atom_id = ATOM_CRTC1; ++ return true; ++ case CONTROLLER_ID_D1: ++ *atom_id = ATOM_CRTC2; ++ return true; ++ case CONTROLLER_ID_D2: ++ *atom_id = ATOM_CRTC3; ++ return true; ++ case CONTROLLER_ID_D3: ++ *atom_id = ATOM_CRTC4; ++ return true; ++ case CONTROLLER_ID_D4: ++ *atom_id = ATOM_CRTC5; ++ return true; ++ case CONTROLLER_ID_D5: ++ *atom_id = ATOM_CRTC6; ++ return true; ++ /* TODO :case CONTROLLER_ID_UNDERLAY0: ++ *atom_id = ATOM_UNDERLAY_PIPE0; ++ return true; ++ */ ++ case CONTROLLER_ID_UNDEFINED: ++ *atom_id = ATOM_CRTC_INVALID; ++ return true; ++ default: ++ /* Wrong controller id */ ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++} ++ ++/** ++* translate_transmitter_bp_to_atom ++* ++* @brief ++* Translate the Transmitter to the corresponding ATOM BIOS value ++* ++* @param ++* input transmitter ++* output digitalTransmitter ++* // =00: Digital Transmitter1 ( UNIPHY linkAB ) ++* // =01: Digital Transmitter2 ( UNIPHY linkCD ) ++* // =02: Digital Transmitter3 ( UNIPHY linkEF ) ++*/ ++uint8_t dal_cmd_table_helper_transmitter_bp_to_atom2( ++ enum transmitter t) ++{ ++ switch (t) { ++ case TRANSMITTER_UNIPHY_A: ++ case TRANSMITTER_UNIPHY_B: ++ case TRANSMITTER_TRAVIS_LCD: ++ return 0; ++ case TRANSMITTER_UNIPHY_C: ++ case TRANSMITTER_UNIPHY_D: ++ return 1; ++ case TRANSMITTER_UNIPHY_E: ++ case TRANSMITTER_UNIPHY_F: ++ return 2; ++ default: ++ /* Invalid Transmitter Type! */ ++ BREAK_TO_DEBUGGER(); ++ return 0; ++ } ++} ++ ++uint32_t dal_cmd_table_helper_encoder_mode_bp_to_atom2( ++ enum signal_type s, ++ bool enable_dp_audio) ++{ ++ switch (s) { ++ case SIGNAL_TYPE_DVI_SINGLE_LINK: ++ case SIGNAL_TYPE_DVI_DUAL_LINK: ++ return ATOM_ENCODER_MODE_DVI; ++ case SIGNAL_TYPE_HDMI_TYPE_A: ++ return ATOM_ENCODER_MODE_HDMI; ++ case SIGNAL_TYPE_LVDS: ++ return ATOM_ENCODER_MODE_LVDS; ++ case SIGNAL_TYPE_EDP: ++ case SIGNAL_TYPE_DISPLAY_PORT_MST: ++ case SIGNAL_TYPE_DISPLAY_PORT: ++ case SIGNAL_TYPE_VIRTUAL: ++ if (enable_dp_audio) ++ return ATOM_ENCODER_MODE_DP_AUDIO; ++ else ++ return ATOM_ENCODER_MODE_DP; ++ case SIGNAL_TYPE_RGB: ++ return ATOM_ENCODER_MODE_CRT; ++ default: ++ return ATOM_ENCODER_MODE_CRT; ++ } ++} ++ ++bool dal_cmd_table_helper_clock_source_id_to_ref_clk_src2( ++ enum clock_source_id id, ++ uint32_t *ref_clk_src_id) ++{ ++ if (ref_clk_src_id == NULL) { ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++ ++ switch (id) { ++ case CLOCK_SOURCE_ID_PLL1: ++ *ref_clk_src_id = ENCODER_REFCLK_SRC_P1PLL; ++ return true; ++ case CLOCK_SOURCE_ID_PLL2: ++ *ref_clk_src_id = ENCODER_REFCLK_SRC_P2PLL; ++ return true; ++ /*TODO:case CLOCK_SOURCE_ID_DCPLL: ++ *ref_clk_src_id = ENCODER_REFCLK_SRC_DCPLL; ++ return true; ++ */ ++ case CLOCK_SOURCE_ID_EXTERNAL: ++ *ref_clk_src_id = ENCODER_REFCLK_SRC_EXTCLK; ++ return true; ++ case CLOCK_SOURCE_ID_UNDEFINED: ++ *ref_clk_src_id = ENCODER_REFCLK_SRC_INVALID; ++ return true; ++ default: ++ /* Unsupported clock source id */ ++ BREAK_TO_DEBUGGER(); ++ return false; ++ } ++} ++ ++uint8_t dal_cmd_table_helper_encoder_id_to_atom2( ++ enum encoder_id id) ++{ ++ switch (id) { ++ case ENCODER_ID_INTERNAL_LVDS: ++ return ENCODER_OBJECT_ID_INTERNAL_LVDS; ++ case ENCODER_ID_INTERNAL_TMDS1: ++ return ENCODER_OBJECT_ID_INTERNAL_TMDS1; ++ case ENCODER_ID_INTERNAL_TMDS2: ++ return ENCODER_OBJECT_ID_INTERNAL_TMDS2; ++ case ENCODER_ID_INTERNAL_DAC1: ++ return ENCODER_OBJECT_ID_INTERNAL_DAC1; ++ case ENCODER_ID_INTERNAL_DAC2: ++ return ENCODER_OBJECT_ID_INTERNAL_DAC2; ++ case ENCODER_ID_INTERNAL_LVTM1: ++ return ENCODER_OBJECT_ID_INTERNAL_LVTM1; ++ case ENCODER_ID_INTERNAL_HDMI: ++ return ENCODER_OBJECT_ID_HDMI_INTERNAL; ++ case ENCODER_ID_EXTERNAL_TRAVIS: ++ return ENCODER_OBJECT_ID_TRAVIS; ++ case ENCODER_ID_EXTERNAL_NUTMEG: ++ return ENCODER_OBJECT_ID_NUTMEG; ++ case ENCODER_ID_INTERNAL_KLDSCP_TMDS1: ++ return ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1; ++ case ENCODER_ID_INTERNAL_KLDSCP_DAC1: ++ return ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1; ++ case ENCODER_ID_INTERNAL_KLDSCP_DAC2: ++ return ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2; ++ case ENCODER_ID_EXTERNAL_MVPU_FPGA: ++ return ENCODER_OBJECT_ID_MVPU_FPGA; ++ case ENCODER_ID_INTERNAL_DDI: ++ return ENCODER_OBJECT_ID_INTERNAL_DDI; ++ case ENCODER_ID_INTERNAL_UNIPHY: ++ return ENCODER_OBJECT_ID_INTERNAL_UNIPHY; ++ case ENCODER_ID_INTERNAL_KLDSCP_LVTMA: ++ return ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA; ++ case ENCODER_ID_INTERNAL_UNIPHY1: ++ return ENCODER_OBJECT_ID_INTERNAL_UNIPHY1; ++ case ENCODER_ID_INTERNAL_UNIPHY2: ++ return ENCODER_OBJECT_ID_INTERNAL_UNIPHY2; ++ case ENCODER_ID_INTERNAL_UNIPHY3: ++ return ENCODER_OBJECT_ID_INTERNAL_UNIPHY3; ++ case ENCODER_ID_INTERNAL_WIRELESS: ++ return ENCODER_OBJECT_ID_INTERNAL_VCE; ++ case ENCODER_ID_INTERNAL_VIRTUAL: ++ return ENCODER_OBJECT_ID_NONE; ++ case ENCODER_ID_UNKNOWN: ++ return ENCODER_OBJECT_ID_NONE; ++ default: ++ /* Invalid encoder id */ ++ BREAK_TO_DEBUGGER(); ++ return ENCODER_OBJECT_ID_NONE; ++ } ++} +diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h +new file mode 100644 +index 0000000..9f587c9 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h +@@ -0,0 +1,82 @@ ++/* ++ * Copyright 2012-15 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#ifndef __DAL_COMMAND_TABLE_HELPER2_H__ ++#define __DAL_COMMAND_TABLE_HELPER2_H__ ++ ++#include "dce80/command_table_helper_dce80.h" ++#include "dce110/command_table_helper_dce110.h" ++#include "dce112/command_table_helper2_dce112.h" ++ ++struct command_table_helper { ++ bool (*controller_id_to_atom)(enum controller_id id, uint8_t *atom_id); ++ uint8_t (*encoder_action_to_atom)( ++ enum bp_encoder_control_action action); ++ uint32_t (*encoder_mode_bp_to_atom)(enum signal_type s, ++ bool enable_dp_audio); ++ bool (*engine_bp_to_atom)(enum engine_id engine_id, ++ uint32_t *atom_engine_id); ++ bool (*clock_source_id_to_atom)(enum clock_source_id id, ++ uint32_t *atom_pll_id); ++ bool (*clock_source_id_to_ref_clk_src)( ++ enum clock_source_id id, ++ uint32_t *ref_clk_src_id); ++ uint8_t (*transmitter_bp_to_atom)(enum transmitter t); ++ uint8_t (*encoder_id_to_atom)(enum encoder_id id); ++ uint8_t (*clock_source_id_to_atom_phy_clk_src_id)( ++ enum clock_source_id id); ++ uint8_t (*signal_type_to_atom_dig_mode)(enum signal_type s); ++ uint8_t (*hpd_sel_to_atom)(enum hpd_source_id id); ++ uint8_t (*dig_encoder_sel_to_atom)(enum engine_id engine_id); ++ uint8_t (*phy_id_to_atom)(enum transmitter t); ++ uint8_t (*disp_power_gating_action_to_atom)( ++ enum bp_pipe_control_action action); ++ bool (*dc_clock_type_to_atom)(enum bp_dce_clock_type id, ++ uint32_t *atom_clock_type); ++ uint8_t (*transmitter_color_depth_to_atom)( ++ enum transmitter_color_depth id); ++}; ++ ++bool dal_bios_parser_init_cmd_tbl_helper2(const struct command_table_helper **h, ++ enum dce_version dce); ++ ++bool dal_cmd_table_helper_controller_id_to_atom2( ++ enum controller_id id, ++ uint8_t *atom_id); ++ ++uint32_t dal_cmd_table_helper_encoder_mode_bp_to_atom2( ++ enum signal_type s, ++ bool enable_dp_audio); ++ ++bool dal_cmd_table_helper_clock_source_id_to_ref_clk_src2( ++ enum clock_source_id id, ++ uint32_t *ref_clk_src_id); ++ ++uint8_t dal_cmd_table_helper_transmitter_bp_to_atom2( ++ enum transmitter t); ++ ++uint8_t dal_cmd_table_helper_encoder_id_to_atom2( ++ enum encoder_id id); ++#endif +diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c +new file mode 100644 +index 0000000..d342cde +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c +@@ -0,0 +1,418 @@ ++/* ++ * Copyright 2012-15 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#include "dm_services.h" ++ ++#include "atom.h" ++ ++#include "include/bios_parser_types.h" ++ ++#include "../command_table_helper2.h" ++ ++static uint8_t phy_id_to_atom(enum transmitter t) ++{ ++ uint8_t atom_phy_id; ++ ++ switch (t) { ++ case TRANSMITTER_UNIPHY_A: ++ atom_phy_id = ATOM_PHY_ID_UNIPHYA; ++ break; ++ case TRANSMITTER_UNIPHY_B: ++ atom_phy_id = ATOM_PHY_ID_UNIPHYB; ++ break; ++ case TRANSMITTER_UNIPHY_C: ++ atom_phy_id = ATOM_PHY_ID_UNIPHYC; ++ break; ++ case TRANSMITTER_UNIPHY_D: ++ atom_phy_id = ATOM_PHY_ID_UNIPHYD; ++ break; ++ case TRANSMITTER_UNIPHY_E: ++ atom_phy_id = ATOM_PHY_ID_UNIPHYE; ++ break; ++ case TRANSMITTER_UNIPHY_F: ++ atom_phy_id = ATOM_PHY_ID_UNIPHYF; ++ break; ++ case TRANSMITTER_UNIPHY_G: ++ atom_phy_id = ATOM_PHY_ID_UNIPHYG; ++ break; ++ default: ++ atom_phy_id = ATOM_PHY_ID_UNIPHYA; ++ break; ++ } ++ return atom_phy_id; ++} ++ ++static uint8_t signal_type_to_atom_dig_mode(enum signal_type s) ++{ ++ uint8_t atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP; ++ ++ switch (s) { ++ case SIGNAL_TYPE_DISPLAY_PORT: ++ case SIGNAL_TYPE_EDP: ++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP; ++ break; ++ case SIGNAL_TYPE_DVI_SINGLE_LINK: ++ case SIGNAL_TYPE_DVI_DUAL_LINK: ++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DVI; ++ break; ++ case SIGNAL_TYPE_HDMI_TYPE_A: ++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_HDMI; ++ break; ++ case SIGNAL_TYPE_DISPLAY_PORT_MST: ++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DP_MST; ++ break; ++ default: ++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V6_DVI; ++ break; ++ } ++ ++ return atom_dig_mode; ++} ++ ++static uint8_t clock_source_id_to_atom_phy_clk_src_id( ++ enum clock_source_id id) ++{ ++ uint8_t atom_phy_clk_src_id = 0; ++ ++ switch (id) { ++ case CLOCK_SOURCE_ID_PLL0: ++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P0PLL; ++ break; ++ case CLOCK_SOURCE_ID_PLL1: ++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL; ++ break; ++ case CLOCK_SOURCE_ID_PLL2: ++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P2PLL; ++ break; ++ case CLOCK_SOURCE_ID_EXTERNAL: ++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SRC_EXT; ++ break; ++ default: ++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL; ++ break; ++ } ++ ++ return atom_phy_clk_src_id >> 2; ++} ++ ++static uint8_t hpd_sel_to_atom(enum hpd_source_id id) ++{ ++ uint8_t atom_hpd_sel = 0; ++ ++ switch (id) { ++ case HPD_SOURCEID1: ++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD1_SEL; ++ break; ++ case HPD_SOURCEID2: ++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD2_SEL; ++ break; ++ case HPD_SOURCEID3: ++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD3_SEL; ++ break; ++ case HPD_SOURCEID4: ++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD4_SEL; ++ break; ++ case HPD_SOURCEID5: ++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD5_SEL; ++ break; ++ case HPD_SOURCEID6: ++ atom_hpd_sel = ATOM_TRANSMITTER_V6_HPD6_SEL; ++ break; ++ case HPD_SOURCEID_UNKNOWN: ++ default: ++ atom_hpd_sel = 0; ++ break; ++ } ++ return atom_hpd_sel; ++} ++ ++static uint8_t dig_encoder_sel_to_atom(enum engine_id id) ++{ ++ uint8_t atom_dig_encoder_sel = 0; ++ ++ switch (id) { ++ case ENGINE_ID_DIGA: ++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL; ++ break; ++ case ENGINE_ID_DIGB: ++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGB_SEL; ++ break; ++ case ENGINE_ID_DIGC: ++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGC_SEL; ++ break; ++ case ENGINE_ID_DIGD: ++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGD_SEL; ++ break; ++ case ENGINE_ID_DIGE: ++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGE_SEL; ++ break; ++ case ENGINE_ID_DIGF: ++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGF_SEL; ++ break; ++ case ENGINE_ID_DIGG: ++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGG_SEL; ++ break; ++ case ENGINE_ID_UNKNOWN: ++ /* No DIG_FRONT is associated to DIG_BACKEND */ ++ atom_dig_encoder_sel = 0; ++ break; ++ default: ++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL; ++ break; ++ } ++ ++ return 0; ++} ++ ++static bool clock_source_id_to_atom( ++ enum clock_source_id id, ++ uint32_t *atom_pll_id) ++{ ++ bool result = true; ++ ++ if (atom_pll_id != NULL) ++ switch (id) { ++ case CLOCK_SOURCE_COMBO_PHY_PLL0: ++ *atom_pll_id = ATOM_COMBOPHY_PLL0; ++ break; ++ case CLOCK_SOURCE_COMBO_PHY_PLL1: ++ *atom_pll_id = ATOM_COMBOPHY_PLL1; ++ break; ++ case CLOCK_SOURCE_COMBO_PHY_PLL2: ++ *atom_pll_id = ATOM_COMBOPHY_PLL2; ++ break; ++ case CLOCK_SOURCE_COMBO_PHY_PLL3: ++ *atom_pll_id = ATOM_COMBOPHY_PLL3; ++ break; ++ case CLOCK_SOURCE_COMBO_PHY_PLL4: ++ *atom_pll_id = ATOM_COMBOPHY_PLL4; ++ break; ++ case CLOCK_SOURCE_COMBO_PHY_PLL5: ++ *atom_pll_id = ATOM_COMBOPHY_PLL5; ++ break; ++ case CLOCK_SOURCE_COMBO_DISPLAY_PLL0: ++ *atom_pll_id = ATOM_PPLL0; ++ break; ++ case CLOCK_SOURCE_ID_DFS: ++ *atom_pll_id = ATOM_GCK_DFS; ++ break; ++ case CLOCK_SOURCE_ID_VCE: ++ *atom_pll_id = ATOM_DP_DTO; ++ break; ++ case CLOCK_SOURCE_ID_DP_DTO: ++ *atom_pll_id = ATOM_DP_DTO; ++ break; ++ case CLOCK_SOURCE_ID_UNDEFINED: ++ /* Should not happen */ ++ *atom_pll_id = ATOM_PPLL_INVALID; ++ result = false; ++ break; ++ default: ++ result = false; ++ break; ++ } ++ ++ return result; ++} ++ ++static bool engine_bp_to_atom(enum engine_id id, uint32_t *atom_engine_id) ++{ ++ bool result = false; ++ ++ if (atom_engine_id != NULL) ++ switch (id) { ++ case ENGINE_ID_DIGA: ++ *atom_engine_id = ASIC_INT_DIG1_ENCODER_ID; ++ result = true; ++ break; ++ case ENGINE_ID_DIGB: ++ *atom_engine_id = ASIC_INT_DIG2_ENCODER_ID; ++ result = true; ++ break; ++ case ENGINE_ID_DIGC: ++ *atom_engine_id = ASIC_INT_DIG3_ENCODER_ID; ++ result = true; ++ break; ++ case ENGINE_ID_DIGD: ++ *atom_engine_id = ASIC_INT_DIG4_ENCODER_ID; ++ result = true; ++ break; ++ case ENGINE_ID_DIGE: ++ *atom_engine_id = ASIC_INT_DIG5_ENCODER_ID; ++ result = true; ++ break; ++ case ENGINE_ID_DIGF: ++ *atom_engine_id = ASIC_INT_DIG6_ENCODER_ID; ++ result = true; ++ break; ++ case ENGINE_ID_DIGG: ++ *atom_engine_id = ASIC_INT_DIG7_ENCODER_ID; ++ result = true; ++ break; ++ case ENGINE_ID_DACA: ++ *atom_engine_id = ASIC_INT_DAC1_ENCODER_ID; ++ result = true; ++ break; ++ default: ++ break; ++ } ++ ++ return result; ++} ++ ++static uint8_t encoder_action_to_atom(enum bp_encoder_control_action action) ++{ ++ uint8_t atom_action = 0; ++ ++ switch (action) { ++ case ENCODER_CONTROL_ENABLE: ++ atom_action = ATOM_ENABLE; ++ break; ++ case ENCODER_CONTROL_DISABLE: ++ atom_action = ATOM_DISABLE; ++ break; ++ case ENCODER_CONTROL_SETUP: ++ atom_action = ATOM_ENCODER_CMD_STREAM_SETUP; ++ break; ++ case ENCODER_CONTROL_INIT: ++ atom_action = ATOM_ENCODER_INIT; ++ break; ++ default: ++ BREAK_TO_DEBUGGER(); /* Unhandle action in driver.!! */ ++ break; ++ } ++ ++ return atom_action; ++} ++ ++static uint8_t disp_power_gating_action_to_atom( ++ enum bp_pipe_control_action action) ++{ ++ uint8_t atom_pipe_action = 0; ++ ++ switch (action) { ++ case ASIC_PIPE_DISABLE: ++ atom_pipe_action = ATOM_DISABLE; ++ break; ++ case ASIC_PIPE_ENABLE: ++ atom_pipe_action = ATOM_ENABLE; ++ break; ++ case ASIC_PIPE_INIT: ++ atom_pipe_action = ATOM_INIT; ++ break; ++ default: ++ ASSERT_CRITICAL(false); /* Unhandle action in driver! */ ++ break; ++ } ++ ++ return atom_pipe_action; ++} ++ ++static bool dc_clock_type_to_atom( ++ enum bp_dce_clock_type id, ++ uint32_t *atom_clock_type) ++{ ++ bool retCode = true; ++ ++ if (atom_clock_type != NULL) { ++ switch (id) { ++ case DCECLOCK_TYPE_DISPLAY_CLOCK: ++ *atom_clock_type = DCE_CLOCK_TYPE_DISPCLK; ++ break; ++ ++ case DCECLOCK_TYPE_DPREFCLK: ++ *atom_clock_type = DCE_CLOCK_TYPE_DPREFCLK; ++ break; ++ ++ default: ++ ASSERT_CRITICAL(false); /* Unhandle action in driver! */ ++ break; ++ } ++ } ++ ++ return retCode; ++} ++ ++static uint8_t transmitter_color_depth_to_atom(enum transmitter_color_depth id) ++{ ++ uint8_t atomColorDepth = 0; ++ ++ switch (id) { ++ case TRANSMITTER_COLOR_DEPTH_24: ++ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS; ++ break; ++ case TRANSMITTER_COLOR_DEPTH_30: ++ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4; ++ break; ++ case TRANSMITTER_COLOR_DEPTH_36: ++ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2; ++ break; ++ case TRANSMITTER_COLOR_DEPTH_48: ++ atomColorDepth = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1; ++ break; ++ default: ++ ASSERT_CRITICAL(false); /* Unhandle action in driver! */ ++ break; ++ } ++ ++ return atomColorDepth; ++} ++ ++/* function table */ ++static const struct command_table_helper command_table_helper_funcs = { ++ .controller_id_to_atom = dal_cmd_table_helper_controller_id_to_atom2, ++ .encoder_action_to_atom = encoder_action_to_atom, ++ .engine_bp_to_atom = engine_bp_to_atom, ++ .clock_source_id_to_atom = clock_source_id_to_atom, ++ .clock_source_id_to_atom_phy_clk_src_id = ++ clock_source_id_to_atom_phy_clk_src_id, ++ .signal_type_to_atom_dig_mode = signal_type_to_atom_dig_mode, ++ .hpd_sel_to_atom = hpd_sel_to_atom, ++ .dig_encoder_sel_to_atom = dig_encoder_sel_to_atom, ++ .phy_id_to_atom = phy_id_to_atom, ++ .disp_power_gating_action_to_atom = disp_power_gating_action_to_atom, ++ .clock_source_id_to_ref_clk_src = NULL, ++ .transmitter_bp_to_atom = NULL, ++ .encoder_id_to_atom = dal_cmd_table_helper_encoder_id_to_atom2, ++ .encoder_mode_bp_to_atom = ++ dal_cmd_table_helper_encoder_mode_bp_to_atom2, ++ .dc_clock_type_to_atom = dc_clock_type_to_atom, ++ .transmitter_color_depth_to_atom = transmitter_color_depth_to_atom, ++}; ++ ++/* ++ * dal_cmd_tbl_helper_dce110_get_table ++ * ++ * @brief ++ * Initialize command table helper functions ++ * ++ * @param ++ * const struct command_table_helper **h - [out] struct of functions ++ * ++ */ ++const struct command_table_helper *dal_cmd_tbl_helper_dce112_get_table2() ++{ ++ return &command_table_helper_funcs; ++} +diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.h b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.h +new file mode 100644 +index 0000000..abf28a0 +--- /dev/null ++++ b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright 2012-15 Advanced Micro Devices, Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: AMD ++ * ++ */ ++ ++#ifndef __DAL_COMMAND_TABLE_HELPER2_DCE112_H__ ++#define __DAL_COMMAND_TABLE_HELPER2_DCE112_H__ ++ ++struct command_table_helper; ++ ++/* Initialize command table helper functions */ ++const struct command_table_helper *dal_cmd_tbl_helper_dce112_get_table2(void); ++ ++#endif /* __DAL_COMMAND_TABLE_HELPER_DCE110_H__ */ +-- +2.7.4 + |