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