summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/bios
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/bios')
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/Makefile48
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser.c3871
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser.h33
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c1934
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser2.h33
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.c288
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.h33
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c82
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h40
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_interface.c56
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal.h72
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal2.h74
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table.c2424
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table.h102
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table2.c812
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table2.h105
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c290
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h90
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c265
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h82
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c364
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.h34
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c418
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.h34
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c418
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.h34
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.c354
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.h33
28 files changed, 12423 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/bios/Makefile b/drivers/gpu/drm/amd/display/dc/bios/Makefile
new file mode 100644
index 000000000000..239e86bbec5a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright 2017 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.
+#
+#
+# Makefile for the 'bios' sub-component of DAL.
+# It provides the parsing and executing controls for atom bios image.
+
+BIOS = bios_parser.o bios_parser_interface.o bios_parser_helper.o command_table.o command_table_helper.o bios_parser_common.o
+
+BIOS += command_table2.o command_table_helper2.o bios_parser2.o
+
+AMD_DAL_BIOS = $(addprefix $(AMDDALPATH)/dc/bios/,$(BIOS))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_BIOS)
+
+###############################################################################
+# DCE 8x
+###############################################################################
+# All DCE8.x are derived from DCE8.0, so 8.0 MUST be defined if ANY of
+# DCE8.x is compiled.
+AMD_DISPLAY_FILES += $(AMDDALPATH)/dc/bios/dce80/command_table_helper_dce80.o
+
+###############################################################################
+# DCE 11x
+###############################################################################
+AMD_DISPLAY_FILES += $(AMDDALPATH)/dc/bios/dce110/command_table_helper_dce110.o
+
+AMD_DISPLAY_FILES += $(AMDDALPATH)/dc/bios/dce112/command_table_helper_dce112.o
+
+AMD_DISPLAY_FILES += $(AMDDALPATH)/dc/bios/dce112/command_table_helper2_dce112.o
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
new file mode 100644
index 000000000000..86e6438c5cf3
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c
@@ -0,0 +1,3871 @@
+/*
+ * 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 "dc_bios_types.h"
+#include "include/gpio_service_interface.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_table.h"
+#include "bios_parser_helper.h"
+#include "command_table_helper.h"
+#include "bios_parser.h"
+#include "bios_parser_types_internal.h"
+#include "bios_parser_interface.h"
+
+#include "bios_parser_common.h"
+/* TODO remove - only needed for default i2c speed */
+#include "dc.h"
+
+#define THREE_PERCENT_OF_10000 300
+
+#define LAST_RECORD_TYPE 0xff
+
+/* GUID to validate external display connection info table (aka OPM module) */
+static const uint8_t ext_display_connection_guid[NUMBER_OF_UCHAR_FOR_GUID] = {
+ 0x91, 0x6E, 0x57, 0x09,
+ 0x3F, 0x6D, 0xD2, 0x11,
+ 0x39, 0x8E, 0x00, 0xA0,
+ 0xC9, 0x69, 0x72, 0x3B};
+
+#define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
+
+static void get_atom_data_table_revision(
+ ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
+ struct atom_data_revision *tbl_revision);
+static uint32_t get_dst_number_from_object(struct bios_parser *bp,
+ ATOM_OBJECT *object);
+static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
+ uint16_t **id_list);
+static uint32_t get_dest_obj_list(struct bios_parser *bp,
+ ATOM_OBJECT *object, uint16_t **id_list);
+static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
+ struct graphics_object_id id);
+static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
+ ATOM_I2C_RECORD *record,
+ struct graphics_object_i2c_info *info);
+static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
+ ATOM_OBJECT *object);
+static struct device_id device_type_from_device_id(uint16_t device_id);
+static uint32_t signal_to_ss_id(enum as_signal_type signal);
+static uint32_t get_support_mask_for_device_id(struct device_id device_id);
+static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
+ struct bios_parser *bp,
+ ATOM_OBJECT *object);
+
+#define BIOS_IMAGE_SIZE_OFFSET 2
+#define BIOS_IMAGE_SIZE_UNIT 512
+
+/*****************************************************************************/
+static bool bios_parser_construct(
+ struct bios_parser *bp,
+ struct bp_init_data *init,
+ enum dce_version dce_version);
+
+static uint8_t bios_parser_get_connectors_number(
+ struct dc_bios *dcb);
+
+static enum bp_result bios_parser_get_embedded_panel_info(
+ struct dc_bios *dcb,
+ struct embedded_panel_info *info);
+
+/*****************************************************************************/
+
+struct dc_bios *bios_parser_create(
+ struct bp_init_data *init,
+ enum dce_version dce_version)
+{
+ struct bios_parser *bp = NULL;
+
+ bp = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
+ if (!bp)
+ return NULL;
+
+ if (bios_parser_construct(bp, init, dce_version))
+ return &bp->base;
+
+ kfree(bp);
+ BREAK_TO_DEBUGGER();
+ return NULL;
+}
+
+static void destruct(struct bios_parser *bp)
+{
+ kfree(bp->base.bios_local_image);
+ kfree(bp->base.integrated_info);
+}
+
+static void bios_parser_destroy(struct dc_bios **dcb)
+{
+ struct bios_parser *bp = BP_FROM_DCB(*dcb);
+
+ if (!bp) {
+ BREAK_TO_DEBUGGER();
+ return;
+ }
+
+ destruct(bp);
+
+ kfree(bp);
+ *dcb = NULL;
+}
+
+static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
+{
+ ATOM_OBJECT_TABLE *table;
+
+ uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
+
+ table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
+
+ if (!table)
+ return 0;
+ else
+ return table->ucNumberOfObjects;
+}
+
+static uint8_t bios_parser_get_connectors_number(struct dc_bios *dcb)
+{
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+ return get_number_of_objects(bp,
+ le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
+}
+
+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);
+
+ uint32_t encoder_table_offset = bp->object_info_tbl_offset
+ + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
+
+ ATOM_OBJECT_TABLE *tbl =
+ GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
+
+ if (tbl && tbl->ucNumberOfObjects > i) {
+ const uint16_t id = le16_to_cpu(tbl->asObjects[i].usObjectID);
+
+ object_id = object_id_from_bios_object_id(id);
+ }
+
+ 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);
+
+ uint32_t connector_table_offset = bp->object_info_tbl_offset
+ + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
+
+ ATOM_OBJECT_TABLE *tbl =
+ GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
+
+ if (tbl && tbl->ucNumberOfObjects > i) {
+ const uint16_t id = le16_to_cpu(tbl->asObjects[i].usObjectID);
+
+ object_id = object_id_from_bios_object_id(id);
+ }
+
+ return object_id;
+}
+
+static uint32_t bios_parser_get_dst_number(struct dc_bios *dcb,
+ struct graphics_object_id id)
+{
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+ ATOM_OBJECT *object = get_bios_object(bp, id);
+
+ return get_dst_number_from_object(bp, object);
+}
+
+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)
+{
+ uint32_t number;
+ uint16_t *id;
+ ATOM_OBJECT *object;
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+ if (!src_object_id)
+ return BP_RESULT_BADINPUT;
+
+ object = get_bios_object(bp, object_id);
+
+ if (!object) {
+ BREAK_TO_DEBUGGER(); /* Invalid object id */
+ return BP_RESULT_BADINPUT;
+ }
+
+ number = get_src_obj_list(bp, object, &id);
+
+ if (number <= index)
+ return BP_RESULT_BADINPUT;
+
+ *src_object_id = object_id_from_bios_object_id(id[index]);
+
+ return BP_RESULT_OK;
+}
+
+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)
+{
+ uint32_t number;
+ uint16_t *id = NULL;
+ ATOM_OBJECT *object;
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+ if (!dest_object_id)
+ return BP_RESULT_BADINPUT;
+
+ object = get_bios_object(bp, object_id);
+
+ number = get_dest_obj_list(bp, object, &id);
+
+ if (number <= index || !id)
+ return BP_RESULT_BADINPUT;
+
+ *dest_object_id = object_id_from_bios_object_id(id[index]);
+
+ return BP_RESULT_OK;
+}
+
+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;
+ ATOM_OBJECT *object;
+ ATOM_COMMON_RECORD_HEADER *header;
+ 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 = le16_to_cpu(object->usRecordOffset)
+ + bp->object_info_tbl_offset;
+
+ for (;;) {
+ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
+
+ if (!header)
+ return BP_RESULT_BADBIOSTABLE;
+
+ if (LAST_RECORD_TYPE == header->ucRecordType ||
+ !header->ucRecordSize)
+ break;
+
+ if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
+ && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
+ /* get the I2C info */
+ record = (ATOM_I2C_RECORD *) header;
+
+ if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
+ return BP_RESULT_OK;
+ }
+
+ offset += header->ucRecordSize;
+ }
+
+ return BP_RESULT_NORECORD;
+}
+
+static enum bp_result get_voltage_ddc_info_v1(uint8_t *i2c_line,
+ ATOM_COMMON_TABLE_HEADER *header,
+ uint8_t *address)
+{
+ enum bp_result result = BP_RESULT_NORECORD;
+ ATOM_VOLTAGE_OBJECT_INFO *info =
+ (ATOM_VOLTAGE_OBJECT_INFO *) address;
+
+ uint8_t *voltage_current_object = (uint8_t *) &info->asVoltageObj[0];
+
+ while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
+ ATOM_VOLTAGE_OBJECT *object =
+ (ATOM_VOLTAGE_OBJECT *) voltage_current_object;
+
+ if ((object->ucVoltageType == SET_VOLTAGE_INIT_MODE) &&
+ (object->ucVoltageType &
+ VOLTAGE_CONTROLLED_BY_I2C_MASK)) {
+
+ *i2c_line = object->asControl.ucVoltageControlI2cLine
+ ^ 0x90;
+ result = BP_RESULT_OK;
+ break;
+ }
+
+ voltage_current_object += object->ucSize;
+ }
+ return result;
+}
+
+static enum bp_result get_voltage_ddc_info_v3(uint8_t *i2c_line,
+ uint32_t index,
+ ATOM_COMMON_TABLE_HEADER *header,
+ uint8_t *address)
+{
+ enum bp_result result = BP_RESULT_NORECORD;
+ ATOM_VOLTAGE_OBJECT_INFO_V3_1 *info =
+ (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *) address;
+
+ uint8_t *voltage_current_object =
+ (uint8_t *) (&(info->asVoltageObj[0]));
+
+ while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
+ ATOM_I2C_VOLTAGE_OBJECT_V3 *object =
+ (ATOM_I2C_VOLTAGE_OBJECT_V3 *) voltage_current_object;
+
+ if (object->sHeader.ucVoltageMode ==
+ ATOM_INIT_VOLTAGE_REGULATOR) {
+ if (object->sHeader.ucVoltageType == index) {
+ *i2c_line = object->ucVoltageControlI2cLine
+ ^ 0x90;
+ result = BP_RESULT_OK;
+ break;
+ }
+ }
+
+ voltage_current_object += le16_to_cpu(object->sHeader.usSize);
+ }
+ 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);
+ ATOM_I2C_ID_CONFIG_ACCESS *config;
+ ATOM_I2C_RECORD record;
+
+ if (!info)
+ return BP_RESULT_BADINPUT;
+
+ config = (ATOM_I2C_ID_CONFIG_ACCESS *) &i2c_channel_id;
+
+ record.sucI2cId.bfHW_Capable = config->sbfAccess.bfHW_Capable;
+ record.sucI2cId.bfI2C_LineMux = config->sbfAccess.bfI2C_LineMux;
+ record.sucI2cId.bfHW_EngineID = config->sbfAccess.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;
+ ATOM_COMMON_TABLE_HEADER *header;
+ struct atom_data_revision revision = {0};
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+ if (!DATA_TABLES(VoltageObjectInfo))
+ return result;
+
+ voltage_info_address = bios_get_image(&bp->base, DATA_TABLES(VoltageObjectInfo), sizeof(ATOM_COMMON_TABLE_HEADER));
+
+ header = (ATOM_COMMON_TABLE_HEADER *) voltage_info_address;
+
+ get_atom_data_table_revision(header, &revision);
+
+ switch (revision.major) {
+ case 1:
+ case 2:
+ result = get_voltage_ddc_info_v1(&i2c_line, header,
+ voltage_info_address);
+ break;
+ case 3:
+ if (revision.minor != 1)
+ break;
+ result = get_voltage_ddc_info_v3(&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;
+}
+
+/* TODO: temporary commented out to suppress 'defined but not used' warning */
+#if 0
+static enum bp_result bios_parser_get_ddc_info_for_i2c_line(
+ struct bios_parser *bp,
+ uint8_t i2c_line, struct graphics_object_i2c_info *info)
+{
+ uint32_t offset;
+ ATOM_OBJECT *object;
+ ATOM_OBJECT_TABLE *table;
+ uint32_t i;
+
+ if (!info)
+ return BP_RESULT_BADINPUT;
+
+ offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
+
+ offset += bp->object_info_tbl_offset;
+
+ table = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
+
+ if (!table)
+ return BP_RESULT_BADBIOSTABLE;
+
+ for (i = 0; i < table->ucNumberOfObjects; i++) {
+ object = &table->asObjects[i];
+
+ if (!object) {
+ BREAK_TO_DEBUGGER(); /* Invalid object id */
+ return BP_RESULT_BADINPUT;
+ }
+
+ offset = le16_to_cpu(object->usRecordOffset)
+ + bp->object_info_tbl_offset;
+
+ for (;;) {
+ ATOM_COMMON_RECORD_HEADER *header =
+ GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
+
+ if (!header)
+ return BP_RESULT_BADBIOSTABLE;
+
+ offset += header->ucRecordSize;
+
+ if (LAST_RECORD_TYPE == header->ucRecordType ||
+ !header->ucRecordSize)
+ break;
+
+ if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
+ && sizeof(ATOM_I2C_RECORD) <=
+ header->ucRecordSize) {
+ ATOM_I2C_RECORD *record =
+ (ATOM_I2C_RECORD *) header;
+
+ if (i2c_line != record->sucI2cId.bfI2C_LineMux)
+ continue;
+
+ /* get the I2C info */
+ if (get_gpio_i2c_info(bp, record, info) ==
+ BP_RESULT_OK)
+ return BP_RESULT_OK;
+ }
+ }
+ }
+
+ return BP_RESULT_NORECORD;
+}
+#endif
+
+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);
+ ATOM_OBJECT *object;
+ 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->ucHPDIntGPIOID;
+ info->hpd_active = record->ucPlugged_PinState;
+ return BP_RESULT_OK;
+ }
+
+ return BP_RESULT_NORECORD;
+}
+
+static enum bp_result bios_parser_get_device_tag_record(
+ struct bios_parser *bp,
+ ATOM_OBJECT *object,
+ ATOM_CONNECTOR_DEVICE_TAG_RECORD **record)
+{
+ ATOM_COMMON_RECORD_HEADER *header;
+ uint32_t offset;
+
+ offset = le16_to_cpu(object->usRecordOffset)
+ + bp->object_info_tbl_offset;
+
+ for (;;) {
+ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
+
+ if (!header)
+ return BP_RESULT_BADBIOSTABLE;
+
+ offset += header->ucRecordSize;
+
+ if (LAST_RECORD_TYPE == header->ucRecordType ||
+ !header->ucRecordSize)
+ break;
+
+ if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
+ header->ucRecordType)
+ continue;
+
+ if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
+ continue;
+
+ *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
+ return BP_RESULT_OK;
+ }
+
+ return BP_RESULT_NORECORD;
+}
+
+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);
+ ATOM_OBJECT *object;
+ ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
+ ATOM_CONNECTOR_DEVICE_TAG *device_tag;
+
+ 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;
+ }
+
+ if (bios_parser_get_device_tag_record(bp, object, &record)
+ != BP_RESULT_OK)
+ return BP_RESULT_NORECORD;
+
+ if (device_tag_index >= record->ucNumberOfDevice)
+ return BP_RESULT_NORECORD;
+
+ device_tag = &record->asDeviceTag[device_tag_index];
+
+ info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
+ info->dev_id =
+ device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
+
+ return BP_RESULT_OK;
+}
+
+static enum bp_result get_firmware_info_v1_4(
+ struct bios_parser *bp,
+ struct dc_firmware_info *info);
+static enum bp_result get_firmware_info_v2_1(
+ struct bios_parser *bp,
+ struct dc_firmware_info *info);
+static enum bp_result get_firmware_info_v2_2(
+ struct bios_parser *bp,
+ struct dc_firmware_info *info);
+
+static enum bp_result bios_parser_get_firmware_info(
+ struct dc_bios *dcb,
+ struct dc_firmware_info *info)
+{
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+ enum bp_result result = BP_RESULT_BADBIOSTABLE;
+ ATOM_COMMON_TABLE_HEADER *header;
+ struct atom_data_revision revision;
+
+ if (info && DATA_TABLES(FirmwareInfo)) {
+ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
+ DATA_TABLES(FirmwareInfo));
+ get_atom_data_table_revision(header, &revision);
+ switch (revision.major) {
+ case 1:
+ switch (revision.minor) {
+ case 4:
+ result = get_firmware_info_v1_4(bp, info);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case 2:
+ switch (revision.minor) {
+ case 1:
+ result = get_firmware_info_v2_1(bp, info);
+ break;
+ case 2:
+ result = get_firmware_info_v2_2(bp, info);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return result;
+}
+
+static enum bp_result get_firmware_info_v1_4(
+ struct bios_parser *bp,
+ struct dc_firmware_info *info)
+{
+ ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
+ GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
+ DATA_TABLES(FirmwareInfo));
+
+ if (!info)
+ return BP_RESULT_BADINPUT;
+
+ if (!firmware_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->pll_info.crystal_frequency =
+ le16_to_cpu(firmware_info->usReferenceClock) * 10;
+ info->pll_info.min_input_pxl_clk_pll_frequency =
+ le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
+ info->pll_info.max_input_pxl_clk_pll_frequency =
+ le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
+ info->pll_info.min_output_pxl_clk_pll_frequency =
+ le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
+ info->pll_info.max_output_pxl_clk_pll_frequency =
+ le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
+
+ if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
+ /* Since there is no information on the SS, report conservative
+ * value 3% for bandwidth calculation */
+ /* unit of 0.01% */
+ info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
+
+ if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
+ /* Since there is no information on the SS,report conservative
+ * value 3% for bandwidth calculation */
+ /* unit of 0.01% */
+ info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
+
+ return BP_RESULT_OK;
+}
+
+static enum bp_result get_ss_info_v3_1(
+ struct bios_parser *bp,
+ uint32_t id,
+ uint32_t index,
+ struct spread_spectrum_info *ss_info);
+
+static enum bp_result get_firmware_info_v2_1(
+ struct bios_parser *bp,
+ struct dc_firmware_info *info)
+{
+ ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
+ GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
+ struct spread_spectrum_info internalSS;
+ uint32_t index;
+
+ if (!info)
+ return BP_RESULT_BADINPUT;
+
+ if (!firmwareInfo)
+ return BP_RESULT_BADBIOSTABLE;
+
+ memset(info, 0, sizeof(*info));
+
+ /* Pixel clock pll information. We need to convert from 10KHz units into
+ * KHz units */
+ info->pll_info.crystal_frequency =
+ le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
+ info->pll_info.min_input_pxl_clk_pll_frequency =
+ le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
+ info->pll_info.max_input_pxl_clk_pll_frequency =
+ le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
+ info->pll_info.min_output_pxl_clk_pll_frequency =
+ le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
+ info->pll_info.max_output_pxl_clk_pll_frequency =
+ le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
+ info->default_display_engine_pll_frequency =
+ le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
+ info->external_clock_source_frequency_for_dp =
+ le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
+ info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
+
+ /* There should be only one entry in the SS info table for Memory Clock
+ */
+ index = 0;
+ if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
+ /* Since there is no information for external SS, report
+ * conservative value 3% for bandwidth calculation */
+ /* unit of 0.01% */
+ info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
+ else if (get_ss_info_v3_1(bp,
+ ASIC_INTERNAL_MEMORY_SS, index, &internalSS) == BP_RESULT_OK) {
+ if (internalSS.spread_spectrum_percentage) {
+ info->feature.memory_clk_ss_percentage =
+ internalSS.spread_spectrum_percentage;
+ if (internalSS.type.CENTER_MODE) {
+ /* if it is centermode, the exact SS Percentage
+ * will be round up of half of the percentage
+ * reported in the SS table */
+ ++info->feature.memory_clk_ss_percentage;
+ info->feature.memory_clk_ss_percentage /= 2;
+ }
+ }
+ }
+
+ /* There should be only one entry in the SS info table for Engine Clock
+ */
+ index = 1;
+ if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
+ /* Since there is no information for external SS, report
+ * conservative value 3% for bandwidth calculation */
+ /* unit of 0.01% */
+ info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
+ else if (get_ss_info_v3_1(bp,
+ ASIC_INTERNAL_ENGINE_SS, index, &internalSS) == BP_RESULT_OK) {
+ if (internalSS.spread_spectrum_percentage) {
+ info->feature.engine_clk_ss_percentage =
+ internalSS.spread_spectrum_percentage;
+ if (internalSS.type.CENTER_MODE) {
+ /* if it is centermode, the exact SS Percentage
+ * will be round up of half of the percentage
+ * reported in the SS table */
+ ++info->feature.engine_clk_ss_percentage;
+ info->feature.engine_clk_ss_percentage /= 2;
+ }
+ }
+ }
+
+ return BP_RESULT_OK;
+}
+
+static enum bp_result get_firmware_info_v2_2(
+ struct bios_parser *bp,
+ struct dc_firmware_info *info)
+{
+ ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
+ struct spread_spectrum_info internal_ss;
+ uint32_t index;
+
+ if (!info)
+ return BP_RESULT_BADINPUT;
+
+ firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
+ DATA_TABLES(FirmwareInfo));
+
+ if (!firmware_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->pll_info.crystal_frequency =
+ le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
+ info->pll_info.min_input_pxl_clk_pll_frequency =
+ le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
+ info->pll_info.max_input_pxl_clk_pll_frequency =
+ le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
+ info->pll_info.min_output_pxl_clk_pll_frequency =
+ le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
+ info->pll_info.max_output_pxl_clk_pll_frequency =
+ le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
+ info->default_display_engine_pll_frequency =
+ le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
+ info->external_clock_source_frequency_for_dp =
+ le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
+
+ /* There should be only one entry in the SS info table for Memory Clock
+ */
+ index = 0;
+ if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
+ /* Since there is no information for external SS, report
+ * conservative value 3% for bandwidth calculation */
+ /* unit of 0.01% */
+ info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
+ else if (get_ss_info_v3_1(bp,
+ ASIC_INTERNAL_MEMORY_SS, index, &internal_ss) == BP_RESULT_OK) {
+ if (internal_ss.spread_spectrum_percentage) {
+ info->feature.memory_clk_ss_percentage =
+ internal_ss.spread_spectrum_percentage;
+ if (internal_ss.type.CENTER_MODE) {
+ /* if it is centermode, the exact SS Percentage
+ * will be round up of half of the percentage
+ * reported in the SS table */
+ ++info->feature.memory_clk_ss_percentage;
+ info->feature.memory_clk_ss_percentage /= 2;
+ }
+ }
+ }
+
+ /* There should be only one entry in the SS info table for Engine Clock
+ */
+ index = 1;
+ if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
+ /* Since there is no information for external SS, report
+ * conservative value 3% for bandwidth calculation */
+ /* unit of 0.01% */
+ info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
+ else if (get_ss_info_v3_1(bp,
+ ASIC_INTERNAL_ENGINE_SS, index, &internal_ss) == BP_RESULT_OK) {
+ if (internal_ss.spread_spectrum_percentage) {
+ info->feature.engine_clk_ss_percentage =
+ internal_ss.spread_spectrum_percentage;
+ if (internal_ss.type.CENTER_MODE) {
+ /* if it is centermode, the exact SS Percentage
+ * will be round up of half of the percentage
+ * reported in the SS table */
+ ++info->feature.engine_clk_ss_percentage;
+ info->feature.engine_clk_ss_percentage /= 2;
+ }
+ }
+ }
+
+ /* Remote Display */
+ info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
+
+ /* Is allowed minimum BL level */
+ info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
+ /* Used starting from CI */
+ info->smu_gpu_pll_output_freq =
+ (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
+
+ return BP_RESULT_OK;
+}
+
+static enum bp_result get_ss_info_v3_1(
+ struct bios_parser *bp,
+ uint32_t id,
+ uint32_t index,
+ struct spread_spectrum_info *ss_info)
+{
+ ATOM_ASIC_INTERNAL_SS_INFO_V3 *ss_table_header_include;
+ ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
+ uint32_t table_size;
+ uint32_t i;
+ uint32_t table_index = 0;
+
+ if (!ss_info)
+ return BP_RESULT_BADINPUT;
+
+ if (!DATA_TABLES(ASIC_InternalSS_Info))
+ return BP_RESULT_UNSUPPORTED;
+
+ ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
+ DATA_TABLES(ASIC_InternalSS_Info));
+ table_size =
+ (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
+ - sizeof(ATOM_COMMON_TABLE_HEADER))
+ / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
+
+ tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
+ &ss_table_header_include->asSpreadSpectrum[0];
+
+ memset(ss_info, 0, sizeof(struct spread_spectrum_info));
+
+ for (i = 0; i < table_size; i++) {
+ if (tbl[i].ucClockIndication != (uint8_t) id)
+ continue;
+
+ if (table_index != index) {
+ table_index++;
+ continue;
+ }
+ /* VBIOS introduced new defines for Version 3, same values as
+ * before, so now use these new ones for Version 3.
+ * Shouldn't affect field VBIOS's V3 as define values are still
+ * same.
+ * #define SS_MODE_V3_CENTRE_SPREAD_MASK 0x01
+ * #define SS_MODE_V3_EXTERNAL_SS_MASK 0x02
+
+ * Old VBIOS defines:
+ * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
+ * #define ATOM_EXTERNAL_SS_MASK 0x00000002
+ */
+
+ if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
+ ss_info->type.EXTERNAL = true;
+
+ if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
+ ss_info->type.CENTER_MODE = true;
+
+ /* Older VBIOS (in field) always provides SS percentage in 0.01%
+ * units set Divider to 100 */
+ ss_info->spread_percentage_divider = 100;
+
+ /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
+ if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
+ & tbl[i].ucSpreadSpectrumMode)
+ ss_info->spread_percentage_divider = 1000;
+
+ ss_info->type.STEP_AND_DELAY_INFO = false;
+ /* convert [10KHz] into [KHz] */
+ ss_info->target_clock_range =
+ le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
+ ss_info->spread_spectrum_percentage =
+ (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
+ ss_info->spread_spectrum_range =
+ (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
+
+ return BP_RESULT_OK;
+ }
+ return BP_RESULT_NORECORD;
+}
+
+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_adjust_pixel_clock(
+ struct dc_bios *dcb,
+ struct bp_adjust_pixel_clock_parameters *bp_params)
+{
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+ if (!bp->cmd_tbl.adjust_display_pll)
+ return BP_RESULT_FAILURE;
+
+ return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
+}
+
+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 enum bp_result bios_parser_enable_spread_spectrum_on_ppll(
+ struct dc_bios *dcb,
+ struct bp_spread_spectrum_parameters *bp_params,
+ bool enable)
+{
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+ if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
+ return BP_RESULT_FAILURE;
+
+ return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
+ bp, bp_params, enable);
+
+}
+
+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_program_display_engine_pll(
+ struct dc_bios *dcb,
+ struct bp_pixel_clock_parameters *bp_params)
+{
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+ if (!bp->cmd_tbl.program_clock)
+ return BP_RESULT_FAILURE;
+
+ return bp->cmd_tbl.program_clock(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_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_1->usDeviceSupport) & mask) != 0;
+}
+
+static enum bp_result bios_parser_crt_control(
+ struct dc_bios *dcb,
+ enum engine_id engine_id,
+ bool enable,
+ uint32_t pixel_clock)
+{
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+ uint8_t standard;
+
+ if (!bp->cmd_tbl.dac1_encoder_control &&
+ engine_id == ENGINE_ID_DACA)
+ return BP_RESULT_FAILURE;
+ if (!bp->cmd_tbl.dac2_encoder_control &&
+ engine_id == ENGINE_ID_DACB)
+ return BP_RESULT_FAILURE;
+ /* validate params */
+ switch (engine_id) {
+ case ENGINE_ID_DACA:
+ case ENGINE_ID_DACB:
+ break;
+ default:
+ /* unsupported engine */
+ return BP_RESULT_FAILURE;
+ }
+
+ standard = ATOM_DAC1_PS2; /* == ATOM_DAC2_PS2 */
+
+ if (enable) {
+ if (engine_id == ENGINE_ID_DACA) {
+ bp->cmd_tbl.dac1_encoder_control(bp, enable,
+ pixel_clock, standard);
+ if (bp->cmd_tbl.dac1_output_control != NULL)
+ bp->cmd_tbl.dac1_output_control(bp, enable);
+ } else {
+ bp->cmd_tbl.dac2_encoder_control(bp, enable,
+ pixel_clock, standard);
+ if (bp->cmd_tbl.dac2_output_control != NULL)
+ bp->cmd_tbl.dac2_output_control(bp, enable);
+ }
+ } else {
+ if (engine_id == ENGINE_ID_DACA) {
+ if (bp->cmd_tbl.dac1_output_control != NULL)
+ bp->cmd_tbl.dac1_output_control(bp, enable);
+ bp->cmd_tbl.dac1_encoder_control(bp, enable,
+ pixel_clock, standard);
+ } else {
+ if (bp->cmd_tbl.dac2_output_control != NULL)
+ bp->cmd_tbl.dac2_output_control(bp, enable);
+ bp->cmd_tbl.dac2_encoder_control(bp, enable,
+ pixel_clock, standard);
+ }
+ }
+
+ return BP_RESULT_OK;
+}
+
+static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
+ ATOM_OBJECT *object)
+{
+ ATOM_COMMON_RECORD_HEADER *header;
+ uint32_t offset;
+
+ if (!object) {
+ BREAK_TO_DEBUGGER(); /* Invalid object */
+ return NULL;
+ }
+
+ offset = le16_to_cpu(object->usRecordOffset)
+ + bp->object_info_tbl_offset;
+
+ for (;;) {
+ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
+
+ if (!header)
+ return NULL;
+
+ if (LAST_RECORD_TYPE == header->ucRecordType ||
+ !header->ucRecordSize)
+ break;
+
+ if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
+ && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
+ return (ATOM_HPD_INT_RECORD *) header;
+
+ offset += header->ucRecordSize;
+ }
+
+ return NULL;
+}
+
+/**
+ * Get I2C information of input object id
+ *
+ * search all records to find the ATOM_I2C_RECORD_TYPE record IR
+ */
+static ATOM_I2C_RECORD *get_i2c_record(
+ struct bios_parser *bp,
+ ATOM_OBJECT *object)
+{
+ uint32_t offset;
+ ATOM_COMMON_RECORD_HEADER *record_header;
+
+ if (!object) {
+ BREAK_TO_DEBUGGER();
+ /* Invalid object */
+ return NULL;
+ }
+
+ offset = le16_to_cpu(object->usRecordOffset)
+ + bp->object_info_tbl_offset;
+
+ for (;;) {
+ record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
+
+ if (!record_header)
+ return NULL;
+
+ if (LAST_RECORD_TYPE == record_header->ucRecordType ||
+ 0 == record_header->ucRecordSize)
+ break;
+
+ if (ATOM_I2C_RECORD_TYPE == record_header->ucRecordType &&
+ sizeof(ATOM_I2C_RECORD) <=
+ record_header->ucRecordSize) {
+ return (ATOM_I2C_RECORD *)record_header;
+ }
+
+ offset += record_header->ucRecordSize;
+ }
+
+ return NULL;
+}
+
+static enum bp_result get_ss_info_from_ss_info_table(
+ struct bios_parser *bp,
+ uint32_t id,
+ struct spread_spectrum_info *ss_info);
+static enum bp_result get_ss_info_from_tbl(
+ struct bios_parser *bp,
+ uint32_t id,
+ struct spread_spectrum_info *ss_info);
+/**
+ * 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;
+ uint32_t clk_id_ss = 0;
+ ATOM_COMMON_TABLE_HEADER *header;
+ struct atom_data_revision tbl_revision;
+
+ if (!ss_info) /* check for bad input */
+ return BP_RESULT_BADINPUT;
+ /* signal translation */
+ clk_id_ss = signal_to_ss_id(signal);
+
+ if (!DATA_TABLES(ASIC_InternalSS_Info))
+ if (!index)
+ return get_ss_info_from_ss_info_table(bp, clk_id_ss,
+ ss_info);
+
+ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
+ DATA_TABLES(ASIC_InternalSS_Info));
+ get_atom_data_table_revision(header, &tbl_revision);
+
+ switch (tbl_revision.major) {
+ case 2:
+ switch (tbl_revision.minor) {
+ case 1:
+ /* there can not be more then one entry for Internal
+ * SS Info table version 2.1 */
+ if (!index)
+ return get_ss_info_from_tbl(bp, clk_id_ss,
+ ss_info);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case 3:
+ switch (tbl_revision.minor) {
+ case 1:
+ return get_ss_info_v3_1(bp, clk_id_ss, 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_ss_info_from_internal_ss_info_tbl_V2_1(
+ struct bios_parser *bp,
+ uint32_t id,
+ struct spread_spectrum_info *info);
+
+/**
+ * get_ss_info_from_table
+ * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
+ * SS_Info table from the VBIOS
+ * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
+ * SS_Info.
+ *
+ * @param this
+ * @param id, spread sprectrum info index
+ * @param pSSinfo, sprectrum information structure,
+ * @return Bios parser result code
+ */
+static enum bp_result get_ss_info_from_tbl(
+ struct bios_parser *bp,
+ uint32_t id,
+ struct spread_spectrum_info *ss_info)
+{
+ if (!ss_info) /* check for bad input, if ss_info is not NULL */
+ return BP_RESULT_BADINPUT;
+ /* for SS_Info table only support DP and LVDS */
+ if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
+ return get_ss_info_from_ss_info_table(bp, id, ss_info);
+ else
+ return get_ss_info_from_internal_ss_info_tbl_V2_1(bp, id,
+ ss_info);
+}
+
+/**
+ * get_ss_info_from_internal_ss_info_tbl_V2_1
+ * Get spread sprectrum information from the ASIC_InternalSS_Info table Ver 2.1
+ * from the VBIOS
+ * There will not be multiple entry for Ver 2.1
+ *
+ * @param id, spread sprectrum info index
+ * @param pSSinfo, sprectrum information structure,
+ * @return Bios parser result code
+ */
+static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
+ struct bios_parser *bp,
+ uint32_t id,
+ struct spread_spectrum_info *info)
+{
+ enum bp_result result = BP_RESULT_UNSUPPORTED;
+ ATOM_ASIC_INTERNAL_SS_INFO_V2 *header;
+ ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
+ uint32_t tbl_size, i;
+
+ if (!DATA_TABLES(ASIC_InternalSS_Info))
+ return result;
+
+ header = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
+ DATA_TABLES(ASIC_InternalSS_Info));
+
+ memset(info, 0, sizeof(struct spread_spectrum_info));
+
+ tbl_size = (le16_to_cpu(header->sHeader.usStructureSize)
+ - sizeof(ATOM_COMMON_TABLE_HEADER))
+ / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
+
+ tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
+ &(header->asSpreadSpectrum[0]);
+ for (i = 0; i < tbl_size; i++) {
+ result = BP_RESULT_NORECORD;
+
+ if (tbl[i].ucClockIndication != (uint8_t)id)
+ continue;
+
+ if (ATOM_EXTERNAL_SS_MASK
+ & tbl[i].ucSpreadSpectrumMode) {
+ info->type.EXTERNAL = true;
+ }
+ if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
+ & tbl[i].ucSpreadSpectrumMode) {
+ info->type.CENTER_MODE = true;
+ }
+ info->type.STEP_AND_DELAY_INFO = false;
+ /* convert [10KHz] into [KHz] */
+ info->target_clock_range =
+ le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
+ info->spread_spectrum_percentage =
+ (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
+ info->spread_spectrum_range =
+ (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
+ result = BP_RESULT_OK;
+ break;
+ }
+
+ return result;
+
+}
+
+/**
+ * get_ss_info_from_ss_info_table
+ * Get spread sprectrum information from the SS_Info table from the VBIOS
+ * if the pointer to info is NULL, indicate the caller what to know the number
+ * of entries that matches the id
+ * for, the SS_Info table, there should not be more than 1 entry match.
+ *
+ * @param [in] id, spread sprectrum id
+ * @param [out] pSSinfo, sprectrum information structure,
+ * @return Bios parser result code
+ */
+static enum bp_result get_ss_info_from_ss_info_table(
+ struct bios_parser *bp,
+ uint32_t id,
+ struct spread_spectrum_info *ss_info)
+{
+ enum bp_result result = BP_RESULT_UNSUPPORTED;
+ ATOM_SPREAD_SPECTRUM_INFO *tbl;
+ ATOM_COMMON_TABLE_HEADER *header;
+ uint32_t table_size;
+ uint32_t i;
+ uint32_t id_local = SS_ID_UNKNOWN;
+ struct atom_data_revision revision;
+
+ /* exist of the SS_Info table */
+ /* check for bad input, pSSinfo can not be NULL */
+ if (!DATA_TABLES(SS_Info) || !ss_info)
+ return result;
+
+ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(SS_Info));
+ get_atom_data_table_revision(header, &revision);
+
+ tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info));
+
+ if (1 != revision.major || 2 > revision.minor)
+ return result;
+
+ /* have to convert from Internal_SS format to SS_Info format */
+ switch (id) {
+ case ASIC_INTERNAL_SS_ON_DP:
+ id_local = SS_ID_DP1;
+ break;
+ case ASIC_INTERNAL_SS_ON_LVDS:
+ {
+ struct embedded_panel_info panel_info;
+
+ if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
+ == BP_RESULT_OK)
+ id_local = panel_info.ss_id;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (id_local == SS_ID_UNKNOWN)
+ return result;
+
+ table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
+ sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
+
+ for (i = 0; i < table_size; i++) {
+ if (id_local != (uint32_t)tbl->asSS_Info[i].ucSS_Id)
+ continue;
+
+ memset(ss_info, 0, sizeof(struct spread_spectrum_info));
+
+ if (ATOM_EXTERNAL_SS_MASK &
+ tbl->asSS_Info[i].ucSpreadSpectrumType)
+ ss_info->type.EXTERNAL = true;
+
+ if (ATOM_SS_CENTRE_SPREAD_MODE_MASK &
+ tbl->asSS_Info[i].ucSpreadSpectrumType)
+ ss_info->type.CENTER_MODE = true;
+
+ ss_info->type.STEP_AND_DELAY_INFO = true;
+ ss_info->spread_spectrum_percentage =
+ (uint32_t)le16_to_cpu(tbl->asSS_Info[i].usSpreadSpectrumPercentage);
+ ss_info->step_and_delay_info.step = tbl->asSS_Info[i].ucSS_Step;
+ ss_info->step_and_delay_info.delay =
+ tbl->asSS_Info[i].ucSS_Delay;
+ ss_info->step_and_delay_info.recommended_ref_div =
+ tbl->asSS_Info[i].ucRecommendedRef_Div;
+ ss_info->spread_spectrum_range =
+ (uint32_t)tbl->asSS_Info[i].ucSS_Range * 10000;
+
+ /* there will be only one entry for each display type in SS_info
+ * table */
+ result = BP_RESULT_OK;
+ break;
+ }
+
+ return result;
+}
+static enum bp_result get_embedded_panel_info_v1_2(
+ struct bios_parser *bp,
+ struct embedded_panel_info *info);
+static enum bp_result get_embedded_panel_info_v1_3(
+ struct bios_parser *bp,
+ struct embedded_panel_info *info);
+
+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);
+ ATOM_COMMON_TABLE_HEADER *hdr;
+
+ if (!DATA_TABLES(LCD_Info))
+ return BP_RESULT_FAILURE;
+
+ hdr = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(LCD_Info));
+
+ if (!hdr)
+ return BP_RESULT_BADBIOSTABLE;
+
+ switch (hdr->ucTableFormatRevision) {
+ case 1:
+ switch (hdr->ucTableContentRevision) {
+ case 0:
+ case 1:
+ case 2:
+ return get_embedded_panel_info_v1_2(bp, info);
+ case 3:
+ return get_embedded_panel_info_v1_3(bp, info);
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ return BP_RESULT_FAILURE;
+}
+
+static enum bp_result get_embedded_panel_info_v1_2(
+ struct bios_parser *bp,
+ struct embedded_panel_info *info)
+{
+ ATOM_LVDS_INFO_V12 *lvds;
+
+ if (!info)
+ return BP_RESULT_BADINPUT;
+
+ if (!DATA_TABLES(LVDS_Info))
+ return BP_RESULT_UNSUPPORTED;
+
+ lvds =
+ GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
+
+ if (!lvds)
+ return BP_RESULT_BADBIOSTABLE;
+
+ if (1 != lvds->sHeader.ucTableFormatRevision
+ || 2 > lvds->sHeader.ucTableContentRevision)
+ 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->sLCDTiming.usPixClk) * 10;
+ /* usHActive does not include borders, according to VBIOS team*/
+ info->lcd_timing.horizontal_addressable =
+ le16_to_cpu(lvds->sLCDTiming.usHActive);
+ /* usHBlanking_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.horizontal_blanking_time =
+ le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
+ /* usVActive does not include borders, according to VBIOS team*/
+ info->lcd_timing.vertical_addressable =
+ le16_to_cpu(lvds->sLCDTiming.usVActive);
+ /* 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->sLCDTiming.usVBlanking_Time);
+ info->lcd_timing.horizontal_sync_offset =
+ le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
+ info->lcd_timing.horizontal_sync_width =
+ le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
+ info->lcd_timing.vertical_sync_offset =
+ le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
+ info->lcd_timing.vertical_sync_width =
+ le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
+ info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
+ info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
+ info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
+ info->lcd_timing.misc_info.H_SYNC_POLARITY =
+ ~(uint32_t)
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
+ info->lcd_timing.misc_info.V_SYNC_POLARITY =
+ ~(uint32_t)
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
+ info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
+ info->lcd_timing.misc_info.H_REPLICATION_BY2 =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
+ info->lcd_timing.misc_info.V_REPLICATION_BY2 =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
+ info->lcd_timing.misc_info.COMPOSITE_SYNC =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
+ info->lcd_timing.misc_info.INTERLACE =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
+ info->lcd_timing.misc_info.DOUBLE_CLOCK =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
+ info->ss_id = lvds->ucSS_Id;
+
+ {
+ uint8_t rr = le16_to_cpu(lvds->usSupportedRefreshRate);
+ /* Get minimum supported refresh rate*/
+ if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
+ info->supported_rr.REFRESH_RATE_30HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
+ info->supported_rr.REFRESH_RATE_40HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
+ info->supported_rr.REFRESH_RATE_48HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
+ info->supported_rr.REFRESH_RATE_50HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
+ info->supported_rr.REFRESH_RATE_60HZ = 1;
+ }
+
+ /*Drr panel support can be reported by VBIOS*/
+ if (LCDPANEL_CAP_DRR_SUPPORTED
+ & lvds->ucLCDPanel_SpecialHandlingCap)
+ info->drr_enabled = 1;
+
+ if (ATOM_PANEL_MISC_DUAL & lvds->ucLVDS_Misc)
+ info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
+
+ if (ATOM_PANEL_MISC_888RGB & lvds->ucLVDS_Misc)
+ info->lcd_timing.misc_info.RGB888 = true;
+
+ info->lcd_timing.misc_info.GREY_LEVEL =
+ (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL &
+ lvds->ucLVDS_Misc) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT;
+
+ if (ATOM_PANEL_MISC_SPATIAL & lvds->ucLVDS_Misc)
+ info->lcd_timing.misc_info.SPATIAL = true;
+
+ if (ATOM_PANEL_MISC_TEMPORAL & lvds->ucLVDS_Misc)
+ info->lcd_timing.misc_info.TEMPORAL = true;
+
+ if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
+ info->lcd_timing.misc_info.API_ENABLED = true;
+
+ return BP_RESULT_OK;
+}
+
+static enum bp_result get_embedded_panel_info_v1_3(
+ struct bios_parser *bp,
+ struct embedded_panel_info *info)
+{
+ ATOM_LCD_INFO_V13 *lvds;
+
+ if (!info)
+ return BP_RESULT_BADINPUT;
+
+ if (!DATA_TABLES(LCD_Info))
+ return BP_RESULT_UNSUPPORTED;
+
+ lvds = GET_IMAGE(ATOM_LCD_INFO_V13, DATA_TABLES(LCD_Info));
+
+ if (!lvds)
+ return BP_RESULT_BADBIOSTABLE;
+
+ if (!((1 == lvds->sHeader.ucTableFormatRevision)
+ && (3 <= lvds->sHeader.ucTableContentRevision)))
+ 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->sLCDTiming.usPixClk) * 10;
+ /* usHActive does not include borders, according to VBIOS team */
+ info->lcd_timing.horizontal_addressable =
+ le16_to_cpu(lvds->sLCDTiming.usHActive);
+ /* usHBlanking_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.horizontal_blanking_time =
+ le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
+ /* usVActive does not include borders, according to VBIOS team*/
+ info->lcd_timing.vertical_addressable =
+ le16_to_cpu(lvds->sLCDTiming.usVActive);
+ /* 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->sLCDTiming.usVBlanking_Time);
+ info->lcd_timing.horizontal_sync_offset =
+ le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
+ info->lcd_timing.horizontal_sync_width =
+ le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
+ info->lcd_timing.vertical_sync_offset =
+ le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
+ info->lcd_timing.vertical_sync_width =
+ le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
+ info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
+ info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
+ info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
+ info->lcd_timing.misc_info.H_SYNC_POLARITY =
+ ~(uint32_t)
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
+ info->lcd_timing.misc_info.V_SYNC_POLARITY =
+ ~(uint32_t)
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
+ info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
+ info->lcd_timing.misc_info.H_REPLICATION_BY2 =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
+ info->lcd_timing.misc_info.V_REPLICATION_BY2 =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
+ info->lcd_timing.misc_info.COMPOSITE_SYNC =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
+ info->lcd_timing.misc_info.INTERLACE =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
+ info->lcd_timing.misc_info.DOUBLE_CLOCK =
+ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
+ info->ss_id = lvds->ucSS_Id;
+
+ /* Drr panel support can be reported by VBIOS*/
+ if (LCDPANEL_CAP_V13_DRR_SUPPORTED
+ & lvds->ucLCDPanel_SpecialHandlingCap)
+ info->drr_enabled = 1;
+
+ /* Get supported refresh rate*/
+ if (info->drr_enabled == 1) {
+ uint8_t min_rr =
+ lvds->sRefreshRateSupport.ucMinRefreshRateForDRR;
+ uint8_t rr = lvds->sRefreshRateSupport.ucSupportedRefreshRate;
+
+ if (min_rr != 0) {
+ if (SUPPORTED_LCD_REFRESHRATE_30Hz & min_rr)
+ info->supported_rr.REFRESH_RATE_30HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_40Hz & min_rr)
+ info->supported_rr.REFRESH_RATE_40HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_48Hz & min_rr)
+ info->supported_rr.REFRESH_RATE_48HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_50Hz & min_rr)
+ info->supported_rr.REFRESH_RATE_50HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_60Hz & min_rr)
+ info->supported_rr.REFRESH_RATE_60HZ = 1;
+ } else {
+ if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
+ info->supported_rr.REFRESH_RATE_30HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
+ info->supported_rr.REFRESH_RATE_40HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
+ info->supported_rr.REFRESH_RATE_48HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
+ info->supported_rr.REFRESH_RATE_50HZ = 1;
+ else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
+ info->supported_rr.REFRESH_RATE_60HZ = 1;
+ }
+ }
+
+ if (ATOM_PANEL_MISC_V13_DUAL & lvds->ucLCD_Misc)
+ info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
+
+ if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR & lvds->ucLCD_Misc)
+ info->lcd_timing.misc_info.RGB888 = true;
+
+ info->lcd_timing.misc_info.GREY_LEVEL =
+ (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
+ lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
+
+ return BP_RESULT_OK;
+}
+
+/**
+ * bios_parser_get_encoder_cap_info
+ *
+ * @brief
+ * Get encoder capability information of input object id
+ *
+ * @param object_id, Object id
+ * @param object_id, encoder cap information structure
+ *
+ * @return Bios parser result code
+ *
+ */
+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);
+ ATOM_OBJECT *object;
+ ATOM_ENCODER_CAP_RECORD_V2 *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_EN = record->usHBR2En;
+ info->DP_HBR3_EN = record->usHBR3En;
+ info->HDMI_6GB_EN = record->usHDMI6GEn;
+ return BP_RESULT_OK;
+}
+
+/**
+ * get_encoder_cap_record
+ *
+ * @brief
+ * Get encoder cap record for the object
+ *
+ * @param object, ATOM object
+ *
+ * @return atom encoder cap record
+ *
+ * @note
+ * search all records to find the ATOM_ENCODER_CAP_RECORD_V2 record
+ */
+static ATOM_ENCODER_CAP_RECORD_V2 *get_encoder_cap_record(
+ struct bios_parser *bp,
+ ATOM_OBJECT *object)
+{
+ ATOM_COMMON_RECORD_HEADER *header;
+ uint32_t offset;
+
+ if (!object) {
+ BREAK_TO_DEBUGGER(); /* Invalid object */
+ return NULL;
+ }
+
+ offset = le16_to_cpu(object->usRecordOffset)
+ + bp->object_info_tbl_offset;
+
+ for (;;) {
+ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
+
+ if (!header)
+ return NULL;
+
+ offset += header->ucRecordSize;
+
+ if (LAST_RECORD_TYPE == header->ucRecordType ||
+ !header->ucRecordSize)
+ break;
+
+ if (ATOM_ENCODER_CAP_RECORD_TYPE != header->ucRecordType)
+ continue;
+
+ if (sizeof(ATOM_ENCODER_CAP_RECORD_V2) <= header->ucRecordSize)
+ return (ATOM_ENCODER_CAP_RECORD_V2 *)header;
+ }
+
+ return NULL;
+}
+
+static uint32_t get_ss_entry_number(
+ struct bios_parser *bp,
+ uint32_t id);
+static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
+ struct bios_parser *bp,
+ uint32_t id);
+static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
+ struct bios_parser *bp,
+ uint32_t id);
+static uint32_t get_ss_entry_number_from_ss_info_tbl(
+ struct bios_parser *bp,
+ uint32_t id);
+
+/**
+ * BiosParserObject::GetNumberofSpreadSpectrumEntry
+ * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
+ * the VBIOS that match the SSid (to be converted from signal)
+ *
+ * @param[in] signal, ASSignalType to be converted to SSid
+ * @return number of SS Entry that match the signal
+ */
+static uint32_t bios_parser_get_ss_entry_number(
+ struct dc_bios *dcb,
+ enum as_signal_type signal)
+{
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+ uint32_t ss_id = 0;
+ ATOM_COMMON_TABLE_HEADER *header;
+ struct atom_data_revision revision;
+
+ ss_id = signal_to_ss_id(signal);
+
+ if (!DATA_TABLES(ASIC_InternalSS_Info))
+ return get_ss_entry_number_from_ss_info_tbl(bp, ss_id);
+
+ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
+ DATA_TABLES(ASIC_InternalSS_Info));
+ get_atom_data_table_revision(header, &revision);
+
+ switch (revision.major) {
+ case 2:
+ switch (revision.minor) {
+ case 1:
+ return get_ss_entry_number(bp, ss_id);
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (revision.minor) {
+ case 1:
+ return
+ get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
+ bp, ss_id);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * get_ss_entry_number_from_ss_info_tbl
+ * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
+ *
+ * @note There can only be one entry for each id for SS_Info Table
+ *
+ * @param [in] id, spread spectrum id
+ * @return number of SS Entry that match the id
+ */
+static uint32_t get_ss_entry_number_from_ss_info_tbl(
+ struct bios_parser *bp,
+ uint32_t id)
+{
+ ATOM_SPREAD_SPECTRUM_INFO *tbl;
+ ATOM_COMMON_TABLE_HEADER *header;
+ uint32_t table_size;
+ uint32_t i;
+ uint32_t number = 0;
+ uint32_t id_local = SS_ID_UNKNOWN;
+ struct atom_data_revision revision;
+
+ /* SS_Info table exist */
+ if (!DATA_TABLES(SS_Info))
+ return number;
+
+ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
+ DATA_TABLES(SS_Info));
+ get_atom_data_table_revision(header, &revision);
+
+ tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO,
+ DATA_TABLES(SS_Info));
+
+ if (1 != revision.major || 2 > revision.minor)
+ return number;
+
+ /* have to convert from Internal_SS format to SS_Info format */
+ switch (id) {
+ case ASIC_INTERNAL_SS_ON_DP:
+ id_local = SS_ID_DP1;
+ break;
+ case ASIC_INTERNAL_SS_ON_LVDS: {
+ struct embedded_panel_info panel_info;
+
+ if (bios_parser_get_embedded_panel_info(&bp->base, &panel_info)
+ == BP_RESULT_OK)
+ id_local = panel_info.ss_id;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (id_local == SS_ID_UNKNOWN)
+ return number;
+
+ table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
+ sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
+
+ for (i = 0; i < table_size; i++)
+ if (id_local == (uint32_t)tbl->asSS_Info[i].ucSS_Id) {
+ number = 1;
+ break;
+ }
+
+ return number;
+}
+
+/**
+ * get_ss_entry_number
+ * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
+ * SS_Info table from the VBIOS
+ * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
+ * SS_Info.
+ *
+ * @param id, spread sprectrum info index
+ * @return Bios parser result code
+ */
+static uint32_t get_ss_entry_number(struct bios_parser *bp, uint32_t id)
+{
+ if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
+ return get_ss_entry_number_from_ss_info_tbl(bp, id);
+
+ return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp, id);
+}
+
+/**
+ * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
+ * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
+ * Ver 2.1 from the VBIOS
+ * There will not be multiple entry for Ver 2.1
+ *
+ * @param id, spread sprectrum info index
+ * @return number of SS Entry that match the id
+ */
+static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
+ struct bios_parser *bp,
+ uint32_t id)
+{
+ ATOM_ASIC_INTERNAL_SS_INFO_V2 *header_include;
+ ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
+ uint32_t size;
+ uint32_t i;
+
+ if (!DATA_TABLES(ASIC_InternalSS_Info))
+ return 0;
+
+ header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
+ DATA_TABLES(ASIC_InternalSS_Info));
+
+ size = (le16_to_cpu(header_include->sHeader.usStructureSize)
+ - sizeof(ATOM_COMMON_TABLE_HEADER))
+ / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
+
+ tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
+ &header_include->asSpreadSpectrum[0];
+ for (i = 0; i < size; i++)
+ if (tbl[i].ucClockIndication == (uint8_t)id)
+ return 1;
+
+ return 0;
+}
+/**
+ * get_ss_entry_number_from_internal_ss_info_table_V3_1
+ * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
+ * the VBIOS that matches id
+ *
+ * @param[in] id, spread sprectrum id
+ * @return number of SS Entry that match the id
+ */
+static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
+ struct bios_parser *bp,
+ uint32_t id)
+{
+ uint32_t number = 0;
+ ATOM_ASIC_INTERNAL_SS_INFO_V3 *header_include;
+ ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
+ uint32_t size;
+ uint32_t i;
+
+ if (!DATA_TABLES(ASIC_InternalSS_Info))
+ return number;
+
+ header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
+ DATA_TABLES(ASIC_InternalSS_Info));
+ size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
+ sizeof(ATOM_COMMON_TABLE_HEADER)) /
+ sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
+
+ tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
+ &header_include->asSpreadSpectrum[0];
+
+ for (i = 0; i < size; i++)
+ if (tbl[i].ucClockIndication == (uint8_t)id)
+ number++;
+
+ return number;
+}
+
+/**
+ * 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);
+ ATOM_GPIO_PIN_LUT *header;
+ uint32_t count = 0;
+ uint32_t i = 0;
+
+ if (!DATA_TABLES(GPIO_Pin_LUT))
+ return BP_RESULT_BADBIOSTABLE;
+
+ header = GET_IMAGE(ATOM_GPIO_PIN_LUT, DATA_TABLES(GPIO_Pin_LUT));
+ if (!header)
+ return BP_RESULT_BADBIOSTABLE;
+
+ if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_PIN_LUT)
+ > le16_to_cpu(header->sHeader.usStructureSize))
+ return BP_RESULT_BADBIOSTABLE;
+
+ if (1 != header->sHeader.ucTableContentRevision)
+ return BP_RESULT_UNSUPPORTED;
+
+ count = (le16_to_cpu(header->sHeader.usStructureSize)
+ - sizeof(ATOM_COMMON_TABLE_HEADER))
+ / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
+ for (i = 0; i < count; ++i) {
+ if (header->asGPIO_Pin[i].ucGPIO_ID != gpio_id)
+ continue;
+
+ info->offset =
+ (uint32_t) le16_to_cpu(header->asGPIO_Pin[i].usGpioPin_AIndex);
+ info->offset_y = info->offset + 2;
+ info->offset_en = info->offset + 1;
+ info->offset_mask = info->offset - 1;
+
+ info->mask = (uint32_t) (1 <<
+ header->asGPIO_Pin[i].ucGpioPinBitShift);
+ 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 enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
+ ATOM_I2C_RECORD *record,
+ struct graphics_object_i2c_info *info)
+{
+ ATOM_GPIO_I2C_INFO *header;
+ uint32_t count = 0;
+
+ if (!info)
+ return BP_RESULT_BADINPUT;
+
+ /* get the GPIO_I2C info */
+ if (!DATA_TABLES(GPIO_I2C_Info))
+ return BP_RESULT_BADBIOSTABLE;
+
+ header = GET_IMAGE(ATOM_GPIO_I2C_INFO, DATA_TABLES(GPIO_I2C_Info));
+ if (!header)
+ return BP_RESULT_BADBIOSTABLE;
+
+ if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_I2C_ASSIGMENT)
+ > le16_to_cpu(header->sHeader.usStructureSize))
+ return BP_RESULT_BADBIOSTABLE;
+
+ if (1 != header->sHeader.ucTableContentRevision)
+ return BP_RESULT_UNSUPPORTED;
+
+ /* get data count */
+ count = (le16_to_cpu(header->sHeader.usStructureSize)
+ - sizeof(ATOM_COMMON_TABLE_HEADER))
+ / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
+ if (count < record->sucI2cId.bfI2C_LineMux)
+ return BP_RESULT_BADBIOSTABLE;
+
+ /* get the GPIO_I2C_INFO */
+ info->i2c_hw_assist = record->sucI2cId.bfHW_Capable;
+ info->i2c_line = record->sucI2cId.bfI2C_LineMux;
+ info->i2c_engine_id = record->sucI2cId.bfHW_EngineID;
+ info->i2c_slave_address = record->ucI2CAddr;
+
+ info->gpio_info.clk_mask_register_index =
+ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkMaskRegisterIndex);
+ info->gpio_info.clk_en_register_index =
+ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkEnRegisterIndex);
+ info->gpio_info.clk_y_register_index =
+ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkY_RegisterIndex);
+ info->gpio_info.clk_a_register_index =
+ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkA_RegisterIndex);
+ info->gpio_info.data_mask_register_index =
+ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataMaskRegisterIndex);
+ info->gpio_info.data_en_register_index =
+ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataEnRegisterIndex);
+ info->gpio_info.data_y_register_index =
+ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataY_RegisterIndex);
+ info->gpio_info.data_a_register_index =
+ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataA_RegisterIndex);
+
+ info->gpio_info.clk_mask_shift =
+ header->asGPIO_Info[info->i2c_line].ucClkMaskShift;
+ info->gpio_info.clk_en_shift =
+ header->asGPIO_Info[info->i2c_line].ucClkEnShift;
+ info->gpio_info.clk_y_shift =
+ header->asGPIO_Info[info->i2c_line].ucClkY_Shift;
+ info->gpio_info.clk_a_shift =
+ header->asGPIO_Info[info->i2c_line].ucClkA_Shift;
+ info->gpio_info.data_mask_shift =
+ header->asGPIO_Info[info->i2c_line].ucDataMaskShift;
+ info->gpio_info.data_en_shift =
+ header->asGPIO_Info[info->i2c_line].ucDataEnShift;
+ info->gpio_info.data_y_shift =
+ header->asGPIO_Info[info->i2c_line].ucDataY_Shift;
+ info->gpio_info.data_a_shift =
+ header->asGPIO_Info[info->i2c_line].ucDataA_Shift;
+
+ return BP_RESULT_OK;
+}
+
+static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
+ struct graphics_object_id id)
+{
+ uint32_t offset;
+ ATOM_OBJECT_TABLE *tbl;
+ uint32_t i;
+
+ switch (id.type) {
+ case OBJECT_TYPE_ENCODER:
+ offset = le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
+ break;
+
+ case OBJECT_TYPE_CONNECTOR:
+ offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
+ break;
+
+ case OBJECT_TYPE_ROUTER:
+ offset = le16_to_cpu(bp->object_info_tbl.v1_1->usRouterObjectTableOffset);
+ break;
+
+ case OBJECT_TYPE_GENERIC:
+ if (bp->object_info_tbl.revision.minor < 3)
+ return NULL;
+ offset = le16_to_cpu(bp->object_info_tbl.v1_3->usMiscObjectTableOffset);
+ break;
+
+ default:
+ return NULL;
+ }
+
+ offset += bp->object_info_tbl_offset;
+
+ tbl = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
+ if (!tbl)
+ return NULL;
+
+ for (i = 0; i < tbl->ucNumberOfObjects; i++)
+ if (dal_graphics_object_id_is_equal(id,
+ object_id_from_bios_object_id(
+ le16_to_cpu(tbl->asObjects[i].usObjectID))))
+ return &tbl->asObjects[i];
+
+ return NULL;
+}
+
+static uint32_t get_dest_obj_list(struct bios_parser *bp,
+ ATOM_OBJECT *object, uint16_t **id_list)
+{
+ uint32_t offset;
+ uint8_t *number;
+
+ if (!object) {
+ BREAK_TO_DEBUGGER(); /* Invalid object id */
+ return 0;
+ }
+
+ offset = le16_to_cpu(object->usSrcDstTableOffset)
+ + bp->object_info_tbl_offset;
+
+ number = GET_IMAGE(uint8_t, offset);
+ if (!number)
+ return 0;
+
+ offset += sizeof(uint8_t);
+ offset += sizeof(uint16_t) * (*number);
+
+ number = GET_IMAGE(uint8_t, offset);
+ if ((!number) || (!*number))
+ return 0;
+
+ offset += sizeof(uint8_t);
+ *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
+
+ if (!*id_list)
+ return 0;
+
+ return *number;
+}
+
+static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
+ uint16_t **id_list)
+{
+ uint32_t offset;
+ uint8_t *number;
+
+ if (!object) {
+ BREAK_TO_DEBUGGER(); /* Invalid object id */
+ return 0;
+ }
+
+ offset = le16_to_cpu(object->usSrcDstTableOffset)
+ + bp->object_info_tbl_offset;
+
+ number = GET_IMAGE(uint8_t, offset);
+ if (!number)
+ return 0;
+
+ offset += sizeof(uint8_t);
+ *id_list = (uint16_t *)bios_get_image(&bp->base, offset, *number * sizeof(uint16_t));
+
+ if (!*id_list)
+ return 0;
+
+ return *number;
+}
+
+static uint32_t get_dst_number_from_object(struct bios_parser *bp,
+ ATOM_OBJECT *object)
+{
+ uint32_t offset;
+ uint8_t *number;
+
+ if (!object) {
+ BREAK_TO_DEBUGGER(); /* Invalid encoder object id*/
+ return 0;
+ }
+
+ offset = le16_to_cpu(object->usSrcDstTableOffset)
+ + bp->object_info_tbl_offset;
+
+ number = GET_IMAGE(uint8_t, offset);
+ if (!number)
+ return 0;
+
+ offset += sizeof(uint8_t);
+ offset += sizeof(uint16_t) * (*number);
+
+ number = GET_IMAGE(uint8_t, offset);
+
+ if (!number)
+ return 0;
+
+ return *number;
+}
+
+static struct device_id device_type_from_device_id(uint16_t device_id)
+{
+
+ struct device_id result_device_id;
+
+ switch (device_id) {
+ case ATOM_DEVICE_LCD1_SUPPORT:
+ result_device_id.device_type = DEVICE_TYPE_LCD;
+ result_device_id.enum_id = 1;
+ break;
+
+ case ATOM_DEVICE_LCD2_SUPPORT:
+ result_device_id.device_type = DEVICE_TYPE_LCD;
+ result_device_id.enum_id = 2;
+ break;
+
+ case ATOM_DEVICE_CRT1_SUPPORT:
+ result_device_id.device_type = DEVICE_TYPE_CRT;
+ result_device_id.enum_id = 1;
+ break;
+
+ case ATOM_DEVICE_CRT2_SUPPORT:
+ result_device_id.device_type = DEVICE_TYPE_CRT;
+ result_device_id.enum_id = 2;
+ break;
+
+ case ATOM_DEVICE_DFP1_SUPPORT:
+ result_device_id.device_type = DEVICE_TYPE_DFP;
+ result_device_id.enum_id = 1;
+ break;
+
+ case ATOM_DEVICE_DFP2_SUPPORT:
+ result_device_id.device_type = DEVICE_TYPE_DFP;
+ result_device_id.enum_id = 2;
+ break;
+
+ case ATOM_DEVICE_DFP3_SUPPORT:
+ result_device_id.device_type = DEVICE_TYPE_DFP;
+ result_device_id.enum_id = 3;
+ break;
+
+ case ATOM_DEVICE_DFP4_SUPPORT:
+ result_device_id.device_type = DEVICE_TYPE_DFP;
+ result_device_id.enum_id = 4;
+ break;
+
+ case ATOM_DEVICE_DFP5_SUPPORT:
+ result_device_id.device_type = DEVICE_TYPE_DFP;
+ result_device_id.enum_id = 5;
+ break;
+
+ case ATOM_DEVICE_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 void get_atom_data_table_revision(
+ 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) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl);
+ tbl_revision->minor =
+ (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl);
+}
+
+static uint32_t signal_to_ss_id(enum as_signal_type signal)
+{
+ uint32_t clk_id_ss = 0;
+
+ switch (signal) {
+ case AS_SIGNAL_TYPE_DVI:
+ clk_id_ss = ASIC_INTERNAL_SS_ON_TMDS;
+ break;
+ case AS_SIGNAL_TYPE_HDMI:
+ clk_id_ss = ASIC_INTERNAL_SS_ON_HDMI;
+ break;
+ case AS_SIGNAL_TYPE_LVDS:
+ clk_id_ss = ASIC_INTERNAL_SS_ON_LVDS;
+ break;
+ case AS_SIGNAL_TYPE_DISPLAY_PORT:
+ clk_id_ss = ASIC_INTERNAL_SS_ON_DP;
+ break;
+ case AS_SIGNAL_TYPE_GPU_PLL:
+ clk_id_ss = ASIC_INTERNAL_GPUPLL_SS;
+ break;
+ default:
+ break;
+ }
+ return clk_id_ss;
+}
+
+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_DEVICE_LCD1_SUPPORT;
+ case 2:
+ return ATOM_DEVICE_LCD2_SUPPORT;
+ default:
+ break;
+ }
+ break;
+ case DEVICE_TYPE_CRT:
+ switch (enum_id) {
+ case 1:
+ return ATOM_DEVICE_CRT1_SUPPORT;
+ case 2:
+ return ATOM_DEVICE_CRT2_SUPPORT;
+ default:
+ break;
+ }
+ break;
+ case DEVICE_TYPE_DFP:
+ switch (enum_id) {
+ case 1:
+ return ATOM_DEVICE_DFP1_SUPPORT;
+ case 2:
+ return ATOM_DEVICE_DFP2_SUPPORT;
+ case 3:
+ return ATOM_DEVICE_DFP3_SUPPORT;
+ case 4:
+ return ATOM_DEVICE_DFP4_SUPPORT;
+ case 5:
+ return ATOM_DEVICE_DFP5_SUPPORT;
+ case 6:
+ return ATOM_DEVICE_DFP6_SUPPORT;
+ default:
+ break;
+ }
+ break;
+ case DEVICE_TYPE_CV:
+ switch (enum_id) {
+ case 1:
+ return ATOM_DEVICE_CV_SUPPORT;
+ default:
+ break;
+ }
+ break;
+ case DEVICE_TYPE_TV:
+ switch (enum_id) {
+ case 1:
+ return ATOM_DEVICE_TV1_SUPPORT;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ };
+
+ /* Unidentified device ID, return empty support mask. */
+ return 0;
+}
+
+/**
+ * HwContext interface for writing MM registers
+ */
+
+static bool i2c_read(
+ struct bios_parser *bp,
+ struct graphics_object_i2c_info *i2c_info,
+ uint8_t *buffer,
+ uint32_t length)
+{
+ struct ddc *ddc;
+ uint8_t offset[2] = { 0, 0 };
+ bool result = false;
+ struct i2c_command cmd;
+ struct gpio_ddc_hw_info hw_info = {
+ i2c_info->i2c_hw_assist,
+ i2c_info->i2c_line };
+
+ ddc = dal_gpio_create_ddc(bp->base.ctx->gpio_service,
+ i2c_info->gpio_info.clk_a_register_index,
+ (1 << i2c_info->gpio_info.clk_a_shift), &hw_info);
+
+ if (!ddc)
+ return result;
+
+ /*Using SW engine */
+ cmd.engine = I2C_COMMAND_ENGINE_SW;
+ cmd.speed = ddc->ctx->dc->caps.i2c_speed_in_khz;
+
+ {
+ struct i2c_payload payloads[] = {
+ {
+ .address = i2c_info->i2c_slave_address >> 1,
+ .data = offset,
+ .length = sizeof(offset),
+ .write = true
+ },
+ {
+ .address = i2c_info->i2c_slave_address >> 1,
+ .data = buffer,
+ .length = length,
+ .write = false
+ }
+ };
+
+ cmd.payloads = payloads;
+ cmd.number_of_payloads = ARRAY_SIZE(payloads);
+
+ /* TODO route this through drm i2c_adapter */
+ result = dal_i2caux_submit_i2c_command(
+ ddc->ctx->i2caux,
+ ddc,
+ &cmd);
+ }
+
+ dal_gpio_destroy_ddc(&ddc);
+
+ return result;
+}
+
+/**
+ * Read external display connection info table through i2c.
+ * validate the GUID and checksum.
+ *
+ * @return enum bp_result whether all data was sucessfully read
+ */
+static enum bp_result get_ext_display_connection_info(
+ struct bios_parser *bp,
+ ATOM_OBJECT *opm_object,
+ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *ext_display_connection_info_tbl)
+{
+ bool config_tbl_present = false;
+ ATOM_I2C_RECORD *i2c_record = NULL;
+ uint32_t i = 0;
+
+ if (opm_object == NULL)
+ return BP_RESULT_BADINPUT;
+
+ i2c_record = get_i2c_record(bp, opm_object);
+
+ if (i2c_record != NULL) {
+ ATOM_GPIO_I2C_INFO *gpio_i2c_header;
+ struct graphics_object_i2c_info i2c_info;
+
+ gpio_i2c_header = GET_IMAGE(ATOM_GPIO_I2C_INFO,
+ bp->master_data_tbl->ListOfDataTables.GPIO_I2C_Info);
+
+ if (NULL == gpio_i2c_header)
+ return BP_RESULT_BADBIOSTABLE;
+
+ if (get_gpio_i2c_info(bp, i2c_record, &i2c_info) !=
+ BP_RESULT_OK)
+ return BP_RESULT_BADBIOSTABLE;
+
+ if (i2c_read(bp,
+ &i2c_info,
+ (uint8_t *)ext_display_connection_info_tbl,
+ sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO))) {
+ config_tbl_present = true;
+ }
+ }
+
+ /* Validate GUID */
+ if (config_tbl_present)
+ for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; i++) {
+ if (ext_display_connection_info_tbl->ucGuid[i]
+ != ext_display_connection_guid[i]) {
+ config_tbl_present = false;
+ break;
+ }
+ }
+
+ /* Validate checksum */
+ if (config_tbl_present) {
+ uint8_t check_sum = 0;
+ uint8_t *buf =
+ (uint8_t *)ext_display_connection_info_tbl;
+
+ for (i = 0; i < sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO);
+ i++) {
+ check_sum += buf[i];
+ }
+
+ if (check_sum != 0)
+ config_tbl_present = false;
+ }
+
+ if (config_tbl_present)
+ return BP_RESULT_OK;
+ else
+ return BP_RESULT_FAILURE;
+}
+
+/*
+ * Gets the first device ID in the same group as the given ID for enumerating.
+ * For instance, if any DFP device ID is passed, returns the device ID for DFP1.
+ *
+ * The first device ID in the same group as the passed device ID, or 0 if no
+ * matching device group found.
+ */
+static uint32_t enum_first_device_id(uint32_t dev_id)
+{
+ /* Return the first in the group that this ID belongs to. */
+ if (dev_id & ATOM_DEVICE_CRT_SUPPORT)
+ return ATOM_DEVICE_CRT1_SUPPORT;
+ else if (dev_id & ATOM_DEVICE_DFP_SUPPORT)
+ return ATOM_DEVICE_DFP1_SUPPORT;
+ else if (dev_id & ATOM_DEVICE_LCD_SUPPORT)
+ return ATOM_DEVICE_LCD1_SUPPORT;
+ else if (dev_id & ATOM_DEVICE_TV_SUPPORT)
+ return ATOM_DEVICE_TV1_SUPPORT;
+ else if (dev_id & ATOM_DEVICE_CV_SUPPORT)
+ return ATOM_DEVICE_CV_SUPPORT;
+
+ /* No group found for this device ID. */
+
+ dm_error("%s: incorrect input %d\n", __func__, dev_id);
+ /* No matching support flag for given device ID */
+ return 0;
+}
+
+/*
+ * Gets the next device ID in the group for a given device ID.
+ *
+ * The current device ID being enumerated on.
+ *
+ * The next device ID in the group, or 0 if no device exists.
+ */
+static uint32_t enum_next_dev_id(uint32_t dev_id)
+{
+ /* Get next device ID in the group. */
+ switch (dev_id) {
+ case ATOM_DEVICE_CRT1_SUPPORT:
+ return ATOM_DEVICE_CRT2_SUPPORT;
+ case ATOM_DEVICE_LCD1_SUPPORT:
+ return ATOM_DEVICE_LCD2_SUPPORT;
+ case ATOM_DEVICE_DFP1_SUPPORT:
+ return ATOM_DEVICE_DFP2_SUPPORT;
+ case ATOM_DEVICE_DFP2_SUPPORT:
+ return ATOM_DEVICE_DFP3_SUPPORT;
+ case ATOM_DEVICE_DFP3_SUPPORT:
+ return ATOM_DEVICE_DFP4_SUPPORT;
+ case ATOM_DEVICE_DFP4_SUPPORT:
+ return ATOM_DEVICE_DFP5_SUPPORT;
+ case ATOM_DEVICE_DFP5_SUPPORT:
+ return ATOM_DEVICE_DFP6_SUPPORT;
+ }
+
+ /* Done enumerating through devices. */
+ return 0;
+}
+
+/*
+ * Returns the new device tag record for patched BIOS object.
+ *
+ * [IN] pExtDisplayPath - External display path to copy device tag from.
+ * [IN] deviceSupport - Bit vector for device ID support flags.
+ * [OUT] pDeviceTag - Device tag structure to fill with patched data.
+ *
+ * True if a compatible device ID was found, false otherwise.
+ */
+static bool get_patched_device_tag(
+ struct bios_parser *bp,
+ EXT_DISPLAY_PATH *ext_display_path,
+ uint32_t device_support,
+ ATOM_CONNECTOR_DEVICE_TAG *device_tag)
+{
+ uint32_t dev_id;
+ /* Use fallback behaviour if not supported. */
+ if (!bp->remap_device_tags) {
+ device_tag->ulACPIDeviceEnum =
+ cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
+ device_tag->usDeviceID =
+ cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceTag));
+ return true;
+ }
+
+ /* Find the first unused in the same group. */
+ dev_id = enum_first_device_id(le16_to_cpu(ext_display_path->usDeviceTag));
+ while (dev_id != 0) {
+ /* Assign this device ID if supported. */
+ if ((device_support & dev_id) != 0) {
+ device_tag->ulACPIDeviceEnum =
+ cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
+ device_tag->usDeviceID = cpu_to_le16((USHORT) dev_id);
+ return true;
+ }
+
+ dev_id = enum_next_dev_id(dev_id);
+ }
+
+ /* No compatible device ID found. */
+ return false;
+}
+
+/*
+ * Adds a device tag to a BIOS object's device tag record if there is
+ * matching device ID supported.
+ *
+ * pObject - Pointer to the BIOS object to add the device tag to.
+ * pExtDisplayPath - Display path to retrieve base device ID from.
+ * pDeviceSupport - Pointer to bit vector for supported device IDs.
+ */
+static void add_device_tag_from_ext_display_path(
+ struct bios_parser *bp,
+ ATOM_OBJECT *object,
+ EXT_DISPLAY_PATH *ext_display_path,
+ uint32_t *device_support)
+{
+ /* Get device tag record for object. */
+ ATOM_CONNECTOR_DEVICE_TAG *device_tag = NULL;
+ ATOM_CONNECTOR_DEVICE_TAG_RECORD *device_tag_record = NULL;
+ enum bp_result result =
+ bios_parser_get_device_tag_record(
+ bp, object, &device_tag_record);
+
+ if ((le16_to_cpu(ext_display_path->usDeviceTag) != CONNECTOR_OBJECT_ID_NONE)
+ && (result == BP_RESULT_OK)) {
+ uint8_t index;
+
+ if ((device_tag_record->ucNumberOfDevice == 1) &&
+ (le16_to_cpu(device_tag_record->asDeviceTag[0].usDeviceID) == 0)) {
+ /*Workaround bug in current VBIOS releases where
+ * ucNumberOfDevice = 1 but there is no actual device
+ * tag data. This w/a is temporary until the updated
+ * VBIOS is distributed. */
+ device_tag_record->ucNumberOfDevice =
+ device_tag_record->ucNumberOfDevice - 1;
+ }
+
+ /* Attempt to find a matching device ID. */
+ index = device_tag_record->ucNumberOfDevice;
+ device_tag = &device_tag_record->asDeviceTag[index];
+ if (get_patched_device_tag(
+ bp,
+ ext_display_path,
+ *device_support,
+ device_tag)) {
+ /* Update cached device support to remove assigned ID.
+ */
+ *device_support &= ~le16_to_cpu(device_tag->usDeviceID);
+ device_tag_record->ucNumberOfDevice++;
+ }
+ }
+}
+
+/*
+ * Read out a single EXT_DISPLAY_PATH from the external display connection info
+ * table. The specific entry in the table is determined by the enum_id passed
+ * in.
+ *
+ * EXT_DISPLAY_PATH describing a single Configuration table entry
+ */
+
+#define INVALID_CONNECTOR 0xffff
+
+static EXT_DISPLAY_PATH *get_ext_display_path_entry(
+ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *config_table,
+ uint32_t bios_object_id)
+{
+ EXT_DISPLAY_PATH *ext_display_path;
+ uint32_t ext_display_path_index =
+ ((bios_object_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT) - 1;
+
+ if (ext_display_path_index >= MAX_NUMBER_OF_EXT_DISPLAY_PATH)
+ return NULL;
+
+ ext_display_path = &config_table->sPath[ext_display_path_index];
+
+ if (le16_to_cpu(ext_display_path->usDeviceConnector) == INVALID_CONNECTOR)
+ ext_display_path->usDeviceConnector = cpu_to_le16(0);
+
+ return ext_display_path;
+}
+
+/*
+ * Get AUX/DDC information of input object id
+ *
+ * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
+ * IR
+ */
+static ATOM_CONNECTOR_AUXDDC_LUT_RECORD *get_ext_connector_aux_ddc_lut_record(
+ struct bios_parser *bp,
+ ATOM_OBJECT *object)
+{
+ uint32_t offset;
+ ATOM_COMMON_RECORD_HEADER *header;
+
+ if (!object) {
+ BREAK_TO_DEBUGGER();
+ /* Invalid object */
+ return NULL;
+ }
+
+ offset = le16_to_cpu(object->usRecordOffset)
+ + bp->object_info_tbl_offset;
+
+ for (;;) {
+ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
+
+ if (!header)
+ return NULL;
+
+ if (LAST_RECORD_TYPE == header->ucRecordType ||
+ 0 == header->ucRecordSize)
+ break;
+
+ if (ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE ==
+ header->ucRecordType &&
+ sizeof(ATOM_CONNECTOR_AUXDDC_LUT_RECORD) <=
+ header->ucRecordSize)
+ return (ATOM_CONNECTOR_AUXDDC_LUT_RECORD *)(header);
+
+ offset += header->ucRecordSize;
+ }
+
+ return NULL;
+}
+
+/*
+ * Get AUX/DDC information of input object id
+ *
+ * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
+ * IR
+ */
+static ATOM_CONNECTOR_HPDPIN_LUT_RECORD *get_ext_connector_hpd_pin_lut_record(
+ struct bios_parser *bp,
+ ATOM_OBJECT *object)
+{
+ uint32_t offset;
+ ATOM_COMMON_RECORD_HEADER *header;
+
+ if (!object) {
+ BREAK_TO_DEBUGGER();
+ /* Invalid object */
+ return NULL;
+ }
+
+ offset = le16_to_cpu(object->usRecordOffset)
+ + bp->object_info_tbl_offset;
+
+ for (;;) {
+ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
+
+ if (!header)
+ return NULL;
+
+ if (LAST_RECORD_TYPE == header->ucRecordType ||
+ 0 == header->ucRecordSize)
+ break;
+
+ if (ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE ==
+ header->ucRecordType &&
+ sizeof(ATOM_CONNECTOR_HPDPIN_LUT_RECORD) <=
+ header->ucRecordSize)
+ return (ATOM_CONNECTOR_HPDPIN_LUT_RECORD *)header;
+
+ offset += header->ucRecordSize;
+ }
+
+ return NULL;
+}
+
+/*
+ * Check whether we need to patch the VBIOS connector info table with
+ * data from an external display connection info table. This is
+ * necessary to support MXM boards with an OPM (output personality
+ * module). With these designs, the VBIOS connector info table
+ * specifies an MXM_CONNECTOR with a unique ID. The driver retrieves
+ * the external connection info table through i2c and then looks up the
+ * connector ID to find the real connector type (e.g. DFP1).
+ *
+ */
+static enum bp_result patch_bios_image_from_ext_display_connection_info(
+ struct bios_parser *bp)
+{
+ ATOM_OBJECT_TABLE *connector_tbl;
+ uint32_t connector_tbl_offset;
+ struct graphics_object_id object_id;
+ ATOM_OBJECT *object;
+ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO ext_display_connection_info_tbl;
+ EXT_DISPLAY_PATH *ext_display_path;
+ ATOM_CONNECTOR_AUXDDC_LUT_RECORD *aux_ddc_lut_record = NULL;
+ ATOM_I2C_RECORD *i2c_record = NULL;
+ ATOM_CONNECTOR_HPDPIN_LUT_RECORD *hpd_pin_lut_record = NULL;
+ ATOM_HPD_INT_RECORD *hpd_record = NULL;
+ ATOM_OBJECT_TABLE *encoder_table;
+ uint32_t encoder_table_offset;
+ ATOM_OBJECT *opm_object = NULL;
+ uint32_t i = 0;
+ struct graphics_object_id opm_object_id =
+ dal_graphics_object_id_init(
+ GENERIC_ID_MXM_OPM,
+ ENUM_ID_1,
+ OBJECT_TYPE_GENERIC);
+ ATOM_CONNECTOR_DEVICE_TAG_RECORD *dev_tag_record;
+ uint32_t cached_device_support =
+ le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport);
+
+ uint32_t dst_number;
+ uint16_t *dst_object_id_list;
+
+ opm_object = get_bios_object(bp, opm_object_id);
+ if (!opm_object)
+ return BP_RESULT_UNSUPPORTED;
+
+ memset(&ext_display_connection_info_tbl, 0,
+ sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO));
+
+ connector_tbl_offset = bp->object_info_tbl_offset
+ + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
+ connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
+
+ /* Read Connector info table from EEPROM through i2c */
+ if (get_ext_display_connection_info(bp,
+ opm_object,
+ &ext_display_connection_info_tbl) != BP_RESULT_OK) {
+
+ dm_logger_write(bp->base.ctx->logger, LOG_WARNING,
+ "%s: Failed to read Connection Info Table", __func__);
+ return BP_RESULT_UNSUPPORTED;
+ }
+
+ /* Get pointer to AUX/DDC and HPD LUTs */
+ aux_ddc_lut_record =
+ get_ext_connector_aux_ddc_lut_record(bp, opm_object);
+ hpd_pin_lut_record =
+ get_ext_connector_hpd_pin_lut_record(bp, opm_object);
+
+ if ((aux_ddc_lut_record == NULL) || (hpd_pin_lut_record == NULL))
+ return BP_RESULT_UNSUPPORTED;
+
+ /* Cache support bits for currently unmapped device types. */
+ if (bp->remap_device_tags) {
+ for (i = 0; i < connector_tbl->ucNumberOfObjects; ++i) {
+ uint32_t j;
+ /* Remove support for all non-MXM connectors. */
+ object = &connector_tbl->asObjects[i];
+ object_id = object_id_from_bios_object_id(
+ le16_to_cpu(object->usObjectID));
+ if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
+ (CONNECTOR_ID_MXM == object_id.id))
+ continue;
+
+ /* Remove support for all device tags. */
+ if (bios_parser_get_device_tag_record(
+ bp, object, &dev_tag_record) != BP_RESULT_OK)
+ continue;
+
+ for (j = 0; j < dev_tag_record->ucNumberOfDevice; ++j) {
+ ATOM_CONNECTOR_DEVICE_TAG *device_tag =
+ &dev_tag_record->asDeviceTag[j];
+ cached_device_support &=
+ ~le16_to_cpu(device_tag->usDeviceID);
+ }
+ }
+ }
+
+ /* Find all MXM connector objects and patch them with connector info
+ * from the external display connection info table. */
+ for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
+ uint32_t j;
+
+ object = &connector_tbl->asObjects[i];
+ object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
+ if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
+ (CONNECTOR_ID_MXM != object_id.id))
+ continue;
+
+ /* Get the correct connection info table entry based on the enum
+ * id. */
+ ext_display_path = get_ext_display_path_entry(
+ &ext_display_connection_info_tbl,
+ le16_to_cpu(object->usObjectID));
+ if (!ext_display_path)
+ return BP_RESULT_FAILURE;
+
+ /* Patch device connector ID */
+ object->usObjectID =
+ cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceConnector));
+
+ /* Patch device tag, ulACPIDeviceEnum. */
+ add_device_tag_from_ext_display_path(
+ bp,
+ object,
+ ext_display_path,
+ &cached_device_support);
+
+ /* Patch HPD info */
+ if (ext_display_path->ucExtHPDPINLutIndex <
+ MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES) {
+ hpd_record = get_hpd_record(bp, object);
+ if (hpd_record) {
+ uint8_t index =
+ ext_display_path->ucExtHPDPINLutIndex;
+ hpd_record->ucHPDIntGPIOID =
+ hpd_pin_lut_record->ucHPDPINMap[index];
+ } else {
+ BREAK_TO_DEBUGGER();
+ /* Invalid hpd record */
+ return BP_RESULT_FAILURE;
+ }
+ }
+
+ /* Patch I2C/AUX info */
+ if (ext_display_path->ucExtHPDPINLutIndex <
+ MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES) {
+ i2c_record = get_i2c_record(bp, object);
+ if (i2c_record) {
+ uint8_t index =
+ ext_display_path->ucExtAUXDDCLutIndex;
+ i2c_record->sucI2cId =
+ aux_ddc_lut_record->ucAUXDDCMap[index];
+ } else {
+ BREAK_TO_DEBUGGER();
+ /* Invalid I2C record */
+ return BP_RESULT_FAILURE;
+ }
+ }
+
+ /* Merge with other MXM connectors that map to the same physical
+ * connector. */
+ for (j = i + 1;
+ j < connector_tbl->ucNumberOfObjects; j++) {
+ ATOM_OBJECT *next_object;
+ struct graphics_object_id next_object_id;
+ EXT_DISPLAY_PATH *next_ext_display_path;
+
+ next_object = &connector_tbl->asObjects[j];
+ next_object_id = object_id_from_bios_object_id(
+ le16_to_cpu(next_object->usObjectID));
+
+ if ((OBJECT_TYPE_CONNECTOR != next_object_id.type) &&
+ (CONNECTOR_ID_MXM == next_object_id.id))
+ continue;
+
+ next_ext_display_path = get_ext_display_path_entry(
+ &ext_display_connection_info_tbl,
+ le16_to_cpu(next_object->usObjectID));
+
+ if (next_ext_display_path == NULL)
+ return BP_RESULT_FAILURE;
+
+ /* Merge if using same connector. */
+ if ((le16_to_cpu(next_ext_display_path->usDeviceConnector) ==
+ le16_to_cpu(ext_display_path->usDeviceConnector)) &&
+ (le16_to_cpu(ext_display_path->usDeviceConnector) != 0)) {
+ /* Clear duplicate connector from table. */
+ next_object->usObjectID = cpu_to_le16(0);
+ add_device_tag_from_ext_display_path(
+ bp,
+ object,
+ ext_display_path,
+ &cached_device_support);
+ }
+ }
+ }
+
+ /* Find all encoders which have an MXM object as their destination.
+ * Replace the MXM object with the real connector Id from the external
+ * display connection info table */
+
+ encoder_table_offset = bp->object_info_tbl_offset
+ + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
+ encoder_table = GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
+
+ for (i = 0; i < encoder_table->ucNumberOfObjects; i++) {
+ uint32_t j;
+
+ object = &encoder_table->asObjects[i];
+
+ dst_number = get_dest_obj_list(bp, object, &dst_object_id_list);
+
+ for (j = 0; j < dst_number; j++) {
+ object_id = object_id_from_bios_object_id(
+ dst_object_id_list[j]);
+
+ if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
+ (CONNECTOR_ID_MXM != object_id.id))
+ continue;
+
+ /* Get the correct connection info table entry based on
+ * the enum id. */
+ ext_display_path =
+ get_ext_display_path_entry(
+ &ext_display_connection_info_tbl,
+ dst_object_id_list[j]);
+
+ if (ext_display_path == NULL)
+ return BP_RESULT_FAILURE;
+
+ dst_object_id_list[j] =
+ le16_to_cpu(ext_display_path->usDeviceConnector);
+ }
+ }
+
+ return BP_RESULT_OK;
+}
+
+/*
+ * Check whether we need to patch the VBIOS connector info table with
+ * data from an external display connection info table. This is
+ * necessary to support MXM boards with an OPM (output personality
+ * module). With these designs, the VBIOS connector info table
+ * specifies an MXM_CONNECTOR with a unique ID. The driver retrieves
+ * the external connection info table through i2c and then looks up the
+ * connector ID to find the real connector type (e.g. DFP1).
+ *
+ */
+
+static void process_ext_display_connection_info(struct bios_parser *bp)
+{
+ ATOM_OBJECT_TABLE *connector_tbl;
+ uint32_t connector_tbl_offset;
+ struct graphics_object_id object_id;
+ ATOM_OBJECT *object;
+ bool mxm_connector_found = false;
+ bool null_entry_found = false;
+ uint32_t i = 0;
+
+ connector_tbl_offset = bp->object_info_tbl_offset +
+ le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
+ connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
+
+ /* Look for MXM connectors to determine whether we need patch the VBIOS
+ * connector info table. Look for null entries to determine whether we
+ * need to compact connector table. */
+ for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
+ object = &connector_tbl->asObjects[i];
+ object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
+
+ if ((OBJECT_TYPE_CONNECTOR == object_id.type) &&
+ (CONNECTOR_ID_MXM == object_id.id)) {
+ /* Once we found MXM connector - we can break */
+ mxm_connector_found = true;
+ break;
+ } else if (OBJECT_TYPE_CONNECTOR != object_id.type) {
+ /* We need to continue looping - to check if MXM
+ * connector present */
+ null_entry_found = true;
+ }
+ }
+
+ /* Patch BIOS image */
+ if (mxm_connector_found || null_entry_found) {
+ uint32_t connectors_num = 0;
+ uint8_t *original_bios;
+ /* Step 1: Replace bios image with the new copy which will be
+ * patched */
+ bp->base.bios_local_image = kzalloc(bp->base.bios_size,
+ GFP_KERNEL);
+ if (bp->base.bios_local_image == NULL) {
+ BREAK_TO_DEBUGGER();
+ /* Failed to alloc bp->base.bios_local_image */
+ return;
+ }
+
+ memmove(bp->base.bios_local_image, bp->base.bios, bp->base.bios_size);
+ original_bios = bp->base.bios;
+ bp->base.bios = bp->base.bios_local_image;
+ connector_tbl =
+ GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
+
+ /* Step 2: (only if MXM connector found) Patch BIOS image with
+ * info from external module */
+ if (mxm_connector_found &&
+ patch_bios_image_from_ext_display_connection_info(bp) !=
+ BP_RESULT_OK) {
+ /* Patching the bios image has failed. We will copy
+ * again original image provided and afterwards
+ * only remove null entries */
+ memmove(
+ bp->base.bios_local_image,
+ original_bios,
+ bp->base.bios_size);
+ }
+
+ /* Step 3: Compact connector table (remove null entries, valid
+ * entries moved to beginning) */
+ for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
+ object = &connector_tbl->asObjects[i];
+ object_id = object_id_from_bios_object_id(
+ le16_to_cpu(object->usObjectID));
+
+ if (OBJECT_TYPE_CONNECTOR != object_id.type)
+ continue;
+
+ if (i != connectors_num) {
+ memmove(
+ &connector_tbl->
+ asObjects[connectors_num],
+ object,
+ sizeof(ATOM_OBJECT));
+ }
+ ++connectors_num;
+ }
+ connector_tbl->ucNumberOfObjects = (uint8_t)connectors_num;
+ }
+}
+
+static void bios_parser_post_init(struct dc_bios *dcb)
+{
+ struct bios_parser *bp = BP_FROM_DCB(dcb);
+
+ process_ext_display_connection_info(bp);
+}
+
+/**
+ * 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);
+}
+
+/*
+ * get_integrated_info_v8
+ *
+ * @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_v8(
+ struct bios_parser *bp,
+ struct integrated_info *info)
+{
+ ATOM_INTEGRATED_SYSTEM_INFO_V1_8 *info_v8;
+ uint32_t i;
+
+ info_v8 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8,
+ bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
+
+ if (info_v8 == NULL)
+ return BP_RESULT_BADBIOSTABLE;
+ info->boot_up_engine_clock = le32_to_cpu(info_v8->ulBootUpEngineClock) * 10;
+ info->dentist_vco_freq = le32_to_cpu(info_v8->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_v8->sDISPCLK_Voltage[i].
+ ulMaximumSupportedCLK) * 10;
+ info->disp_clk_voltage[i].voltage_index =
+ le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
+ }
+
+ info->boot_up_req_display_vector =
+ le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
+ info->gpu_cap_info =
+ le32_to_cpu(info_v8->ulGPUCapInfo);
+
+ /*
+ * 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_v8->ulSystemConfig);
+ info->cpu_cap_info = le32_to_cpu(info_v8->ulCPUCapInfo);
+ info->boot_up_nb_voltage =
+ le16_to_cpu(info_v8->usBootUpNBVoltage);
+ info->ext_disp_conn_info_offset =
+ le16_to_cpu(info_v8->usExtDispConnInfoOffset);
+ info->memory_type = info_v8->ucMemoryType;
+ info->ma_channel_number = info_v8->ucUMAChannelNumber;
+ info->gmc_restore_reset_time =
+ le32_to_cpu(info_v8->ulGMCRestoreResetTime);
+
+ info->minimum_n_clk =
+ le32_to_cpu(info_v8->ulNbpStateNClkFreq[0]);
+ for (i = 1; i < 4; ++i)
+ info->minimum_n_clk =
+ info->minimum_n_clk < le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]) ?
+ info->minimum_n_clk : le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]);
+
+ info->idle_n_clk = le32_to_cpu(info_v8->ulIdleNClk);
+ info->ddr_dll_power_up_time =
+ le32_to_cpu(info_v8->ulDDR_DLL_PowerUpTime);
+ info->ddr_pll_power_up_time =
+ le32_to_cpu(info_v8->ulDDR_PLL_PowerUpTime);
+ info->pcie_clk_ss_type = le16_to_cpu(info_v8->usPCIEClkSSType);
+ info->lvds_ss_percentage =
+ le16_to_cpu(info_v8->usLvdsSSPercentage);
+ info->lvds_sspread_rate_in_10hz =
+ le16_to_cpu(info_v8->usLvdsSSpreadRateIn10Hz);
+ info->hdmi_ss_percentage =
+ le16_to_cpu(info_v8->usHDMISSPercentage);
+ info->hdmi_sspread_rate_in_10hz =
+ le16_to_cpu(info_v8->usHDMISSpreadRateIn10Hz);
+ info->dvi_ss_percentage =
+ le16_to_cpu(info_v8->usDVISSPercentage);
+ info->dvi_sspread_rate_in_10_hz =
+ le16_to_cpu(info_v8->usDVISSpreadRateIn10Hz);
+
+ info->max_lvds_pclk_freq_in_single_link =
+ le16_to_cpu(info_v8->usMaxLVDSPclkFreqInSingleLink);
+ info->lvds_misc = info_v8->ucLvdsMisc;
+ info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
+ info_v8->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
+ info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
+ info_v8->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
+ info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
+ info_v8->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
+ info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
+ info_v8->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
+ info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
+ info_v8->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
+ info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
+ info_v8->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
+ info->lvds_off_to_on_delay_in_4ms =
+ info_v8->ucLVDSOffToOnDelay_in4Ms;
+ info->lvds_bit_depth_control_val =
+ le32_to_cpu(info_v8->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_v8->sAvail_SCLK[i].ulSupportedSCLK) * 10;
+ info->avail_s_clk[i].voltage_index =
+ le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageIndex);
+ info->avail_s_clk[i].voltage_id =
+ le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageID);
+ }
+
+ for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
+ info->ext_disp_conn_info.gu_id[i] =
+ info_v8->sExtDispConnInfo.ucGuid[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_v8->sExtDispConnInfo.sPath[i].usDeviceConnector));
+
+ info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
+ object_id_from_bios_object_id(
+ le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
+
+ info->ext_disp_conn_info.path[i].device_tag =
+ le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceTag);
+ info->ext_disp_conn_info.path[i].device_acpi_enum =
+ le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
+ info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
+ info_v8->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
+ info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
+ info_v8->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
+ info->ext_disp_conn_info.path[i].channel_mapping.raw =
+ info_v8->sExtDispConnInfo.sPath[i].ucChannelMapping;
+ }
+ info->ext_disp_conn_info.checksum =
+ info_v8->sExtDispConnInfo.ucChecksum;
+
+ return BP_RESULT_OK;
+}
+
+/*
+ * get_integrated_info_v8
+ *
+ * @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_v9(
+ struct bios_parser *bp,
+ struct integrated_info *info)
+{
+ ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info_v9;
+ uint32_t i;
+
+ info_v9 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9,
+ bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
+
+ if (!info_v9)
+ return BP_RESULT_BADBIOSTABLE;
+
+ info->boot_up_engine_clock = le32_to_cpu(info_v9->ulBootUpEngineClock) * 10;
+ info->dentist_vco_freq = le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
+ info->boot_up_uma_clock = le32_to_cpu(info_v9->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_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
+ info->disp_clk_voltage[i].voltage_index =
+ le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
+ }
+
+ info->boot_up_req_display_vector =
+ le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
+ info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
+
+ /*
+ * 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_v9->ulSystemConfig);
+ info->cpu_cap_info = le32_to_cpu(info_v9->ulCPUCapInfo);
+ info->boot_up_nb_voltage = le16_to_cpu(info_v9->usBootUpNBVoltage);
+ info->ext_disp_conn_info_offset = le16_to_cpu(info_v9->usExtDispConnInfoOffset);
+ info->memory_type = info_v9->ucMemoryType;
+ info->ma_channel_number = info_v9->ucUMAChannelNumber;
+ info->gmc_restore_reset_time = le32_to_cpu(info_v9->ulGMCRestoreResetTime);
+
+ info->minimum_n_clk = le32_to_cpu(info_v9->ulNbpStateNClkFreq[0]);
+ for (i = 1; i < 4; ++i)
+ info->minimum_n_clk =
+ info->minimum_n_clk < le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]) ?
+ info->minimum_n_clk : le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]);
+
+ info->idle_n_clk = le32_to_cpu(info_v9->ulIdleNClk);
+ info->ddr_dll_power_up_time = le32_to_cpu(info_v9->ulDDR_DLL_PowerUpTime);
+ info->ddr_pll_power_up_time = le32_to_cpu(info_v9->ulDDR_PLL_PowerUpTime);
+ info->pcie_clk_ss_type = le16_to_cpu(info_v9->usPCIEClkSSType);
+ info->lvds_ss_percentage = le16_to_cpu(info_v9->usLvdsSSPercentage);
+ info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v9->usLvdsSSpreadRateIn10Hz);
+ info->hdmi_ss_percentage = le16_to_cpu(info_v9->usHDMISSPercentage);
+ info->hdmi_sspread_rate_in_10hz = le16_to_cpu(info_v9->usHDMISSpreadRateIn10Hz);
+ info->dvi_ss_percentage = le16_to_cpu(info_v9->usDVISSPercentage);
+ info->dvi_sspread_rate_in_10_hz = le16_to_cpu(info_v9->usDVISSpreadRateIn10Hz);
+
+ info->max_lvds_pclk_freq_in_single_link =
+ le16_to_cpu(info_v9->usMaxLVDSPclkFreqInSingleLink);
+ info->lvds_misc = info_v9->ucLvdsMisc;
+ info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
+ info_v9->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
+ info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
+ info_v9->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
+ info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
+ info_v9->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
+ info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
+ info_v9->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
+ info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
+ info_v9->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
+ info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
+ info_v9->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
+ info->lvds_off_to_on_delay_in_4ms =
+ info_v9->ucLVDSOffToOnDelay_in4Ms;
+ info->lvds_bit_depth_control_val =
+ le32_to_cpu(info_v9->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_v9->sAvail_SCLK[i].ulSupportedSCLK) * 10;
+ info->avail_s_clk[i].voltage_index =
+ le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageIndex);
+ info->avail_s_clk[i].voltage_id =
+ le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageID);
+ }
+
+ for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
+ info->ext_disp_conn_info.gu_id[i] =
+ info_v9->sExtDispConnInfo.ucGuid[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_v9->sExtDispConnInfo.sPath[i].usDeviceConnector));
+
+ info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
+ object_id_from_bios_object_id(
+ le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
+
+ info->ext_disp_conn_info.path[i].device_tag =
+ le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceTag);
+ info->ext_disp_conn_info.path[i].device_acpi_enum =
+ le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
+ info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
+ info_v9->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
+ info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
+ info_v9->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
+ info->ext_disp_conn_info.path[i].channel_mapping.raw =
+ info_v9->sExtDispConnInfo.sPath[i].ucChannelMapping;
+ }
+ info->ext_disp_conn_info.checksum =
+ info_v9->sExtDispConnInfo.ucChecksum;
+
+ 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;
+
+ ATOM_COMMON_TABLE_HEADER *header;
+ struct atom_data_revision revision;
+
+ if (bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo) {
+ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
+ bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
+
+ get_atom_data_table_revision(header, &revision);
+
+ /* Don't need to check major revision as they are all 1 */
+ switch (revision.minor) {
+ case 8:
+ result = get_integrated_info_v8(bp, info);
+ break;
+ case 9:
+ result = get_integrated_info_v9(bp, info);
+ break;
+ default:
+ return result;
+
+ }
+ }
+
+ /* Sort voltage table from low to high*/
+ if (result == BP_RESULT_OK) {
+ struct clock_voltage_caps temp = {0, 0};
+ uint32_t i;
+ uint32_t j;
+
+ 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 = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);
+
+ if (info == NULL) {
+ ASSERT_CRITICAL(0);
+ return NULL;
+ }
+
+ if (construct_integrated_info(bp, info) == BP_RESULT_OK)
+ return info;
+
+ kfree(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_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,
+
+ /* bios scratch register communication */
+ .is_accelerated_mode = bios_is_accelerated_mode,
+
+ .set_scratch_critical_state = bios_parser_set_scratch_critical_state,
+
+ .is_device_id_supported = bios_parser_is_device_id_supported,
+
+ /* COMMANDS */
+ .encoder_control = bios_parser_encoder_control,
+
+ .transmitter_control = bios_parser_transmitter_control,
+
+ .crt_control = bios_parser_crt_control, /* not used in DAL3. keep for now in case we need to support VGA on Bonaire */
+
+ .enable_crtc = bios_parser_enable_crtc,
+
+ .adjust_pixel_clock = bios_parser_adjust_pixel_clock,
+
+ .set_pixel_clock = bios_parser_set_pixel_clock,
+
+ .set_dce_clock = bios_parser_set_dce_clock,
+
+ .enable_spread_spectrum_on_ppll = bios_parser_enable_spread_spectrum_on_ppll,
+
+ .program_crtc_timing = bios_parser_program_crtc_timing, /* still use. should probably retire and program directly */
+
+ .crtc_source_select = bios_parser_crtc_source_select, /* still use. should probably retire and program directly */
+
+ .program_display_engine_pll = bios_parser_program_display_engine_pll,
+
+ .enable_disp_power_gating = bios_parser_enable_disp_power_gating,
+
+ /* SW init and patch */
+ .post_init = bios_parser_post_init, /* patch vbios table for mxm module by reading i2c */
+
+ .bios_parser_destroy = bios_parser_destroy,
+};
+
+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;
+ ATOM_ROM_HEADER *rom_header = NULL;
+ ATOM_OBJECT_HEADER *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[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
+
+ bp->base.ctx = init->ctx;
+ bp->base.bios_local_image = NULL;
+
+ rom_header_offset =
+ GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
+
+ if (!rom_header_offset)
+ return false;
+
+ rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
+
+ if (!rom_header)
+ return false;
+
+ get_atom_data_table_revision(&rom_header->sHeader, &tbl_rev);
+ if (tbl_rev.major >= 2 && tbl_rev.minor >= 2)
+ return false;
+
+ bp->master_data_tbl =
+ GET_IMAGE(ATOM_MASTER_DATA_TABLE,
+ rom_header->usMasterDataTableOffset);
+
+ if (!bp->master_data_tbl)
+ return false;
+
+ bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
+
+ if (!bp->object_info_tbl_offset)
+ return false;
+
+ object_info_tbl =
+ GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
+
+ if (!object_info_tbl)
+ return false;
+
+ get_atom_data_table_revision(&object_info_tbl->sHeader,
+ &bp->object_info_tbl.revision);
+
+ if (bp->object_info_tbl.revision.major == 1
+ && bp->object_info_tbl.revision.minor >= 3) {
+ ATOM_OBJECT_HEADER_V3 *tbl_v3;
+
+ tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
+ bp->object_info_tbl_offset);
+ if (!tbl_v3)
+ return false;
+
+ bp->object_info_tbl.v1_3 = tbl_v3;
+ } else if (bp->object_info_tbl.revision.major == 1
+ && bp->object_info_tbl.revision.minor >= 1)
+ bp->object_info_tbl.v1_1 = object_info_tbl;
+ else
+ return false;
+
+ dal_bios_parser_init_cmd_tbl(bp);
+ dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
+
+ bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base);
+
+ return true;
+}
+
+/******************************************************************************/
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.h
new file mode 100644
index 000000000000..d6f16275048f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.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_PARSER_H__
+#define __DAL_BIOS_PARSER_H__
+
+struct dc_bios *bios_parser_create(
+ struct bp_init_data *init,
+ enum dce_version dce_version);
+
+#endif
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 000000000000..1ee1717f2e6f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -0,0 +1,1934 @@
+/*
+ * 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 "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"
+
+#include "bios_parser_common.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 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 dc_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 dc_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)
+{
+ kfree(bp->base.bios_local_image);
+ kfree(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);
+
+ kfree(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;
+}
+
+/* BIOS oject table displaypath is per connector.
+ * There is extra path not for connector. BIOS fill its encoderid as 0
+ */
+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)
+ 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 = bios_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;
+
+ result_device_id.raw_device_tag = 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;
+
+ if (!ss_info)
+ return BP_RESULT_BADINPUT;
+
+ if (!DATA_TABLES(dce_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;
+
+ 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:
+ /* atom_firmware: DAL only get data from dce_info table.
+ * if data within smu_info is needed for DAL, VBIOS should
+ * copy it into dce_info
+ */
+ result = BP_RESULT_UNSUPPORTED;
+ break;
+ default:
+ result = BP_RESULT_UNSUPPORTED;
+ }
+
+ return result;
+}
+
+static enum bp_result get_ss_info_v4_2(
+ 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_2 *disp_cntl_tbl = NULL;
+ struct atom_smu_info_v3_1 *smu_info = 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_2,
+ DATA_TABLES(dce_info));
+ if (!disp_cntl_tbl)
+ return BP_RESULT_BADBIOSTABLE;
+
+ smu_info = GET_IMAGE(struct atom_smu_info_v3_1, DATA_TABLES(smu_info));
+ if (!smu_info)
+ 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 =
+ smu_info->gpuclk_ss_percentage;
+ ss_info->spread_spectrum_range =
+ smu_info->gpuclk_ss_rate_10hz * 10;
+ if (smu_info->gpuclk_ss_mode & ATOM_SS_CENTRE_SPREAD_MODE)
+ ss_info->type.CENTER_MODE = true;
+ break;
+ case AS_SIGNAL_TYPE_GPU_PLL:
+ /* atom_firmware: DAL only get data from dce_info table.
+ * if data within smu_info is needed for DAL, VBIOS should
+ * copy it into dce_info
+ */
+ result = BP_RESULT_UNSUPPORTED;
+ 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);
+ case 2:
+ return get_ss_info_v4_2(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);
+
+ 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 dc_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 dc_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;
+ /*dp_phy_ref_clk is not correct for atom_display_controller_info_v4_2, but we don't use it*/
+ 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.path[i].caps =
+ le16_to_cpu(info_v11->extdispconninfo.path[i].caps);
+ }
+ info->ext_disp_conn_info.checksum =
+ info_v11->extdispconninfo.checksum;
+
+ info->dp0_ext_hdmi_slv_addr = info_v11->dp0_retimer_set.HdmiSlvAddr;
+ info->dp0_ext_hdmi_reg_num = info_v11->dp0_retimer_set.HdmiRegNum;
+ for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
+ info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
+ info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
+ info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
+ info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
+ }
+ info->dp0_ext_hdmi_6g_reg_num = info_v11->dp0_retimer_set.Hdmi6GRegNum;
+ for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
+ info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
+ info_v11->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
+ info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_val =
+ info_v11->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
+ }
+
+ info->dp1_ext_hdmi_slv_addr = info_v11->dp1_retimer_set.HdmiSlvAddr;
+ info->dp1_ext_hdmi_reg_num = info_v11->dp1_retimer_set.HdmiRegNum;
+ for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
+ info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
+ info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
+ info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
+ info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
+ }
+ info->dp1_ext_hdmi_6g_reg_num = info_v11->dp1_retimer_set.Hdmi6GRegNum;
+ for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
+ info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
+ info_v11->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
+ info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_val =
+ info_v11->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
+ }
+
+ info->dp2_ext_hdmi_slv_addr = info_v11->dp2_retimer_set.HdmiSlvAddr;
+ info->dp2_ext_hdmi_reg_num = info_v11->dp2_retimer_set.HdmiRegNum;
+ for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
+ info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
+ info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
+ info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
+ info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
+ }
+ info->dp2_ext_hdmi_6g_reg_num = info_v11->dp2_retimer_set.Hdmi6GRegNum;
+ for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
+ info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
+ info_v11->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
+ info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_val =
+ info_v11->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
+ }
+
+ info->dp3_ext_hdmi_slv_addr = info_v11->dp3_retimer_set.HdmiSlvAddr;
+ info->dp3_ext_hdmi_reg_num = info_v11->dp3_retimer_set.HdmiRegNum;
+ for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
+ info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
+ info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
+ info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
+ info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
+ }
+ info->dp3_ext_hdmi_6g_reg_num = info_v11->dp3_retimer_set.Hdmi6GRegNum;
+ for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
+ info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
+ info_v11->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
+ info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_val =
+ info_v11->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
+ }
+
+
+ /** 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 = kzalloc(sizeof(struct integrated_info), GFP_KERNEL);
+
+ if (info == NULL) {
+ ASSERT_CRITICAL(0);
+ return NULL;
+ }
+
+ if (construct_integrated_info(bp, info) == BP_RESULT_OK)
+ return info;
+
+ kfree(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 = kzalloc(sizeof(struct bios_parser), GFP_KERNEL);
+ if (!bp)
+ return NULL;
+
+ if (bios_parser_construct(bp, init, dce_version))
+ return &bp->base;
+
+ kfree(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 000000000000..cb40546cdafe
--- /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_common.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.c
new file mode 100644
index 000000000000..a8cb039d2572
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.c
@@ -0,0 +1,288 @@
+/*
+ * 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 "bios_parser_common.h"
+#include "include/grph_object_ctrl_defs.h"
+
+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 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;
+}
+
+static 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 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;
+ }
+}
+
+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 (OBJECT_TYPE_UNKNOWN == type)
+ return go_id;
+
+ enum_id = enum_id_from_bios_object_id(bios_object_id);
+
+ if (ENUM_ID_UNKNOWN == enum_id)
+ 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;
+}
+
+
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.h
new file mode 100644
index 000000000000..a076c61dfae4
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.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 __BIOS_PARSER_COMMON_H__
+#define __BIOS_PARSER_COMMON_H__
+
+#include "dm_services.h"
+#include "ObjectID.h"
+
+struct graphics_object_id object_id_from_bios_object_id(uint32_t bios_object_id);
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
new file mode 100644
index 000000000000..5c9e5108c32c
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c
@@ -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
+ *
+ */
+
+#include "dm_services.h"
+
+#include "atom.h"
+
+#include "include/bios_parser_types.h"
+#include "bios_parser_helper.h"
+#include "command_table_helper.h"
+#include "command_table.h"
+#include "bios_parser_types_internal.h"
+
+uint8_t *bios_get_image(struct dc_bios *bp,
+ uint32_t offset,
+ uint32_t size)
+{
+ if (bp->bios && offset + size < bp->bios_size)
+ return bp->bios + offset;
+ else
+ return NULL;
+}
+
+#include "reg_helper.h"
+
+#define CTX \
+ bios->ctx
+#define REG(reg)\
+ (bios->regs->reg)
+
+#undef FN
+#define FN(reg_name, field_name) \
+ ATOM_ ## field_name ## _SHIFT, ATOM_ ## field_name
+
+bool bios_is_accelerated_mode(
+ struct dc_bios *bios)
+{
+ uint32_t acc_mode;
+ REG_GET(BIOS_SCRATCH_6, S6_ACC_MODE, &acc_mode);
+ return (acc_mode == 1);
+}
+
+
+void bios_set_scratch_acc_mode_change(
+ struct dc_bios *bios)
+{
+ REG_UPDATE(BIOS_SCRATCH_6, S6_ACC_MODE, 1);
+}
+
+
+void bios_set_scratch_critical_state(
+ struct dc_bios *bios,
+ bool state)
+{
+ uint32_t critial_state = state ? 1 : 0;
+ REG_UPDATE(BIOS_SCRATCH_6, S6_CRITICAL_STATE, critial_state);
+}
+
+
+
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
new file mode 100644
index 000000000000..c0047efeb006
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-16 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_HELPER_H__
+#define __DAL_BIOS_PARSER_HELPER_H__
+
+struct bios_parser;
+
+uint8_t *bios_get_image(struct dc_bios *bp, uint32_t offset,
+ uint32_t size);
+
+bool bios_is_accelerated_mode(struct dc_bios *bios);
+void bios_set_scratch_acc_mode_change(struct dc_bios *bios);
+void bios_set_scratch_critical_state(struct dc_bios *bios, bool state);
+
+#define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type)))
+
+#endif
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_interface.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_interface.c
new file mode 100644
index 000000000000..0079a1e26efd
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_interface.c
@@ -0,0 +1,56 @@
+/*
+ * 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 "include/logger_interface.h"
+
+#include "bios_parser_interface.h"
+#include "bios_parser.h"
+
+#include "bios_parser2.h"
+
+
+struct dc_bios *dal_bios_parser_create(
+ struct bp_init_data *init,
+ enum dce_version dce_version)
+{
+ struct dc_bios *bios = NULL;
+
+ bios = firmware_parser_create(init, dce_version);
+
+ /* Fall back to old bios parser for older asics */
+ if (bios == NULL)
+ bios = bios_parser_create(init, dce_version);
+
+ return bios;
+}
+
+void dal_bios_parser_destroy(struct dc_bios **dcb)
+{
+ struct dc_bios *bios = *dcb;
+
+ bios->funcs->bios_parser_destroy(dcb);
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal.h
new file mode 100644
index 000000000000..5918923bfb93
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal.h
@@ -0,0 +1,72 @@
+/*
+ * 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_BIOS_H__
+#define __DAL_BIOS_PARSER_TYPES_BIOS_H__
+
+#include "dc_bios_types.h"
+#include "bios_parser_helper.h"
+
+struct atom_data_revision {
+ uint32_t major;
+ uint32_t minor;
+};
+
+struct object_info_table {
+ struct atom_data_revision revision;
+ union {
+ ATOM_OBJECT_HEADER *v1_1;
+ ATOM_OBJECT_HEADER_V3 *v1_3;
+ };
+};
+
+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;
+ ATOM_MASTER_DATA_TABLE *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/bios_parser_types_internal2.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal2.h
new file mode 100644
index 000000000000..bf1f5c86e65c
--- /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_table.c b/drivers/gpu/drm/amd/display/dc/bios/command_table.c
new file mode 100644
index 000000000000..3f7b2dabc2b0
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c
@@ -0,0 +1,2424 @@
+/*
+ * 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_interface.h"
+
+#include "command_table.h"
+#include "command_table_helper.h"
+#include "bios_parser_helper.h"
+#include "bios_parser_types_internal.h"
+
+#define EXEC_BIOS_CMD_TABLE(command, params)\
+ (cgs_atom_exec_cmd_table(bp->base.ctx->cgs_device, \
+ GetIndexIntoMasterTable(COMMAND, command), \
+ &params) == 0)
+
+#define BIOS_CMD_TABLE_REVISION(command, frev, crev)\
+ cgs_atom_get_cmd_table_revs(bp->base.ctx->cgs_device, \
+ GetIndexIntoMasterTable(COMMAND, command), &frev, &crev)
+
+#define BIOS_CMD_TABLE_PARA_REVISION(command)\
+ bios_cmd_table_para_revision(bp->base.ctx->cgs_device, \
+ GetIndexIntoMasterTable(COMMAND, command))
+
+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_enable_spread_spectrum_on_ppll(struct bios_parser *bp);
+static void init_adjust_display_pll(struct bios_parser *bp);
+static void init_dac_encoder_control(struct bios_parser *bp);
+static void init_dac_output_control(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_enable_crtc_mem_req(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_program_clock(struct bios_parser *bp);
+static void init_set_dce_clock(struct bios_parser *bp);
+
+void dal_bios_parser_init_cmd_tbl(struct bios_parser *bp)
+{
+ init_dig_encoder_control(bp);
+ init_transmitter_control(bp);
+ init_set_pixel_clock(bp);
+ init_enable_spread_spectrum_on_ppll(bp);
+ init_adjust_display_pll(bp);
+ init_dac_encoder_control(bp);
+ init_dac_output_control(bp);
+ init_set_crtc_timing(bp);
+ init_select_crtc_source(bp);
+ init_enable_crtc(bp);
+ init_enable_crtc_mem_req(bp);
+ init_program_clock(bp);
+ init_external_encoder_control(bp);
+ init_enable_disp_power_gating(bp);
+ init_set_dce_clock(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_v3(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl);
+
+static enum bp_result encoder_control_digx_v4(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl);
+
+static enum bp_result encoder_control_digx_v5(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl);
+
+static void init_encoder_control_dig_v1(struct bios_parser *bp);
+
+static void init_dig_encoder_control(struct bios_parser *bp)
+{
+ uint32_t version =
+ BIOS_CMD_TABLE_PARA_REVISION(DIGxEncoderControl);
+
+ switch (version) {
+ case 2:
+ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v3;
+ break;
+ case 4:
+ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v4;
+ break;
+
+ case 5:
+ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v5;
+ break;
+
+ default:
+ init_encoder_control_dig_v1(bp);
+ break;
+ }
+}
+
+static enum bp_result encoder_control_dig_v1(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl);
+static enum bp_result encoder_control_dig1_v1(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl);
+static enum bp_result encoder_control_dig2_v1(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl);
+
+static void init_encoder_control_dig_v1(struct bios_parser *bp)
+{
+ struct cmd_tbl *cmd_tbl = &bp->cmd_tbl;
+
+ if (1 == BIOS_CMD_TABLE_PARA_REVISION(DIG1EncoderControl))
+ cmd_tbl->encoder_control_dig1 = encoder_control_dig1_v1;
+ else
+ cmd_tbl->encoder_control_dig1 = NULL;
+
+ if (1 == BIOS_CMD_TABLE_PARA_REVISION(DIG2EncoderControl))
+ cmd_tbl->encoder_control_dig2 = encoder_control_dig2_v1;
+ else
+ cmd_tbl->encoder_control_dig2 = NULL;
+
+ cmd_tbl->dig_encoder_control = encoder_control_dig_v1;
+}
+
+static enum bp_result encoder_control_dig_v1(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ struct cmd_tbl *cmd_tbl = &bp->cmd_tbl;
+
+ if (cntl != NULL)
+ switch (cntl->engine_id) {
+ case ENGINE_ID_DIGA:
+ if (cmd_tbl->encoder_control_dig1 != NULL)
+ result =
+ cmd_tbl->encoder_control_dig1(bp, cntl);
+ break;
+ case ENGINE_ID_DIGB:
+ if (cmd_tbl->encoder_control_dig2 != NULL)
+ result =
+ cmd_tbl->encoder_control_dig2(bp, cntl);
+ break;
+
+ default:
+ break;
+ }
+
+ return result;
+}
+
+static enum bp_result encoder_control_dig1_v1(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DIG_ENCODER_CONTROL_PARAMETERS_V2 params = {0};
+
+ bp->cmd_helper->assign_control_parameter(bp->cmd_helper, cntl, &params);
+
+ if (EXEC_BIOS_CMD_TABLE(DIG1EncoderControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result encoder_control_dig2_v1(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DIG_ENCODER_CONTROL_PARAMETERS_V2 params = {0};
+
+ bp->cmd_helper->assign_control_parameter(bp->cmd_helper, cntl, &params);
+
+ if (EXEC_BIOS_CMD_TABLE(DIG2EncoderControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result encoder_control_digx_v3(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DIG_ENCODER_CONTROL_PARAMETERS_V3 params = {0};
+
+ if (LANE_COUNT_FOUR < cntl->lanes_number)
+ params.acConfig.ucDPLinkRate = 1; /* dual link 2.7GHz */
+ else
+ params.acConfig.ucDPLinkRate = 0; /* single link 1.62GHz */
+
+ params.acConfig.ucDigSel = (uint8_t)(cntl->engine_id);
+
+ /* We need to convert from KHz units into 10KHz units */
+ params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action);
+ params.usPixelClock = cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
+ params.ucEncoderMode =
+ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
+ cntl->signal,
+ cntl->enable_dp_audio);
+ params.ucLaneNum = (uint8_t)(cntl->lanes_number);
+
+ if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result encoder_control_digx_v4(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DIG_ENCODER_CONTROL_PARAMETERS_V4 params = {0};
+
+ if (LANE_COUNT_FOUR < cntl->lanes_number)
+ params.acConfig.ucDPLinkRate = 1; /* dual link 2.7GHz */
+ else
+ params.acConfig.ucDPLinkRate = 0; /* single link 1.62GHz */
+
+ params.acConfig.ucDigSel = (uint8_t)(cntl->engine_id);
+
+ /* We need to convert from KHz units into 10KHz units */
+ params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action);
+ params.usPixelClock = cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
+ params.ucEncoderMode =
+ (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom(
+ cntl->signal,
+ cntl->enable_dp_audio));
+ params.ucLaneNum = (uint8_t)(cntl->lanes_number);
+
+ if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result encoder_control_digx_v5(
+ struct bios_parser *bp,
+ struct bp_encoder_control *cntl)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ ENCODER_STREAM_SETUP_PARAMETERS_V5 params = {0};
+
+ params.ucDigId = (uint8_t)(cntl->engine_id);
+ params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action);
+
+ params.ulPixelClock = cntl->pixel_clock / 10;
+ params.ucDigMode =
+ (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom(
+ cntl->signal,
+ cntl->enable_dp_audio));
+ params.ucLaneNum = (uint8_t)(cntl->lanes_number);
+
+ switch (cntl->color_depth) {
+ case COLOR_DEPTH_888:
+ params.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ break;
+ case COLOR_DEPTH_101010:
+ params.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+ break;
+ case COLOR_DEPTH_121212:
+ params.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+ break;
+ case COLOR_DEPTH_161616:
+ params.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+ break;
+ default:
+ break;
+ }
+
+ if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A)
+ switch (cntl->color_depth) {
+ case COLOR_DEPTH_101010:
+ params.ulPixelClock =
+ (params.ulPixelClock * 30) / 24;
+ break;
+ case COLOR_DEPTH_121212:
+ params.ulPixelClock =
+ (params.ulPixelClock * 36) / 24;
+ break;
+ case COLOR_DEPTH_161616:
+ params.ulPixelClock =
+ (params.ulPixelClock * 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_v2(
+ struct bios_parser *bp,
+ struct bp_transmitter_control *cntl);
+static enum bp_result transmitter_control_v3(
+ struct bios_parser *bp,
+ struct bp_transmitter_control *cntl);
+static enum bp_result transmitter_control_v4(
+ struct bios_parser *bp,
+ struct bp_transmitter_control *cntl);
+static enum bp_result transmitter_control_v1_5(
+ struct bios_parser *bp,
+ struct bp_transmitter_control *cntl);
+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(UNIPHYTransmitterControl,
+ frev, crev) != 0)
+ BREAK_TO_DEBUGGER();
+ switch (crev) {
+ case 2:
+ bp->cmd_tbl.transmitter_control = transmitter_control_v2;
+ break;
+ case 3:
+ bp->cmd_tbl.transmitter_control = transmitter_control_v3;
+ break;
+ case 4:
+ bp->cmd_tbl.transmitter_control = transmitter_control_v4;
+ break;
+ case 5:
+ bp->cmd_tbl.transmitter_control = transmitter_control_v1_5;
+ break;
+ 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_v2(
+ struct bios_parser *bp,
+ struct bp_transmitter_control *cntl)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 params;
+ enum connector_id connector_id =
+ dal_graphics_object_id_get_connector_id(cntl->connector_obj_id);
+
+ memset(&params, 0, sizeof(params));
+
+ switch (cntl->transmitter) {
+ case TRANSMITTER_UNIPHY_A:
+ case TRANSMITTER_UNIPHY_B:
+ case TRANSMITTER_UNIPHY_C:
+ case TRANSMITTER_UNIPHY_D:
+ case TRANSMITTER_UNIPHY_E:
+ case TRANSMITTER_UNIPHY_F:
+ case TRANSMITTER_TRAVIS_LCD:
+ break;
+ default:
+ return BP_RESULT_BADINPUT;
+ }
+
+ switch (cntl->action) {
+ case TRANSMITTER_CONTROL_INIT:
+ if ((CONNECTOR_ID_DUAL_LINK_DVII == connector_id) ||
+ (CONNECTOR_ID_DUAL_LINK_DVID == connector_id))
+ /* on INIT this bit should be set according to the
+ * phisycal connector
+ * Bit0: dual link connector flag
+ * =0 connector is single link connector
+ * =1 connector is dual link connector
+ */
+ params.acConfig.fDualLinkConnector = 1;
+
+ /* connector object id */
+ params.usInitInfo =
+ cpu_to_le16((uint8_t)cntl->connector_obj_id.id);
+ break;
+ case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS:
+ /* votage swing and pre-emphsis */
+ params.asMode.ucLaneSel = (uint8_t)cntl->lane_select;
+ params.asMode.ucLaneSet = (uint8_t)cntl->lane_settings;
+ break;
+ default:
+ /* if dual-link */
+ if (LANE_COUNT_FOUR < cntl->lanes_number) {
+ /* on ENABLE/DISABLE this bit should be set according to
+ * actual timing (number of lanes)
+ * Bit0: dual link connector flag
+ * =0 connector is single link connector
+ * =1 connector is dual link connector
+ */
+ params.acConfig.fDualLinkConnector = 1;
+
+ /* link rate, half for dual link
+ * We need to convert from KHz units into 20KHz units
+ */
+ params.usPixelClock =
+ cpu_to_le16((uint16_t)(cntl->pixel_clock / 20));
+ } else
+ /* link rate, half for dual link
+ * We need to convert from KHz units into 10KHz units
+ */
+ params.usPixelClock =
+ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
+ break;
+ }
+
+ /* 00 - coherent mode
+ * 01 - incoherent mode
+ */
+
+ params.acConfig.fCoherentMode = cntl->coherent;
+
+ if ((TRANSMITTER_UNIPHY_B == cntl->transmitter)
+ || (TRANSMITTER_UNIPHY_D == cntl->transmitter)
+ || (TRANSMITTER_UNIPHY_F == cntl->transmitter))
+ /* Bit2: Transmitter Link selection
+ * =0 when bit0=0, single link A/C/E, when bit0=1,
+ * master link A/C/E
+ * =1 when bit0=0, single link B/D/F, when bit0=1,
+ * master link B/D/F
+ */
+ params.acConfig.ucLinkSel = 1;
+
+ if (ENGINE_ID_DIGB == cntl->engine_id)
+ /* Bit3: Transmitter data source selection
+ * =0 DIGA is data source.
+ * =1 DIGB is data source.
+ * This bit is only useful when ucAction= ATOM_ENABLE
+ */
+ params.acConfig.ucEncoderSel = 1;
+
+ if (CONNECTOR_ID_DISPLAY_PORT == connector_id)
+ /* Bit4: DP connector flag
+ * =0 connector is none-DP connector
+ * =1 connector is DP connector
+ */
+ params.acConfig.fDPConnector = 1;
+
+ /* Bit[7:6]: Transmitter selection
+ * =0 UNIPHY_ENCODER: UNIPHYA/B
+ * =1 UNIPHY1_ENCODER: UNIPHYC/D
+ * =2 UNIPHY2_ENCODER: UNIPHYE/F
+ * =3 reserved
+ */
+ params.acConfig.ucTransmitterSel =
+ (uint8_t)bp->cmd_helper->transmitter_bp_to_atom(
+ cntl->transmitter);
+
+ params.ucAction = (uint8_t)cntl->action;
+
+ if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result transmitter_control_v3(
+ struct bios_parser *bp,
+ struct bp_transmitter_control *cntl)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 params;
+ uint32_t pll_id;
+ enum connector_id conn_id =
+ dal_graphics_object_id_get_connector_id(cntl->connector_obj_id);
+ const struct command_table_helper *cmd = bp->cmd_helper;
+ bool dual_link_conn = (CONNECTOR_ID_DUAL_LINK_DVII == conn_id)
+ || (CONNECTOR_ID_DUAL_LINK_DVID == conn_id);
+
+ memset(&params, 0, sizeof(params));
+
+ switch (cntl->transmitter) {
+ case TRANSMITTER_UNIPHY_A:
+ case TRANSMITTER_UNIPHY_B:
+ case TRANSMITTER_UNIPHY_C:
+ case TRANSMITTER_UNIPHY_D:
+ case TRANSMITTER_UNIPHY_E:
+ case TRANSMITTER_UNIPHY_F:
+ case TRANSMITTER_TRAVIS_LCD:
+ break;
+ default:
+ return BP_RESULT_BADINPUT;
+ }
+
+ if (!cmd->clock_source_id_to_atom(cntl->pll_id, &pll_id))
+ return BP_RESULT_BADINPUT;
+
+ /* fill information based on the action */
+ switch (cntl->action) {
+ case TRANSMITTER_CONTROL_INIT:
+ if (dual_link_conn) {
+ /* on INIT this bit should be set according to the
+ * phisycal connector
+ * Bit0: dual link connector flag
+ * =0 connector is single link connector
+ * =1 connector is dual link connector
+ */
+ params.acConfig.fDualLinkConnector = 1;
+ }
+
+ /* connector object id */
+ params.usInitInfo =
+ cpu_to_le16((uint8_t)(cntl->connector_obj_id.id));
+ break;
+ case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS:
+ /* votage swing and pre-emphsis */
+ params.asMode.ucLaneSel = (uint8_t)cntl->lane_select;
+ params.asMode.ucLaneSet = (uint8_t)cntl->lane_settings;
+ break;
+ default:
+ if (dual_link_conn && cntl->multi_path)
+ /* on ENABLE/DISABLE this bit should be set according to
+ * actual timing (number of lanes)
+ * Bit0: dual link connector flag
+ * =0 connector is single link connector
+ * =1 connector is dual link connector
+ */
+ params.acConfig.fDualLinkConnector = 1;
+
+ /* if dual-link */
+ if (LANE_COUNT_FOUR < cntl->lanes_number) {
+ /* on ENABLE/DISABLE this bit should be set according to
+ * actual timing (number of lanes)
+ * Bit0: dual link connector flag
+ * =0 connector is single link connector
+ * =1 connector is dual link connector
+ */
+ params.acConfig.fDualLinkConnector = 1;
+
+ /* link rate, half for dual link
+ * We need to convert from KHz units into 20KHz units
+ */
+ params.usPixelClock =
+ cpu_to_le16((uint16_t)(cntl->pixel_clock / 20));
+ } else {
+ /* link rate, half for dual link
+ * We need to convert from KHz units into 10KHz units
+ */
+ params.usPixelClock =
+ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
+ }
+ break;
+ }
+
+ /* 00 - coherent mode
+ * 01 - incoherent mode
+ */
+
+ params.acConfig.fCoherentMode = cntl->coherent;
+
+ if ((TRANSMITTER_UNIPHY_B == cntl->transmitter)
+ || (TRANSMITTER_UNIPHY_D == cntl->transmitter)
+ || (TRANSMITTER_UNIPHY_F == cntl->transmitter))
+ /* Bit2: Transmitter Link selection
+ * =0 when bit0=0, single link A/C/E, when bit0=1,
+ * master link A/C/E
+ * =1 when bit0=0, single link B/D/F, when bit0=1,
+ * master link B/D/F
+ */
+ params.acConfig.ucLinkSel = 1;
+
+ if (ENGINE_ID_DIGB == cntl->engine_id)
+ /* Bit3: Transmitter data source selection
+ * =0 DIGA is data source.
+ * =1 DIGB is data source.
+ * This bit is only useful when ucAction= ATOM_ENABLE
+ */
+ params.acConfig.ucEncoderSel = 1;
+
+ /* Bit[7:6]: Transmitter selection
+ * =0 UNIPHY_ENCODER: UNIPHYA/B
+ * =1 UNIPHY1_ENCODER: UNIPHYC/D
+ * =2 UNIPHY2_ENCODER: UNIPHYE/F
+ * =3 reserved
+ */
+ params.acConfig.ucTransmitterSel =
+ (uint8_t)cmd->transmitter_bp_to_atom(cntl->transmitter);
+
+ params.ucLaneNum = (uint8_t)cntl->lanes_number;
+
+ params.acConfig.ucRefClkSource = (uint8_t)pll_id;
+
+ params.ucAction = (uint8_t)cntl->action;
+
+ if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result transmitter_control_v4(
+ struct bios_parser *bp,
+ struct bp_transmitter_control *cntl)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 params;
+ uint32_t ref_clk_src_id;
+ enum connector_id conn_id =
+ dal_graphics_object_id_get_connector_id(cntl->connector_obj_id);
+ const struct command_table_helper *cmd = bp->cmd_helper;
+
+ memset(&params, 0, sizeof(params));
+
+ switch (cntl->transmitter) {
+ case TRANSMITTER_UNIPHY_A:
+ case TRANSMITTER_UNIPHY_B:
+ case TRANSMITTER_UNIPHY_C:
+ case TRANSMITTER_UNIPHY_D:
+ case TRANSMITTER_UNIPHY_E:
+ case TRANSMITTER_UNIPHY_F:
+ case TRANSMITTER_TRAVIS_LCD:
+ break;
+ default:
+ return BP_RESULT_BADINPUT;
+ }
+
+ if (!cmd->clock_source_id_to_ref_clk_src(cntl->pll_id, &ref_clk_src_id))
+ return BP_RESULT_BADINPUT;
+
+ switch (cntl->action) {
+ case TRANSMITTER_CONTROL_INIT:
+ {
+ if ((CONNECTOR_ID_DUAL_LINK_DVII == conn_id) ||
+ (CONNECTOR_ID_DUAL_LINK_DVID == conn_id))
+ /* on INIT this bit should be set according to the
+ * phisycal connector
+ * Bit0: dual link connector flag
+ * =0 connector is single link connector
+ * =1 connector is dual link connector
+ */
+ params.acConfig.fDualLinkConnector = 1;
+
+ /* connector object id */
+ params.usInitInfo =
+ cpu_to_le16((uint8_t)(cntl->connector_obj_id.id));
+ }
+ break;
+ case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS:
+ /* votage swing and pre-emphsis */
+ params.asMode.ucLaneSel = (uint8_t)(cntl->lane_select);
+ params.asMode.ucLaneSet = (uint8_t)(cntl->lane_settings);
+ break;
+ default:
+ if ((CONNECTOR_ID_DUAL_LINK_DVII == conn_id) ||
+ (CONNECTOR_ID_DUAL_LINK_DVID == conn_id))
+ /* on ENABLE/DISABLE this bit should be set according to
+ * actual timing (number of lanes)
+ * Bit0: dual link connector flag
+ * =0 connector is single link connector
+ * =1 connector is dual link connector
+ */
+ params.acConfig.fDualLinkConnector = 1;
+
+ /* if dual-link */
+ if (LANE_COUNT_FOUR < cntl->lanes_number)
+ /* link rate, half for dual link
+ * We need to convert from KHz units into 20KHz units
+ */
+ params.usPixelClock =
+ cpu_to_le16((uint16_t)(cntl->pixel_clock / 20));
+ else {
+ /* link rate, half for dual link
+ * We need to convert from KHz units into 10KHz units
+ */
+ params.usPixelClock =
+ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
+ }
+ break;
+ }
+
+ /* 00 - coherent mode
+ * 01 - incoherent mode
+ */
+
+ params.acConfig.fCoherentMode = cntl->coherent;
+
+ if ((TRANSMITTER_UNIPHY_B == cntl->transmitter)
+ || (TRANSMITTER_UNIPHY_D == cntl->transmitter)
+ || (TRANSMITTER_UNIPHY_F == cntl->transmitter))
+ /* Bit2: Transmitter Link selection
+ * =0 when bit0=0, single link A/C/E, when bit0=1,
+ * master link A/C/E
+ * =1 when bit0=0, single link B/D/F, when bit0=1,
+ * master link B/D/F
+ */
+ params.acConfig.ucLinkSel = 1;
+
+ if (ENGINE_ID_DIGB == cntl->engine_id)
+ /* Bit3: Transmitter data source selection
+ * =0 DIGA is data source.
+ * =1 DIGB is data source.
+ * This bit is only useful when ucAction= ATOM_ENABLE
+ */
+ params.acConfig.ucEncoderSel = 1;
+
+ /* Bit[7:6]: Transmitter selection
+ * =0 UNIPHY_ENCODER: UNIPHYA/B
+ * =1 UNIPHY1_ENCODER: UNIPHYC/D
+ * =2 UNIPHY2_ENCODER: UNIPHYE/F
+ * =3 reserved
+ */
+ params.acConfig.ucTransmitterSel =
+ (uint8_t)(cmd->transmitter_bp_to_atom(cntl->transmitter));
+ params.ucLaneNum = (uint8_t)(cntl->lanes_number);
+ params.acConfig.ucRefClkSource = (uint8_t)(ref_clk_src_id);
+ params.ucAction = (uint8_t)(cntl->action);
+
+ if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result transmitter_control_v1_5(
+ 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;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 params;
+
+ memset(&params, 0, sizeof(params));
+ params.ucPhyId = cmd->phy_id_to_atom(cntl->transmitter);
+ params.ucAction = (uint8_t)cntl->action;
+ params.ucLaneNum = (uint8_t)cntl->lanes_number;
+ params.ucConnObjId = (uint8_t)cntl->connector_obj_id.id;
+
+ params.ucDigMode =
+ cmd->signal_type_to_atom_dig_mode(cntl->signal);
+ params.asConfig.ucPhyClkSrcId =
+ cmd->clock_source_id_to_atom_phy_clk_src_id(cntl->pll_id);
+ /* 00 - coherent mode */
+ params.asConfig.ucCoherentMode = cntl->coherent;
+ params.asConfig.ucHPDSel =
+ cmd->hpd_sel_to_atom(cntl->hpd_sel);
+ params.ucDigEncoderSel =
+ cmd->dig_encoder_sel_to_atom(cntl->engine_id);
+ params.ucDPLaneSet = (uint8_t) cntl->lane_settings;
+ params.usSymClock = cpu_to_le16((uint16_t) (cntl->pixel_clock / 10));
+ /*
+ * In SI/TN case, caller have to set usPixelClock as following:
+ * DP mode: usPixelClock = DP_LINK_CLOCK/10
+ * (DP_LINK_CLOCK = 1.62GHz, 2.7GHz, 5.4GHz)
+ * DVI single link mode: usPixelClock = pixel clock
+ * DVI dual link mode: usPixelClock = pixel clock
+ * HDMI mode: usPixelClock = pixel clock * deep_color_ratio
+ * (=1: 8bpp, =1.25: 10bpp, =1.5:12bpp, =2: 16bpp)
+ * LVDS mode: usPixelClock = pixel clock
+ */
+
+ if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+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;
+ DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_6 params;
+
+ memset(&params, 0, sizeof(params));
+ params.ucPhyId = cmd->phy_id_to_atom(cntl->transmitter);
+ params.ucAction = (uint8_t)cntl->action;
+
+ if (cntl->action == TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS)
+ params.ucDPLaneSet = (uint8_t)cntl->lane_settings;
+ else
+ params.ucDigMode = cmd->signal_type_to_atom_dig_mode(cntl->signal);
+
+ params.ucLaneNum = (uint8_t)cntl->lanes_number;
+ params.ucHPDSel = cmd->hpd_sel_to_atom(cntl->hpd_sel);
+ params.ucDigEncoderSel = cmd->dig_encoder_sel_to_atom(cntl->engine_id);
+ params.ucConnObjId = (uint8_t)cntl->connector_obj_id.id;
+ params.ulSymClock = cntl->pixel_clock/10;
+
+ /*
+ * In SI/TN case, caller have to set usPixelClock as following:
+ * DP mode: usPixelClock = DP_LINK_CLOCK/10
+ * (DP_LINK_CLOCK = 1.62GHz, 2.7GHz, 5.4GHz)
+ * DVI single link mode: usPixelClock = pixel clock
+ * DVI dual link mode: usPixelClock = pixel clock
+ * HDMI mode: usPixelClock = pixel clock * deep_color_ratio
+ * (=1: 8bpp, =1.25: 10bpp, =1.5:12bpp, =2: 16bpp)
+ * LVDS mode: usPixelClock = pixel clock
+ */
+ switch (cntl->signal) {
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ switch (cntl->color_depth) {
+ case COLOR_DEPTH_101010:
+ params.ulSymClock =
+ cpu_to_le16((le16_to_cpu(params.ulSymClock) * 30) / 24);
+ break;
+ case COLOR_DEPTH_121212:
+ params.ulSymClock =
+ cpu_to_le16((le16_to_cpu(params.ulSymClock) * 36) / 24);
+ break;
+ case COLOR_DEPTH_161616:
+ params.ulSymClock =
+ cpu_to_le16((le16_to_cpu(params.ulSymClock) * 48) / 24);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params))
+ result = BP_RESULT_OK;
+ return result;
+}
+
+/*******************************************************************************
+ ********************************************************************************
+ **
+ ** SET PIXEL CLOCK
+ **
+ ********************************************************************************
+ *******************************************************************************/
+
+static enum bp_result set_pixel_clock_v3(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params);
+static enum bp_result set_pixel_clock_v5(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params);
+static enum bp_result set_pixel_clock_v6(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params);
+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 3:
+ bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v3;
+ break;
+ case 5:
+ bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v5;
+ break;
+ case 6:
+ bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v6;
+ break;
+ 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_v3(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ PIXEL_CLOCK_PARAMETERS_V3 *params;
+ SET_PIXEL_CLOCK_PS_ALLOCATION allocation;
+
+ memset(&allocation, 0, sizeof(allocation));
+
+ if (CLOCK_SOURCE_ID_PLL1 == bp_params->pll_id)
+ allocation.sPCLKInput.ucPpll = ATOM_PPLL1;
+ else if (CLOCK_SOURCE_ID_PLL2 == bp_params->pll_id)
+ allocation.sPCLKInput.ucPpll = ATOM_PPLL2;
+ else
+ return BP_RESULT_BADINPUT;
+
+ allocation.sPCLKInput.usRefDiv =
+ cpu_to_le16((uint16_t)bp_params->reference_divider);
+ allocation.sPCLKInput.usFbDiv =
+ cpu_to_le16((uint16_t)bp_params->feedback_divider);
+ allocation.sPCLKInput.ucFracFbDiv =
+ (uint8_t)bp_params->fractional_feedback_divider;
+ allocation.sPCLKInput.ucPostDiv =
+ (uint8_t)bp_params->pixel_clock_post_divider;
+
+ /* We need to convert from KHz units into 10KHz units */
+ allocation.sPCLKInput.usPixelClock =
+ cpu_to_le16((uint16_t)(bp_params->target_pixel_clock / 10));
+
+ params = (PIXEL_CLOCK_PARAMETERS_V3 *)&allocation.sPCLKInput;
+ params->ucTransmitterId =
+ bp->cmd_helper->encoder_id_to_atom(
+ dal_graphics_object_id_get_encoder_id(
+ bp_params->encoder_object_id));
+ params->ucEncoderMode =
+ (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom(
+ bp_params->signal_type, false));
+
+ if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL)
+ params->ucMiscInfo |= PIXEL_CLOCK_MISC_FORCE_PROG_PPLL;
+
+ if (bp_params->flags.USE_E_CLOCK_AS_SOURCE_FOR_D_CLOCK)
+ params->ucMiscInfo |= PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK;
+
+ if (CONTROLLER_ID_D1 != bp_params->controller_id)
+ params->ucMiscInfo |= PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
+
+ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, allocation))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+#ifndef SET_PIXEL_CLOCK_PS_ALLOCATION_V5
+/* video bios did not define this: */
+typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION_V5 {
+ PIXEL_CLOCK_PARAMETERS_V5 sPCLKInput;
+ /* Caller doesn't need to init this portion */
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;
+} SET_PIXEL_CLOCK_PS_ALLOCATION_V5;
+#endif
+
+#ifndef SET_PIXEL_CLOCK_PS_ALLOCATION_V6
+/* video bios did not define this: */
+typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION_V6 {
+ PIXEL_CLOCK_PARAMETERS_V6 sPCLKInput;
+ /* Caller doesn't need to init this portion */
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;
+} SET_PIXEL_CLOCK_PS_ALLOCATION_V6;
+#endif
+
+static enum bp_result set_pixel_clock_v5(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ SET_PIXEL_CLOCK_PS_ALLOCATION_V5 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)) {
+ clk.sPCLKInput.ucCRTC = controller_id;
+ clk.sPCLKInput.ucPpll = (uint8_t)pll_id;
+ clk.sPCLKInput.ucRefDiv =
+ (uint8_t)(bp_params->reference_divider);
+ clk.sPCLKInput.usFbDiv =
+ cpu_to_le16((uint16_t)(bp_params->feedback_divider));
+ clk.sPCLKInput.ulFbDivDecFrac =
+ cpu_to_le32(bp_params->fractional_feedback_divider);
+ clk.sPCLKInput.ucPostDiv =
+ (uint8_t)(bp_params->pixel_clock_post_divider);
+ clk.sPCLKInput.ucTransmitterID =
+ bp->cmd_helper->encoder_id_to_atom(
+ dal_graphics_object_id_get_encoder_id(
+ bp_params->encoder_object_id));
+ clk.sPCLKInput.ucEncoderMode =
+ (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.sPCLKInput.usPixelClock =
+ cpu_to_le16((uint16_t)(bp_params->target_pixel_clock / 10));
+
+ if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL)
+ clk.sPCLKInput.ucMiscInfo |=
+ PIXEL_CLOCK_MISC_FORCE_PROG_PPLL;
+
+ if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC)
+ clk.sPCLKInput.ucMiscInfo |=
+ PIXEL_CLOCK_MISC_REF_DIV_SRC;
+
+ /* clkV5.ucMiscInfo bit[3:2]= HDMI panel bit depth: =0: 24bpp
+ * =1:30bpp, =2:32bpp
+ * driver choose program it itself, i.e. here we program it
+ * to 888 by default.
+ */
+
+ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk))
+ result = BP_RESULT_OK;
+ }
+
+ return result;
+}
+
+static enum bp_result set_pixel_clock_v6(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ SET_PIXEL_CLOCK_PS_ALLOCATION_V6 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.sPCLKInput.ulCrtcPclkFreq.ucCRTC = controller_id;
+ clk.sPCLKInput.ucPpll = (uint8_t) pll_id;
+ clk.sPCLKInput.ucRefDiv =
+ (uint8_t) bp_params->reference_divider;
+ clk.sPCLKInput.usFbDiv =
+ cpu_to_le16((uint16_t) bp_params->feedback_divider);
+ clk.sPCLKInput.ulFbDivDecFrac =
+ cpu_to_le32(bp_params->fractional_feedback_divider);
+ clk.sPCLKInput.ucPostDiv =
+ (uint8_t) bp_params->pixel_clock_post_divider;
+ clk.sPCLKInput.ucTransmitterID =
+ bp->cmd_helper->encoder_id_to_atom(
+ dal_graphics_object_id_get_encoder_id(
+ bp_params->encoder_object_id));
+ clk.sPCLKInput.ucEncoderMode =
+ (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.sPCLKInput.ulCrtcPclkFreq.ulPixelClock =
+ cpu_to_le32(bp_params->target_pixel_clock / 10);
+
+ if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) {
+ clk.sPCLKInput.ucMiscInfo |=
+ PIXEL_CLOCK_V6_MISC_FORCE_PROG_PPLL;
+ }
+
+ if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC) {
+ clk.sPCLKInput.ucMiscInfo |=
+ PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
+ }
+
+ /* clkV6.ucMiscInfo bit[3:2]= HDMI panel bit depth: =0:
+ * 24bpp =1:30bpp, =2:32bpp
+ * driver choose program it itself, i.e. here we pass required
+ * target rate that includes deep color.
+ */
+
+ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk))
+ result = BP_RESULT_OK;
+ }
+
+ return result;
+}
+
+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;
+ PIXEL_CLOCK_PARAMETERS_V7 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.ucCRTC = controller_id;
+ clk.ucPpll = (uint8_t) pll_id;
+ clk.ucTransmitterID = bp->cmd_helper->encoder_id_to_atom(dal_graphics_object_id_get_encoder_id(bp_params->encoder_object_id));
+ clk.ucEncoderMode = (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.ulPixelClock = cpu_to_le32(bp_params->target_pixel_clock * 10);
+
+ clk.ucDeepColorRatio = (uint8_t) bp->cmd_helper->transmitter_color_depth_to_atom(bp_params->color_depth);
+
+ if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL)
+ clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_FORCE_PROG_PPLL;
+
+ if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC)
+ clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_REF_DIV_SRC;
+
+ if (bp_params->flags.PROGRAM_PHY_PLL_ONLY)
+ clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_PROG_PHYPLL;
+
+ if (bp_params->flags.SUPPORT_YUV_420)
+ clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_YUV420_MODE;
+
+ if (bp_params->flags.SET_XTALIN_REF_SRC)
+ clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_REF_DIV_SRC_XTALIN;
+
+ if (bp_params->flags.SET_GENLOCK_REF_DIV_SRC)
+ clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_REF_DIV_SRC_GENLK;
+
+ if (bp_params->signal_type == SIGNAL_TYPE_DVI_DUAL_LINK)
+ clk.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN;
+
+ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk))
+ result = BP_RESULT_OK;
+ }
+ return result;
+}
+
+/*******************************************************************************
+ ********************************************************************************
+ **
+ ** ENABLE PIXEL CLOCK SS
+ **
+ ********************************************************************************
+ *******************************************************************************/
+static enum bp_result enable_spread_spectrum_on_ppll_v1(
+ struct bios_parser *bp,
+ struct bp_spread_spectrum_parameters *bp_params,
+ bool enable);
+static enum bp_result enable_spread_spectrum_on_ppll_v2(
+ struct bios_parser *bp,
+ struct bp_spread_spectrum_parameters *bp_params,
+ bool enable);
+static enum bp_result enable_spread_spectrum_on_ppll_v3(
+ struct bios_parser *bp,
+ struct bp_spread_spectrum_parameters *bp_params,
+ bool enable);
+
+static void init_enable_spread_spectrum_on_ppll(struct bios_parser *bp)
+{
+ switch (BIOS_CMD_TABLE_PARA_REVISION(EnableSpreadSpectrumOnPPLL)) {
+ case 1:
+ bp->cmd_tbl.enable_spread_spectrum_on_ppll =
+ enable_spread_spectrum_on_ppll_v1;
+ break;
+ case 2:
+ bp->cmd_tbl.enable_spread_spectrum_on_ppll =
+ enable_spread_spectrum_on_ppll_v2;
+ break;
+ case 3:
+ bp->cmd_tbl.enable_spread_spectrum_on_ppll =
+ enable_spread_spectrum_on_ppll_v3;
+ break;
+ default:
+ bp->cmd_tbl.enable_spread_spectrum_on_ppll = NULL;
+ break;
+ }
+}
+
+static enum bp_result enable_spread_spectrum_on_ppll_v1(
+ struct bios_parser *bp,
+ struct bp_spread_spectrum_parameters *bp_params,
+ bool enable)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL params;
+
+ memset(&params, 0, sizeof(params));
+
+ if ((enable == true) && (bp_params->percentage > 0))
+ params.ucEnable = ATOM_ENABLE;
+ else
+ params.ucEnable = ATOM_DISABLE;
+
+ params.usSpreadSpectrumPercentage =
+ cpu_to_le16((uint16_t)bp_params->percentage);
+ params.ucSpreadSpectrumStep =
+ (uint8_t)bp_params->ver1.step;
+ params.ucSpreadSpectrumDelay =
+ (uint8_t)bp_params->ver1.delay;
+ /* convert back to unit of 10KHz */
+ params.ucSpreadSpectrumRange =
+ (uint8_t)(bp_params->ver1.range / 10000);
+
+ if (bp_params->flags.EXTERNAL_SS)
+ params.ucSpreadSpectrumType |= ATOM_EXTERNAL_SS_MASK;
+
+ if (bp_params->flags.CENTER_SPREAD)
+ params.ucSpreadSpectrumType |= ATOM_SS_CENTRE_SPREAD_MODE;
+
+ if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL1)
+ params.ucPpll = ATOM_PPLL1;
+ else if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL2)
+ params.ucPpll = ATOM_PPLL2;
+ else
+ BREAK_TO_DEBUGGER(); /* Unexpected PLL value!! */
+
+ if (EXEC_BIOS_CMD_TABLE(EnableSpreadSpectrumOnPPLL, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result enable_spread_spectrum_on_ppll_v2(
+ struct bios_parser *bp,
+ struct bp_spread_spectrum_parameters *bp_params,
+ bool enable)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 params;
+
+ memset(&params, 0, sizeof(params));
+
+ if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL1)
+ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V2_P1PLL;
+ else if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL2)
+ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V2_P2PLL;
+ else
+ BREAK_TO_DEBUGGER(); /* Unexpected PLL value!! */
+
+ if ((enable == true) && (bp_params->percentage > 0)) {
+ params.ucEnable = ATOM_ENABLE;
+
+ params.usSpreadSpectrumPercentage =
+ cpu_to_le16((uint16_t)(bp_params->percentage));
+ params.usSpreadSpectrumStep =
+ cpu_to_le16((uint16_t)(bp_params->ds.ds_frac_size));
+
+ if (bp_params->flags.EXTERNAL_SS)
+ params.ucSpreadSpectrumType |=
+ ATOM_PPLL_SS_TYPE_V2_EXT_SPREAD;
+
+ if (bp_params->flags.CENTER_SPREAD)
+ params.ucSpreadSpectrumType |=
+ ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD;
+
+ /* Both amounts need to be left shifted first before bit
+ * comparison. Otherwise, the result will always be zero here
+ */
+ params.usSpreadSpectrumAmount = cpu_to_le16((uint16_t)(
+ ((bp_params->ds.feedback_amount <<
+ ATOM_PPLL_SS_AMOUNT_V2_FBDIV_SHIFT) &
+ ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK) |
+ ((bp_params->ds.nfrac_amount <<
+ ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
+ ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK)));
+ } else
+ params.ucEnable = ATOM_DISABLE;
+
+ if (EXEC_BIOS_CMD_TABLE(EnableSpreadSpectrumOnPPLL, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result enable_spread_spectrum_on_ppll_v3(
+ struct bios_parser *bp,
+ struct bp_spread_spectrum_parameters *bp_params,
+ bool enable)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 params;
+
+ memset(&params, 0, sizeof(params));
+
+ switch (bp_params->pll_id) {
+ case CLOCK_SOURCE_ID_PLL0:
+ /* ATOM_PPLL_SS_TYPE_V3_P0PLL; this is pixel clock only,
+ * not for SI display clock.
+ */
+ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_DCPLL;
+ break;
+ case CLOCK_SOURCE_ID_PLL1:
+ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_P1PLL;
+ break;
+
+ case CLOCK_SOURCE_ID_PLL2:
+ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_P2PLL;
+ break;
+
+ case CLOCK_SOURCE_ID_DCPLL:
+ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_DCPLL;
+ break;
+
+ default:
+ BREAK_TO_DEBUGGER();
+ /* Unexpected PLL value!! */
+ return result;
+ }
+
+ if (enable == true) {
+ params.ucEnable = ATOM_ENABLE;
+
+ params.usSpreadSpectrumAmountFrac =
+ cpu_to_le16((uint16_t)(bp_params->ds_frac_amount));
+ params.usSpreadSpectrumStep =
+ cpu_to_le16((uint16_t)(bp_params->ds.ds_frac_size));
+
+ if (bp_params->flags.EXTERNAL_SS)
+ params.ucSpreadSpectrumType |=
+ ATOM_PPLL_SS_TYPE_V3_EXT_SPREAD;
+ if (bp_params->flags.CENTER_SPREAD)
+ params.ucSpreadSpectrumType |=
+ ATOM_PPLL_SS_TYPE_V3_CENTRE_SPREAD;
+
+ /* Both amounts need to be left shifted first before bit
+ * comparison. Otherwise, the result will always be zero here
+ */
+ params.usSpreadSpectrumAmount = cpu_to_le16((uint16_t)(
+ ((bp_params->ds.feedback_amount <<
+ ATOM_PPLL_SS_AMOUNT_V3_FBDIV_SHIFT) &
+ ATOM_PPLL_SS_AMOUNT_V3_FBDIV_MASK) |
+ ((bp_params->ds.nfrac_amount <<
+ ATOM_PPLL_SS_AMOUNT_V3_NFRAC_SHIFT) &
+ ATOM_PPLL_SS_AMOUNT_V3_NFRAC_MASK)));
+ } else
+ params.ucEnable = ATOM_DISABLE;
+
+ if (EXEC_BIOS_CMD_TABLE(EnableSpreadSpectrumOnPPLL, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+/*******************************************************************************
+ ********************************************************************************
+ **
+ ** ADJUST DISPLAY PLL
+ **
+ ********************************************************************************
+ *******************************************************************************/
+
+static enum bp_result adjust_display_pll_v2(
+ struct bios_parser *bp,
+ struct bp_adjust_pixel_clock_parameters *bp_params);
+static enum bp_result adjust_display_pll_v3(
+ struct bios_parser *bp,
+ struct bp_adjust_pixel_clock_parameters *bp_params);
+
+static void init_adjust_display_pll(struct bios_parser *bp)
+{
+ switch (BIOS_CMD_TABLE_PARA_REVISION(AdjustDisplayPll)) {
+ case 2:
+ bp->cmd_tbl.adjust_display_pll = adjust_display_pll_v2;
+ break;
+ case 3:
+ bp->cmd_tbl.adjust_display_pll = adjust_display_pll_v3;
+ break;
+ default:
+ bp->cmd_tbl.adjust_display_pll = NULL;
+ break;
+ }
+}
+
+static enum bp_result adjust_display_pll_v2(
+ struct bios_parser *bp,
+ struct bp_adjust_pixel_clock_parameters *bp_params)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ ADJUST_DISPLAY_PLL_PS_ALLOCATION params = { 0 };
+
+ /* We need to convert from KHz units into 10KHz units and then convert
+ * output pixel clock back 10KHz-->KHz */
+ uint32_t pixel_clock_10KHz_in = bp_params->pixel_clock / 10;
+
+ params.usPixelClock = cpu_to_le16((uint16_t)(pixel_clock_10KHz_in));
+ params.ucTransmitterID =
+ bp->cmd_helper->encoder_id_to_atom(
+ dal_graphics_object_id_get_encoder_id(
+ bp_params->encoder_object_id));
+ params.ucEncodeMode =
+ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
+ bp_params->signal_type, false);
+ return result;
+}
+
+static enum bp_result adjust_display_pll_v3(
+ struct bios_parser *bp,
+ struct bp_adjust_pixel_clock_parameters *bp_params)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 params;
+ uint32_t pixel_clk_10_kHz_in = bp_params->pixel_clock / 10;
+
+ memset(&params, 0, sizeof(params));
+
+ /* We need to convert from KHz units into 10KHz units and then convert
+ * output pixel clock back 10KHz-->KHz */
+ params.sInput.usPixelClock = cpu_to_le16((uint16_t)pixel_clk_10_kHz_in);
+ params.sInput.ucTransmitterID =
+ bp->cmd_helper->encoder_id_to_atom(
+ dal_graphics_object_id_get_encoder_id(
+ bp_params->encoder_object_id));
+ params.sInput.ucEncodeMode =
+ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
+ bp_params->signal_type, false);
+
+ if (bp_params->ss_enable == true)
+ params.sInput.ucDispPllConfig |= DISPPLL_CONFIG_SS_ENABLE;
+
+ if (bp_params->signal_type == SIGNAL_TYPE_DVI_DUAL_LINK)
+ params.sInput.ucDispPllConfig |= DISPPLL_CONFIG_DUAL_LINK;
+
+ if (EXEC_BIOS_CMD_TABLE(AdjustDisplayPll, params)) {
+ /* Convert output pixel clock back 10KHz-->KHz: multiply
+ * original pixel clock in KHz by ratio
+ * [output pxlClk/input pxlClk] */
+ uint64_t pixel_clk_10_khz_out =
+ (uint64_t)le32_to_cpu(params.sOutput.ulDispPllFreq);
+ uint64_t pixel_clk = (uint64_t)bp_params->pixel_clock;
+
+ if (pixel_clk_10_kHz_in != 0) {
+ bp_params->adjusted_pixel_clock =
+ div_u64(pixel_clk * pixel_clk_10_khz_out,
+ pixel_clk_10_kHz_in);
+ } else {
+ bp_params->adjusted_pixel_clock = 0;
+ BREAK_TO_DEBUGGER();
+ }
+
+ bp_params->reference_divider = params.sOutput.ucRefDiv;
+ bp_params->pixel_clock_post_divider = params.sOutput.ucPostDiv;
+
+ result = BP_RESULT_OK;
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ ********************************************************************************
+ **
+ ** DAC ENCODER CONTROL
+ **
+ ********************************************************************************
+ *******************************************************************************/
+
+static enum bp_result dac1_encoder_control_v1(
+ struct bios_parser *bp,
+ bool enable,
+ uint32_t pixel_clock,
+ uint8_t dac_standard);
+static enum bp_result dac2_encoder_control_v1(
+ struct bios_parser *bp,
+ bool enable,
+ uint32_t pixel_clock,
+ uint8_t dac_standard);
+
+static void init_dac_encoder_control(struct bios_parser *bp)
+{
+ switch (BIOS_CMD_TABLE_PARA_REVISION(DAC1EncoderControl)) {
+ case 1:
+ bp->cmd_tbl.dac1_encoder_control = dac1_encoder_control_v1;
+ break;
+ default:
+ bp->cmd_tbl.dac1_encoder_control = NULL;
+ break;
+ }
+ switch (BIOS_CMD_TABLE_PARA_REVISION(DAC2EncoderControl)) {
+ case 1:
+ bp->cmd_tbl.dac2_encoder_control = dac2_encoder_control_v1;
+ break;
+ default:
+ bp->cmd_tbl.dac2_encoder_control = NULL;
+ break;
+ }
+}
+
+static void dac_encoder_control_prepare_params(
+ DAC_ENCODER_CONTROL_PS_ALLOCATION *params,
+ bool enable,
+ uint32_t pixel_clock,
+ uint8_t dac_standard)
+{
+ params->ucDacStandard = dac_standard;
+ if (enable)
+ params->ucAction = ATOM_ENABLE;
+ else
+ params->ucAction = ATOM_DISABLE;
+
+ /* We need to convert from KHz units into 10KHz units
+ * it looks as if the TvControl do not care about pixel clock
+ */
+ params->usPixelClock = cpu_to_le16((uint16_t)(pixel_clock / 10));
+}
+
+static enum bp_result dac1_encoder_control_v1(
+ struct bios_parser *bp,
+ bool enable,
+ uint32_t pixel_clock,
+ uint8_t dac_standard)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DAC_ENCODER_CONTROL_PS_ALLOCATION params;
+
+ dac_encoder_control_prepare_params(
+ &params,
+ enable,
+ pixel_clock,
+ dac_standard);
+
+ if (EXEC_BIOS_CMD_TABLE(DAC1EncoderControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result dac2_encoder_control_v1(
+ struct bios_parser *bp,
+ bool enable,
+ uint32_t pixel_clock,
+ uint8_t dac_standard)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DAC_ENCODER_CONTROL_PS_ALLOCATION params;
+
+ dac_encoder_control_prepare_params(
+ &params,
+ enable,
+ pixel_clock,
+ dac_standard);
+
+ if (EXEC_BIOS_CMD_TABLE(DAC2EncoderControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+/*******************************************************************************
+ ********************************************************************************
+ **
+ ** DAC OUTPUT CONTROL
+ **
+ ********************************************************************************
+ *******************************************************************************/
+static enum bp_result dac1_output_control_v1(
+ struct bios_parser *bp,
+ bool enable);
+static enum bp_result dac2_output_control_v1(
+ struct bios_parser *bp,
+ bool enable);
+
+static void init_dac_output_control(struct bios_parser *bp)
+{
+ switch (BIOS_CMD_TABLE_PARA_REVISION(DAC1OutputControl)) {
+ case 1:
+ bp->cmd_tbl.dac1_output_control = dac1_output_control_v1;
+ break;
+ default:
+ bp->cmd_tbl.dac1_output_control = NULL;
+ break;
+ }
+ switch (BIOS_CMD_TABLE_PARA_REVISION(DAC2OutputControl)) {
+ case 1:
+ bp->cmd_tbl.dac2_output_control = dac2_output_control_v1;
+ break;
+ default:
+ bp->cmd_tbl.dac2_output_control = NULL;
+ break;
+ }
+}
+
+static enum bp_result dac1_output_control_v1(
+ struct bios_parser *bp, bool enable)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION params;
+
+ if (enable)
+ params.ucAction = ATOM_ENABLE;
+ else
+ params.ucAction = ATOM_DISABLE;
+
+ if (EXEC_BIOS_CMD_TABLE(DAC1OutputControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result dac2_output_control_v1(
+ struct bios_parser *bp, bool enable)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION params;
+
+ if (enable)
+ params.ucAction = ATOM_ENABLE;
+ else
+ params.ucAction = ATOM_DISABLE;
+
+ if (EXEC_BIOS_CMD_TABLE(DAC2OutputControl, params))
+ 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 enum bp_result set_crtc_timing_v1(
+ 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);
+ if (dtd_version > 2)
+ 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;
+ }
+ else
+ switch (BIOS_CMD_TABLE_PARA_REVISION(SetCRTC_Timing)) {
+ case 1:
+ bp->cmd_tbl.set_crtc_timing = set_crtc_timing_v1;
+ break;
+ default:
+ bp->cmd_tbl.set_crtc_timing = NULL;
+ break;
+ }
+}
+
+static enum bp_result set_crtc_timing_v1(
+ struct bios_parser *bp,
+ struct bp_hw_crtc_timing_parameters *bp_params)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION params = {0};
+ uint8_t atom_controller_id;
+
+ if (bp->cmd_helper->controller_id_to_atom(
+ bp_params->controller_id, &atom_controller_id))
+ params.ucCRTC = atom_controller_id;
+
+ params.usH_Total = cpu_to_le16((uint16_t)(bp_params->h_total));
+ params.usH_Disp = cpu_to_le16((uint16_t)(bp_params->h_addressable));
+ params.usH_SyncStart = cpu_to_le16((uint16_t)(bp_params->h_sync_start));
+ params.usH_SyncWidth = cpu_to_le16((uint16_t)(bp_params->h_sync_width));
+ params.usV_Total = cpu_to_le16((uint16_t)(bp_params->v_total));
+ params.usV_Disp = cpu_to_le16((uint16_t)(bp_params->v_addressable));
+ params.usV_SyncStart =
+ cpu_to_le16((uint16_t)(bp_params->v_sync_start));
+ params.usV_SyncWidth =
+ cpu_to_le16((uint16_t)(bp_params->v_sync_width));
+
+ /* VBIOS does not expect any value except zero into this call, for
+ * underscan use another entry ProgramOverscan call but when mode
+ * 1776x1000 with the overscan 72x44 .e.i. 1920x1080 @30 DAL2 is ok,
+ * but when same ,but 60 Hz there is corruption
+ * DAL1 does not allow the mode 1776x1000@60
+ */
+ params.ucOverscanRight = (uint8_t)bp_params->h_overscan_right;
+ params.ucOverscanLeft = (uint8_t)bp_params->h_overscan_left;
+ params.ucOverscanBottom = (uint8_t)bp_params->v_overscan_bottom;
+ params.ucOverscanTop = (uint8_t)bp_params->v_overscan_top;
+
+ if (0 == bp_params->flags.HSYNC_POSITIVE_POLARITY)
+ params.susModeMiscInfo.usAccess =
+ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_HSYNC_POLARITY);
+
+ if (0 == bp_params->flags.VSYNC_POSITIVE_POLARITY)
+ params.susModeMiscInfo.usAccess =
+ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_VSYNC_POLARITY);
+
+ if (bp_params->flags.INTERLACE) {
+ params.susModeMiscInfo.usAccess =
+ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_INTERLACE);
+
+ /* original DAL code has this condition to apply tis 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.usV_SyncStart =
+ cpu_to_le16((uint16_t)(bp_params->v_sync_start + 1));
+ }
+
+ if (bp_params->flags.HORZ_COUNT_BY_TWO)
+ params.susModeMiscInfo.usAccess =
+ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_DOUBLE_CLOCK_MODE);
+
+ if (EXEC_BIOS_CMD_TABLE(SetCRTC_Timing, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+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;
+ 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.ucCRTC = atom_controller_id;
+
+ /* bios usH_Size wants h addressable size */
+ params.usH_Size = cpu_to_le16((uint16_t)bp_params->h_addressable);
+ /* bios usH_Blanking_Time wants borders included in blanking */
+ params.usH_Blanking_Time =
+ cpu_to_le16((uint16_t)(bp_params->h_total - bp_params->h_addressable));
+ /* bios usV_Size wants v addressable size */
+ params.usV_Size = cpu_to_le16((uint16_t)bp_params->v_addressable);
+ /* bios usV_Blanking_Time wants borders included in blanking */
+ params.usV_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.usH_SyncOffset =
+ cpu_to_le16((uint16_t)(bp_params->h_sync_start - bp_params->h_addressable));
+ params.usH_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.usV_SyncOffset =
+ cpu_to_le16((uint16_t)(bp_params->v_sync_start - bp_params->v_addressable));
+ params.usV_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 (0 == bp_params->flags.HSYNC_POSITIVE_POLARITY)
+ params.susModeMiscInfo.usAccess =
+ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_HSYNC_POLARITY);
+
+ if (0 == bp_params->flags.VSYNC_POSITIVE_POLARITY)
+ params.susModeMiscInfo.usAccess =
+ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_VSYNC_POLARITY);
+
+ if (bp_params->flags.INTERLACE) {
+ params.susModeMiscInfo.usAccess =
+ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | 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.usV_SyncOffset =
+ cpu_to_le16(le16_to_cpu(params.usV_SyncOffset) + 1);
+
+ }
+ }
+
+ if (bp_params->flags.HORZ_COUNT_BY_TWO)
+ params.susModeMiscInfo.usAccess =
+ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | 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_v2(
+ struct bios_parser *bp,
+ struct bp_crtc_source_select *bp_params);
+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 2:
+ bp->cmd_tbl.select_crtc_source = select_crtc_source_v2;
+ break;
+ 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_v2(
+ struct bios_parser *bp,
+ struct bp_crtc_source_select *bp_params)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+ SELECT_CRTC_SOURCE_PARAMETERS_V2 params;
+ uint8_t atom_controller_id;
+ uint32_t atom_engine_id;
+ enum signal_type s = bp_params->signal;
+
+ memset(&params, 0, sizeof(params));
+
+ /* set controller id */
+ if (bp->cmd_helper->controller_id_to_atom(
+ bp_params->controller_id, &atom_controller_id))
+ params.ucCRTC = atom_controller_id;
+ else
+ return BP_RESULT_FAILURE;
+
+ /* set encoder id */
+ if (bp->cmd_helper->engine_bp_to_atom(
+ bp_params->engine_id, &atom_engine_id))
+ params.ucEncoderID = (uint8_t)atom_engine_id;
+ else
+ return BP_RESULT_FAILURE;
+
+ if (SIGNAL_TYPE_EDP == s ||
+ (SIGNAL_TYPE_DISPLAY_PORT == s &&
+ SIGNAL_TYPE_LVDS == bp_params->sink_signal))
+ s = SIGNAL_TYPE_LVDS;
+
+ params.ucEncodeMode =
+ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
+ s, bp_params->enable_dp_audio);
+
+ if (EXEC_BIOS_CMD_TABLE(SelectCRTC_Source, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result select_crtc_source_v3(
+ struct bios_parser *bp,
+ struct bp_crtc_source_select *bp_params)
+{
+ bool result = BP_RESULT_FAILURE;
+ SELECT_CRTC_SOURCE_PARAMETERS_V3 params;
+ uint8_t atom_controller_id;
+ uint32_t atom_engine_id;
+ enum signal_type s = bp_params->signal;
+
+ memset(&params, 0, sizeof(params));
+
+ if (bp->cmd_helper->controller_id_to_atom(bp_params->controller_id,
+ &atom_controller_id))
+ params.ucCRTC = atom_controller_id;
+ else
+ return result;
+
+ if (bp->cmd_helper->engine_bp_to_atom(bp_params->engine_id,
+ &atom_engine_id))
+ params.ucEncoderID = (uint8_t)atom_engine_id;
+ else
+ return result;
+
+ if (SIGNAL_TYPE_EDP == s ||
+ (SIGNAL_TYPE_DISPLAY_PORT == s &&
+ SIGNAL_TYPE_LVDS == bp_params->sink_signal))
+ s = SIGNAL_TYPE_LVDS;
+
+ params.ucEncodeMode =
+ bp->cmd_helper->encoder_mode_bp_to_atom(
+ s, bp_params->enable_dp_audio);
+ /* Needed for VBIOS Random Spatial Dithering feature */
+ params.ucDstBpc = (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;
+ ENABLE_CRTC_PARAMETERS params = {0};
+ uint8_t id;
+
+ if (bp->cmd_helper->controller_id_to_atom(controller_id, &id))
+ params.ucCRTC = id;
+ else
+ return BP_RESULT_BADINPUT;
+
+ if (enable)
+ params.ucEnable = ATOM_ENABLE;
+ else
+ params.ucEnable = ATOM_DISABLE;
+
+ if (EXEC_BIOS_CMD_TABLE(EnableCRTC, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+/*******************************************************************************
+ ********************************************************************************
+ **
+ ** ENABLE CRTC MEM REQ
+ **
+ ********************************************************************************
+ *******************************************************************************/
+
+static enum bp_result enable_crtc_mem_req_v1(
+ struct bios_parser *bp,
+ enum controller_id controller_id,
+ bool enable);
+
+static void init_enable_crtc_mem_req(struct bios_parser *bp)
+{
+ switch (BIOS_CMD_TABLE_PARA_REVISION(EnableCRTCMemReq)) {
+ case 1:
+ bp->cmd_tbl.enable_crtc_mem_req = enable_crtc_mem_req_v1;
+ break;
+ default:
+ bp->cmd_tbl.enable_crtc_mem_req = NULL;
+ break;
+ }
+}
+
+static enum bp_result enable_crtc_mem_req_v1(
+ struct bios_parser *bp,
+ enum controller_id controller_id,
+ bool enable)
+{
+ bool result = BP_RESULT_BADINPUT;
+ ENABLE_CRTC_PARAMETERS params = {0};
+ uint8_t id;
+
+ if (bp->cmd_helper->controller_id_to_atom(controller_id, &id)) {
+ params.ucCRTC = id;
+
+ if (enable)
+ params.ucEnable = ATOM_ENABLE;
+ else
+ params.ucEnable = ATOM_DISABLE;
+
+ if (EXEC_BIOS_CMD_TABLE(EnableCRTCMemReq, params))
+ result = BP_RESULT_OK;
+ else
+ result = BP_RESULT_FAILURE;
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ ********************************************************************************
+ **
+ ** DISPLAY PLL
+ **
+ ********************************************************************************
+ *******************************************************************************/
+
+static enum bp_result program_clock_v5(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params);
+static enum bp_result program_clock_v6(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params);
+
+static void init_program_clock(struct bios_parser *bp)
+{
+ switch (BIOS_CMD_TABLE_PARA_REVISION(SetPixelClock)) {
+ case 5:
+ bp->cmd_tbl.program_clock = program_clock_v5;
+ break;
+ case 6:
+ bp->cmd_tbl.program_clock = program_clock_v6;
+ break;
+ default:
+ bp->cmd_tbl.program_clock = NULL;
+ break;
+ }
+}
+
+static enum bp_result program_clock_v5(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+
+ SET_PIXEL_CLOCK_PS_ALLOCATION_V5 params;
+ uint32_t atom_pll_id;
+
+ memset(&params, 0, sizeof(params));
+ if (!bp->cmd_helper->clock_source_id_to_atom(
+ bp_params->pll_id, &atom_pll_id)) {
+ BREAK_TO_DEBUGGER(); /* Invalid Inpute!! */
+ return BP_RESULT_BADINPUT;
+ }
+
+ /* We need to convert from KHz units into 10KHz units */
+ params.sPCLKInput.ucPpll = (uint8_t) atom_pll_id;
+ params.sPCLKInput.usPixelClock =
+ cpu_to_le16((uint16_t) (bp_params->target_pixel_clock / 10));
+ params.sPCLKInput.ucCRTC = (uint8_t) ATOM_CRTC_INVALID;
+
+ if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC)
+ params.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
+
+ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+static enum bp_result program_clock_v6(
+ struct bios_parser *bp,
+ struct bp_pixel_clock_parameters *bp_params)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+
+ SET_PIXEL_CLOCK_PS_ALLOCATION_V6 params;
+ uint32_t atom_pll_id;
+
+ memset(&params, 0, sizeof(params));
+
+ if (!bp->cmd_helper->clock_source_id_to_atom(
+ bp_params->pll_id, &atom_pll_id)) {
+ BREAK_TO_DEBUGGER(); /*Invalid Input!!*/
+ return BP_RESULT_BADINPUT;
+ }
+
+ /* We need to convert from KHz units into 10KHz units */
+ params.sPCLKInput.ucPpll = (uint8_t)atom_pll_id;
+ params.sPCLKInput.ulDispEngClkFreq =
+ cpu_to_le32(bp_params->target_pixel_clock / 10);
+
+ if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC)
+ params.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
+
+ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, params)) {
+ /* True display clock is returned by VBIOS if DFS bypass
+ * is enabled. */
+ bp_params->dfs_bypass_display_clock =
+ (uint32_t)(le32_to_cpu(params.sPCLKInput.ulDispEngClkFreq) * 10);
+ result = BP_RESULT_OK;
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ ********************************************************************************
+ **
+ ** 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)
+{
+ enum bp_result result = BP_RESULT_FAILURE;
+
+ /* we need use _PS_Alloc struct */
+ EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 params;
+ EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 *cntl_params;
+ struct graphics_object_id encoder;
+ bool is_input_signal_dp = false;
+
+ memset(&params, 0, sizeof(params));
+
+ cntl_params = &params.sExtEncoder;
+
+ encoder = cntl->encoder_id;
+
+ /* check if encoder supports external encoder control table */
+ switch (dal_graphics_object_id_get_encoder_id(encoder)) {
+ case ENCODER_ID_EXTERNAL_NUTMEG:
+ case ENCODER_ID_EXTERNAL_TRAVIS:
+ is_input_signal_dp = true;
+ break;
+
+ default:
+ BREAK_TO_DEBUGGER();
+ return BP_RESULT_BADINPUT;
+ }
+
+ /* Fill information based on the action
+ *
+ * Bit[6:4]: indicate external encoder, applied to all functions.
+ * =0: external encoder1, mapped to external encoder enum id1
+ * =1: external encoder2, mapped to external encoder enum id2
+ *
+ * enum ObjectEnumId
+ * {
+ * EnumId_Unknown = 0,
+ * EnumId_1,
+ * EnumId_2,
+ * };
+ */
+ cntl_params->ucConfig = (uint8_t)((encoder.enum_id - 1) << 4);
+
+ switch (cntl->action) {
+ case EXTERNAL_ENCODER_CONTROL_INIT:
+ /* output display connector type. Only valid in encoder
+ * initialization */
+ cntl_params->usConnectorId =
+ cpu_to_le16((uint16_t)cntl->connector_obj_id.id);
+ break;
+ case EXTERNAL_ENCODER_CONTROL_SETUP:
+ /* EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 pixel clock unit in
+ * 10KHz
+ * output display device pixel clock frequency in unit of 10KHz.
+ * Only valid in setup and enableoutput
+ */
+ cntl_params->usPixelClock =
+ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
+ /* Indicate display output signal type drive by external
+ * encoder, only valid in setup and enableoutput */
+ cntl_params->ucEncoderMode =
+ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
+ cntl->signal, false);
+
+ if (is_input_signal_dp) {
+ /* Bit[0]: indicate link rate, =1: 2.7Ghz, =0: 1.62Ghz,
+ * only valid in encoder setup with DP mode. */
+ if (LINK_RATE_HIGH == cntl->link_rate)
+ cntl_params->ucConfig |= 1;
+ /* output color depth Indicate encoder data bpc format
+ * in DP mode, only valid in encoder setup in DP mode.
+ */
+ cntl_params->ucBitPerColor =
+ (uint8_t)(cntl->color_depth);
+ }
+ /* Indicate how many lanes used by external encoder, only valid
+ * in encoder setup and enableoutput. */
+ cntl_params->ucLaneNum = (uint8_t)(cntl->lanes_number);
+ break;
+ case EXTERNAL_ENCODER_CONTROL_ENABLE:
+ cntl_params->usPixelClock =
+ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
+ cntl_params->ucEncoderMode =
+ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
+ cntl->signal, false);
+ cntl_params->ucLaneNum = (uint8_t)cntl->lanes_number;
+ break;
+ default:
+ break;
+ }
+
+ cntl_params->ucAction = (uint8_t)cntl->action;
+
+ if (EXEC_BIOS_CMD_TABLE(ExternalEncoderControl, params))
+ result = BP_RESULT_OK;
+
+ return result;
+}
+
+/*******************************************************************************
+ ********************************************************************************
+ **
+ ** 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;
+
+ ENABLE_DISP_POWER_GATING_PS_ALLOCATION params = {0};
+ uint8_t atom_crtc_id;
+
+ if (bp->cmd_helper->controller_id_to_atom(crtc_id, &atom_crtc_id))
+ params.ucDispPipeId = atom_crtc_id;
+ else
+ return BP_RESULT_BADINPUT;
+
+ params.ucEnable =
+ bp->cmd_helper->disp_power_gating_action_to_atom(action);
+
+ if (EXEC_BIOS_CMD_TABLE(EnableDispPowerGating, params))
+ 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;
+
+ 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(&params, 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.asParam.ucDCEClkSrc = atom_pll_id;
+ params.asParam.ucDCEClkType = atom_clock_type;
+
+ if (bp_params->clock_type == DCECLOCK_TYPE_DPREFCLK) {
+ if (bp_params->flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK)
+ params.asParam.ucDCEClkFlag |= DCE_CLOCK_FLAG_PLL_REFCLK_SRC_GENLK;
+
+ if (bp_params->flags.USE_PCIE_AS_SOURCE_FOR_DPREFCLK)
+ params.asParam.ucDCEClkFlag |= DCE_CLOCK_FLAG_PLL_REFCLK_SRC_PCIE;
+
+ if (bp_params->flags.USE_XTALIN_AS_SOURCE_FOR_DPREFCLK)
+ params.asParam.ucDCEClkFlag |= DCE_CLOCK_FLAG_PLL_REFCLK_SRC_XTALIN;
+
+ if (bp_params->flags.USE_GENERICA_AS_SOURCE_FOR_DPREFCLK)
+ params.asParam.ucDCEClkFlag |= 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.asParam.ulDCEClkFreq = cpu_to_le32(bp_params->target_clock_frequency / 10);
+
+ if (EXEC_BIOS_CMD_TABLE(SetDCEClock, params)) {
+ /* Convert from 10KHz units back to KHz */
+ bp_params->target_clock_frequency = le32_to_cpu(params.asParam.ulDCEClkFreq) * 10;
+ result = BP_RESULT_OK;
+ }
+
+ return result;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.h b/drivers/gpu/drm/amd/display/dc/bios/command_table.h
new file mode 100644
index 000000000000..94f3d43a7471
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.h
@@ -0,0 +1,102 @@
+/*
+ * 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_H__
+#define __DAL_COMMAND_TABLE_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);
+};
+
+void dal_bios_parser_init_cmd_tbl(struct bios_parser *bp);
+
+#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 000000000000..ba68693758a7
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
@@ -0,0 +1,812 @@
+/*
+ * 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 "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), \
+ &params) == 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_BIOS,\
+ "%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_BIOS,\
+ "%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(&params, 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(&params, 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_BIOS,
+ "%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 000000000000..59061b806df5
--- /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_helper.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c
new file mode 100644
index 000000000000..2979358c6a55
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c
@@ -0,0 +1,290 @@
+/*
+ * 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_helper.h"
+
+bool dal_bios_parser_init_cmd_tbl_helper(
+ const struct command_table_helper **h,
+ enum dce_version dce)
+{
+ switch (dce) {
+ case DCE_VERSION_8_0:
+ case DCE_VERSION_8_1:
+ case DCE_VERSION_8_3:
+ *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_table();
+ return true;
+
+ default:
+ /* Unsupported DCE */
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+}
+
+/* real implementations */
+
+bool dal_cmd_table_helper_controller_id_to_atom(
+ 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;
+ 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_atom(
+ 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_atom(
+ 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;
+ }
+}
+
+void dal_cmd_table_helper_assign_control_parameter(
+ const struct command_table_helper *h,
+ struct bp_encoder_control *control,
+ DIG_ENCODER_CONTROL_PARAMETERS_V2 *ctrl_param)
+{
+ /* there are three transmitter blocks, each one has two links 4-lanes
+ * each, A+B, C+D, E+F, Uniphy A, C and E are enumerated as link 0 in
+ * each transmitter block B, D and F as link 1, third transmitter block
+ * has non splitable links (UniphyE and UniphyF can not be configured
+ * separately to drive two different streams)
+ */
+ if ((control->transmitter == TRANSMITTER_UNIPHY_B) ||
+ (control->transmitter == TRANSMITTER_UNIPHY_D) ||
+ (control->transmitter == TRANSMITTER_UNIPHY_F)) {
+ /* Bit2: Link Select
+ * =0: PHY linkA/C/E
+ * =1: PHY linkB/D/F
+ */
+ ctrl_param->acConfig.ucLinkSel = 1;
+ }
+
+ /* Bit[4:3]: Transmitter Selection
+ * =00: Digital Transmitter1 ( UNIPHY linkAB )
+ * =01: Digital Transmitter2 ( UNIPHY linkCD )
+ * =02: Digital Transmitter3 ( UNIPHY linkEF )
+ * =03: Reserved
+ */
+ ctrl_param->acConfig.ucTransmitterSel =
+ (uint8_t)(h->transmitter_bp_to_atom(control->transmitter));
+
+ /* We need to convert from KHz units into 10KHz units */
+ ctrl_param->ucAction = h->encoder_action_to_atom(control->action);
+ ctrl_param->usPixelClock = cpu_to_le16((uint16_t)(control->pixel_clock / 10));
+ ctrl_param->ucEncoderMode =
+ (uint8_t)(h->encoder_mode_bp_to_atom(
+ control->signal, control->enable_dp_audio));
+ ctrl_param->ucLaneNum = (uint8_t)(control->lanes_number);
+}
+
+bool dal_cmd_table_helper_clock_source_id_to_ref_clk_src(
+ 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;
+ 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_atom(
+ 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_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_helper.h b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h
new file mode 100644
index 000000000000..1fab634b66be
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h
@@ -0,0 +1,90 @@
+/*
+ * 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_HELPER_H__
+#define __DAL_COMMAND_TABLE_HELPER_H__
+
+#include "dce80/command_table_helper_dce80.h"
+#include "dce110/command_table_helper_dce110.h"
+#include "dce112/command_table_helper_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);
+ void (*assign_control_parameter)(
+ const struct command_table_helper *h,
+ struct bp_encoder_control *control,
+ DIG_ENCODER_CONTROL_PARAMETERS_V2 *ctrl_param);
+ 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_helper(const struct command_table_helper **h,
+ enum dce_version dce);
+
+bool dal_cmd_table_helper_controller_id_to_atom(
+ enum controller_id id,
+ uint8_t *atom_id);
+
+uint32_t dal_cmd_table_helper_encoder_mode_bp_to_atom(
+ enum signal_type s,
+ bool enable_dp_audio);
+
+void dal_cmd_table_helper_assign_control_parameter(
+ const struct command_table_helper *h,
+ struct bp_encoder_control *control,
+DIG_ENCODER_CONTROL_PARAMETERS_V2 *ctrl_param);
+
+bool dal_cmd_table_helper_clock_source_id_to_ref_clk_src(
+ enum clock_source_id id,
+ uint32_t *ref_clk_src_id);
+
+uint8_t dal_cmd_table_helper_transmitter_bp_to_atom(
+ enum transmitter t);
+
+uint8_t dal_cmd_table_helper_encoder_id_to_atom(
+ enum encoder_id id);
+#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 000000000000..9a4d30dd4969
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
@@ -0,0 +1,265 @@
+/*
+ * 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 "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:
+ case DCE_VERSION_8_1:
+ case DCE_VERSION_8_3:
+ *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_DCN1_0)
+ case DCN_VERSION_1_0:
+ *h = dal_cmd_tbl_helper_dce112_get_table2();
+ return true;
+#endif
+
+ case DCE_VERSION_12_0:
+ *h = dal_cmd_tbl_helper_dce112_get_table2();
+ return true;
+
+ 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 000000000000..9f587c91d843
--- /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/dce110/command_table_helper_dce110.c b/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c
new file mode 100644
index 000000000000..ca24154468c7
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c
@@ -0,0 +1,364 @@
+/*
+ * 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_helper.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_V5_DP;
+
+ switch (s) {
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_EDP:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP;
+ break;
+ case SIGNAL_TYPE_LVDS:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_LVDS;
+ break;
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DVI;
+ break;
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_HDMI;
+ break;
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP_MST;
+ break;
+ default:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_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_CONFIG_V5_HPD1_SEL;
+ break;
+ case HPD_SOURCEID2:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD2_SEL;
+ break;
+ case HPD_SOURCEID3:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD3_SEL;
+ break;
+ case HPD_SOURCEID4:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD4_SEL;
+ break;
+ case HPD_SOURCEID5:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD5_SEL;
+ break;
+ case HPD_SOURCEID6:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD6_SEL;
+ break;
+ case HPD_SOURCEID_UNKNOWN:
+ default:
+ atom_hpd_sel = 0;
+ break;
+ }
+ return atom_hpd_sel >> 4;
+}
+
+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_V5__DIGA_SEL;
+ break;
+ case ENGINE_ID_DIGB:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGB_SEL;
+ break;
+ case ENGINE_ID_DIGC:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGC_SEL;
+ break;
+ case ENGINE_ID_DIGD:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGD_SEL;
+ break;
+ case ENGINE_ID_DIGE:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGE_SEL;
+ break;
+ case ENGINE_ID_DIGF:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGF_SEL;
+ break;
+ case ENGINE_ID_DIGG:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__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_V5__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_ID_PLL0:
+ *atom_pll_id = ATOM_PPLL0;
+ break;
+ case CLOCK_SOURCE_ID_PLL1:
+ *atom_pll_id = ATOM_PPLL1;
+ break;
+ case CLOCK_SOURCE_ID_PLL2:
+ *atom_pll_id = ATOM_PPLL2;
+ break;
+ case CLOCK_SOURCE_ID_EXTERNAL:
+ *atom_pll_id = ATOM_PPLL_INVALID;
+ break;
+ case CLOCK_SOURCE_ID_DFS:
+ *atom_pll_id = ATOM_EXT_PLL1;
+ break;
+ case CLOCK_SOURCE_ID_VCE:
+ /* for VCE encoding,
+ * we need to pass in ATOM_PPLL_INVALID
+ */
+ *atom_pll_id = ATOM_PPLL_INVALID;
+ break;
+ case CLOCK_SOURCE_ID_DP_DTO:
+ /* When programming DP DTO PLL ID should be invalid */
+ *atom_pll_id = ATOM_PPLL_INVALID;
+ 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_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;
+}
+
+/* function table */
+static const struct command_table_helper command_table_helper_funcs = {
+ .controller_id_to_atom = dal_cmd_table_helper_controller_id_to_atom,
+ .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,
+ .assign_control_parameter = NULL,
+ .clock_source_id_to_ref_clk_src = NULL,
+ .transmitter_bp_to_atom = NULL,
+ .encoder_id_to_atom = dal_cmd_table_helper_encoder_id_to_atom,
+ .encoder_mode_bp_to_atom = dal_cmd_table_helper_encoder_mode_bp_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_dce110_get_table(void)
+{
+ return &command_table_helper_funcs;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.h b/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.h
new file mode 100644
index 000000000000..eb60c2ead992
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.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_HELPER_DCE110_H__
+#define __DAL_COMMAND_TABLE_HELPER_DCE110_H__
+
+struct command_table_helper;
+
+/* Initialize command table helper functions */
+const struct command_table_helper *dal_cmd_tbl_helper_dce110_get_table(void);
+
+#endif /* __DAL_COMMAND_TABLE_HELPER_DCE110_H__ */
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 000000000000..0237ae575068
--- /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(void)
+{
+ 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 000000000000..abf28a06f5bc
--- /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__ */
diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c
new file mode 100644
index 000000000000..452034f83e4c
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_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_helper.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_atom,
+ .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,
+ .assign_control_parameter = NULL,
+ .clock_source_id_to_ref_clk_src = NULL,
+ .transmitter_bp_to_atom = NULL,
+ .encoder_id_to_atom = dal_cmd_table_helper_encoder_id_to_atom,
+ .encoder_mode_bp_to_atom = dal_cmd_table_helper_encoder_mode_bp_to_atom,
+ .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_table(void)
+{
+ return &command_table_helper_funcs;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.h b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.h
new file mode 100644
index 000000000000..dc3660951355
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_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_HELPER_DCE112_H__
+#define __DAL_COMMAND_TABLE_HELPER_DCE112_H__
+
+struct command_table_helper;
+
+/* Initialize command table helper functions */
+const struct command_table_helper *dal_cmd_tbl_helper_dce112_get_table(void);
+
+#endif /* __DAL_COMMAND_TABLE_HELPER_DCE110_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.c b/drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.c
new file mode 100644
index 000000000000..8b30b558cf1f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.c
@@ -0,0 +1,354 @@
+/*
+ * 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/grph_object_id.h"
+#include "include/grph_object_defs.h"
+#include "include/bios_parser_types.h"
+
+#include "../command_table_helper.h"
+
+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_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 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 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_ID_PLL0:
+ *atom_pll_id = ATOM_PPLL0;
+ break;
+ case CLOCK_SOURCE_ID_PLL1:
+ *atom_pll_id = ATOM_PPLL1;
+ break;
+ case CLOCK_SOURCE_ID_PLL2:
+ *atom_pll_id = ATOM_PPLL2;
+ break;
+ case CLOCK_SOURCE_ID_EXTERNAL:
+ *atom_pll_id = ATOM_PPLL_INVALID;
+ break;
+ case CLOCK_SOURCE_ID_DFS:
+ *atom_pll_id = ATOM_EXT_PLL1;
+ break;
+ case CLOCK_SOURCE_ID_VCE:
+ /* for VCE encoding,
+ * we need to pass in ATOM_PPLL_INVALID
+ */
+ *atom_pll_id = ATOM_PPLL_INVALID;
+ break;
+ case CLOCK_SOURCE_ID_DP_DTO:
+ /* When programming DP DTO PLL ID should be invalid */
+ *atom_pll_id = ATOM_PPLL_INVALID;
+ break;
+ case CLOCK_SOURCE_ID_UNDEFINED:
+ BREAK_TO_DEBUGGER(); /* check when this will happen! */
+ *atom_pll_id = ATOM_PPLL_INVALID;
+ result = false;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+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 signal_type_to_atom_dig_mode(enum signal_type s)
+{
+ uint8_t atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP;
+
+ switch (s) {
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ case SIGNAL_TYPE_EDP:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP;
+ break;
+ case SIGNAL_TYPE_LVDS:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_LVDS;
+ break;
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DVI;
+ break;
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_HDMI;
+ break;
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP_MST;
+ break;
+ default:
+ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DVI;
+ break;
+ }
+
+ return atom_dig_mode;
+}
+
+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_CONFIG_V5_HPD1_SEL;
+ break;
+ case HPD_SOURCEID2:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD2_SEL;
+ break;
+ case HPD_SOURCEID3:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD3_SEL;
+ break;
+ case HPD_SOURCEID4:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD4_SEL;
+ break;
+ case HPD_SOURCEID5:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD5_SEL;
+ break;
+ case HPD_SOURCEID6:
+ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD6_SEL;
+ break;
+ case HPD_SOURCEID_UNKNOWN:
+ default:
+ atom_hpd_sel = 0;
+ break;
+ }
+ return atom_hpd_sel >> 4;
+}
+
+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_V5__DIGA_SEL;
+ break;
+ case ENGINE_ID_DIGB:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGB_SEL;
+ break;
+ case ENGINE_ID_DIGC:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGC_SEL;
+ break;
+ case ENGINE_ID_DIGD:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGD_SEL;
+ break;
+ case ENGINE_ID_DIGE:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGE_SEL;
+ break;
+ case ENGINE_ID_DIGF:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGF_SEL;
+ break;
+ case ENGINE_ID_DIGG:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGG_SEL;
+ break;
+ default:
+ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGA_SEL;
+ break;
+ }
+
+ return atom_dig_encoder_sel;
+}
+
+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 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:
+ BREAK_TO_DEBUGGER(); /* Unhandle action in driver! */
+ break;
+ }
+
+ return atom_pipe_action;
+}
+
+static const struct command_table_helper command_table_helper_funcs = {
+ .controller_id_to_atom = dal_cmd_table_helper_controller_id_to_atom,
+ .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,
+ .assign_control_parameter =
+ dal_cmd_table_helper_assign_control_parameter,
+ .clock_source_id_to_ref_clk_src =
+ dal_cmd_table_helper_clock_source_id_to_ref_clk_src,
+ .transmitter_bp_to_atom = dal_cmd_table_helper_transmitter_bp_to_atom,
+ .encoder_id_to_atom = dal_cmd_table_helper_encoder_id_to_atom,
+ .encoder_mode_bp_to_atom =
+ dal_cmd_table_helper_encoder_mode_bp_to_atom,
+};
+
+const struct command_table_helper *dal_cmd_tbl_helper_dce80_get_table(void)
+{
+ return &command_table_helper_funcs;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.h b/drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.h
new file mode 100644
index 000000000000..e675c359e306
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.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_COMMAND_TABLE_HELPER_DCE80_H__
+#define __DAL_COMMAND_TABLE_HELPER_DCE80_H__
+
+struct command_table_helper;
+
+const struct command_table_helper *dal_cmd_tbl_helper_dce80_get_table(void);
+
+#endif