drm/amd/display: get board layout for edid emulation

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>
This commit is contained in:
Samson Tam 2018-05-30 15:44:50 -04:00 committed by Alex Deucher
parent 7f93c1de64
commit 1eeedbcc20
5 changed files with 474 additions and 1 deletions

View 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(

View File

@ -43,6 +43,29 @@
#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(

View 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 {

View File

@ -37,6 +37,10 @@
* ********************************************************************
*/
#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

View 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