[PATCH 063/100] drm/amd/display: Add DCE12 bios parser support

Mike Lothian mike at fireburn.co.uk
Thu Aug 3 21:04:12 UTC 2017


Hi

I've just tested out the new amd-staging-drm-next branch and noticed the
following warning caused by this patch

drivers/gpu/drm/amd/amdgpu/../display/dc/bios/bios_parser2.c: In function
‘get_embedded_panel_info_v2_1’:
drivers/gpu/drm/amd/amdgpu/../display/dc/bios/bios_parser2.c:1335:3:
warning: overflow in implicit constant conversion [-Woverflow]
   lvds->lcd_timing.miscinfo & ATOM_INTERLACE;
   ^~~~

Cheers

Mike

On Mon, 20 Mar 2017 at 20:35 Alex Deucher <alexdeucher at gmail.com> wrote:

> From: Harry Wentland <harry.wentland at amd.com>
>
> Signed-off-by: Harry Wentland <harry.wentland at amd.com>
> Signed-off-by: Alex Deucher <alexander.deucher at 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_di
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/amd-gfx/attachments/20170803/c008b2a9/attachment-0001.html>


More information about the amd-gfx mailing list