drm/amd/display: get board layout for edid emulation
authorSamson Tam <Samson.Tam@amd.com>
Wed, 30 May 2018 19:44:50 +0000 (15:44 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 5 Jul 2018 21:38:45 +0000 (16:38 -0500)
Signed-off-by: Samson Tam <Samson.Tam@amd.com>
Reviewed-by: Aric Cyr <Aric.Cyr@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
drivers/gpu/drm/amd/display/dc/dc_bios_types.h
drivers/gpu/drm/amd/display/include/grph_object_defs.h
drivers/gpu/drm/amd/display/include/grph_object_id.h

index c7f0b27e457e433588897bc9027947e11c92859c..be8a2494355a45e20fb329f81cdccd341e19b0d8 100644 (file)
@@ -3762,6 +3762,200 @@ static struct integrated_info *bios_parser_create_integrated_info(
        return NULL;
 }
 
+enum bp_result update_slot_layout_info(
+       struct dc_bios *dcb,
+       unsigned int i,
+       struct slot_layout_info *slot_layout_info,
+       unsigned int record_offset)
+{
+       unsigned int j;
+       struct bios_parser *bp;
+       ATOM_BRACKET_LAYOUT_RECORD *record;
+       ATOM_COMMON_RECORD_HEADER *record_header;
+       enum bp_result result = BP_RESULT_NORECORD;
+
+       bp = BP_FROM_DCB(dcb);
+       record = NULL;
+       record_header = NULL;
+
+       for (;;) {
+
+               record_header = (ATOM_COMMON_RECORD_HEADER *)
+                       GET_IMAGE(ATOM_COMMON_RECORD_HEADER, record_offset);
+               if (record_header == NULL) {
+                       result = BP_RESULT_BADBIOSTABLE;
+                       break;
+               }
+
+               /* the end of the list */
+               if (record_header->ucRecordType == 0xff ||
+                       record_header->ucRecordSize == 0)       {
+                       break;
+               }
+
+               if (record_header->ucRecordType ==
+                       ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
+                       sizeof(ATOM_BRACKET_LAYOUT_RECORD)
+                       <= record_header->ucRecordSize) {
+                       record = (ATOM_BRACKET_LAYOUT_RECORD *)
+                               (record_header);
+                       result = BP_RESULT_OK;
+                       break;
+               }
+
+               record_offset += record_header->ucRecordSize;
+       }
+
+       /* return if the record not found */
+       if (result != BP_RESULT_OK)
+               return result;
+
+       /* get slot sizes */
+       slot_layout_info->length = record->ucLength;
+       slot_layout_info->width = record->ucWidth;
+
+       /* get info for each connector in the slot */
+       slot_layout_info->num_of_connectors = record->ucConnNum;
+       for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
+               slot_layout_info->connectors[j].connector_type =
+                       (enum connector_layout_type)
+                       (record->asConnInfo[j].ucConnectorType);
+               switch (record->asConnInfo[j].ucConnectorType) {
+               case CONNECTOR_TYPE_DVI_D:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_DVI_D;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_DVI;
+                       break;
+
+               case CONNECTOR_TYPE_HDMI:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_HDMI;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_HDMI;
+                       break;
+
+               case CONNECTOR_TYPE_DISPLAY_PORT:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_DP;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_DP;
+                       break;
+
+               case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_MINI_DP;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_MINI_DP;
+                       break;
+
+               default:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_UNKNOWN;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_UNKNOWN;
+               }
+
+               slot_layout_info->connectors[j].position =
+                       record->asConnInfo[j].ucPosition;
+               slot_layout_info->connectors[j].connector_id =
+                       object_id_from_bios_object_id(
+                               record->asConnInfo[j].usConnectorObjectId);
+       }
+       return result;
+}
+
+
+enum bp_result get_bracket_layout_record(
+       struct dc_bios *dcb,
+       unsigned int bracket_layout_id,
+       struct slot_layout_info *slot_layout_info)
+{
+       unsigned int i;
+       unsigned int record_offset;
+       struct bios_parser *bp;
+       enum bp_result result;
+       ATOM_OBJECT *object;
+       ATOM_OBJECT_TABLE *object_table;
+       unsigned int genericTableOffset;
+
+       bp = BP_FROM_DCB(dcb);
+       object = NULL;
+       if (slot_layout_info == NULL) {
+               DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
+               return BP_RESULT_BADINPUT;
+       }
+
+
+       genericTableOffset = bp->object_info_tbl_offset +
+               bp->object_info_tbl.v1_3->usMiscObjectTableOffset;
+       object_table = (ATOM_OBJECT_TABLE *)
+               GET_IMAGE(ATOM_OBJECT_TABLE, genericTableOffset);
+       if (!object_table)
+               return BP_RESULT_FAILURE;
+
+       result = BP_RESULT_NORECORD;
+       for (i = 0; i < object_table->ucNumberOfObjects; ++i) {
+
+               if (bracket_layout_id ==
+                       object_table->asObjects[i].usObjectID) {
+
+                       object = &object_table->asObjects[i];
+                       record_offset = object->usRecordOffset +
+                               bp->object_info_tbl_offset;
+
+                       result = update_slot_layout_info(dcb, i,
+                               slot_layout_info, record_offset);
+                       break;
+               }
+       }
+       return result;
+}
+
+static enum bp_result bios_get_board_layout_info(
+       struct dc_bios *dcb,
+       struct board_layout_info *board_layout_info)
+{
+       unsigned int i;
+       struct bios_parser *bp;
+       enum bp_result record_result;
+
+       const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
+               GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
+               GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
+               0, 0
+       };
+
+       bp = BP_FROM_DCB(dcb);
+       if (board_layout_info == NULL) {
+               DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
+               return BP_RESULT_BADINPUT;
+       }
+
+       board_layout_info->num_of_slots = 0;
+
+       for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
+               record_result = get_bracket_layout_record(dcb,
+                       slot_index_to_vbios_id[i],
+                       &board_layout_info->slots[i]);
+
+               if (record_result == BP_RESULT_NORECORD && i > 0)
+                       break; /* no more slots present in bios */
+               else if (record_result != BP_RESULT_OK)
+                       return record_result;  /* fail */
+
+               ++board_layout_info->num_of_slots;
+       }
+
+       /* all data is valid */
+       board_layout_info->is_number_of_slots_valid = 1;
+       board_layout_info->is_slots_size_valid = 1;
+       board_layout_info->is_connector_offsets_valid = 1;
+       board_layout_info->is_connector_lengths_valid = 1;
+
+       return BP_RESULT_OK;
+}
+
 /******************************************************************************/
 
 static const struct dc_vbios_funcs vbios_funcs = {
@@ -3836,6 +4030,8 @@ static const struct dc_vbios_funcs vbios_funcs = {
        .post_init = bios_parser_post_init,  /* patch vbios table for mxm module by reading i2c */
 
        .bios_parser_destroy = bios_parser_destroy,
+
+       .get_board_layout_info = bios_get_board_layout_info,
 };
 
 static bool bios_parser_construct(
index b8cef7af3c4afb4515757b09a3e3a6e521f6c3a0..aeb56e402cccfda8863b3fe177bf84873d1857c0 100644 (file)
 #include "bios_parser_interface.h"
 
 #include "bios_parser_common.h"
+
+/* Temporarily add in defines until ObjectID.h patch is updated in a few days */
+#ifndef GENERIC_OBJECT_ID_BRACKET_LAYOUT
+#define GENERIC_OBJECT_ID_BRACKET_LAYOUT          0x05
+#endif /* GENERIC_OBJECT_ID_BRACKET_LAYOUT */
+
+#ifndef GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1
+#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1  \
+       (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
+       GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+       GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT)
+#endif /* GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1 */
+
+#ifndef GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2
+#define GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2  \
+       (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\
+       GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+       GENERIC_OBJECT_ID_BRACKET_LAYOUT << OBJECT_ID_SHIFT)
+#endif /* GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2 */
+
+#define DC_LOGGER \
+       bp->base.ctx->logger
+
 #define LAST_RECORD_TYPE 0xff
 #define SMU9_SYSPLL0_ID  0
 
@@ -86,7 +109,6 @@ static struct atom_encoder_caps_record *get_encoder_cap_record(
 
 #define DATA_TABLES(table) (bp->master_data_tbl->listOfdatatables.table)
 
-
 static void destruct(struct bios_parser *bp)
 {
        kfree(bp->base.bios_local_image);
@@ -1854,6 +1876,198 @@ static struct integrated_info *bios_parser_create_integrated_info(
        return NULL;
 }
 
+static enum bp_result update_slot_layout_info(
+       struct dc_bios *dcb,
+       unsigned int i,
+       struct slot_layout_info *slot_layout_info)
+{
+       unsigned int record_offset;
+       unsigned int j;
+       struct atom_display_object_path_v2 *object;
+       struct atom_bracket_layout_record *record;
+       struct atom_common_record_header *record_header;
+       enum bp_result result;
+       struct bios_parser *bp;
+       struct object_info_table *tbl;
+       struct display_object_info_table_v1_4 *v1_4;
+
+       record = NULL;
+       record_header = NULL;
+       result = BP_RESULT_NORECORD;
+
+       bp = BP_FROM_DCB(dcb);
+       tbl = &bp->object_info_tbl;
+       v1_4 = tbl->v1_4;
+
+       object = &v1_4->display_path[i];
+       record_offset = (unsigned int)
+               (object->disp_recordoffset) +
+               (unsigned int)(bp->object_info_tbl_offset);
+
+       for (;;) {
+
+               record_header = (struct atom_common_record_header *)
+                       GET_IMAGE(struct atom_common_record_header,
+                       record_offset);
+               if (record_header == NULL) {
+                       result = BP_RESULT_BADBIOSTABLE;
+                       break;
+               }
+
+               /* the end of the list */
+               if (record_header->record_type == 0xff ||
+                       record_header->record_size == 0)        {
+                       break;
+               }
+
+               if (record_header->record_type ==
+                       ATOM_BRACKET_LAYOUT_RECORD_TYPE &&
+                       sizeof(struct atom_bracket_layout_record)
+                       <= record_header->record_size) {
+                       record = (struct atom_bracket_layout_record *)
+                               (record_header);
+                       result = BP_RESULT_OK;
+                       break;
+               }
+
+               record_offset += record_header->record_size;
+       }
+
+       /* return if the record not found */
+       if (result != BP_RESULT_OK)
+               return result;
+
+       /* get slot sizes */
+       slot_layout_info->length = record->bracketlen;
+       slot_layout_info->width = record->bracketwidth;
+
+       /* get info for each connector in the slot */
+       slot_layout_info->num_of_connectors = record->conn_num;
+       for (j = 0; j < slot_layout_info->num_of_connectors; ++j) {
+               slot_layout_info->connectors[j].connector_type =
+                       (enum connector_layout_type)
+                       (record->conn_info[j].connector_type);
+               switch (record->conn_info[j].connector_type) {
+               case CONNECTOR_TYPE_DVI_D:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_DVI_D;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_DVI;
+                       break;
+
+               case CONNECTOR_TYPE_HDMI:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_HDMI;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_HDMI;
+                       break;
+
+               case CONNECTOR_TYPE_DISPLAY_PORT:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_DP;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_DP;
+                       break;
+
+               case CONNECTOR_TYPE_MINI_DISPLAY_PORT:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_MINI_DP;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_MINI_DP;
+                       break;
+
+               default:
+                       slot_layout_info->connectors[j].connector_type =
+                               CONNECTOR_LAYOUT_TYPE_UNKNOWN;
+                       slot_layout_info->connectors[j].length =
+                               CONNECTOR_SIZE_UNKNOWN;
+               }
+
+               slot_layout_info->connectors[j].position =
+                       record->conn_info[j].position;
+               slot_layout_info->connectors[j].connector_id =
+                       object_id_from_bios_object_id(
+                               record->conn_info[j].connectorobjid);
+       }
+       return result;
+}
+
+
+static enum bp_result get_bracket_layout_record(
+       struct dc_bios *dcb,
+       unsigned int bracket_layout_id,
+       struct slot_layout_info *slot_layout_info)
+{
+       unsigned int i;
+       struct bios_parser *bp = BP_FROM_DCB(dcb);
+       enum bp_result result;
+       struct object_info_table *tbl;
+       struct display_object_info_table_v1_4 *v1_4;
+
+       if (slot_layout_info == NULL) {
+               DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n");
+               return BP_RESULT_BADINPUT;
+       }
+       tbl = &bp->object_info_tbl;
+       v1_4 = tbl->v1_4;
+
+       result = BP_RESULT_NORECORD;
+       for (i = 0; i < v1_4->number_of_path; ++i)      {
+
+               if (bracket_layout_id ==
+                       v1_4->display_path[i].display_objid) {
+                       result = update_slot_layout_info(dcb, i,
+                               slot_layout_info);
+                       break;
+               }
+       }
+       return result;
+}
+
+static enum bp_result bios_get_board_layout_info(
+       struct dc_bios *dcb,
+       struct board_layout_info *board_layout_info)
+{
+       unsigned int i;
+       struct bios_parser *bp;
+       enum bp_result record_result;
+
+       const unsigned int slot_index_to_vbios_id[MAX_BOARD_SLOTS] = {
+               GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID1,
+               GENERICOBJECT_BRACKET_LAYOUT_ENUM_ID2,
+               0, 0
+       };
+
+       bp = BP_FROM_DCB(dcb);
+       if (board_layout_info == NULL) {
+               DC_LOG_DETECTION_EDID_PARSER("Invalid board_layout_info\n");
+               return BP_RESULT_BADINPUT;
+       }
+
+       board_layout_info->num_of_slots = 0;
+
+       for (i = 0; i < MAX_BOARD_SLOTS; ++i) {
+               record_result = get_bracket_layout_record(dcb,
+                       slot_index_to_vbios_id[i],
+                       &board_layout_info->slots[i]);
+
+               if (record_result == BP_RESULT_NORECORD && i > 0)
+                       break; /* no more slots present in bios */
+               else if (record_result != BP_RESULT_OK)
+                       return record_result;  /* fail */
+
+               ++board_layout_info->num_of_slots;
+       }
+
+       /* all data is valid */
+       board_layout_info->is_number_of_slots_valid = 1;
+       board_layout_info->is_slots_size_valid = 1;
+       board_layout_info->is_connector_offsets_valid = 1;
+       board_layout_info->is_connector_lengths_valid = 1;
+
+       return BP_RESULT_OK;
+}
+
 static const struct dc_vbios_funcs vbios_funcs = {
        .get_connectors_number = bios_parser_get_connectors_number,
 
@@ -1925,6 +2139,8 @@ static const struct dc_vbios_funcs vbios_funcs = {
        .bios_parser_destroy = firmware_parser_destroy,
 
        .get_smu_clock_info = bios_parser_get_smu_clock_info,
+
+       .get_board_layout_info = bios_get_board_layout_info,
 };
 
 static bool bios_parser_construct(
index d9b84ec7954c511d599683772cf28e1be02e974b..90082bab71f072237c8e4dd63b2783c56f3aa91a 100644 (file)
@@ -198,6 +198,10 @@ struct dc_vbios_funcs {
        void (*post_init)(struct dc_bios *bios);
 
        void (*bios_parser_destroy)(struct dc_bios **dcb);
+
+       enum bp_result (*get_board_layout_info)(
+               struct dc_bios *dcb,
+               struct board_layout_info *board_layout_info);
 };
 
 struct bios_registers {
index 2941b882b0b6b266d40198a832abde05043204a4..58bb42ed85cab0b3540352e93351644403584872 100644 (file)
  * ********************************************************************
  */
 
+#define MAX_CONNECTOR_NUMBER_PER_SLOT  (16)
+#define MAX_BOARD_SLOTS                                        (4)
+#define INVALID_CONNECTOR_INDEX                        ((unsigned int)(-1))
+
 /* HPD unit id - HW direct translation */
 enum hpd_source_id {
        HPD_SOURCEID1 = 0,
@@ -136,5 +140,47 @@ enum sync_source {
        SYNC_SOURCE_DUAL_GPU_PIN
 };
 
+/* connector sizes in millimeters - from BiosParserTypes.hpp */
+#define CONNECTOR_SIZE_DVI                     40
+#define CONNECTOR_SIZE_VGA                     32
+#define CONNECTOR_SIZE_HDMI                    16
+#define CONNECTOR_SIZE_DP                      16
+#define CONNECTOR_SIZE_MINI_DP                 9
+#define CONNECTOR_SIZE_UNKNOWN                 30
+
+enum connector_layout_type {
+       CONNECTOR_LAYOUT_TYPE_UNKNOWN,
+       CONNECTOR_LAYOUT_TYPE_DVI_D,
+       CONNECTOR_LAYOUT_TYPE_DVI_I,
+       CONNECTOR_LAYOUT_TYPE_VGA,
+       CONNECTOR_LAYOUT_TYPE_HDMI,
+       CONNECTOR_LAYOUT_TYPE_DP,
+       CONNECTOR_LAYOUT_TYPE_MINI_DP,
+};
+struct connector_layout_info {
+       struct graphics_object_id connector_id;
+       enum connector_layout_type connector_type;
+       unsigned int length;
+       unsigned int position;  /* offset in mm from right side of the board */
+};
+
+/* length and width in mm */
+struct slot_layout_info {
+       unsigned int length;
+       unsigned int width;
+       unsigned int num_of_connectors;
+       struct connector_layout_info connectors[MAX_CONNECTOR_NUMBER_PER_SLOT];
+};
+
+struct board_layout_info {
+       unsigned int num_of_slots;
 
+       /* indicates valid information in bracket layout structure. */
+       unsigned int is_number_of_slots_valid : 1;
+       unsigned int is_slots_size_valid : 1;
+       unsigned int is_connector_offsets_valid : 1;
+       unsigned int is_connector_lengths_valid : 1;
+
+       struct slot_layout_info slots[MAX_BOARD_SLOTS];
+};
 #endif
index 92cc6c112ea6926653b005685bd796d8a46cb689..33b3d755fe655523d9486f5aff3f4e7901afb6a3 100644 (file)
@@ -292,4 +292,15 @@ static inline enum engine_id dal_graphics_object_id_get_engine_id(
                return (enum engine_id) id.id;
        return ENGINE_ID_UNKNOWN;
 }
+
+static inline bool dal_graphics_object_id_equal(
+       struct graphics_object_id id_1,
+       struct graphics_object_id id_2)
+{
+       if ((id_1.id == id_2.id) && (id_1.enum_id == id_2.enum_id) &&
+               (id_1.type == id_2.type)) {
+               return true;
+       }
+       return false;
+}
 #endif